From 6c952e227f2ac8f299c50223b33a7be69351696e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20D=C5=82ugosz?= Date: Thu, 25 Oct 2012 21:39:10 +0200 Subject: [PATCH 001/107] Empik plugin --- src/calibre/customize/builtins.py | 11 +++ src/calibre/gui2/store/stores/empik_plugin.py | 80 +++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 src/calibre/gui2/store/stores/empik_plugin.py diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py index e665f31b2e..693a9c4a6a 100644 --- a/src/calibre/customize/builtins.py +++ b/src/calibre/customize/builtins.py @@ -1394,6 +1394,16 @@ class StoreEKnigiStore(StoreBase): formats = ['EPUB', 'PDF', 'HTML'] affiliate = True +class StoreEmpikStore(StoreBase): + name = 'Empik' + author = u'Tomasz Długosz' + description = u'Empik to marka o unikalnym dziedzictwie i legendarne miejsce, dawne “okno na świat”. Jest obecna w polskim krajobrazie kulturalnym od 60 lat (wcześniej jako Kluby Międzynarodowej Prasy i Książki).' + actual_plugin = 'calibre.gui2.store.stores.empik_plugin:EmpikStore' + + headquarters = 'PL' + formats = ['EPUB', 'MOBI', 'PDF'] + affiliate = True + class StoreEscapeMagazineStore(StoreBase): name = 'EscapeMagazine' author = u'Tomasz Długosz' @@ -1661,6 +1671,7 @@ plugins += [ StoreEbooksGratuitsStore, StoreEHarlequinStore, StoreEKnigiStore, + StoreEmpikStore, StoreEscapeMagazineStore, StoreFeedbooksStore, StoreFoylesUKStore, diff --git a/src/calibre/gui2/store/stores/empik_plugin.py b/src/calibre/gui2/store/stores/empik_plugin.py new file mode 100644 index 0000000000..da8ca3fe56 --- /dev/null +++ b/src/calibre/gui2/store/stores/empik_plugin.py @@ -0,0 +1,80 @@ +# -*- coding: utf-8 -*- + +from __future__ import (unicode_literals, division, absolute_import, print_function) + +__license__ = 'GPL 3' +__copyright__ = '2011-2012, Tomasz Długosz ' +__docformat__ = 'restructuredtext en' + +import re +import urllib +from contextlib import closing + +from lxml import html + +from PyQt4.Qt import QUrl + +from calibre import browser, url_slash_cleaner +from calibre.gui2 import open_url +from calibre.gui2.store import StorePlugin +from calibre.gui2.store.basic_config import BasicStoreConfig +from calibre.gui2.store.search_result import SearchResult +from calibre.gui2.store.web_store_dialog import WebStoreDialog + +class EmpikStore(BasicStoreConfig, StorePlugin): + + def open(self, parent=None, detail_item=None, external=False): + plain_url = 'http://www.empik.com/ebooki' + url = 'https://ssl.afiliant.com/affskrypt,,2f9de2,,11483,,,?u=(' + plain_url + ')' + detail_url = None + + if detail_item: + detail_url = 'https://ssl.afiliant.com/affskrypt,,2f9de2,,11483,,,?u=(' + detail_item + ')' + + if external or self.config.get('open_external', False): + open_url(QUrl(url_slash_cleaner(detail_item if detail_item else url))) + else: + d = WebStoreDialog(self.gui, url, parent, detail_url) + d.setWindowTitle(self.name) + d.set_tags(self.config.get('tags', '')) + d.exec_() + + def search(self, query, max_results=10, timeout=60): + url = 'http://www.empik.com/szukaj/produkt?c=ebooki-ebooki&q=' + urllib.quote(query) + '&qtype=basicForm&start=1&catalogType=pl&searchCategory=3501&resultsPP=' + str(max_results) + + br = browser() + + counter = max_results + with closing(br.open(url, timeout=timeout)) as f: + doc = html.fromstring(f.read()) + for data in doc.xpath('//div[@class="productsSet"]/div'): + if counter <= 0: + break + + id = ''.join(data.xpath('.//a[@class="productBox-450Title"]/@href')) + if not id: + continue + + cover_url = ''.join(data.xpath('.//div[@class="productBox-450Pic"]/a/img/@src')) + title = ''.join(data.xpath('.//a[@class="productBox-450Title"]/text()')) + title = re.sub(r' \(ebook\)', '', title) + author = ''.join(data.xpath('.//div[@class="productBox-450Author"]/a/text()')) + price = ''.join(data.xpath('.//div[@class="actPrice"]/text()')) + formats = ''.join(data.xpath('.//div[@class="productBox-450Type"]/text()')) + formats = re.sub(r'Ebook *,? *','', formats) + formats = re.sub(r'\(.*\)','', formats) + drm = data.xpath('boolean(.//div[@class="productBox-450Type" and contains(text(), "ADE")])') + + counter -= 1 + + s = SearchResult() + s.cover_url = cover_url + s.title = title.strip() + ' ' + formats + s.author = author.strip() + s.price = price + s.detail_item = 'http://empik.com' + id.strip() + s.formats = formats.upper().strip() + s.drm = SearchResult.DRM_LOCKED if drm else SearchResult.DRM_UNLOCKED + + yield s + From 71b76765ebb3714255514b95d009aa9785a4a0ed Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 26 Oct 2012 09:49:56 +0530 Subject: [PATCH 002/107] ... --- src/calibre/library/database2.py | 7 ++++--- src/calibre/utils/filenames.py | 11 +++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py index 05f5cdec74..4abc851f44 100644 --- a/src/calibre/library/database2.py +++ b/src/calibre/library/database2.py @@ -646,12 +646,13 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): spath = os.path.join(self.library_path, *current_path.split('/')) tpath = os.path.join(self.library_path, *path.split('/')) - wam = WindowsAtomicFolderMove(spath) if iswindows and current_path else None + source_ok = current_path and os.path.exists(spath) + wam = WindowsAtomicFolderMove(spath) if iswindows and source_ok else None try: if not os.path.exists(tpath): os.makedirs(tpath) - if current_path and os.path.exists(spath): # Migrate existing files + if source_ok: # Migrate existing files self.copy_cover_to(id, os.path.join(tpath, 'cover.jpg'), index_is_id=True, windows_atomic_move=wam, use_hardlink=True) @@ -669,7 +670,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): self.conn.commit() self.data.set(id, self.FIELD_MAP['path'], path, row_is_id=True) # Delete not needed directories - if current_path and os.path.exists(spath): + if source_ok: if not samefile(spath, tpath): if wam is not None: wam.delete_originals() diff --git a/src/calibre/utils/filenames.py b/src/calibre/utils/filenames.py index b49c039ffe..5c31c92c33 100644 --- a/src/calibre/utils/filenames.py +++ b/src/calibre/utils/filenames.py @@ -314,6 +314,17 @@ class WindowsAtomicFolderMove(object): break f.write(raw) + def release_file(self, path): + key = None + for p, h in self.handle_map.iteritems(): + if samefile_windows(path, p): + key = (p, h) + break + if key is not None: + import win32file + win32file.CloseHandle(key[1]) + self.handle_map.pop(key[0]) + def close_handles(self): import win32file for h in self.handle_map.itervalues(): From 5f4799cae73e75c0b4fd37594ac3bf22fbd12cf6 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 26 Oct 2012 09:54:43 +0530 Subject: [PATCH 003/107] version 0.9.4 --- Changelog.yaml | 46 ++++++++++++++++++++++++++++++++++++++++ src/calibre/constants.py | 2 +- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/Changelog.yaml b/Changelog.yaml index a17cb4b82f..e4c771efd7 100644 --- a/Changelog.yaml +++ b/Changelog.yaml @@ -19,6 +19,52 @@ # new recipes: # - title: +- version: 0.9.4 + date: 2012-10-26 + + new features: + - title: "Conversion: Add an option to embed a font family into the book." + description: "The embedded font is used as the base font for all text that does not specify its own font family in the input document. Works only with output formats that support font embedding, principally EPUB/AZW3. Option is found under Look & Feel in the conversion dialog. You can ensure that the font is used for all text, regardless of the input document's styles by filtering out font family styles via the Filter Style Information option in the Conversion dialog." + type: major + + - title: "When changing the title/author of a book, use hard links instead of copying the books' files, for a large speedup. Only works on filesystems that support hardlinks." + + bug fixes: + - title: "Windows: Check if any of the files of a book are in use before changing the title/author, this prevents the creation of duplicate files if one of the files is open in another program" + + - title: "Kobo driver: Fix the ondevice status for some books getting lost." + tickets: [1069403] + + - title: "Catalogs: Fix regression that broke use of prefix rules." + tickets: [1070086] + + - title: "Tag Browser: Fix sorting incorrect for accented letters" + tickets: [1069835] + + - title: "Make the bundled Liberation fonts available on all platforms for embedding" + + - title: "Use mimetype for fonts from the EPUB 3 specification" + + - title: "Get Books: Handle website change that broke the SONY Store plugin" + + - title: "Generate cover: If the default font cannot render characters in the metadata (for example for east asian languages) try to automatically find a font on the system that is capable of rendering the characters" + + - title: "Fix regression that broke certain types of CSS selectors." + tickets: [1068937] + + - title: "Use font-weight:bold instead of font-weight:bolder for the and tags as ADE cant handle bolder when embedded fonts are used" + + improved recipes: + - New York Post + - PC World + - TIME Magazine + - Associated Press + + new recipes: + - title: Yazihane + author: A Erdogan + + - version: 0.9.3 date: 2012-10-19 diff --git a/src/calibre/constants.py b/src/calibre/constants.py index 6bc9995384..f098b77f9a 100644 --- a/src/calibre/constants.py +++ b/src/calibre/constants.py @@ -4,7 +4,7 @@ __license__ = 'GPL v3' __copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net' __docformat__ = 'restructuredtext en' __appname__ = u'calibre' -numeric_version = (0, 9, 3) +numeric_version = (0, 9, 4) __version__ = u'.'.join(map(unicode, numeric_version)) __author__ = u"Kovid Goyal " From d44809201fece1fbaaf999b230806e90942c31b2 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 26 Oct 2012 09:57:10 +0530 Subject: [PATCH 004/107] ... --- src/calibre/library/database2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py index 4abc851f44..d4cdf8cc1f 100644 --- a/src/calibre/library/database2.py +++ b/src/calibre/library/database2.py @@ -1433,7 +1433,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): if use_hardlink: try: hardlink_file(path, dest) - return + return True except: pass with lopen(dest, 'wb') as d: From f8cdf39c5f4abd84b8735862721ae4d86f43dfbd Mon Sep 17 00:00:00 2001 From: Translators <> Date: Fri, 26 Oct 2012 04:55:32 +0000 Subject: [PATCH 005/107] Launchpad automatic translations update. --- src/calibre/translations/fr.po | 109 ++++++++++++++++----------------- src/calibre/translations/nl.po | 32 ++++++++-- src/calibre/translations/ru.po | 32 ++++++---- 3 files changed, 100 insertions(+), 73 deletions(-) diff --git a/src/calibre/translations/fr.po b/src/calibre/translations/fr.po index 34e60cdafa..9bc931671d 100644 --- a/src/calibre/translations/fr.po +++ b/src/calibre/translations/fr.po @@ -8,15 +8,15 @@ msgstr "" "Project-Id-Version: calibre 0.4.22\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-10-24 04:12+0000\n" -"PO-Revision-Date: 2012-10-24 17:46+0000\n" -"Last-Translator: sengian \n" +"PO-Revision-Date: 2012-10-25 06:36+0000\n" +"Last-Translator: Franck \n" "Language-Team: PCGen\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:18+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-26 04:55+0000\n" +"X-Generator: Launchpad (build 16194)\n" "Language: fr\n" "X-Poedit-Bookmarks: 1177,1104,-1,-1,-1,-1,-1,-1,-1,-1\n" "Generated-By: pygettext.py 1.5\n" @@ -1096,15 +1096,15 @@ msgid "" "iTunes menu item.

Enabling the Apple driver for direct connection " "to iDevices is an unsupported advanced user mode.

" msgstr "" -"

Si vous ne voulez pas que calibre reconaisse votre iAppareil Apple quand " +"

Si vous ne voulez pas que calibre reconnaisse votre iAppareil Apple quand " "il est connecté à l’ordinateur, cliquez sur Désactiver le driver " "Apple.

Pour transférer les livres sur votre iAppareil, cliquez sur " "Désactiver le driver Apple, puis utilisez la méthode « Connecter à " "iTunes » recommandée dans la FAQ " "calibre + iAppareils, en utilisant l’entrée de menu " -"Connecter/Partager|Connecter à iTunes.

Activer les " -"driver Apple pour une connection directe aux iAppareils est une mode pour " +"Connecter/Partager|Connecter à iTunes.

Activer le " +"driver Apple pour une connexion directe aux iAppareils est un mode pour " "utilisateur avancé non pris en charge.

" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:78 @@ -11266,7 +11266,7 @@ msgstr "&Arrêter tous les travaux ne concernant pas les appareils" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/jobs_ui.py:81 msgid "&Hide all jobs" -msgstr "&Cacher toute les tâches" +msgstr "&Cacher toutes les tâches" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/message_box.py:52 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/message_box.py:298 @@ -13014,13 +13014,13 @@ msgid "" "virus manager asking you if it is OK for calibre to connect to the network. " "Please answer yes. If you do not, wireless connections will not work." msgstr "" -"

Démarrer les connections de périphériques sans fil. Actuellement, " +"

Démarrer les connexions de périphériques sans fil. Actuellement, " "seulement utilisé\n" " par Calibre " "Companion.\n" -"

Vosu pouvez voir s'afficher des messages de votre anti-virus ou de " +"

Vous pouvez voir s'afficher des messages de votre anti-virus ou de " "votre pare-feu vous demandant si Calibre peut se connecter au réseau. " -"Veuillez répondre oui. Si vous ne le faites pas, les connections ne " +"Veuillez répondre oui. Si vous ne le faites pas, les connexions ne " "fonctionneront pas." #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/smartdevice_ui.py:90 @@ -13053,7 +13053,7 @@ msgstr "&Utiliser un port fixe" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/smartdevice_ui.py:98 msgid "&Automatically allow connections at calibre startup" -msgstr "&Autoriser automatiquement les connections au démarrage de Calibre" +msgstr "&Autoriser automatiquement les connexions au démarrage de Calibre" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories.py:60 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:164 @@ -13769,7 +13769,7 @@ msgstr "Choisir une famille de polices dans la liste ci-dessous :" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:187 msgid "Choose &font family" -msgstr "Choisir la %famille de polices" +msgstr "Choisir la &famille de polices" #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 @@ -16995,7 +16995,7 @@ msgid "" msgstr "" "\n" "\n" -"\\n\\nCe module d’extension a été désactivé" +"Ce module d’extension a été désactivé" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins.py:237 msgid "Search for plugin" @@ -20271,7 +20271,7 @@ msgstr "&Port :" #: /home/kovid/work/calibre/src/calibre/gui2/wizard/send_email_ui.py:132 msgid "" "The port your mail server listens for connections on. The default is 25" -msgstr "Le port d’écoute de votre serveur de messagerie. Par défault : 25" +msgstr "Le port d’écoute de votre serveur de messagerie. Par défaut : 25" #: /home/kovid/work/calibre/src/calibre/gui2/wizard/send_email_ui.py:134 msgid "Your username on the mail server" @@ -20567,8 +20567,8 @@ msgid "" "Default: '%default'\n" "Applies to: AZW3, ePub, MOBI output formats" msgstr "" -"Titre du catalogue généré utilisé comme titre dans les métadonnées.\\n\n" -"Par défaut : '%default'\\n\n" +"Titre du catalogue généré utilisé comme titre dans les métadonnées.\n" +"Par défaut : '%default'\n" "S’applique aux formats de sortie : AZW3,ePub, MOBI" #: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi.py:48 @@ -20582,8 +20582,8 @@ msgid "" msgstr "" "Enregistrer la sortie à différentes étapes du processus de conversion vers " "le répertoire spécifié. Utile si vous n'êtes pas sûr de l'étape de la " -"conversion à laquelle se produit le bogue.\\n\n" -"Par défaut : '%default'\\n\n" +"conversion à laquelle se produit le bogue.\n" +"Par défaut : '%default'\n" "S’applique aux formats de sortie : AZW3,ePub, MOBI" #: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi.py:58 @@ -20594,9 +20594,8 @@ msgid "" "'+', the default tag for read books.\n" "Applies to: AZW3, ePub, MOBI output formats" msgstr "" -"Expression rationnelle décrivant les étiquettes à exclure comme genres.\\n\n" -"Par défaut : '%default' exclue les étiquettes entre crochets, ex. '[]'\\" -"n\n" +"Expression rationnelle décrivant les étiquettes à exclure comme genres.\n" +"Par défaut : '%default' exclue les étiquettes entre crochets, ex. '[]'\n" "S’applique aux formats de sortie : AZW3,ePub, MOBI" #: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi.py:66 @@ -20632,8 +20631,8 @@ msgid "" "Default: '%default'\n" "Applies to: AZW3, ePub, MOBI output formats" msgstr "" -"Inclure la section 'Auteurs' dans le catalogue.\\n\n" -"Par défaut : '%default'\\n\n" +"Inclure la section 'Auteurs' dans le catalogue.\n" +"Par défaut : '%default'\n" "S’applique aux formats de sortie : AZW3, ePub, MOBI" #: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi.py:87 @@ -20643,8 +20642,8 @@ msgid "" "Default: '%default'\n" "Applies to: AZW3, ePub, MOBI output formats" msgstr "" -"Inclure la section 'Descriptions' dans le catalogue.\\n\n" -"Par défaut : '%default'\\n\n" +"Inclure la section 'Descriptions' dans le catalogue.\n" +"Par défaut : '%default'\n" "S’applique aux formats de sortie : AZW3, ePub, MOBI" #: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi.py:94 @@ -20654,8 +20653,8 @@ msgid "" "Default: '%default'\n" "Applies to: AZW3, ePub, MOBI output formats" msgstr "" -"Inclure la section 'Genres' dans le catalogue.\\n\n" -"Par défaut : '%default'\\n\n" +"Inclure la section 'Genres' dans le catalogue.\n" +"Par défaut : '%default'\n" "S’applique aux formats de sortie : AZW3, ePub, MOBI" #: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi.py:101 @@ -20665,8 +20664,8 @@ msgid "" "Default: '%default'\n" "Applies to: AZW3, ePub, MOBI output formats" msgstr "" -"Inclure la section 'Titres' dans le catalogue.\\n\n" -"Par défaut : '%default'\\n\n" +"Inclure la section 'Titres' dans le catalogue.\n" +"Par défaut : '%default'\n" "S’applique aux formats de sortie : AZW3, ePub, MOBI" #: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi.py:108 @@ -20676,8 +20675,8 @@ msgid "" "Default: '%default'\n" "Applies to: AZW3, ePub, MOBI output formats" msgstr "" -"Inclure la section 'Séries' dans le catalogue.\\n\n" -"Par défaut : '%default'\\n\n" +"Inclure la section 'Séries' dans le catalogue.\n" +"Par défaut : '%default'\n" "S’applique aux formats de sortie : AZW3, ePub, MOBI" #: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi.py:115 @@ -20687,8 +20686,8 @@ msgid "" "Default: '%default'\n" "Applies to: AZW3, ePub, MOBI output formats" msgstr "" -"Inclure la section 'Ajoutés récemment' dans le catalogue.\\n\n" -"Par défaut : '%default'\\n\n" +"Inclure la section 'Ajoutés récemment' dans le catalogue.\n" +"Par défaut : '%default'\n" "S’applique aux formats de sortie : AZW3, ePub, MOBI" #: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi.py:122 @@ -20699,8 +20698,8 @@ msgid "" "Applies to: AZW3, ePub, MOBI output formats" msgstr "" "Champ personnalisé contenant une note de texte à insérer dans l'en-tête de " -"Description.\\n\n" -"Par défaut : '%default'\\n\n" +"Description.\n" +"Par défaut : '%default'\n" "S’applique aux formats de sortie : AZW3, ePub, MOBI" #: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi.py:129 @@ -20713,13 +20712,13 @@ msgid "" "Default: '%default'\n" "Applies to AZW3, ePub, MOBI output formats" msgstr "" -" : spécifie [before|after]:[True|False] avec :\\n\n" +" : spécifie [before|after]:[True|False] avec :\n" " Champ personnalisé contenant des notes à fusionner avec les " -"Commentaires\\n\n" -" [before|after] Placement de notes par rapport au Commentaires\\n\n" +"Commentaires\n" +" [before|after] Placement de notes par rapport au Commentaires\n" " [True|False] - Une règle horizontale est insérée entre les notes et les " -"Commentaires\\n\n" -"Par défaut : '%default'\\n\n" +"Commentaires\n" +"Par défaut : '%default'\n" "S’applique aux formats de sortie : AZW3, ePub, MOBI" #: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi.py:139 @@ -20735,8 +20734,8 @@ msgstr "" "Spécifie le profil de sortie. Dans certains cas, un profil de sortie est " "requis pour optimiser le catalogue pour cet appareil. Par exemple, 'kindle' " "ou 'kindle_dx' créé une Tables des Matières structurée avec des Sections et " -"Articles.\\n\n" -"Par défaut : '%default'\\n\n" +"Articles.\n" +"Par défaut : '%default'\n" "S’applique aux formats de sortie : AZW3, ePub, MOBI" #: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi.py:146 @@ -20764,8 +20763,8 @@ msgid "" "Default: '%default'\n" "Applies to: AZW3, ePub, MOBI output formats" msgstr "" -"Remplace la couverture existante lorsque le catalogue est généré.\\n\n" -"Par défaut : '%default'\\n\n" +"Remplace la couverture existante lorsque le catalogue est généré.\n" +"Par défaut : '%default'\n" "S’applique aux formats de sortie : AZW3, ePub, MOBI" #: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi.py:162 @@ -20777,9 +20776,9 @@ msgid "" "Applies to AZW3, ePub, MOBI output formats" msgstr "" "Indice de taille (en pouces) pour les couvertures de livres dans le " -"catalogue.\\n\n" -"Gamme : 1.0 - 2.0\\n\n" -"Par défaut : '%default'\\n\n" +"catalogue.\n" +"Gamme : 1.0 - 2.0\n" +"Par défaut : '%default'\n" "S’applique aux formats de sortie : AZW3, ePub, MOBI" #: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi.py:272 @@ -20797,12 +20796,12 @@ msgstr "Symboles" #: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:280 msgid "No genres to catalog.\n" -msgstr "Pas de genres à cataloguer.\\n\n" +msgstr "Pas de genres à cataloguer.\n" #: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:282 msgid "Check 'Excluded genres' regex in E-book options.\n" msgstr "" -"Vérifier l’expression régulière 'Genres exclus' dans les options E-book.\\n\n" +"Vérifier l’expression régulière 'Genres exclus' dans les options E-book.\n" #: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:284 msgid "No books available to catalog" @@ -22939,8 +22938,8 @@ msgstr "" "formats qui a un certain moment on été associés avec le livre. Li n'y a " "aucune garantie que cette liste est correcte, bien qu'elle le soit " "probablement. Cette fonction peut-être appelée en mode de modèle de " -"programme en utilisant le modèle \\\"{:'approximate_formats()'}\\\". Notez " -"que ces noms de formats sont toujours en majuscule, comme dans EPUB." +"programme en utilisant le modèle \"{:'approximate_formats()'}\". Notez que " +"ces noms de formats sont toujours en majuscule, comme dans EPUB." #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:620 msgid "" @@ -23328,7 +23327,7 @@ msgid "" msgstr "" "current_library_path() -- retourne le chemin de la bibliothèque calibre " "avctuelle. Cette fonction peut-être appelée en mode de modèle de programme " -"en utilisant le modèle \\\"{:'current_library_path()'}\\\"." +"en utilisant le modèle \"{:'current_library_path()'}\"." #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:1200 msgid "" @@ -24926,8 +24925,8 @@ msgstr "" "ceci en, par\n" "exemple, '127.0.0.1' pour écouter seulement les connexions à partir de la " "machine locale, ou\n" -"en '::' pour écouter toutes les connexions entrantes en IPv6 et IPv4 " -"connections (ceci peut ne pas\n" +"en '::' pour écouter toutes les connexions entrantes en IPv6 et IPv4 (ceci " +"peut ne pas\n" "fonctionner sur tous les systèmes d’exploitation)" #: /home/kovid/work/calibre/resources/default_tweaks.py:458 diff --git a/src/calibre/translations/nl.po b/src/calibre/translations/nl.po index d6055d2787..9f9b0c9236 100644 --- a/src/calibre/translations/nl.po +++ b/src/calibre/translations/nl.po @@ -57,15 +57,15 @@ msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-10-24 04:12+0000\n" -"PO-Revision-Date: 2012-10-24 18:19+0000\n" -"Last-Translator: Bart Bone \n" +"PO-Revision-Date: 2012-10-26 04:33+0000\n" +"Last-Translator: drMerry \n" "Language-Team: Dutch \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:17+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-26 04:54+0000\n" +"X-Generator: Launchpad (build 16194)\n" "X-Poedit-Country: NETHERLANDS\n" "X-Poedit-Language: Dutch\n" @@ -6977,10 +6977,32 @@ msgid "" " library.\n" " " msgstr "" +"

Over Boek Aanpassen

\n" +"

Boek Aanpassen geeft u de mogelijkheid het uiterlijk van een " +"\n" +" ebook aan te passen door kleine wijzigingen aan de interne " +"structuur\n" +" te maken. Om Boek Aanpassen te gebruiken, moet u iets weten " +"over\n" +" HTML en CSS, technieken die worden gebruikt in E-boeken.\n" +" Doorloop de volgende stappen:

\n" +"
\n" +"
    \n" +"
  1. Klik \"Boek uitpakken\": Dit zal het boek \"uitpakken\" in " +"de\n" +" individuele componenten.
  2. \n" +"
  3. Klik met de rechter muisknop op een willekeurig bestand\n" +" en selecteer \"Openen met...\" om het te bewerken in\n" +" de tekstverwerker van uw voorkeur.
  4. \n" +"
  5. Als u klaar bent met aanpassen: Sluit de bestandsmap\n" +" en de tekstverwerker die u heeft gebrukt om aanpassingen\n" +" te maken. Klik de \"Boek herbouwen\" knop om het boek\n" +" bij te werken in uw calibre bibliotheek.
  6. \n" +"
" #: /home/kovid/work/calibre/src/calibre/gui2/actions/tweak_epub.py:103 msgid "&Explode Book" -msgstr "Boek &Uitpakken" +msgstr "Boek &uitpakken" #: /home/kovid/work/calibre/src/calibre/gui2/actions/tweak_epub.py:104 msgid "&Preview Book" diff --git a/src/calibre/translations/ru.po b/src/calibre/translations/ru.po index 674c10ca39..1eb296ab29 100644 --- a/src/calibre/translations/ru.po +++ b/src/calibre/translations/ru.po @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: calibre 0.4.55\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-10-24 04:12+0000\n" -"PO-Revision-Date: 2012-10-21 09:03+0000\n" +"PO-Revision-Date: 2012-10-25 17:27+0000\n" "Last-Translator: Baz <_baz_@rambler.ru>\n" "Language-Team: American English \n" "MIME-Version: 1.0\n" @@ -15,8 +15,8 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:27+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-26 04:55+0000\n" +"X-Generator: Launchpad (build 16194)\n" "X-Poedit-Country: RUSSIAN FEDERATION\n" "X-Poedit-Language: Russian\n" "X-Poedit-SourceCharset: utf-8\n" @@ -2850,7 +2850,7 @@ msgstr "Не обрабатывать изображения" #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plugins/comic_input.py:63 msgid "Do not convert the image to grayscale (black and white)" -msgstr "Не преобразовать изображение в градации серого (черный и белый)" +msgstr "Не преобразовывать изображение в оттенки серого (чёрный и белый)" #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plugins/comic_input.py:65 msgid "" @@ -3736,6 +3736,12 @@ msgid "" "to remove fonts from the input document. Note that font embedding only works " "with some output formats, principally EPUB and AZW3." msgstr "" +"Вставить указанное семейство шрифтов в книгу. Указывается \"основной\" шрифт " +"использованный в книге. Если исходный документ имеет указание шрифта, то он " +"будет перезаписан этой настройкой. Вы можете использовать настройку фильтра " +"стилей для удаления шрифта из исходного документа. Помните, что вставка " +"шрифта работает только с некоторыми выходными форматами, в основном EPUB и " +"AZW3." #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:209 msgid "" @@ -6662,7 +6668,7 @@ msgstr "Сохранить на диск в одну директорию тол #: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:38 msgid "Save single format to disk..." -msgstr "Сохранить единый формат диска..." +msgstr "Сохранить на диск один из форматов ..." #: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:60 #: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:81 @@ -6675,7 +6681,7 @@ msgstr "Выберите формат для сохранения на диск" #: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:84 msgid "Choose destination directory" -msgstr "Выберете директорию получателя" +msgstr "Выберите папку назначения" #: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:92 msgid "" @@ -8618,7 +8624,7 @@ msgstr "&Размер строки" #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:237 msgid "&Embed font family:" -msgstr "" +msgstr "Вставить семейство шрифтов:" #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:238 msgid "&Disable font size rescaling" @@ -9045,7 +9051,7 @@ msgstr "Открыть книгу" #: /home/kovid/work/calibre/src/calibre/gui2/convert/regex_builder.py:215 msgid "Click the Open button below to open a ebook to use for testing." -msgstr "" +msgstr "Нажмите ниже кнопку Открыть, что бы открыть книгу для проверки." #: /home/kovid/work/calibre/src/calibre/gui2/convert/regex_builder_ui.py:90 msgid "Regex Builder" @@ -13394,7 +13400,7 @@ msgstr "Регулярное выражение (?P)" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:122 msgid "Choose font family" -msgstr "" +msgstr "Выберите семейство шрифтов" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:137 #: /home/kovid/work/calibre/src/calibre/gui2/keyboard.py:377 @@ -13414,11 +13420,11 @@ msgstr "Ничего" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:159 msgid "Choose a font family from the list below:" -msgstr "" +msgstr "Выберите семейство шрифтов из списка ниже:" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:187 msgid "Choose &font family" -msgstr "" +msgstr "Выберите семейство шрифтов" #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 @@ -14134,7 +14140,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:273 #, python-format msgid "Could not open \"%s\". Is it being used by another program?" -msgstr "" +msgstr "Не могу открыть \"%s\". Возможно используется другой программой." #: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:306 msgid "" @@ -21942,7 +21948,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/utils/filenames.py:284 msgid "File is open in another process" -msgstr "" +msgstr "Файл открыт другим процессом" #: /home/kovid/work/calibre/src/calibre/utils/formatter.py:31 #: /home/kovid/work/calibre/src/calibre/utils/formatter.py:182 From 7e226bff16dd7a2864167d5fead331eb2fe2626e Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 26 Oct 2012 10:31:57 +0530 Subject: [PATCH 006/107] IGN:Tag release --- src/calibre/translations/calibre.pot | 68 +++++++++++++++------------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/src/calibre/translations/calibre.pot b/src/calibre/translations/calibre.pot index 799d7bc4fb..8648b192c0 100644 --- a/src/calibre/translations/calibre.pot +++ b/src/calibre/translations/calibre.pot @@ -4,9 +4,9 @@ # msgid "" msgstr "" -"Project-Id-Version: calibre 0.9.3\n" -"POT-Creation-Date: 2012-10-24 09:36+IST\n" -"PO-Revision-Date: 2012-10-24 09:36+IST\n" +"Project-Id-Version: calibre 0.9.4\n" +"POT-Creation-Date: 2012-10-26 09:57+IST\n" +"PO-Revision-Date: 2012-10-26 09:57+IST\n" "Last-Translator: Automatically generated\n" "Language-Team: LANGUAGE\n" "MIME-Version: 1.0\n" @@ -173,12 +173,12 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -882,26 +882,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1048,14 +1048,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1099,10 +1099,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -11001,6 +11001,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -12216,7 +12220,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -15287,7 +15291,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -15854,35 +15858,35 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "The position at which to open the specified book. The position is a location as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -17358,17 +17362,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" From 39716497b47f114b92ae4ab7e8c80ca4be18b0e3 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 26 Oct 2012 12:45:49 +0530 Subject: [PATCH 007/107] ... --- Changelog.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Changelog.yaml b/Changelog.yaml index e4c771efd7..31908315f3 100644 --- a/Changelog.yaml +++ b/Changelog.yaml @@ -28,6 +28,8 @@ type: major - title: "When changing the title/author of a book, use hard links instead of copying the books' files, for a large speedup. Only works on filesystems that support hardlinks." + + - title: "Linux installer: Resume interrupted downloads and verify the SHA-512 signature of the downloaded file before installing it." bug fixes: - title: "Windows: Check if any of the files of a book are in use before changing the title/author, this prevents the creation of duplicate files if one of the files is open in another program" From 529a32360f501902e0464bc4b1162c4b06d60f1c Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 26 Oct 2012 19:34:46 +0530 Subject: [PATCH 008/107] Nicer error message if the user tries to embed a font family that does not have a regular typeface --- src/calibre/ebooks/oeb/transforms/flatcss.py | 5 +++++ src/calibre/gui2/font_family_chooser.py | 15 +++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/calibre/ebooks/oeb/transforms/flatcss.py b/src/calibre/ebooks/oeb/transforms/flatcss.py index cb5720c08a..6aae85d8d1 100644 --- a/src/calibre/ebooks/oeb/transforms/flatcss.py +++ b/src/calibre/ebooks/oeb/transforms/flatcss.py @@ -184,6 +184,11 @@ class CSSFlattener(object): faces = fontconfig.fonts_for_family(family) if not faces or not u'normal' in faces: msg = (u'No embeddable fonts found for family: %r'%self.opts.embed_font_family) + if faces: + msg = (u'The selected font %s has no Regular typeface, only' + ' %s faces, it cannot be used.')%( + self.opts.embed_font_family, + ', '.join(faces.iterkeys())) if failure_critical: raise ValueError(msg) self.oeb.log.warn(msg) diff --git a/src/calibre/gui2/font_family_chooser.py b/src/calibre/gui2/font_family_chooser.py index b69d596d5f..5110e92d24 100644 --- a/src/calibre/gui2/font_family_chooser.py +++ b/src/calibre/gui2/font_family_chooser.py @@ -13,6 +13,7 @@ from PyQt4.Qt import (QFontInfo, QFontMetrics, Qt, QFont, QFontDatabase, QPen, QToolButton, QGridLayout, QListView, QWidget, QDialogButtonBox, QIcon, QHBoxLayout, QLabel, QModelIndex) +from calibre.gui2 import error_dialog from calibre.utils.icu import sort_key def writing_system_for_font(font): @@ -173,6 +174,20 @@ class FontFamilyDialog(QDialog): if idx == 0: return None return self.families[idx] + def accept(self): + ff = self.font_family + if ff: + from calibre.utils.fonts import fontconfig + faces = fontconfig.fonts_for_family(ff) or {} + faces = frozenset(faces.iterkeys()) + if 'normal' not in faces: + error_dialog(self, _('Not a useable font'), + _('The %s font family does not have a Regular typeface, so it' + ' cannot be used. It has only the "%s" face(s).')%( + ff, ', '.join(faces)), show=True) + return + QDialog.accept(self) + class FontFamilyChooser(QWidget): family_changed = pyqtSignal(object) From eb2ea97f6f7c79bc58e5f72fe94cd95834eb0323 Mon Sep 17 00:00:00 2001 From: Translators <> Date: Sat, 27 Oct 2012 04:58:49 +0000 Subject: [PATCH 009/107] Launchpad automatic translations update. --- setup/iso_639/ca.po | 50 +++---- src/calibre/translations/af.po | 68 ++++----- src/calibre/translations/ar.po | 68 ++++----- src/calibre/translations/ast.po | 68 ++++----- src/calibre/translations/az.po | 68 ++++----- src/calibre/translations/ber.po | 68 ++++----- src/calibre/translations/bg.po | 68 ++++----- src/calibre/translations/bn.po | 68 ++++----- src/calibre/translations/br.po | 68 ++++----- src/calibre/translations/bs.po | 68 ++++----- src/calibre/translations/ca.po | 72 +++++----- src/calibre/translations/cs.po | 68 ++++----- src/calibre/translations/cy.po | 68 ++++----- src/calibre/translations/da.po | 68 ++++----- src/calibre/translations/de.po | 72 +++++----- src/calibre/translations/el.po | 68 ++++----- src/calibre/translations/en_AU.po | 68 ++++----- src/calibre/translations/en_CA.po | 68 ++++----- src/calibre/translations/en_GB.po | 72 +++++----- src/calibre/translations/eo.po | 68 ++++----- src/calibre/translations/es.po | 115 ++++++++++------ src/calibre/translations/et.po | 68 ++++----- src/calibre/translations/eu.po | 68 ++++----- src/calibre/translations/fa.po | 68 ++++----- src/calibre/translations/fi.po | 68 ++++----- src/calibre/translations/fo.po | 68 ++++----- src/calibre/translations/fr.po | 70 +++++----- src/calibre/translations/fr_CA.po | 68 ++++----- src/calibre/translations/fur.po | 68 ++++----- src/calibre/translations/gl.po | 68 ++++----- src/calibre/translations/gu.po | 68 ++++----- src/calibre/translations/he.po | 68 ++++----- src/calibre/translations/hi.po | 68 ++++----- src/calibre/translations/him.po | 68 ++++----- src/calibre/translations/hr.po | 68 ++++----- src/calibre/translations/hu.po | 71 +++++----- src/calibre/translations/id.po | 68 ++++----- src/calibre/translations/is.po | 68 ++++----- src/calibre/translations/it.po | 109 ++++++++------- src/calibre/translations/ja.po | 68 ++++----- src/calibre/translations/jv.po | 68 ++++----- src/calibre/translations/ka.po | 68 ++++----- src/calibre/translations/kn.po | 68 ++++----- src/calibre/translations/ko.po | 68 ++++----- src/calibre/translations/ku.po | 68 ++++----- src/calibre/translations/lt.po | 68 ++++----- src/calibre/translations/ltg.po | 68 ++++----- src/calibre/translations/lv.po | 68 ++++----- src/calibre/translations/mk.po | 68 ++++----- src/calibre/translations/ml.po | 68 ++++----- src/calibre/translations/mr.po | 68 ++++----- src/calibre/translations/ms.po | 68 ++++----- src/calibre/translations/nb.po | 68 ++++----- src/calibre/translations/nds.po | 68 ++++----- src/calibre/translations/nl.po | 70 +++++----- src/calibre/translations/nn.po | 68 ++++----- src/calibre/translations/oc.po | 68 ++++----- src/calibre/translations/pa.po | 68 ++++----- src/calibre/translations/pl.po | 72 +++++----- src/calibre/translations/pt.po | 68 ++++----- src/calibre/translations/pt_BR.po | 68 ++++----- src/calibre/translations/ro.po | 68 ++++----- src/calibre/translations/ru.po | 197 ++++++++++++++++----------- src/calibre/translations/sc.po | 68 ++++----- src/calibre/translations/si.po | 68 ++++----- src/calibre/translations/sk.po | 72 +++++----- src/calibre/translations/sl.po | 68 ++++----- src/calibre/translations/sq.po | 68 ++++----- src/calibre/translations/sr.po | 68 ++++----- src/calibre/translations/sr@latin.po | 68 ++++----- src/calibre/translations/sv.po | 68 ++++----- src/calibre/translations/ta.po | 68 ++++----- src/calibre/translations/te.po | 68 ++++----- src/calibre/translations/th.po | 68 ++++----- src/calibre/translations/tr.po | 80 ++++++----- src/calibre/translations/uk.po | 78 ++++++----- src/calibre/translations/ur.po | 68 ++++----- src/calibre/translations/vi.po | 68 ++++----- src/calibre/translations/wa.po | 68 ++++----- src/calibre/translations/yi.po | 68 ++++----- src/calibre/translations/zh_CN.po | 68 ++++----- src/calibre/translations/zh_HK.po | 68 ++++----- src/calibre/translations/zh_TW.po | 72 +++++----- 83 files changed, 3131 insertions(+), 2765 deletions(-) diff --git a/setup/iso_639/ca.po b/setup/iso_639/ca.po index a6064b3da6..5012e48969 100644 --- a/setup/iso_639/ca.po +++ b/setup/iso_639/ca.po @@ -12,14 +12,14 @@ msgstr "" "Report-Msgid-Bugs-To: Debian iso-codes team \n" "POT-Creation-Date: 2011-11-25 14:01+0000\n" -"PO-Revision-Date: 2012-10-21 16:27+0000\n" +"PO-Revision-Date: 2012-10-26 17:42+0000\n" "Last-Translator: Ferran Rius \n" "Language-Team: Catalan \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-22 04:39+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:58+0000\n" +"X-Generator: Launchpad (build 16194)\n" "Language: ca\n" #. name for aaa @@ -10560,19 +10560,19 @@ msgstr "" #. name for jah msgid "Jah Hut" -msgstr "" +msgstr "Jah Hut" #. name for jaj msgid "Zazao" -msgstr "" +msgstr "Zazao" #. name for jak msgid "Jakun" -msgstr "" +msgstr "Jakun" #. name for jal msgid "Yalahatan" -msgstr "" +msgstr "Jalahatan" #. name for jam msgid "Creole English; Jamaican" @@ -10580,31 +10580,31 @@ msgstr "Anglès crioll; Jamaica" #. name for jao msgid "Yanyuwa" -msgstr "" +msgstr "Yanyula" #. name for jaq msgid "Yaqay" -msgstr "" +msgstr "Yaqay" #. name for jar msgid "Jarawa (Nigeria)" -msgstr "" +msgstr "Jarawa (Nigèria)" #. name for jas msgid "Javanese; New Caledonian" -msgstr "" +msgstr "Javanès; Nova Caledònia" #. name for jat msgid "Jakati" -msgstr "" +msgstr "Jakati" #. name for jau msgid "Yaur" -msgstr "" +msgstr "Yaur" #. name for jav msgid "Javanese" -msgstr "" +msgstr "Javanès" #. name for jax msgid "Malay; Jambi" @@ -10612,11 +10612,11 @@ msgstr "Malai; Jambi" #. name for jay msgid "Yan-nhangu" -msgstr "" +msgstr "Jarnango" #. name for jaz msgid "Jawe" -msgstr "" +msgstr "Jawe" #. name for jbe msgid "Judeo-Berber" @@ -10624,27 +10624,27 @@ msgstr "Judeo-berber" #. name for jbj msgid "Arandai" -msgstr "" +msgstr "Arandai" #. name for jbn msgid "Nafusi" -msgstr "" +msgstr "Djerbi" #. name for jbo msgid "Lojban" -msgstr "" +msgstr "Lojban" #. name for jbr msgid "Jofotek-Bromnya" -msgstr "" +msgstr "Jofotek-Bromnya" #. name for jbt msgid "Jabutí" -msgstr "" +msgstr "Jaboti" #. name for jbu msgid "Jukun Takum" -msgstr "" +msgstr "Jukun Takum" #. name for jcs msgid "Jamaican Country Sign Language" @@ -10652,11 +10652,11 @@ msgstr "Llenguatge de signes del país jamaicà" #. name for jct msgid "Krymchak" -msgstr "" +msgstr "Judeocrimeà" #. name for jda msgid "Jad" -msgstr "" +msgstr "Jad" #. name for jdg msgid "Jadgali" @@ -11012,7 +11012,7 @@ msgstr "" #. name for jvn msgid "Javanese; Caribbean" -msgstr "" +msgstr "Javanès; Carib" #. name for jwi msgid "Jwira-Pepesa" diff --git a/src/calibre/translations/af.po b/src/calibre/translations/af.po index d32815fac8..424c350a23 100644 --- a/src/calibre/translations/af.po +++ b/src/calibre/translations/af.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-08-14 16:03+0000\n" "Last-Translator: Albé Theunissen \n" "Language-Team: Afrikaans \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:13+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:37+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "Doen absolute niks" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -942,26 +942,26 @@ msgstr "Pad na biblioteek te lank. Moet minder as %d karakters wees." #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "Ja" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "Hoof" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "Kaart A" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "Kaart B" @@ -1151,14 +1151,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Nuus" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Katalogus" @@ -1208,10 +1208,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12075,6 +12075,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13368,7 +13372,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16719,7 +16723,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17310,39 +17314,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18946,17 +18950,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/ar.po b/src/calibre/translations/ar.po index e49ef5b071..94aef7bfc1 100644 --- a/src/calibre/translations/ar.po +++ b/src/calibre/translations/ar.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: iso_639_3\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/calibre\n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-05-24 09:38+0000\n" "Last-Translator: abbas \n" "Language-Team: awadh alghaamdi \n" @@ -17,8 +17,8 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n % 100 >= " "3 && n % 100 <= 10 ? 3 : n % 100 >= 11 && n % 100 <= 99 ? 4 : 5;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:14+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:38+0000\n" +"X-Generator: Launchpad (build 16194)\n" "X-Poedit-Country: SAUDI ARABIA\n" "Language: ar\n" "X-Poedit-Language: Arabic\n" @@ -219,12 +219,12 @@ msgstr "لا يفعل شيئًا" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -1009,26 +1009,26 @@ msgstr "الطريق إلى المكتبة وقتا طويلا. يجب أن يك #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "نعم" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "الصفحة الرئيسية" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "بلكبيبي" @@ -1224,14 +1224,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "الأخبار" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "الفهرس" @@ -1284,10 +1284,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12327,6 +12327,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13627,7 +13631,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16992,7 +16996,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "نتذكر الماضي حجم الإطار المستخدمة" @@ -17555,39 +17559,39 @@ msgstr "" msgid "Loading ebook..." msgstr "يتم تحميل الكتاب الإلكتروني..." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "لم يتمكن من فتح الكتاب الإلكتروني" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -19194,17 +19198,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/ast.po b/src/calibre/translations/ast.po index 426874ddc2..3b24c0a27a 100644 --- a/src/calibre/translations/ast.po +++ b/src/calibre/translations/ast.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2011-09-26 16:28+0000\n" "Last-Translator: Xandru \n" "Language-Team: Asturian \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:14+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:38+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "Nun fai nada" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -935,26 +935,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1129,14 +1129,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1184,10 +1184,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12044,6 +12044,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13337,7 +13341,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16688,7 +16692,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17279,39 +17283,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18915,17 +18919,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/az.po b/src/calibre/translations/az.po index 5b46a4e4b2..e5d0db3b58 100644 --- a/src/calibre/translations/az.po +++ b/src/calibre/translations/az.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-08-07 14:00+0000\n" "Last-Translator: Emin Mastizadeh \n" "Language-Team: Azerbaijani \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:14+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:38+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "Heç bir şey etmir" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -933,26 +933,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1127,14 +1127,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1182,10 +1182,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12042,6 +12042,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13335,7 +13339,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16686,7 +16690,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17277,39 +17281,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18913,17 +18917,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/ber.po b/src/calibre/translations/ber.po index d7e0ba5879..52fd355b59 100644 --- a/src/calibre/translations/ber.po +++ b/src/calibre/translations/ber.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-10-14 04:57+0000\n" "Last-Translator: Walid AMMOU \n" "Language-Team: Berber (Other) \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:15+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:39+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -929,26 +929,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1123,14 +1123,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "ⵉⵏⵖⵎⵉⵙⵏ" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1178,10 +1178,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12038,6 +12038,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13331,7 +13335,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16682,7 +16686,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17273,39 +17277,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18909,17 +18913,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/bg.po b/src/calibre/translations/bg.po index 83273bcc42..cbe92c0c64 100644 --- a/src/calibre/translations/bg.po +++ b/src/calibre/translations/bg.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre 0.4.51\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-10-24 13:23+0000\n" "Last-Translator: Nelly Hoang \n" "Language-Team: bg\n" @@ -14,8 +14,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:15+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:40+0000\n" +"X-Generator: Launchpad (build 16194)\n" "Generated-By: pygettext.py 1.5\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 @@ -175,12 +175,12 @@ msgstr "Не прави абсолютно нищо" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -993,26 +993,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "Да" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1217,14 +1217,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Новини" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Каталог" @@ -1272,10 +1272,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12150,6 +12150,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13443,7 +13447,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16796,7 +16800,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17387,39 +17391,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -19023,17 +19027,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/bn.po b/src/calibre/translations/bn.po index c2d0eb74ff..bfd1cd8822 100644 --- a/src/calibre/translations/bn.po +++ b/src/calibre/translations/bn.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-04-12 14:19+0000\n" "Last-Translator: Kazi Shahnoor Ashraf \n" "Language-Team: Bengali \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:15+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:39+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "আসলে কিছুই করে না" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -929,26 +929,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1123,14 +1123,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1178,10 +1178,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12038,6 +12038,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13331,7 +13335,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16682,7 +16686,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17273,39 +17277,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18909,17 +18913,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/br.po b/src/calibre/translations/br.po index acbe62f963..c59f168120 100644 --- a/src/calibre/translations/br.po +++ b/src/calibre/translations/br.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2011-08-13 04:22+0000\n" "Last-Translator: Denis \n" "Language-Team: Breton \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:15+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:39+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "Ne ra netra da vat" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -932,26 +932,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1126,14 +1126,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Keleier" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Katalog" @@ -1181,10 +1181,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12044,6 +12044,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13337,7 +13341,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16688,7 +16692,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17279,39 +17283,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18915,17 +18919,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/bs.po b/src/calibre/translations/bs.po index aa77564d7c..30f993da4e 100644 --- a/src/calibre/translations/bs.po +++ b/src/calibre/translations/bs.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-01-02 13:31+0000\n" "Last-Translator: Kenan Dervišević \n" "Language-Team: Bosnian \n" @@ -16,8 +16,8 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:15+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:39+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -176,12 +176,12 @@ msgstr "Ne radi apsolutno ništa" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -935,26 +935,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1129,14 +1129,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Vijesti" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Katalog" @@ -1184,10 +1184,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12045,6 +12045,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13338,7 +13342,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16693,7 +16697,7 @@ msgid "Options to customize the ebook viewer" msgstr "Opcije za prilagođavanje preglednika e-knjiga" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "Zapamti zadnju korištenu veličinu prozora" @@ -17284,39 +17288,39 @@ msgstr "Upravljanje zabilješkama" msgid "Loading ebook..." msgstr "Učitavam e-knjigu..." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "Nije moguće otvoriti e-knjigu" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "Opcije pomoću kojih se kontroliše preglednik e-knjiga" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18920,17 +18924,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/ca.po b/src/calibre/translations/ca.po index cb6c854470..2521ce5943 100644 --- a/src/calibre/translations/ca.po +++ b/src/calibre/translations/ca.po @@ -10,7 +10,7 @@ msgid "" msgstr "" "Project-Id-Version: ca\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-10-21 14:25+0000\n" "Last-Translator: Ferran Rius \n" "Language-Team: \n" @@ -18,8 +18,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:16+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:40+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -178,12 +178,12 @@ msgstr "No fa res" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -1000,26 +1000,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "Sí" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "Inici" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "Targeta A" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "Targeta B" @@ -1238,14 +1238,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Notícies" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Catàleg" @@ -1301,10 +1301,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -13589,6 +13589,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -15013,13 +15017,9 @@ msgstr "Procés d'addició" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" -"Si s'activa, aquesta opció fa que el calibre comprovi si un\n" -" fitxer que s'està afegint automàticament ja està a la\n" -" biblioteca del calibre. Si és així un missatge emergent\n" -" us demanarà si el voleu afegir igualment." #: /home/kovid/work/calibre/src/calibre/gui2/preferences/adding_ui.py:152 msgid "Check for &duplicates when auto-adding files" @@ -18896,7 +18896,7 @@ msgid "Options to customize the ebook viewer" msgstr "Opcions per personalitzar el visor de llibres electrònics" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "Recorda la darrera mida de finestra que s'ha fet servir" @@ -19525,38 +19525,38 @@ msgstr "Gestiona els marcadors" msgid "Loading ebook..." msgstr "S'està carregant el llibre..." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "No s'ha pogut obrir el llibre" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "Error desconegut" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "Opcions de control del visor de llibres" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" "Si s'indica, la finestra del visor intentarà anar al primer pla quan " "s'iniciï." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" "Si s'indica, s'intentarà que la finestra del visor s'obri en pantalla " "completa." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" "Dirigeix les alertes de javascript i els missatges de consola a la consola" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." @@ -19564,7 +19564,7 @@ msgstr "" "La posició que s'obrirà el llibre especificat. La posició és una ubicació " "que es mostra a la cantonada superior esquerra del visor." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -21572,18 +21572,18 @@ msgstr "s'ha restaurat la preferència " msgid "creating custom column " msgstr "s'està creant una columna personalitzada " -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" "

S'està migrant la base de dades antiga a la biblioteca de %s

" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "S'està copiant %s" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "S'està compactant la base de dades" diff --git a/src/calibre/translations/cs.po b/src/calibre/translations/cs.po index 21a2a64638..6a0821c846 100644 --- a/src/calibre/translations/cs.po +++ b/src/calibre/translations/cs.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-07-31 12:00+0000\n" "Last-Translator: Štěpán Krb \n" "Language-Team: Czech \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:16+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:40+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "Nedělá vůbec nic" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -974,26 +974,26 @@ msgstr "Cesta ke složce knihovny je moc dlouhá. Musí mít méně než %d znak #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "Ano" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "Hlavní" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "Karta A" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "Karta B" @@ -1195,14 +1195,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Zprávy" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Katalog" @@ -1257,10 +1257,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12824,6 +12824,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -14142,7 +14146,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -17560,7 +17564,7 @@ msgid "Options to customize the ebook viewer" msgstr "Možnosti úpravy prohlížeče elektronických knih" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "Zapamatuj si posledně použitou velikost okna" @@ -18162,41 +18166,41 @@ msgstr "Spravovat záložky" msgid "Loading ebook..." msgstr "Načítám knihu..." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "Nemohu otevřít eknihu" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "Volby ke kontrole prohlížeče ebooků" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "Pokud specifikováno, okno prohlížeče se zobrazí po startu v popředí." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" "Pokud je zadáno, pokusí se při spuštění otevřít okno prohlížeče na celou " "obrazovku." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "Tisknout upozornění javascriptu a konzolové zprávy do konzole" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -19914,17 +19918,17 @@ msgstr "" msgid "creating custom column " msgstr "vytváření uživatelských sloupců " -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "

Migruji starou databázi do knihovy ebooků v %s

" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "Kopírování %s" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "Zhutňování databáze" diff --git a/src/calibre/translations/cy.po b/src/calibre/translations/cy.po index a4bfc216be..5014375bc5 100644 --- a/src/calibre/translations/cy.po +++ b/src/calibre/translations/cy.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-02-26 20:21+0000\n" "Last-Translator: Rachael Munns \n" "Language-Team: Welsh \n" @@ -16,8 +16,8 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=n==1 ? 0 : n==2 ? 1 : (n != 8 && n != 11) ? " "2 : 3;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:31+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:55+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -176,12 +176,12 @@ msgstr "Dim yn gwneud dim byd" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -940,26 +940,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "Iawn" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "Sail" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "Cerdyn A" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "Cerdyn B" @@ -1134,14 +1134,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Newyddion" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Catalog" @@ -1189,10 +1189,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12050,6 +12050,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13343,7 +13347,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16694,7 +16698,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17285,39 +17289,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18921,17 +18925,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/da.po b/src/calibre/translations/da.po index 60f1033059..72e9126f2c 100644 --- a/src/calibre/translations/da.po +++ b/src/calibre/translations/da.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-07-13 17:59+0000\n" "Last-Translator: Jens Holm \n" "Language-Team: Danish \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:16+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:40+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "Gør absolut ingenting" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -977,26 +977,26 @@ msgstr "Sti til bibliotek for lang. Skal være kortere end %d tegn." #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "Ja" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "Main/hjem/primær" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "Kort A" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "Kort B" @@ -1203,14 +1203,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Nyheder" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Katalog" @@ -1265,10 +1265,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12584,6 +12584,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13900,7 +13904,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -17356,7 +17360,7 @@ msgid "Options to customize the ebook viewer" msgstr "Indstillinger til tilpasning af e-bogsviseren" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "Husk størrelsen på vinduet" @@ -17952,41 +17956,41 @@ msgstr "Administrér bogmærker" msgid "Loading ebook..." msgstr "Henter e-bog..." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "Kunne ikke åbne e-bog" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "Valg til at styre e-bogsviser" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" "Hvis specificeret, vil visningsvindue prøve at komme i front ved start." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" "Hvis angivet, vil oversigtsvindue prøve at åbne i fuld skærm under start." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "Udskriv javascript alert og konsol beskeder til konsolen" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -19805,17 +19809,17 @@ msgstr "" msgid "creating custom column " msgstr "opret tilpasset søjle " -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "

Flytter gammel database til e-bogsbibliotek i %s

" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "Kopierer %s" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "Komprimerer database" diff --git a/src/calibre/translations/de.po b/src/calibre/translations/de.po index c6cbdf3ace..c5e2cb6a62 100644 --- a/src/calibre/translations/de.po +++ b/src/calibre/translations/de.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: de\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-10-20 14:01+0000\n" "Last-Translator: SimonFS \n" "Language-Team: American English \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:19+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:43+0000\n" +"X-Generator: Launchpad (build 16194)\n" "X-Poedit-Bookmarks: 3327,-1,-1,-1,-1,-1,-1,-1,-1,-1\n" "Generated-By: pygettext.py 1.5\n" @@ -177,12 +177,12 @@ msgstr "Macht absolut gar nichts" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -998,26 +998,26 @@ msgstr "Pfad zur Datenbank zu lang. Muss kürzer als %d Zeichen sein" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "Ja" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "Haupt" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "Karte A" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "Karte B" @@ -1234,14 +1234,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Nachrichten" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Katalog" @@ -1297,10 +1297,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -13676,6 +13676,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -15103,13 +15107,9 @@ msgstr "Der Hinzufügen &Prozess" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" -"Wenn gesetzt, wird calibre prüfen, ob eine Datei\n" -" die automatisch hinzugefügt wird, schon in der Bibliothek ist.\n" -" Wenn ja, wird eine Popup-Nachricht angezeigt, ob\n" -" Sie die Datei trotzdem hinzufügen wollen." #: /home/kovid/work/calibre/src/calibre/gui2/preferences/adding_ui.py:152 msgid "Check for &duplicates when auto-adding files" @@ -19020,7 +19020,7 @@ msgid "Options to customize the ebook viewer" msgstr "Einstellungen zum Anpassen des E-Book-Betrachters" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "Zuletzt verwendete Fenstergröße merken" @@ -19653,37 +19653,37 @@ msgstr "Lesezeichen verwalten" msgid "Loading ebook..." msgstr "Lade E-Book..." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "Konnte E-Book nicht öffnen" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "Unbekannter Fehler" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "Einstellungen zur Steuerung des E-Book-Betrachters" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" "Falls ausgewählt, wird das Betrachterfenster nach Möglichkeit im Vordergrund " "geöffnet." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" "Falls ausgewählt, wird das Betrachterfenster nach Möglichkeit im " "Vollbildmodus geöffnet." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "Javascript Alarme und Konsolennachrichten auf der Konsole ausgeben" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." @@ -19691,7 +19691,7 @@ msgstr "" "Bildschirmposition, an der das Buch geöffnet werden soll. Die Stelle wird " "oben links im Betrachter angezeigt" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -21701,17 +21701,17 @@ msgstr "wiederhergestellte Einstellung " msgid "creating custom column " msgstr "Erstelle benutzerdefinierte Spalte " -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "

Migriere alte Datenbank zu E-Book Bibliothek in %s

" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "Kopiere %s" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "Komprimiere Datenbank" diff --git a/src/calibre/translations/el.po b/src/calibre/translations/el.po index 2ed9a46887..789cbb1478 100644 --- a/src/calibre/translations/el.po +++ b/src/calibre/translations/el.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-07-22 09:51+0000\n" "Last-Translator: SteliosGero \n" "Language-Team: Greek \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:19+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:43+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "Δεν κάνει τίποτα" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -997,26 +997,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "Ναι" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "Κύρια μνήμη" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "Κάρτα μνήμης Α" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "Κάρτα μνήμης Β" @@ -1196,14 +1196,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Ειδήσεις" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Κατάλογος" @@ -1259,10 +1259,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12257,6 +12257,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13550,7 +13554,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16901,7 +16905,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17492,39 +17496,39 @@ msgstr "Διαχείριση Σελιδοδεικτών" msgid "Loading ebook..." msgstr "Γίνεται φόρτωση του eBook..." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "Δεν ήταν δυνατή η φόρτωση του eBook" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -19146,17 +19150,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "Συμπίεση βάσης δεδομένων" diff --git a/src/calibre/translations/en_AU.po b/src/calibre/translations/en_AU.po index 392f2bb7a6..283a252e4f 100644 --- a/src/calibre/translations/en_AU.po +++ b/src/calibre/translations/en_AU.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-07-14 23:02+0000\n" "Last-Translator: Cruz Bishop \n" "Language-Team: English (Australia) \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:33+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:57+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "Does absolutely nothing" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -935,26 +935,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1129,14 +1129,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1184,10 +1184,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12044,6 +12044,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13337,7 +13341,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16688,7 +16692,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17279,39 +17283,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18915,17 +18919,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/en_CA.po b/src/calibre/translations/en_CA.po index 17da8ef264..4b8b3b45ed 100644 --- a/src/calibre/translations/en_CA.po +++ b/src/calibre/translations/en_CA.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2011-08-05 17:28+0000\n" "Last-Translator: Kovid Goyal \n" "Language-Team: English (Canada) \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:34+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:57+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "Does absolutely nothing" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -933,26 +933,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1127,14 +1127,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "News" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1182,10 +1182,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12115,6 +12115,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13408,7 +13412,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16759,7 +16763,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17350,39 +17354,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18986,17 +18990,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/en_GB.po b/src/calibre/translations/en_GB.po index a35a357979..069b88e379 100644 --- a/src/calibre/translations/en_GB.po +++ b/src/calibre/translations/en_GB.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-05-28 15:00+0000\n" "Last-Translator: Vibhav Pant \n" "Language-Team: English (United Kingdom) \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:33+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:56+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "Does absolutely nothing" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -975,26 +975,26 @@ msgstr "Path to library too long. Must be less than %d characters." #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "Yes" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "Main" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "Card A" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "Card B" @@ -1195,14 +1195,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "News" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Catalogue" @@ -1256,10 +1256,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -13148,6 +13148,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -14549,13 +14553,9 @@ msgstr "The Add &Process" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" -" you want to add it anyway." -msgstr "" -"If set, this option will causes calibre to check if a file\n" -" being auto-added is already in the calibre library.\n" " If it is, a message will pop up asking you whether\n" " you want to add it anyway." +msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/adding_ui.py:152 msgid "Check for &duplicates when auto-adding files" @@ -18310,7 +18310,7 @@ msgid "Options to customize the ebook viewer" msgstr "Options to customise the ebook viewer" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "Remember last used window size" @@ -18920,35 +18920,35 @@ msgstr "Manage Bookmarks" msgid "Loading ebook..." msgstr "Loading ebook..." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "Could not open ebook" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "Options to control the ebook viewer" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" "If specified, viewer window will try to come to the front when started." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" "If specified, viewer window will try to open full screen when started." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "Print javascript alert and console messages to the console" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." @@ -18956,7 +18956,7 @@ msgstr "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -20822,17 +20822,17 @@ msgstr "" msgid "creating custom column " msgstr "creating custom column " -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "

Migrating old database to ebook library in %s

" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "Copying %s" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "Compacting database" diff --git a/src/calibre/translations/eo.po b/src/calibre/translations/eo.po index 9e6bb9ff54..d5cc595652 100644 --- a/src/calibre/translations/eo.po +++ b/src/calibre/translations/eo.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-08-03 13:00+0000\n" "Last-Translator: Cyril \n" "Language-Team: Esperanto \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:17+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:41+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "Faras absolute nenion" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -958,26 +958,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1152,14 +1152,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1207,10 +1207,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12070,6 +12070,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13363,7 +13367,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16714,7 +16718,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17305,39 +17309,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18941,17 +18945,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/es.po b/src/calibre/translations/es.po index 674ba17f63..1898dd95fc 100644 --- a/src/calibre/translations/es.po +++ b/src/calibre/translations/es.po @@ -10,16 +10,16 @@ msgid "" msgstr "" "Project-Id-Version: es\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" -"PO-Revision-Date: 2012-10-19 12:46+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" +"PO-Revision-Date: 2012-10-26 14:44+0000\n" "Last-Translator: Jellby \n" "Language-Team: Español; Castellano <>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:29+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:52+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:533 msgid "" @@ -194,12 +194,12 @@ msgstr "No hace absolutamente nada" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -1008,26 +1008,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "Sí" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "Principal" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "Tarjeta A" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "Tarjeta B" @@ -1245,14 +1245,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Noticias" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Catálogo" @@ -1308,10 +1308,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -3805,6 +3805,12 @@ msgid "" "to remove fonts from the input document. Note that font embedding only works " "with some output formats, principally EPUB and AZW3." msgstr "" +"Incluirel tipo de letra especificado en el libro. Esto establece el tipo de " +"letra «base» usado en el libro. Si el documento de entrada especifica sus " +"propios tipos de letra, pueden tener prioridad sobre este tipo de letra " +"base. Puede usar la opción de filtrar estilos para eliminar tipos de letra " +"del documento de entrada. Tenga en cuenta que la inclusión de tipos de letra " +"sólo funciona con algunos formatos de salida, principalmente EPUB y AZW3." #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:209 msgid "" @@ -8733,7 +8739,7 @@ msgstr "&Altura de línea:" #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:237 msgid "&Embed font family:" -msgstr "" +msgstr "&Incluir tipo de letra:" #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:238 msgid "&Disable font size rescaling" @@ -9161,7 +9167,7 @@ msgstr "Abrir libro" #: /home/kovid/work/calibre/src/calibre/gui2/convert/regex_builder.py:215 msgid "Click the Open button below to open a ebook to use for testing." -msgstr "" +msgstr "Pulse el botón «Abrir» para abrir un libro como prueba." #: /home/kovid/work/calibre/src/calibre/gui2/convert/regex_builder_ui.py:90 msgid "Regex Builder" @@ -13546,7 +13552,7 @@ msgstr "Expresión regular (?P)" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:122 msgid "Choose font family" -msgstr "" +msgstr "Escoger tipo de letra" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:137 #: /home/kovid/work/calibre/src/calibre/gui2/keyboard.py:377 @@ -13566,11 +13572,15 @@ msgstr "Ninguno" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:159 msgid "Choose a font family from the list below:" -msgstr "" +msgstr "Escoja un tipo de letra de la siguiente lista:" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:187 msgid "Choose &font family" -msgstr "" +msgstr "Escoger &tipo de letra" + +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "Limpiar tipo de letra" #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 @@ -14292,7 +14302,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:273 #, python-format msgid "Could not open \"%s\". Is it being used by another program?" -msgstr "" +msgstr "No se pudo abrir «%s». Puede que esté en uso por otro programa." #: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:306 msgid "" @@ -14995,13 +15005,12 @@ msgstr "&Proceso de adición" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" -"Si se activa, esta opción hace que calibre compruebe si un\n" -"archivo que se añade automáticamente ya existe en la\n" -"biblioteca de calibre. Si es así, aparecerá un mensaje\n" -"preguntando si desea añadirlo de todas formas." +"Si se activa esta opción calibre comprobará si un archivo autoañadido ya " +"existe en la biblioteca de calibre. Si es así, se mostrará un mensaje que le " +"dará la opción de añadirlo o no." #: /home/kovid/work/calibre/src/calibre/gui2/preferences/adding_ui.py:152 msgid "Check for &duplicates when auto-adding files" @@ -18849,7 +18858,7 @@ msgid "Options to customize the ebook viewer" msgstr "Opciones para personalizar el visor de libros electrónicos" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "&Recordar el último tamaño de ventana usado" @@ -19477,36 +19486,36 @@ msgstr "Administrar marcadores" msgid "Loading ebook..." msgstr "Cargando libro electrónico..." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "No se pudo abrir el libro electrónico" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "Error desconocido" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "Opciones para controlar el visor de libros electrónicos" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" "Si se especifica, la ventana del visor intentará situarse en el frente " "cuando se inicie el programa." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" "Si se activa, la ventana del visor tratará de iniciarse a pantalla completa." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "Dirigir alertas de javascript y mensajes de consola a la consola" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." @@ -19514,7 +19523,7 @@ msgstr "" "Posición en la que abrir el libro especificado. La posición es una ubicación " "mostrada en la esquina superior izquierda del visor." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -21115,6 +21124,24 @@ msgid "" "that a new OPF has been createdsince the column was added). You will see the " "JSON for the\"display\" for the new column in the OPF." msgstr "" +"Un diccionario de opciones para personalizar cómo se interpretan los datos " +"en esta columna. Es un texto en formato JSON. Para columnas de enumeración " +"use --display=\"{\\\"enum_values\\\":[\\\"val1\\\", \\\"val2\\\"]}\"\n" +"Hay muchas opciones que pueden figurar en la variable «display». Las " +"opciones por tipo de columna son:\n" +"composite: composite_template, composite_sort, make_category,contains_html, " +"use_decorations\n" +"datetime: date_format\n" +"enumeration: enum_values, enum_colors, use_decorations\n" +"int, float: number_format\n" +"text: is_names, use_decoration\n" +"\n" +"La mejor manera de obtener combinaciones válidas es crear una columna " +"personalizada del tipo apropiado en la interfaz gráfica y luego examinar el " +"archivo OPF creado como copia de seguridad para un libro (asegúrese de que " +"se ha creado un nuevo archivo OPF después de añadir la columna). Verá el " +"texto en formato JSON para la variable «display» de la nueva columna en el " +"archivo OPF." #: /home/kovid/work/calibre/src/calibre/library/cli.py:721 msgid "You must specify label, name and datatype" @@ -21522,19 +21549,19 @@ msgstr "restaurada preferencia " msgid "creating custom column " msgstr "creando columna personalizada " -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" "

Migrando la base de datos antigua a la biblioteca de libros electrónicos " "en %s

" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "Copiando %s" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "Compactando la base de datos" @@ -22190,7 +22217,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/utils/filenames.py:284 msgid "File is open in another process" -msgstr "" +msgstr "El archivo está abierto en otro proceso" #: /home/kovid/work/calibre/src/calibre/utils/formatter.py:31 #: /home/kovid/work/calibre/src/calibre/utils/formatter.py:182 diff --git a/src/calibre/translations/et.po b/src/calibre/translations/et.po index e68ca33007..18b04a4ce5 100644 --- a/src/calibre/translations/et.po +++ b/src/calibre/translations/et.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-05-02 00:16+0000\n" "Last-Translator: Kaur Alasoo \n" "Language-Team: Estonian \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:17+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:41+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "Ei tee midagi" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -952,26 +952,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "Jah" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "Peamine" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "Kaart A" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "Kaart B" @@ -1146,14 +1146,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1201,10 +1201,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12063,6 +12063,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13356,7 +13360,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16707,7 +16711,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17298,39 +17302,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18934,17 +18938,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/eu.po b/src/calibre/translations/eu.po index d6ba2fb550..5db051499c 100644 --- a/src/calibre/translations/eu.po +++ b/src/calibre/translations/eu.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-09-19 22:56+0000\n" "Last-Translator: gorkaazk \n" "Language-Team: http://librezale.org/wiki/Calibre\n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:14+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:38+0000\n" +"X-Generator: Launchpad (build 16194)\n" "Language: eu\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 @@ -176,12 +176,12 @@ msgstr "Ez du ezer egiten" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -1011,26 +1011,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "Bai" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "Nagusia" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "A txartela" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "B txartela" @@ -1236,14 +1236,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Albisteak" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Katalogoa" @@ -1298,10 +1298,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12984,6 +12984,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -14320,7 +14324,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -17840,7 +17844,7 @@ msgid "Options to customize the ebook viewer" msgstr "Liburu elektronikoen irakurgailua pertsonalizatzeko aukerak" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "Gogoratu erabilitako azken leiho tamaina" @@ -18446,43 +18450,43 @@ msgstr "Kudeatu laster-markak" msgid "Loading ebook..." msgstr "Liburu elektronikoa kargatzen..." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "Ezin izan da liburua zabaldu" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "Liburu elektronikoen irakurgailua kontrolatzeko aukerak" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" "Zehazten bada, ikustailearen leihoa saiatuko da aurreko aldera etortzen " "hasterakoan." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" "Hauxe hautatu eginez gero, ikusiko den leihoa saiatuko da pantaila osoa " "zabaltzen hasi eta berehalakoan." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "Inprimatu javascript alerta eta kontsola mezuak kontsolara" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -20329,19 +20333,19 @@ msgstr "" msgid "creating custom column " msgstr "zutabe pertsonalizatua sortzen " -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" "

Migrazioa egiten datu base zaharretik liburu elektronikoen liburutegira " "zera honetan: %s

" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "Kopiatzen %s" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "Trinkotzen datu basea" diff --git a/src/calibre/translations/fa.po b/src/calibre/translations/fa.po index 45e5f98107..0e9aa3ec05 100644 --- a/src/calibre/translations/fa.po +++ b/src/calibre/translations/fa.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-06-07 03:13+0000\n" "Last-Translator: Farhood M,K, Kiazand \n" "Language-Team: Persian \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:26+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:49+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -956,26 +956,26 @@ msgstr "آدرس برای کتاب خانه طولانی است. باید کمت #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "بلی" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "اصلی" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1150,14 +1150,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1205,10 +1205,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12068,6 +12068,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13361,7 +13365,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16712,7 +16716,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17303,39 +17307,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18939,17 +18943,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/fi.po b/src/calibre/translations/fi.po index 99ee526c5b..520f966684 100644 --- a/src/calibre/translations/fi.po +++ b/src/calibre/translations/fi.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-02-03 12:13+0000\n" "Last-Translator: Jaakko Perttilä \n" "Language-Team: Finnish \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:18+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:42+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "Ei tee mitään" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -972,26 +972,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1171,14 +1171,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Uutiset" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Luettelo" @@ -1227,10 +1227,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12154,6 +12154,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13447,7 +13451,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16798,7 +16802,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17389,39 +17393,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -19036,17 +19040,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/fo.po b/src/calibre/translations/fo.po index d5372d9f26..ee0a9a1dbe 100644 --- a/src/calibre/translations/fo.po +++ b/src/calibre/translations/fo.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2011-08-05 17:17+0000\n" "Last-Translator: Kovid Goyal \n" "Language-Team: Faroese \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:17+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:41+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -929,26 +929,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1123,14 +1123,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1178,10 +1178,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12038,6 +12038,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13331,7 +13335,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16682,7 +16686,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17273,39 +17277,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18909,17 +18913,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/fr.po b/src/calibre/translations/fr.po index 9bc931671d..cbd899bb35 100644 --- a/src/calibre/translations/fr.po +++ b/src/calibre/translations/fr.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre 0.4.22\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-10-25 06:36+0000\n" "Last-Translator: Franck \n" "Language-Team: PCGen\n" @@ -15,7 +15,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Launchpad-Export-Date: 2012-10-26 04:55+0000\n" +"X-Launchpad-Export-Date: 2012-10-27 04:42+0000\n" "X-Generator: Launchpad (build 16194)\n" "Language: fr\n" "X-Poedit-Bookmarks: 1177,1104,-1,-1,-1,-1,-1,-1,-1,-1\n" @@ -178,12 +178,12 @@ msgstr "Ne fait strictement rien" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -1018,26 +1018,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "Oui" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "Principal" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "Carte A" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "Carte B" @@ -1256,14 +1256,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Informations" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Catalogue" @@ -1319,10 +1319,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -13771,6 +13771,10 @@ msgstr "Choisir une famille de polices dans la liste ci-dessous :" msgid "Choose &font family" msgstr "Choisir la &famille de polices" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -15208,13 +15212,9 @@ msgstr "Le processus d’&Ajout" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" -"Si elle est activée, cette option entraînera une vérification\n" -" par calibre, de la présence du fichier dans la bibliothèque lors\n" -" de son ajout automatique. Si c’est le cas, un message apparaîtra\n" -" pour vous demander s'il doit quand même être ajouté." #: /home/kovid/work/calibre/src/calibre/gui2/preferences/adding_ui.py:152 msgid "Check for &duplicates when auto-adding files" @@ -19139,7 +19139,7 @@ msgid "Options to customize the ebook viewer" msgstr "Options de personnalisation du visionneur de livre numérique" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "Se souvenir de la dernière taille de fenêtre utilisée" @@ -19774,38 +19774,38 @@ msgstr "Gérer les Signets" msgid "Loading ebook..." msgstr "Chargement du livre numérique…" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "Impossible d’ouvrir le livre numérique" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "Erreur inconnue" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "Options pour contrôler le visionneur de livre numérique" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" "Si spécifié, la fenêtre du visionneur essaiera d’apparaître au premier plan " "au lancement." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" "Si précisé, la fenêtre du visionneur essaiera de s’ouvrir en plein écran au " "démarrage." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" "Afficher les alertes javascript et les messages console dans la console" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." @@ -19814,7 +19814,7 @@ msgstr "" "endroit tel celui qui est affiché dans le coin inférieur gauche du " "visionneur." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -21816,17 +21816,17 @@ msgstr "préférences restaurées " msgid "creating custom column " msgstr "crée des colonnes personnalisées " -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "

Migre l’ancienne base vers la bibliothèque dans %s

" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "Copie %s" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "Compacte la base" diff --git a/src/calibre/translations/fr_CA.po b/src/calibre/translations/fr_CA.po index 51478203ee..75bfdd11b4 100644 --- a/src/calibre/translations/fr_CA.po +++ b/src/calibre/translations/fr_CA.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-03-30 13:27+0000\n" "Last-Translator: Richard Boudreau \n" "Language-Team: French (Canada) \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:33+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:56+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "Ne fait strictement rien" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -981,26 +981,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1175,14 +1175,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1230,10 +1230,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12090,6 +12090,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13383,7 +13387,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16734,7 +16738,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17325,39 +17329,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18961,17 +18965,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/fur.po b/src/calibre/translations/fur.po index 1d9164caf1..94560d2aeb 100644 --- a/src/calibre/translations/fur.po +++ b/src/calibre/translations/fur.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-10-14 15:48+0000\n" "Last-Translator: Mauro Ermacora \n" "Language-Team: Friulian \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:18+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:42+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -932,26 +932,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1126,14 +1126,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1181,10 +1181,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12041,6 +12041,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13334,7 +13338,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16685,7 +16689,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17276,39 +17280,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18912,17 +18916,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/gl.po b/src/calibre/translations/gl.po index d7308f1382..316f73c633 100644 --- a/src/calibre/translations/gl.po +++ b/src/calibre/translations/gl.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-04-24 07:58+0000\n" "Last-Translator: Miguel Anxo Bouzada \n" "Language-Team: dev@gl.openoffice.org\n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:19+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:43+0000\n" +"X-Generator: Launchpad (build 16194)\n" "Language: gl\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 @@ -176,12 +176,12 @@ msgstr "Non facer nada" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -991,26 +991,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "Si" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "Principal" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "Tarxeta A" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "Tarxeta B" @@ -1219,14 +1219,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Noticias" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Catálogo" @@ -1280,10 +1280,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12942,6 +12942,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -14307,7 +14311,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -17935,7 +17939,7 @@ msgid "Options to customize the ebook viewer" msgstr "Opcións para personalizar o visualizador de libros" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "Lembrar o tamaño da última xanela usada" @@ -18540,42 +18544,42 @@ msgstr "Xestionar os marcadores" msgid "Loading ebook..." msgstr "Cargando libro..." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "Non se puido abrir o libro" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "Opcións de control do visor de libros" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" "Se se especifica, a xanela do visor tentará situarse na fronte cando se " "inicie o programa." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" "Se se activa, a xanela do visor tentará iniciarse a pantalla completa." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "Dirixir alertas de JavaScript e mensaxes de consola á consola" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -20421,19 +20425,19 @@ msgstr "" msgid "creating custom column " msgstr "creando columna personalizada " -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" "

Migrando a base de datos antiga á biblioteca de libros electrónicos en " "%s

" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "Copiando %s" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "Compactando a base de datos" diff --git a/src/calibre/translations/gu.po b/src/calibre/translations/gu.po index c5213e3f4f..e6e9160e9e 100644 --- a/src/calibre/translations/gu.po +++ b/src/calibre/translations/gu.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2011-08-20 06:46+0000\n" "Last-Translator: Hasit Bhatt \n" "Language-Team: Gujarati \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:20+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:44+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "કઈ પણ કરતું નથી" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -929,26 +929,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1123,14 +1123,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1178,10 +1178,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12038,6 +12038,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13331,7 +13335,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16682,7 +16686,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17273,39 +17277,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18909,17 +18913,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/he.po b/src/calibre/translations/he.po index 815b2a1671..39f7c7500a 100644 --- a/src/calibre/translations/he.po +++ b/src/calibre/translations/he.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-07-18 17:43+0000\n" "Last-Translator: Tal Nisan \n" "Language-Team: Hebrew \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:20+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:44+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "לא עושה דבר" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -954,26 +954,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "כן" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "ראשי" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "כרטיס A" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "כרטיס B" @@ -1155,14 +1155,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "חדשות" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "קטלוג" @@ -1212,10 +1212,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12090,6 +12090,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13383,7 +13387,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16734,7 +16738,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17325,39 +17329,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18961,17 +18965,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/hi.po b/src/calibre/translations/hi.po index 6924666564..0ebed443c7 100644 --- a/src/calibre/translations/hi.po +++ b/src/calibre/translations/hi.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-03-18 12:52+0000\n" "Last-Translator: Vibhav Pant \n" "Language-Team: Hindi \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:20+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:44+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "कुछ भी नहीं करता" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -931,26 +931,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1125,14 +1125,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1180,10 +1180,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12043,6 +12043,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13336,7 +13340,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16687,7 +16691,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17278,39 +17282,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18914,17 +18918,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/him.po b/src/calibre/translations/him.po index 31720252b7..1958c446d9 100644 --- a/src/calibre/translations/him.po +++ b/src/calibre/translations/him.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-07-23 13:49+0000\n" "Last-Translator: FULL NAME \n" "Language-Team: Himachali \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:20+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:44+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -929,26 +929,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1123,14 +1123,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1178,10 +1178,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12038,6 +12038,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13331,7 +13335,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16682,7 +16686,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17273,39 +17277,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18909,17 +18913,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/hr.po b/src/calibre/translations/hr.po index 56761195cf..144367c826 100644 --- a/src/calibre/translations/hr.po +++ b/src/calibre/translations/hr.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-05-04 13:42+0000\n" "Last-Translator: Tomislav Pešut \n" "Language-Team: Croatian \n" @@ -16,8 +16,8 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:28+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:51+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -176,12 +176,12 @@ msgstr "Uopće ne funkcionira" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -953,26 +953,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "Da" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "Glavni" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1147,14 +1147,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Vijesti" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Katalog" @@ -1202,10 +1202,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12307,6 +12307,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13610,7 +13614,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16993,7 +16997,7 @@ msgid "Options to customize the ebook viewer" msgstr "Opcije za prilagodbu preglednika elektroničke knjige" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "Zapamti zadnju korištenu veličinu zaslona" @@ -17588,41 +17592,41 @@ msgstr "Upravljaj Knjižnim Oznakama" msgid "Loading ebook..." msgstr "Učitavanje elektroničke knjige..." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "Nemoguće otvoriti elektroničku knjigu" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "Opcije za kontrolu preglednika" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" "Ako je naznačeno, kod pokretanj će preglednički prozor pokušati da dođe " "ispred." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "Ispiši javascript upozorenje i poruke na kontrolnu ploču" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -19321,18 +19325,18 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" "

Preseljavanje stare baze podataka na ebook biblioteku u %s

" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "Kopiranje %s" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "Sažimanje baze podataka" diff --git a/src/calibre/translations/hu.po b/src/calibre/translations/hu.po index c6a37ac255..204617bb46 100644 --- a/src/calibre/translations/hu.po +++ b/src/calibre/translations/hu.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-08-25 19:23+0000\n" "Last-Translator: Devilinside \n" "Language-Team: Hungarian \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:21+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:45+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "Semmit sem csinál" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -981,26 +981,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "Igen" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "Fő memória" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "„A” kártya" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "„B” kártya" @@ -1206,14 +1206,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Hírek (RSS)" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Katalógus" @@ -1268,10 +1268,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -13303,6 +13303,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -14715,12 +14719,9 @@ msgstr "Könyvek hozzáadásának beállításai" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" -"Ha be van jelölve, akkor a calibre ellenőrzi, hogy\n" -" a fájl szerepel-e már adatbázisban. Ha a fájl\n" -" már megtalálható, akkor a program megerősítést kér." #: /home/kovid/work/calibre/src/calibre/gui2/preferences/adding_ui.py:152 msgid "Check for &duplicates when auto-adding files" @@ -18505,7 +18506,7 @@ msgid "Options to customize the ebook viewer" msgstr "E-book olvasó beállítása" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "Az utoljára használt ablakméret megjegyzése" @@ -19116,43 +19117,43 @@ msgstr "Könyvjelzők kezelése" msgid "Loading ebook..." msgstr "E-book betöltése…" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "Nem lehet megnyitni a könyvet" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "Az e-book olvasó program beállításai" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" "Ha be van állítva, akkor az olvasóprogram megpróbál az előtérbe kerülni " "induláskor." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" "Ha be van állítva, akkor az olvasóprogram megpróbál teljes képernyősként " "indulni" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "Javascript és konzolüzenetek megjelenítése a konzolon" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -21032,17 +21033,17 @@ msgstr "" msgid "creating custom column " msgstr "egyéni oszlop készítése " -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "

Régi adatbázis migrálása a jelenlegibe: %s

" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "Másolás: %s" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "Adatbázis tömörítése" diff --git a/src/calibre/translations/id.po b/src/calibre/translations/id.po index 1b929881fe..9bcec02238 100644 --- a/src/calibre/translations/id.po +++ b/src/calibre/translations/id.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-01-18 11:51+0000\n" "Last-Translator: Amri Ristadi \n" "Language-Team: Indonesian \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:21+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:45+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "Tidak ada apa-apanya" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -954,26 +954,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1148,14 +1148,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1203,10 +1203,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12066,6 +12066,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13359,7 +13363,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16710,7 +16714,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17301,39 +17305,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18937,17 +18941,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/is.po b/src/calibre/translations/is.po index b92601f1ee..cf908caa53 100644 --- a/src/calibre/translations/is.po +++ b/src/calibre/translations/is.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: 20120515-src_calibre_translations_calibre-is\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-05-23 19:33+0000\n" "Last-Translator: Sveinn í Felli \n" "Language-Team: Icelandic \n" @@ -17,8 +17,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:21+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:45+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -177,12 +177,12 @@ msgstr "Gerir nákvæmlega ekkert" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -931,26 +931,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1125,14 +1125,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1180,10 +1180,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12040,6 +12040,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13333,7 +13337,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16684,7 +16688,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17275,39 +17279,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18911,17 +18915,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/it.po b/src/calibre/translations/it.po index 88f498327e..f2c683b8e0 100644 --- a/src/calibre/translations/it.po +++ b/src/calibre/translations/it.po @@ -9,16 +9,16 @@ msgid "" msgstr "" "Project-Id-Version: calibre_calibre-it\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" -"PO-Revision-Date: 2012-10-21 22:18+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" +"PO-Revision-Date: 2012-10-26 08:14+0000\n" "Last-Translator: Vincenzo Reale \n" "Language-Team: Italian \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:22+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:45+0000\n" +"X-Generator: Launchpad (build 16194)\n" "Language: it\n" "X-Poedit-Bookmarks: -1,-1,-1,-1,-1,1105,-1,1312,-1,-1\n" "Generated-By: pygettext.py 1.5\n" @@ -180,12 +180,12 @@ msgstr "Non fa assolutamente niente" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -1003,26 +1003,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "Sì" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "Principale" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "Scheda A" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "Scheda B" @@ -1237,14 +1237,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Notizie" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Catalogo" @@ -1299,10 +1299,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -1882,7 +1882,7 @@ msgid "" "first time you send the book to the device." msgstr "" "Se l'opzione Carica le copertine è selezionata, il driver sostituirà solo le " -"copertine già presenti sul dispositivo. Selezion questa opzione se vuoi che " +"copertine già presenti sul dispositivo. Seleziona questa opzione se vuoi che " "le copertine siano caricate la prima volta che invii un libro al dispositivo." #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1241 @@ -2071,7 +2071,7 @@ msgstr "Oggetto trovato: %s" #: /home/kovid/work/calibre/src/calibre/devices/mtp/windows/driver.py:61 msgid "MTP devices are not supported on Windows XP" -msgstr "I dispositivi MPT non sono supportati su Windows XP" +msgstr "I dispositivi MTP non sono supportati su Windows XP" #: /home/kovid/work/calibre/src/calibre/devices/mtp/windows/driver.py:69 msgid "" @@ -3804,6 +3804,13 @@ msgid "" "to remove fonts from the input document. Note that font embedding only works " "with some output formats, principally EPUB and AZW3." msgstr "" +"Integra la famiglia di caratteri specificata nel libro. Specifica il " +"carattere \"base\" utilizzato per il libro. Se il documento di input " +"specifica i propri caratteri, questi potrebbero scavalcare il carattere " +"base. Puoi utilizzare l'opzione di filtro delle informazioni di stile per " +"rimuovere i caratteri dal documento di input. Nota che l'integrazione di " +"caratteri funziona solo con alcuni formati di output, principalmente EPUB e " +"AZW3." #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:209 msgid "" @@ -5119,7 +5126,7 @@ msgid "" msgstr "" "Questo file MOBI non contiene un libro in formato KF8. KF8 è il nuovo " "formato di Amazon. calibre può ottimizzare solo i file MOBI che contengono " -"libri KF8. I vecchi file MOBI senza KF98 non sono ottimizzabili." +"libri KF8. I vecchi file MOBI senza KF8 non sono ottimizzabili." #: /home/kovid/work/calibre/src/calibre/ebooks/mobi/tweak.py:65 msgid "" @@ -7239,7 +7246,7 @@ msgid "" "Books with the same title as the following already exist in calibre. Add " "them anyway?" msgstr "" -"Libri con lo stesso titolo del seguente esistono già in calibre. Vuioi " +"Libri con lo stesso titolo del seguente esistono già in calibre. Vuoi " "aggiungerli comunque?" #: /home/kovid/work/calibre/src/calibre/gui2/add.py:404 @@ -8681,7 +8688,7 @@ msgstr "Di&mensione riga:" #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:237 msgid "&Embed font family:" -msgstr "" +msgstr "Int&egra la famiglia di caratteri:" #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:238 msgid "&Disable font size rescaling" @@ -9108,6 +9115,8 @@ msgstr "Libro aperto" #: /home/kovid/work/calibre/src/calibre/gui2/convert/regex_builder.py:215 msgid "Click the Open button below to open a ebook to use for testing." msgstr "" +"Fai clic sul pulsante Apri in basso per aprire un ebook da utilizzare per i " +"test." #: /home/kovid/work/calibre/src/calibre/gui2/convert/regex_builder_ui.py:90 msgid "Regex Builder" @@ -13513,7 +13522,7 @@ msgstr "Espressione regolare (?P)" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:122 msgid "Choose font family" -msgstr "" +msgstr "Scegli la famiglia di caratteri" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:137 #: /home/kovid/work/calibre/src/calibre/gui2/keyboard.py:377 @@ -13533,11 +13542,15 @@ msgstr "Nessuno" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:159 msgid "Choose a font family from the list below:" -msgstr "" +msgstr "Scegli una famiglia di caratteri dall'elenco seguente:" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:187 msgid "Choose &font family" -msgstr "" +msgstr "Scegli la &famiglia di caratteri" + +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "Cancella la famiglia di caratteri" #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 @@ -14253,7 +14266,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:273 #, python-format msgid "Could not open \"%s\". Is it being used by another program?" -msgstr "" +msgstr "Impossibile aprire \"%s\". È utilizzato da un altro programma?" #: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:306 msgid "" @@ -14924,13 +14937,13 @@ msgstr "Il &processo di aggiunta" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" -"Se impostata, questa opzione farà si che calibre controlli se un file\n" -" che è stato aggiunto automaticamente sia già presente nella \n" -" biblioteca. In questo caso, apparirà un messaggio di richiesta se\n" -" aggiungere comunque il file." +"Se impostata, questa opzione farà in modo che calibre controlli\n" +" se un file aggiunto automaticamente sia già presente nella\n" +" biblioteca. Se lo è, un messaggio a comparsa ti chiederà se\n" +" se vuoi aggiungerlo comunque." #: /home/kovid/work/calibre/src/calibre/gui2/preferences/adding_ui.py:152 msgid "Check for &duplicates when auto-adding files" @@ -18725,7 +18738,7 @@ msgid "Options to customize the ebook viewer" msgstr "Opzioni per personalizzare il lettore di libri" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "Ricorda la dimensione della finestra usata l'ultima volta" @@ -19356,39 +19369,39 @@ msgstr "Gestire i segnalibri" msgid "Loading ebook..." msgstr "Caricamento libro..." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "Impossibile aprire il libro" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "Errore sconosciuto" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "Opzioni per controllare il visualizzatore di libri" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" "Se specificato, la finestra di visualizzazione tenterà di apparire in primo " "piano quando avviata." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" "Se selezionato, all'avvio la finestra del visualizzatore si aprirà a schermo " "intero." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" "Scrivi avvertenze dall'esecuzione e messaggi dal quadro di comando nella " "finestra del quadro di comando." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." @@ -19396,7 +19409,7 @@ msgstr "" "La posizione alla quale aprire il libro specificato. La posizione è visibile " "nell'angolo in alto a sinistra del visualizzatore." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -20921,7 +20934,7 @@ msgstr "" "\n" " Esporta un catalogo nel formato specificato dall'estensione di " "percorso/di/destinazione.\n" -" Le opxioni controllano il modo in cui le voci sono visualizzate nel " +" Le opzioni controllano il modo in cui le voci sono visualizzate nel " "catalogo generato.\n" " " @@ -21279,18 +21292,18 @@ msgstr "preferenza ripristinata " msgid "creating custom column " msgstr "creazione colonna personalizzata " -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" "

Migrazione del vecchio database nella biblioteca in %s

" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "Sto copiando %s" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "Compattazione database" @@ -22591,7 +22604,7 @@ msgstr "Cinese semplificato" #: /home/kovid/work/calibre/src/calibre/utils/localization.py:142 msgid "Chinese (HK)" -msgstr "Cinese (Honk Kong)" +msgstr "Cinese (Hong Kong)" #: /home/kovid/work/calibre/src/calibre/utils/localization.py:143 msgid "Traditional Chinese" diff --git a/src/calibre/translations/ja.po b/src/calibre/translations/ja.po index 1267f8e6c6..77181cfb42 100644 --- a/src/calibre/translations/ja.po +++ b/src/calibre/translations/ja.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-10-01 17:40+0000\n" "Last-Translator: Shushi Kurose \n" "Language-Team: Japanese \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:22+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:46+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "まったく何もしません" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -941,26 +941,26 @@ msgstr "ライブラリへのパスが長すぎます。%d文字以下でなけ #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "はい" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "主メモリー" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "カードA" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "カードB" @@ -1158,14 +1158,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "ニュース" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "カタログ" @@ -1215,10 +1215,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12530,6 +12530,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13856,7 +13860,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -17397,7 +17401,7 @@ msgid "Options to customize the ebook viewer" msgstr "電子書籍ビューアーをカスタマイズするためのオプション" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "最後に使ったウィンドウのサイズを覚える" @@ -17993,39 +17997,39 @@ msgstr "ブックマークの管理" msgid "Loading ebook..." msgstr "電子書籍をロード中..." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "電子書籍を開けませんでした" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "電子書籍ビューアーをコントロールするオプション" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "指定した場合は、ビューアーウィンドウは起動時に前面へ表示しようとします。" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "指定した場合は、ビューアーウィンドウは起動時に全画面表示しようとします。" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "Javascriptアラートとコンソールメッセージをコンソールへ表示" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "指定された本を開く位置です。位置とは、ビューアーの左上の端が表示されている場所のことです。" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -19812,17 +19816,17 @@ msgstr "" msgid "creating custom column " msgstr "カスタム列を作成 " -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "

古いデータベースを %s の電子書籍ライブラリへ移行

" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "コピー中%s" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "データベースのコンパクト化" diff --git a/src/calibre/translations/jv.po b/src/calibre/translations/jv.po index 32d4f7713f..007244ac1f 100644 --- a/src/calibre/translations/jv.po +++ b/src/calibre/translations/jv.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-08-09 07:28+0000\n" "Last-Translator: anggoro \n" "Language-Team: Javanese \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 0;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:22+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:46+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -935,26 +935,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1129,14 +1129,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1184,10 +1184,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12044,6 +12044,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13337,7 +13341,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16688,7 +16692,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17279,39 +17283,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18915,17 +18919,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/ka.po b/src/calibre/translations/ka.po index 77059c9ba1..c26c401026 100644 --- a/src/calibre/translations/ka.po +++ b/src/calibre/translations/ka.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-08-26 09:07+0000\n" "Last-Translator: clouds ge \n" "Language-Team: Georgian \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:19+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:42+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "საერთოდ არაფერს აკეთებს" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -932,26 +932,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "დიახ" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "მთავარი" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1126,14 +1126,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1181,10 +1181,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12041,6 +12041,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13334,7 +13338,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16685,7 +16689,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17276,39 +17280,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18912,17 +18916,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/kn.po b/src/calibre/translations/kn.po index 5e68a0b61a..bb70572991 100644 --- a/src/calibre/translations/kn.po +++ b/src/calibre/translations/kn.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-05-09 10:16+0000\n" "Last-Translator: s k Nagesh \n" "Language-Team: Kannada \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:22+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:46+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "ಏನನ್ನು ಮಾಡುವುದಿಲ್ಲ" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -932,26 +932,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1126,14 +1126,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1181,10 +1181,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12041,6 +12041,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13334,7 +13338,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16685,7 +16689,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17276,39 +17280,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18912,17 +18916,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/ko.po b/src/calibre/translations/ko.po index fe0722cca9..27f924c947 100644 --- a/src/calibre/translations/ko.po +++ b/src/calibre/translations/ko.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-05-04 11:13+0000\n" "Last-Translator: Hyun-ho Noh \n" "Language-Team: Korean \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:23+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:46+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "아무 것도 안함" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -939,26 +939,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "예" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "주" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "카드 A" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "카드 B" @@ -1140,14 +1140,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "뉴스" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "분류" @@ -1195,10 +1195,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12145,6 +12145,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13440,7 +13444,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16808,7 +16812,7 @@ msgid "Options to customize the ebook viewer" msgstr "전자책 뷰어 사용자 정의 옵션" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "최근 사용된 창 크기를 기억" @@ -17399,39 +17403,39 @@ msgstr "북마크 관리" msgid "Loading ebook..." msgstr "책 불러오는중..." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "전자책을 열 수 없음" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "전자책 뷰어를 제어하는 옵션" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "콘솔에 자바스크립트 경고와 콘솔 메시지를 출력합니다" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -19070,17 +19074,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "%s 복사하는중" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/ku.po b/src/calibre/translations/ku.po index 1149921f9d..a570c8a350 100644 --- a/src/calibre/translations/ku.po +++ b/src/calibre/translations/ku.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2011-12-12 17:33+0000\n" "Last-Translator: Erdal Ronahi \n" "Language-Team: Kurdish \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:23+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:47+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "Tiştek nake" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -929,26 +929,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1123,14 +1123,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1178,10 +1178,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12038,6 +12038,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13331,7 +13335,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16682,7 +16686,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17273,39 +17277,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18909,17 +18913,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/lt.po b/src/calibre/translations/lt.po index fae411f78a..e1ead13b27 100644 --- a/src/calibre/translations/lt.po +++ b/src/calibre/translations/lt.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2011-08-05 16:44+0000\n" "Last-Translator: Mantas Kriaučiūnas \n" "Language-Team: Lithuanian \n" @@ -16,8 +16,8 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "(n%100<10 || n%100>=20) ? 1 : 2;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:23+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:47+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -176,12 +176,12 @@ msgstr "Nieko nedaro" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -936,26 +936,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1130,14 +1130,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Naujienos" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Katalogas" @@ -1185,10 +1185,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12045,6 +12045,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13338,7 +13342,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16689,7 +16693,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17280,39 +17284,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18916,17 +18920,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/ltg.po b/src/calibre/translations/ltg.po index 7ff705dcc5..01ac568bc2 100644 --- a/src/calibre/translations/ltg.po +++ b/src/calibre/translations/ltg.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2011-05-06 12:35+0000\n" "Last-Translator: uGGa \n" "Language-Team: Latgalian \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:34+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:58+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "Pilneigi nikū nadora" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -929,26 +929,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1123,14 +1123,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1178,10 +1178,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12038,6 +12038,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13331,7 +13335,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16682,7 +16686,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17273,39 +17277,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18909,17 +18913,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/lv.po b/src/calibre/translations/lv.po index bc0d10a349..bf60ebe4b5 100644 --- a/src/calibre/translations/lv.po +++ b/src/calibre/translations/lv.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-07-12 09:33+0000\n" "Last-Translator: Kovid Goyal \n" "Language-Team: Latvian \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:23+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:47+0000\n" +"X-Generator: Launchpad (build 16194)\n" "X-Poedit-Country: LATVIA\n" "Language: lv\n" "X-Poedit-Language: Latvian\n" @@ -178,12 +178,12 @@ msgstr "Pilnīgi neko nedara" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -970,26 +970,26 @@ msgstr "Ceļš lídz bibliotēkai pārāk garš. Jābūt mazāk nekā %d simboli #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "Jā" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "Galvenā" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "Karte A" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "Karte B" @@ -1195,14 +1195,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Ziņas" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Katalogs" @@ -1256,10 +1256,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12271,6 +12271,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13575,7 +13579,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16937,7 +16941,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17528,39 +17532,39 @@ msgstr "Pārvaldīt grāmatzīmes." msgid "Loading ebook..." msgstr "Ielasa e-grāmatu..." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "Nevarēja atvērt e-grāmatu" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "Iestatījumi e-grāmatu skatītāja kontrolei" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -19170,17 +19174,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "

Migre veco datubāzi uz e-grāmatu bibliotēku %s

" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "Kopē %s" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "Blīvē datubāzi" diff --git a/src/calibre/translations/mk.po b/src/calibre/translations/mk.po index a46369a0dc..129120b012 100644 --- a/src/calibre/translations/mk.po +++ b/src/calibre/translations/mk.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2011-11-26 20:57+0000\n" "Last-Translator: ScHRiLL \n" "Language-Team: Macedonian \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n % 10 == 1 && n % 100 != 11) ? 0 : 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:24+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:47+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "Неправи апсолутно ништо" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -929,26 +929,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1123,14 +1123,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1178,10 +1178,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12038,6 +12038,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13331,7 +13335,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16682,7 +16686,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17273,39 +17277,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18909,17 +18913,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/ml.po b/src/calibre/translations/ml.po index a404085e54..94c8f1244a 100644 --- a/src/calibre/translations/ml.po +++ b/src/calibre/translations/ml.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2011-08-05 17:53+0000\n" "Last-Translator: Kovid Goyal \n" "Language-Team: Malayalam \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:24+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:47+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "ഒന്നും തന്നെ ചെയ്തില്ല" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -935,26 +935,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1129,14 +1129,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "വാര്‍ത്തകള്‍" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1184,10 +1184,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12049,6 +12049,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13342,7 +13346,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16693,7 +16697,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17284,39 +17288,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18920,17 +18924,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/mr.po b/src/calibre/translations/mr.po index caa7b20bd8..9dc31be4a1 100644 --- a/src/calibre/translations/mr.po +++ b/src/calibre/translations/mr.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2011-08-05 16:46+0000\n" "Last-Translator: Kovid Goyal \n" "Language-Team: Marathi \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:24+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:48+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "काहीच करत नाही" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -936,26 +936,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "हो" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1130,14 +1130,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "वार्ता" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "पुस्तक सूची" @@ -1185,10 +1185,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12045,6 +12045,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13338,7 +13342,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16689,7 +16693,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17280,39 +17284,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18916,17 +18920,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/ms.po b/src/calibre/translations/ms.po index 1e62b51499..28c8c369ce 100644 --- a/src/calibre/translations/ms.po +++ b/src/calibre/translations/ms.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-09-04 04:15+0000\n" "Last-Translator: abuyop \n" "Language-Team: Malay \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:24+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:48+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "Langsung tidak melakukan apa-apa" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -949,26 +949,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1143,14 +1143,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1198,10 +1198,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12061,6 +12061,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13354,7 +13358,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16705,7 +16709,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17296,39 +17300,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18932,17 +18936,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/nb.po b/src/calibre/translations/nb.po index f019e5d7fe..3aaa833350 100644 --- a/src/calibre/translations/nb.po +++ b/src/calibre/translations/nb.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-05-12 04:56+0000\n" "Last-Translator: Øyvind Øritsland \n" "Language-Team: Norwegian Bokmal \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:25+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:49+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "Gjør absolutt ingenting" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -978,26 +978,26 @@ msgstr "Stien til biblioteket er for lang. Den må ha færre enn %d tegn." #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "Ja" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "Hovedvalg" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "Kort A" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "Kort B" @@ -1196,14 +1196,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Nyheter" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Katalog" @@ -1254,10 +1254,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12752,6 +12752,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -14086,7 +14090,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -17550,7 +17554,7 @@ msgid "Options to customize the ebook viewer" msgstr "Valgmuligheter for å egendefinere e-bokleseren" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "Husk sist brukte vindustørrelse" @@ -18151,42 +18155,42 @@ msgstr "Behandle bokmerker" msgid "Loading ebook..." msgstr "Laster e-bok..." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "Kunne ikke åpne e-boken" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "Valgmuligheter for å kontrollere e-bokleseren" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" "Om spesifisert, vil leservinduet forsøke å legge seg foran når den starter." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" "Om spesifisert vil visningsvinduet forsøke å åpne fullskjermsvisning når den " "starter." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "Skriv ut javascriptadvarsel og konsollmeldinger til konsollen" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -19996,17 +20000,17 @@ msgstr "" msgid "creating custom column " msgstr "lager tilpasset kolonne " -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "

Migrerer gammel database til e-bokbiblioteket i %s
" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "Kopierer %s" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "Komprimerer databasen" diff --git a/src/calibre/translations/nds.po b/src/calibre/translations/nds.po index 6fc47db140..e4cb445ab7 100644 --- a/src/calibre/translations/nds.po +++ b/src/calibre/translations/nds.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: nds\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-06-18 12:05+0000\n" "Last-Translator: tbds \n" "Language-Team: German\n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:25+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:48+0000\n" +"X-Generator: Launchpad (build 16194)\n" "X-Poedit-Country: GERMANY\n" "X-Poedit-Language: German\n" "Generated-By: pygettext.py 1.5\n" @@ -178,12 +178,12 @@ msgstr "Makt nix" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -964,26 +964,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1158,14 +1158,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Nachrichten" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1213,10 +1213,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12393,6 +12393,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13698,7 +13702,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -17087,7 +17091,7 @@ msgid "Options to customize the ebook viewer" msgstr "Einstellungen zum Anpassen des eBook Viewers" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "Zuletzt verwendete Fenstergröße merken" @@ -17682,41 +17686,41 @@ msgstr "Lesezeichen verwalten" msgid "Loading ebook..." msgstr "Lade eBook..." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "Konnte eBook nicht öffnen" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "Einstellungen zur Kontrolle des eBook Viewers" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" "Falls angegeben, dann wird das Viewer Fenster beim Start im Vordergrund " "angezeigt." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "Javascript Alarme und Konsolennachrichten auf der Konsole ausgeben" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -19424,17 +19428,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "

Migriere alte Datenbank zu eBook Bibliothek in %s

" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "Kopiere %s" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "Komprimiere Datenbank" diff --git a/src/calibre/translations/nl.po b/src/calibre/translations/nl.po index 9f9b0c9236..a0d79d8ee9 100644 --- a/src/calibre/translations/nl.po +++ b/src/calibre/translations/nl.po @@ -56,7 +56,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-10-26 04:33+0000\n" "Last-Translator: drMerry \n" "Language-Team: Dutch \n" @@ -64,7 +64,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-26 04:54+0000\n" +"X-Launchpad-Export-Date: 2012-10-27 04:41+0000\n" "X-Generator: Launchpad (build 16194)\n" "X-Poedit-Country: NETHERLANDS\n" "X-Poedit-Language: Dutch\n" @@ -233,12 +233,12 @@ msgstr "Doet helemaal niets" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -1039,26 +1039,26 @@ msgstr "Pad naar bibliotheek is te lang. Moet minder dan %d tekens zijn." #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "Ja" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "Hoofdgeheugen" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "Geheugenkaart A" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "Geheugenkaart B" @@ -1273,14 +1273,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Nieuws" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Catalogus" @@ -1336,10 +1336,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -13532,6 +13532,10 @@ msgstr "Kies een lettertype familie uit onderstaande lijst:" msgid "Choose &font family" msgstr "Kies &lettertype familie" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -14939,13 +14943,9 @@ msgstr "Het toevoegings&proces" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" -"Indien ingeschakeld, zorgt deze optie dat calibre controleert of een " -"bestand\n" -" welke automatisch wordt toegevoegd al in de Calibre-bibliotheek staat.\n" -" Zo ja, dan zal calibre u vragen of u het bestand nogmaals wilt toevoegen." #: /home/kovid/work/calibre/src/calibre/gui2/preferences/adding_ui.py:152 msgid "Check for &duplicates when auto-adding files" @@ -18784,7 +18784,7 @@ msgid "Options to customize the ebook viewer" msgstr "Opties om het e-book leesvenster aan te passen" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "De laatstgebruikte venstergrootte onthouden" @@ -19407,37 +19407,37 @@ msgstr "Bladwijzers beheren" msgid "Loading ebook..." msgstr "E-book laden…" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "Kan e-book niet openen" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "Onbekende fout" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "Opties voor de e-book leesvenster" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" "Indien gespecificeerd, zal het leesvenster proberen naar voren te komen na " "het opstarten." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" "Als dit is opgegeven zal het leesvenster proberen om in volledig scherm te " "starten." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "Print javascript waarschuwingen en console berichten op de console" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." @@ -19445,7 +19445,7 @@ msgstr "" "De positie waarop het geselecteerde boek geopend moet worden. De positie is " "een locatie zoals weergeven in de linker bovenhoek van het leesvenster." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -21364,17 +21364,17 @@ msgstr "voorkeuren hersteld " msgid "creating custom column " msgstr "aangepaste kolom aanmaken " -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "

Migreer oude database naar e-book-bibliotheek op %s

" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "%s kopiëren" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "Database comprimeren" diff --git a/src/calibre/translations/nn.po b/src/calibre/translations/nn.po index ef9fbc3ceb..3dfcbd91a0 100644 --- a/src/calibre/translations/nn.po +++ b/src/calibre/translations/nn.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-01-04 03:30+0000\n" "Last-Translator: Yngve Spjeld Landro \n" "Language-Team: Norwegian Nynorsk \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:25+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:48+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "Gjer absolutt ingenting" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -929,26 +929,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1123,14 +1123,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1178,10 +1178,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12038,6 +12038,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13331,7 +13335,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16682,7 +16686,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17273,39 +17277,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18909,17 +18913,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/oc.po b/src/calibre/translations/oc.po index 9606862a37..bd7876112d 100644 --- a/src/calibre/translations/oc.po +++ b/src/calibre/translations/oc.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-04-29 09:54+0000\n" "Last-Translator: Cédric VALMARY (Tot en òc) \n" "Language-Team: Occitan (post 1500) \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:25+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:49+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "Fa estrictament pas res" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -934,26 +934,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "Òc" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "General" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "Carta A" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "Carta B" @@ -1132,14 +1132,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Nòvas" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Catalòg" @@ -1187,10 +1187,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12047,6 +12047,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13340,7 +13344,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16691,7 +16695,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17282,39 +17286,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18918,17 +18922,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/pa.po b/src/calibre/translations/pa.po index 8d389a1b3e..c16441e5af 100644 --- a/src/calibre/translations/pa.po +++ b/src/calibre/translations/pa.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2011-08-05 16:48+0000\n" "Last-Translator: Kovid Goyal \n" "Language-Team: Punjabi \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:26+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:49+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -936,26 +936,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1130,14 +1130,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1185,10 +1185,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12045,6 +12045,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13338,7 +13342,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16689,7 +16693,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17280,39 +17284,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18916,17 +18920,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/pl.po b/src/calibre/translations/pl.po index 30b9ffe81f..5126cc3c5f 100644 --- a/src/calibre/translations/pl.po +++ b/src/calibre/translations/pl.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-09-29 16:04+0000\n" "Last-Translator: Piotr Parafiniuk \n" "Language-Team: Polish \n" @@ -16,8 +16,8 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " "|| n%100>=20) ? 1 : 2;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:26+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:50+0000\n" +"X-Generator: Launchpad (build 16194)\n" "X-Poedit-Bookmarks: -1,3588,-1,-1,-1,-1,-1,-1,-1,-1\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 @@ -177,12 +177,12 @@ msgstr "Ta opcja zupełnie nic nie zmienia" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -985,26 +985,26 @@ msgstr "Zbyt długa ścieżka biblioteki. Nie może być dłuższa niż %d znak #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "Tak" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "Główna" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "Karta A" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "Karta B" @@ -1215,14 +1215,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Newsy" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Katalog" @@ -1277,10 +1277,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -13409,6 +13409,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -14824,13 +14828,9 @@ msgstr "Dodawanie" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" -"Ustawienie tej opcji spowoduje, że calibre będzie sprawdzać\n" -"czy dodawany plik jest już w bibliotece. Jeśli tak \n" -"to zostanie wyświetlone okno dialogowe z pytaniem, \n" -"czy rzeczywiście chcesz dodać ten plik." #: /home/kovid/work/calibre/src/calibre/gui2/preferences/adding_ui.py:152 msgid "Check for &duplicates when auto-adding files" @@ -18654,7 +18654,7 @@ msgid "Options to customize the ebook viewer" msgstr "Opcje odpowiedzialne za personalizacje przeglądarki książek" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "Zapamiętaj ostatnio użyty rozmiar okienka" @@ -19277,37 +19277,37 @@ msgstr "Zarządzaj zakładkami" msgid "Loading ebook..." msgstr "Ładowanie książki..." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "Nie można otworzyć książki" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "Opcje odpowiadające za kontrolę nad przeglądarką książek" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" "Jeśli określone, okno przeglądarki spróbuje pokazać się na wierzchu podczas " "startu." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" "Jeśli określone, okno przeglądarki spróbuje otworzyć się na pełnym ekranie " "podczas startu." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "Wyświetlaj uwagi javascriptu i wiadomości konsolowe w konsoli" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." @@ -19315,7 +19315,7 @@ msgstr "" "Miejsce w którym wskazana książka ma być otwarta. Jest to pozycja widoczna w " "górnym lewym rogu przeglądarki." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -21280,18 +21280,18 @@ msgstr "odzyskane preferencje " msgid "creating custom column " msgstr "tworzenie kolumny użytkownika " -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" "

Przenoszenie starej bazy danych do biblioteki książek w %s

" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "Kopiowanie %s" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "Kompaktowanie bazy danych" diff --git a/src/calibre/translations/pt.po b/src/calibre/translations/pt.po index 57bef4aeb5..f2c9c87e3e 100644 --- a/src/calibre/translations/pt.po +++ b/src/calibre/translations/pt.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-07-26 20:48+0000\n" "Last-Translator: Rafael Antonio Belokurows \n" "Language-Team: Portuguese \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:26+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:50+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "Não faz absolutamente nada" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -980,26 +980,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "Sim" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "Principal" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "Cartão A" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "Cartão B" @@ -1188,14 +1188,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Notícias" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Catálogo" @@ -1251,10 +1251,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12634,6 +12634,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13955,7 +13959,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -17360,7 +17364,7 @@ msgid "Options to customize the ebook viewer" msgstr "Opções para personalizar o Visualizador de livros" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "Lembrar o tamanho da última janela utilizada" @@ -17956,41 +17960,41 @@ msgstr "Gerir Marcadores" msgid "Loading ebook..." msgstr "A carregar o livro..." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "É impossível abrir o livro" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "Opções para controlar o Visualizador de livros" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" "Se especificado a janela do Visualizador vai tentar vir para a frente quando " "iniciada." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "Imprimir alertas javascript e mensagens da consola na consola" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -19698,19 +19702,19 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" "

A migrar a base de dados antiga para a biblioteca de livros em " "%s

" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "A copiar %s" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "A compactar a base de dados" diff --git a/src/calibre/translations/pt_BR.po b/src/calibre/translations/pt_BR.po index c2b46ddeba..1ce5c8056d 100644 --- a/src/calibre/translations/pt_BR.po +++ b/src/calibre/translations/pt_BR.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-10-14 01:49+0000\n" "Last-Translator: Diogo Albuquerque \n" "Language-Team: American English \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:32+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:56+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "Não faz absolutamente nada" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -989,26 +989,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "Sim" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "Principal" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "Cartão A" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "Cartão B" @@ -1215,14 +1215,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Notícias" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Catálogo" @@ -1278,10 +1278,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12946,6 +12946,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -14284,7 +14288,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -17717,7 +17721,7 @@ msgid "Options to customize the ebook viewer" msgstr "Opções de personalização do visualizador de eBooks" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "Lembrar do último tamanho da janela" @@ -18320,41 +18324,41 @@ msgstr "Organizar favoritos" msgid "Loading ebook..." msgstr "Carregando eBook..." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "Não foi possível abrir o eBook" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "Opções de controle do visualizador de eBooks" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" "Se especificado, a janela do visualizador irá tentar vir para frente quando " "iniciada." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "Imprimir alerta javascript e mensagens de console no console" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -20089,19 +20093,19 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" "

Migrando o banco de dados antigo para a biblioteca de ebook em " "%s

" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "Copiando %s" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "Compactando banco de dados" diff --git a/src/calibre/translations/ro.po b/src/calibre/translations/ro.po index 0e04cf7517..ec938973d7 100644 --- a/src/calibre/translations/ro.po +++ b/src/calibre/translations/ro.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-08-17 11:22+0000\n" "Last-Translator: Jorel \n" "Language-Team: Romanian \n" @@ -16,8 +16,8 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n == 1 ? 0: (((n % 100 > 19) || ((n % 100 " "== 0) && (n != 0))) ? 2: 1));\n" -"X-Launchpad-Export-Date: 2012-10-25 05:27+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:50+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -176,12 +176,12 @@ msgstr "Nu face absolut nimic" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -999,26 +999,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "Da" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "Principal" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "Card A" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "Card B" @@ -1223,14 +1223,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Știri" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Catalog" @@ -1285,10 +1285,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -13256,6 +13256,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -14669,7 +14673,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -18443,7 +18447,7 @@ msgid "Options to customize the ebook viewer" msgstr "Opţiuni de personalizare a vizualizatorului" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "Reţine ultima mărime a ferestrei folosită" @@ -19052,43 +19056,43 @@ msgstr "Gestionează semnele de carte" msgid "Loading ebook..." msgstr "Se încarcă e-cartea..." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "Nu s-a putut deschide cartea" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "Opţiuni pentru controlul vizualizatorului cărţilor" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" "Dacă este specificat, fereastra vizualizatorului va încerca să vină în prim " "plan atunci când este pornit." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" "Dacă este specificat, fereastra vizualizatorului va încerca să pornească pe " "tot ecranul." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "Afişează alerta javascript şi mesajele de consolă pe consolă" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -20971,17 +20975,17 @@ msgstr "" msgid "creating custom column " msgstr "se creează coloană personalizată " -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "

Se mută baza de date veche în bibliotecă în %s

" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "Se copiază %s" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "Se compactează baza de date" diff --git a/src/calibre/translations/ru.po b/src/calibre/translations/ru.po index 1eb296ab29..b7fcdefdcb 100644 --- a/src/calibre/translations/ru.po +++ b/src/calibre/translations/ru.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: calibre 0.4.55\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" -"PO-Revision-Date: 2012-10-25 17:27+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" +"PO-Revision-Date: 2012-10-26 18:30+0000\n" "Last-Translator: Baz <_baz_@rambler.ru>\n" "Language-Team: American English \n" "MIME-Version: 1.0\n" @@ -15,7 +15,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -"X-Launchpad-Export-Date: 2012-10-26 04:55+0000\n" +"X-Launchpad-Export-Date: 2012-10-27 04:51+0000\n" "X-Generator: Launchpad (build 16194)\n" "X-Poedit-Country: RUSSIAN FEDERATION\n" "X-Poedit-Language: Russian\n" @@ -180,12 +180,12 @@ msgstr "Ничего не делает" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -987,26 +987,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "Да" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "Основная" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "Карта 1" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "Карта 2" @@ -1216,14 +1216,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Новости" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Каталог" @@ -1278,10 +1278,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -13426,6 +13426,10 @@ msgstr "Выберите семейство шрифтов из списка н msgid "Choose &font family" msgstr "Выберите семейство шрифтов" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "Очистить шрифт" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -14838,13 +14842,13 @@ msgstr "Добавление" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" -"Если включено, то calibre будет проверять\n" -" добавляемые файлы на наличие в библиотеке.\n" -" Если файлы уже имеются, то появится сообщение\n" -" о том желаете ли вы всё равно добавить файлы." +"Если установлена эта опция, то при автоматическом добавлении\n" +" calibre будет проверять наличие добавляемых книг в библиотеке.\n" +" Если похожая книга будет найдена, то появится окно с вопросом\n" +" о необходимости сохранения." #: /home/kovid/work/calibre/src/calibre/gui2/preferences/adding_ui.py:152 msgid "Check for &duplicates when auto-adding files" @@ -18663,7 +18667,7 @@ msgid "Options to customize the ebook viewer" msgstr "Параметры для настройки просмотра книг" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "Запомнить последний использованный размер окна" @@ -19288,35 +19292,35 @@ msgstr "Управление закладками" msgid "Loading ebook..." msgstr "Загружается электронная книга..." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "Не могу открыть электронную книгу" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "Неизвестная ошибка" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "Настройки управления просмотром книг" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" "Если указано, окно вьювера будт пытаться всплыть наверх при открытии." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" "Если указано, окне просмотра будет открыто во весь экран при запуске." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "Выводить предупреждения javascript и консольные сообщения в консоли" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." @@ -19324,7 +19328,7 @@ msgstr "" "Позиция на которой открыта определённая книга. Позиция отображается в " "верхнем левом углу просмотрщика." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -20892,6 +20896,22 @@ msgid "" "that a new OPF has been createdsince the column was added). You will see the " "JSON for the\"display\" for the new column in the OPF." msgstr "" +"Словарь настроек для указания того, как данные в этой колонке будут " +"интерпретированы. Это JSON строка. Для столбцов с перечислением используйте -" +"-display=\"{\\\"enum_values\\\":[\\\"val1\\\", \\\"val2\\\"]}\"\n" +"Есть много настроек которые могуть быть использованы в переменной " +"отображения. Настройки по типам столбцов следующие:\n" +"composite: composite_template, composite_sort, make_category,contains_html, " +"use_decorations\n" +"datetime: date_format\n" +"enumeration: enum_values, enum_colors, use_decorations\n" +"int, float: number_format\n" +"text: is_names, use_decorations\n" +"\n" +"Лучший способ найти правильное сочетание - это создать столбец " +"соответствующего типа в интерфейсе и посмотреть на резервную копию OPF для " +"книги (убедитесь что новый OPF был создан после добавления столбца). Вы " +"увидете JSON для \"отображения\" для нового столбца в OPF." #: /home/kovid/work/calibre/src/calibre/library/cli.py:721 msgid "You must specify label, name and datatype" @@ -21302,17 +21322,17 @@ msgstr "восстановлены настройки " msgid "creating custom column " msgstr "создание пользовательских столбцов " -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "

Миграция старой базы данных в %s

" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "Копирование %s" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "Сжатие базы данных" @@ -24029,53 +24049,75 @@ msgid "" "sony_collection_name_template='{category:||: }{value}'" msgstr "" "Укажите правила переименования для коллекций sony. Эта настройка применима " -"только тогда, когда управление метаданными установлено в автоматический " -"режим. Коллекции на Sony именуются в зависимости от того, какие поля " -"выбраны: стандартные или пользовательские. Коллекция образованная из " -"стандартного поля именуется по его значению. Например, если стандартный " -"столбец 'серии' содержит значение 'Darkover', то название коллекции будет " -"'Darkover'. Коллекция образованная из пользователького поля будет иметь имя " -"поля добавленного к значению. Например, если столбец пользовательских серий " +"только тогда, \n" +"когда управление метаданными установлено в автоматический режим. Коллекции " +"на Sony \n" +"именуются в зависимости от того, какие поля выбраны: стандартные или " +"пользовательские.\n" +"Коллекция образованная из стандартного поля именуется по его значению. " +"Например, если \n" +"стандартный столбец 'серии' содержит значение 'Darkover', то название " +"коллекции \n" +"будет 'Darkover'. Коллекция образованная из пользователького поля будет " +"иметь \n" +"имя поля добавленного к значению. Например, если столбец пользовательских " +"серий \n" "называется 'My Series' и содержит название 'Darkover', то коллекция будет по " -"умолчанию названа 'Darkover (My Series)'. Для этой справки, значение " -"называется 'Darkover' и категория называется 'My Series'. Если две книги " -"имеют поля которые дают одинаковые имена для коллекции, то обе книги будут в " -"этой коллекции. \n" +"умолчанию \n" +"названа 'Darkover (My Series)'. Для этой справки, значение называется " +"'Darkover' и категория \n" +"называется 'My Series'. Если две книги имеют поля которые дают одинаковые " +"имена для \n" +"коллекции, то обе книги будут в этой коллекции. \n" "Установка этих настроек позволит вам указать для стандартной или " -"пользовательской папки как именовать коллекции. Вы можете использовать это " -"для добавления описания к стандартному полю, например 'Foo (Tag)' вместо " -"'Foo'. Вы так же можете использовать это что бы заставить несколько полей " -"оказаться в одной коллекции. Например, вы можете заставить значения в " -"'series', '#my_series_1' и '#my_series_2' оказаться в коллекциях названных " -"'some_value (Series)', объединив этим все поля в один набор коллекций.\n" +"пользовательской папки \n" +"как именовать коллекции. Вы можете использовать это для добавления описания " +"к \n" +"стандартному полю, например 'Foo (Tag)' вместо 'Foo'. Вы так же можете " +"использовать это \n" +"что бы заставить несколько полей оказаться в одной коллекции. Например, вы " +"можете заставить \n" +"значения в 'series', '#my_series_1' и '#my_series_2' оказаться в коллекциях " +"\n" +"названных 'some_value (Series)', объединив этим все поля в один набор " +"коллекций.\n" "Имеются две возможные настройки. Первая определяет имя категории для " -"использования в поле метаданных. Вторая - это шаблон, используемый для " -"определения того, как значение и категория объединяются для создания имени " -"коллекции. Синтаксис первой настройки, sony_collection_renaming_rules, " -"следующий:\n" +"использования \n" +"в поле метаданных. Вторая - это шаблон, используемый для определения того, \n" +"как значение и категория объединяются для создания имени коллекции. " +"Синтаксис \n" +"первой настройки, sony_collection_renaming_rules, следующий:\n" "{'field_lookup_name':'category_name_to_use', 'lookup_name':'name', ...}\n" "Вторая настройка, sony_collection_name_template - шаблон. Он использует тот " -"же язык шаблонов, что и в связях метаданных и сохранении шаблонов. Доступно " -"два поля: {category} и {value} (категория и значение). Поле {value} никогда " -"не пусто. Поле {category} может быть пустым. По умолчанию, вначале идёт " -"значение, затем категория в скобках, которые не должны быть пустыми: " -"'{value} {category:|(|)}'\n" +"же \n" +"язык шаблонов, что и в связях метаданных и сохранении шаблонов. Доступно два " +"\n" +"поля: {category} и {value} (категория и значение). Поле {value} никогда не " +"пусто. \n" +"Поле {category} может быть пустым. По умолчанию, вначале идёт значение, " +"затем \n" +"категория в скобках, которые не должны быть пустыми: '{value} " +"{category:|(|)}'\n" "Примеры: Первые три примера предпологают что вторая настройка не менялась.\n" "1: Я хочу что бы три серии столбцов были объединены в одной группе " -"коллекций. Поисковые имена столбцов 'series', '#series_1' и '#series_2'. Я " -"хочу что бы в скобках было пусто. Значение для использования в настройке " -"должно выглядеть так: sony_collection_renaming_rules={'series':'', " -"'#series_1':'', '#series_2':''}\n" +"коллекций. \n" +"Поисковые имена столбцов 'series', '#series_1' и '#series_2'. Я хочу что бы " +"в скобках \n" +"было пусто. Значение для использования в настройке должно выглядеть так: \n" +"sony_collection_renaming_rules={'series':'', '#series_1':'', " +"'#series_2':''}\n" "2: Я хочу, что бы слово '(Series)' появлялось в коллекциях созданных из " -"серий и слово '(Tag)' появлялось в коллекциях от тэгов. Настройка будет " -"такой: sony_collection_renaming_rules={'series':'Series', 'tags':'Tag'}\n" +"серий \n" +"и слово '(Tag)' появлялось в коллекциях от тэгов. Настройка будет такой: \n" +"sony_collection_renaming_rules={'series':'Series', 'tags':'Tag'}\n" "3: Я хочу, что бы 'series' и '#myseries' были объединены и в имени коллекции " -"было '(Series)'. Правило переименования такое: " +"\n" +"было '(Series)'. Правило переименования такое: \n" "sony_collection_renaming_rules={'series':'Series', '#myseries':'Series'}\n" -"4: То же что и в примере 2, но вместо имеющегося имени категории в скобках и " -"добавления к значению, я хочу добавить и разделить через двоеточие, как в " -"сериях: Darkover. Я должен изменить шаблон используемый для форматирования " -"имени категории\n" +"4: То же что и в примере 2, но вместо имеющегося имени категории в скобках \n" +"и добавления к значению, я хочу добавить и разделить через двоеточие, \n" +"как в сериях: Darkover. Я должен изменить шаблон используемый для \n" +"форматирования имени категории\n" "В результате две настройки будут следующими:\n" "sony_collection_renaming_rules={'series':'Series', 'tags':'Tag'}\n" "sony_collection_name_template='{category:||: }{value}'" @@ -24250,10 +24292,11 @@ msgid "" "default font (Liberation Serif) does not contain glyphs for the language of\n" "the books in your library." msgstr "" -"Полный путь к файлам шрифтов .ttf для использования в названии, авторе и " -"нижнем поле при создании обложки по умолчанию или титульного изображения. " -"Полезно если шрифт по умолчанию (Liberation Serif) не содержит символов " -"подходящих для книг в вашей библиотеке." +"Полный путь к файлам шрифтов .ttf для использования в названии, \n" +"авторе и нижнем поле при создании обложки по умолчанию или титульного \n" +"изображения. Полезно если шрифт по умолчанию (Liberation Serif) не содержит " +"\n" +"символов подходящих для книг в вашей библиотеке." #: /home/kovid/work/calibre/resources/default_tweaks.py:387 msgid "Control behavior of the book list" diff --git a/src/calibre/translations/sc.po b/src/calibre/translations/sc.po index 354e615f1a..094423e11b 100644 --- a/src/calibre/translations/sc.po +++ b/src/calibre/translations/sc.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2010-12-11 02:46+0000\n" "Last-Translator: Kovid Goyal \n" "Language-Team: Sardinian \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n!=1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:29+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:52+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "Does absolutely nothing" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -929,26 +929,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1123,14 +1123,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1178,10 +1178,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12038,6 +12038,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13331,7 +13335,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16682,7 +16686,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17273,39 +17277,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18909,17 +18913,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/si.po b/src/calibre/translations/si.po index 7ed879dc85..a1f147d247 100644 --- a/src/calibre/translations/si.po +++ b/src/calibre/translations/si.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2011-06-16 06:16+0000\n" "Last-Translator: Dinusha \n" "Language-Team: Sinhalese \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:28+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:51+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -929,26 +929,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1123,14 +1123,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1178,10 +1178,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12038,6 +12038,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13331,7 +13335,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16682,7 +16686,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17273,39 +17277,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18909,17 +18913,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/sk.po b/src/calibre/translations/sk.po index 137e97c3db..f7e8cc53a6 100644 --- a/src/calibre/translations/sk.po +++ b/src/calibre/translations/sk.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-05-31 10:38+0000\n" "Last-Translator: Michal Kaliňák \n" "Language-Team: Slovak \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 1 : (n>=2 && n<=4) ? 2 : 0;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:28+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:52+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "Nerobí vôbec nič" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -972,26 +972,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "Áno" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "Základné" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "Karta A" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "Karta B" @@ -1195,14 +1195,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Novinky" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Katalóg" @@ -1257,10 +1257,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -13134,6 +13134,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -14536,13 +14540,9 @@ msgstr "Proces &pridávania" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" -"Pri zapnutí tejto voľby bude Calibre pri automatickom\n" -" pridávaní overovať, či súbor už v knižnici Calibre nie je.\n" -" Ak bude, Calibre sa spýta, či ho chcete napriek tomu\n" -" pridať." #: /home/kovid/work/calibre/src/calibre/gui2/preferences/adding_ui.py:152 msgid "Check for &duplicates when auto-adding files" @@ -18261,7 +18261,7 @@ msgid "Options to customize the ebook viewer" msgstr "Možnosti úpravy prehliadača elektronických kníh" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "Pamätať poslednú veľkosť okna" @@ -18866,33 +18866,33 @@ msgstr "Spravovať záložky" msgid "Loading ebook..." msgstr "Načítavam elektronickú knihu..." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "Nepodarilo sa otvoriť knihu" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "Nastavenie prehliadača elektronických kníh" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "Ak je zadané, okno prehliadača sa po štarte zobrazí v popredí." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "Ak zadané, okno prehliadača sa po štarte otvorí na celú obrazovku." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "Vypísať upozornenia javascriptu a konzolové správy na konzolu" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." @@ -18900,7 +18900,7 @@ msgstr "" "Pozícia, na ktorej sa určená kniha otvorí. Pozícia je miesto v knihe " "zobrazené v ľavom hornom rohu prehliadača." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -20767,18 +20767,18 @@ msgstr "" msgid "creating custom column " msgstr "vytváram vlastný stĺpec " -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" "

Migrujem starú databázu do knižnice elektronických kníh v %s

" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "Kopírujem %s" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "Zmenšujem databázu" diff --git a/src/calibre/translations/sl.po b/src/calibre/translations/sl.po index 2a5ceb5d39..04e6367d5c 100644 --- a/src/calibre/translations/sl.po +++ b/src/calibre/translations/sl.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre 0.8.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-10-15 15:27+0000\n" "Last-Translator: Martin Srebotnjak \n" "Language-Team: Martin Srebotnjak \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || " "n%100==4 ? 3 : 0);\n" -"X-Launchpad-Export-Date: 2012-10-25 05:29+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:52+0000\n" +"X-Generator: Launchpad (build 16194)\n" "X-Poedit-Country: SLOVENIA\n" "X-Poedit-Language: Slovenian\n" "X-Poedit-SourceCharset: iso-8859-1\n" @@ -179,12 +179,12 @@ msgstr "Ne stori ničesar" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -982,26 +982,26 @@ msgstr "Pot do knjižnice je predolga. Imeti mora manj kot %d znakov." #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "Da" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "Glavni pomn." #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "Kartica A" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "Kartica B" @@ -1186,14 +1186,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Novice" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Katalog" @@ -1247,10 +1247,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12333,6 +12333,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13630,7 +13634,7 @@ msgstr "&Postopek dodajanja" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16998,7 +17002,7 @@ msgid "Options to customize the ebook viewer" msgstr "Možnosti za prilagajanje bralnika e-knjig" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "Zapomni si nazadnje uporabljeno velikost okna" @@ -17589,39 +17593,39 @@ msgstr "Upravljaj z zaznamki" msgid "Loading ebook..." msgstr "Nalaganje e-knjige ..." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "E-knjige ni mogoče odpreti" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -19271,18 +19275,18 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" "

Selitev stare zbirke podatkov v knjižnico e-knjig v %s

" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "Kopiranje %s" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "Strnjevanje zbirke podatkov" diff --git a/src/calibre/translations/sq.po b/src/calibre/translations/sq.po index 37e6bce709..2040b5cd78 100644 --- a/src/calibre/translations/sq.po +++ b/src/calibre/translations/sq.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2011-08-07 22:44+0000\n" "Last-Translator: Erlis Mulosmani \n" "Language-Team: Albanian \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:13+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:38+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "nuk bën absolutisht asgjë" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -929,26 +929,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1123,14 +1123,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Lajme" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1178,10 +1178,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12038,6 +12038,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13331,7 +13335,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16682,7 +16686,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17273,39 +17277,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18909,17 +18913,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/sr.po b/src/calibre/translations/sr.po index 113ec5b119..188d93d160 100644 --- a/src/calibre/translations/sr.po +++ b/src/calibre/translations/sr.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-10-23 11:52+0000\n" "Last-Translator: Ozzii \n" "Language-Team: Ozzii\n" @@ -16,8 +16,8 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:27+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:51+0000\n" +"X-Generator: Launchpad (build 16194)\n" "Language: sr\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 @@ -177,12 +177,12 @@ msgstr "Не ради баш ништа" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -978,26 +978,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "Да" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "Основна" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "Картица A" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "Картица B" @@ -1189,14 +1189,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Вести" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Каталог" @@ -1251,10 +1251,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12707,6 +12707,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -14050,7 +14054,7 @@ msgstr "Поступак &додавања" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -17539,7 +17543,7 @@ msgid "Options to customize the ebook viewer" msgstr "Избор за подешавање читача е-књига" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "Запамти последње коришћену величину прозора" @@ -18143,42 +18147,42 @@ msgstr "Уреди обележиваче." msgid "Loading ebook..." msgstr "Учитавам е-књигу..." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "Нисам успео да отворим е-књигу." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "Могућности за контролу читача е-књига." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" "Ако је наведен, прозор читача ће покушати да при покретању дође у први план." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" "Ако је наведено, прозор за читање ће се при покретању отворити преко целог " "екрана." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "Прикажi javascript упозорења и поруке на конзоли." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -20004,18 +20008,18 @@ msgstr "" msgid "creating custom column " msgstr "правим корисничку колону " -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" "

Преводим стару базу података у библиотеку е-књига у %s

" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "Умножавам%s" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "Сажимам базу података" diff --git a/src/calibre/translations/sr@latin.po b/src/calibre/translations/sr@latin.po index adea474fb5..947ed5521d 100644 --- a/src/calibre/translations/sr@latin.po +++ b/src/calibre/translations/sr@latin.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-08-23 11:36+0000\n" "Last-Translator: Radan Putnik \n" "Language-Team: Serbian Latin \n" @@ -16,8 +16,8 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:34+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:58+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -176,12 +176,12 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -930,26 +930,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1124,14 +1124,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1179,10 +1179,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12039,6 +12039,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13332,7 +13336,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16683,7 +16687,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17274,39 +17278,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18910,17 +18914,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/sv.po b/src/calibre/translations/sv.po index 9ed3bc2ec2..0f3ddda96a 100644 --- a/src/calibre/translations/sv.po +++ b/src/calibre/translations/sv.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-10-14 09:43+0000\n" "Last-Translator: Merarom \n" "Language-Team: Swedish \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:29+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:53+0000\n" +"X-Generator: Launchpad (build 16194)\n" "X-Poedit-Country: SWEDEN\n" "X-Poedit-Language: Swedish\n" @@ -177,12 +177,12 @@ msgstr "Gör absolut ingenting" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -977,26 +977,26 @@ msgstr "Sökväg till biblioteket för lång. Måste vara mindre än tecken %d." #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "Ja" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "Allmänt" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "Kort A" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "Kort B" @@ -1204,14 +1204,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Nyheter" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Katalog" @@ -1266,10 +1266,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -13093,6 +13093,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -14491,7 +14495,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -18213,7 +18217,7 @@ msgid "Options to customize the ebook viewer" msgstr "Alternativ för att anpassa läsplattan" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "Kom ihåg senast använd fönsterstorlek" @@ -18821,41 +18825,41 @@ msgstr "Hantera bokmärken" msgid "Loading ebook..." msgstr "Laddar e-bok...." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "Kunde inte öppna e-bok" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "Alternativ för att styra läsplattan" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" "Om angivet, kommer läsfönstret att försöka lägga sig överst vid start." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" "Om vald kommer visningsfönstret försöker öppna helskärm när den startas." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "Skriv javaskriptnotifieringar och konsolmeddelanden till konsolen" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -20717,17 +20721,17 @@ msgstr "" msgid "creating custom column " msgstr "skapa anpassad kolumn " -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "

Migrera den gamla databasen till e-bokbibliotek i %s

" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "Kopierar %s" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "Komprimerar databas" diff --git a/src/calibre/translations/ta.po b/src/calibre/translations/ta.po index e74f2c0e33..a3fca5d032 100644 --- a/src/calibre/translations/ta.po +++ b/src/calibre/translations/ta.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2011-08-05 17:54+0000\n" "Last-Translator: Kovid Goyal \n" "Language-Team: Tamil \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:30+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:53+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "நிச்சயமாக எதுவும் செய்யாத #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -929,26 +929,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1123,14 +1123,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1178,10 +1178,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12041,6 +12041,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13334,7 +13338,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16685,7 +16689,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17276,39 +17280,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18912,17 +18916,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/te.po b/src/calibre/translations/te.po index 8badf6e6fd..73d30950c6 100644 --- a/src/calibre/translations/te.po +++ b/src/calibre/translations/te.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2011-08-05 17:01+0000\n" "Last-Translator: Kovid Goyal \n" "Language-Team: Telugu \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:30+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:53+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -929,26 +929,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1123,14 +1123,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "వార్తలు" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1178,10 +1178,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12038,6 +12038,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13331,7 +13335,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16682,7 +16686,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17273,39 +17277,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18909,17 +18913,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/th.po b/src/calibre/translations/th.po index 1dc3d32da5..b0d1873a26 100644 --- a/src/calibre/translations/th.po +++ b/src/calibre/translations/th.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2011-12-15 15:14+0000\n" "Last-Translator: akarong \n" "Language-Team: Thai \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:30+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:53+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:428 #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:438 @@ -186,12 +186,12 @@ msgstr "ไม่มีอะไรเลย" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -954,26 +954,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "การ์ด ข" @@ -1157,14 +1157,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "ข่าว" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "บัญชีรายชื่อ" @@ -1212,10 +1212,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12170,6 +12170,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13463,7 +13467,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16814,7 +16818,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17405,39 +17409,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -19041,17 +19045,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/tr.po b/src/calibre/translations/tr.po index 01ff7b993c..440a80a144 100644 --- a/src/calibre/translations/tr.po +++ b/src/calibre/translations/tr.po @@ -7,16 +7,16 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" -"PO-Revision-Date: 2012-08-17 16:19+0000\n" -"Last-Translator: thomass \n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" +"PO-Revision-Date: 2012-10-26 15:16+0000\n" +"Last-Translator: Burak Ilgıcıoğlu \n" "Language-Team: Turkish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:30+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:54+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "Hiçbir şey yapmaz" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -631,13 +631,15 @@ msgstr "Şebeke'den ekitap metadatasının nasıl indirileceğini kontrol et" #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1125 #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/mtp_config.py:392 msgid "Ignored devices" -msgstr "" +msgstr "Yoksayılan cihazlar" #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1131 msgid "" "Control which devices calibre will ignore when they are connected to the " "computer." msgstr "" +"Calibre'nin bilgisayara bağlandığında hangi cihazları yoksayacağını kontrol " +"edin." #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1138 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins.py:295 @@ -866,7 +868,7 @@ msgstr "Bu profil Amazon Kindle DX'i hedefler." #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:661 msgid "This profile is intended for the Amazon Kindle PaperWhite" -msgstr "" +msgstr "Bu profil Amazon Kindle PaperWhite içindir" #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:672 msgid "This profile is intended for the Amazon Kindle Fire." @@ -932,7 +934,7 @@ msgid "" "For plugin developers: Path to the directory where you are developing the " "plugin. This command will automatically zip up the plugin and update it in " "calibre." -msgstr "" +msgstr "Eklenti geliştiricileri için:" #: /home/kovid/work/calibre/src/calibre/customize/ui.py:603 msgid "Remove a custom plugin by name. Has no effect on builtin plugins" @@ -975,26 +977,26 @@ msgstr "Kütüphanenin yolu çok uzun. %d karakterden daha az olmalı" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "EVET" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "Ana" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "Kart A" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "Kart B" @@ -1196,14 +1198,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Haberler" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Katalog" @@ -1257,10 +1259,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12547,6 +12549,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13840,7 +13846,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -17201,7 +17207,7 @@ msgid "Options to customize the ebook viewer" msgstr "Ekitap görüntüleyiciyi kişiselleştirmek için seçenekler" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "En son kullanılan pencere boyutunu hatırla" @@ -17798,39 +17804,39 @@ msgstr "Yer imlerini yönet" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -19434,17 +19440,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "%s kopyalanıyor" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/uk.po b/src/calibre/translations/uk.po index 1c7e5586a7..3878859475 100644 --- a/src/calibre/translations/uk.po +++ b/src/calibre/translations/uk.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" -"PO-Revision-Date: 2012-10-24 13:07+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" +"PO-Revision-Date: 2012-10-26 06:50+0000\n" "Last-Translator: Yuri Chornoivan \n" "Language-Team: Ukrainian \n" "MIME-Version: 1.0\n" @@ -17,8 +17,8 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:31+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:54+0000\n" +"X-Generator: Launchpad (build 16194)\n" "Language: uk\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 @@ -178,12 +178,12 @@ msgstr "Не робить абсолютно нічого" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -987,26 +987,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "Так" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "Головна" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "Картка A" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "Картка B" @@ -1220,14 +1220,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Новини" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Каталог" @@ -1281,10 +1281,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -13586,6 +13586,10 @@ msgstr "Виберіть гарнітуру шрифтів з наведеног msgid "Choose &font family" msgstr "Вибрати &гарнітуру шрифтів" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "Спорожнити дані щодо гарнітури шрифту" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -15017,13 +15021,13 @@ msgstr "&Процедура додавання" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" -"Якщо позначено, calibre перевірятиме, чи\n" -" є автоматично доданий файл у бібліотеці calibre.\n" -" Якщо файл вже є, програма покаже запит\n" -" щодо того, чи слід його додати попри це." +"Якщо визначено цей параметр, calibre перевірить,\n" +" чи було файл автоматично додано до бібліотеки calibre раніше.\n" +" Якщо такий доданий файл буде виявлено, програма\n" +" спитає вас, чи хочете ви його додати попри це." #: /home/kovid/work/calibre/src/calibre/gui2/preferences/adding_ui.py:152 msgid "Check for &duplicates when auto-adding files" @@ -18909,7 +18913,7 @@ msgid "Options to customize the ebook viewer" msgstr "Параметри вікна перегляду електронної книги" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "Пам’ятати останні використані розміри вікон" @@ -19540,37 +19544,37 @@ msgstr "Керування закладками" msgid "Loading ebook..." msgstr "Завантаження книги…" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "Не вдалося відкрити ел. книгу" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "Невідома помилка" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "Параметри керування переглядом ел. книги" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" "Якщо вказано, буде виконано спробу перевести вікно перегляду на передній " "план під час запуску." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" "Якщо вказано, буде виконано спробу відкрити вікно перегляду на весь екран " "під час запуску." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "Вивести попередження javascript та консольні повідомлення до консолі" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." @@ -19578,7 +19582,7 @@ msgstr "" "Місце, на якому слід відкрити вказану книгу. Позначка місця визначає " "розташування у тексті верхнього лівого кута сторінки на панелі перегляду." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -21602,19 +21606,19 @@ msgstr "відновлене налаштування " msgid "creating custom column " msgstr "створення нетипового стовпчика " -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" "

Перенесення старої бази даних до бібліотеки електронних книжок у " "%s

" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "Копіювання %s" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "Ущільнення бази даних" diff --git a/src/calibre/translations/ur.po b/src/calibre/translations/ur.po index 35dc6f1368..827cc00377 100644 --- a/src/calibre/translations/ur.po +++ b/src/calibre/translations/ur.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2011-04-02 21:19+0000\n" "Last-Translator: mahmood \n" "Language-Team: Urdu \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:31+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:54+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -929,26 +929,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1123,14 +1123,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1178,10 +1178,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12038,6 +12038,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13331,7 +13335,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16682,7 +16686,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17273,39 +17277,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18909,17 +18913,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/vi.po b/src/calibre/translations/vi.po index 914649d3d6..2a965cabd7 100644 --- a/src/calibre/translations/vi.po +++ b/src/calibre/translations/vi.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-04-16 18:36+0000\n" "Last-Translator: Lunafan \n" "Language-Team: Vietnamese \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:31+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:55+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "Không làm gì cả" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -972,26 +972,26 @@ msgstr "Đường dẫn tới thư viện quá dài. Cần ít hơn %d ký tự" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "Đồng ý" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "Chính" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "Thẻ B" @@ -1195,14 +1195,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "Tin tức" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "Danh mục" @@ -1256,10 +1256,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12362,6 +12362,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13655,7 +13659,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -17021,7 +17025,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17612,39 +17616,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -19251,17 +19255,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/wa.po b/src/calibre/translations/wa.po index 6a5c521708..0515632d9b 100644 --- a/src/calibre/translations/wa.po +++ b/src/calibre/translations/wa.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2011-07-05 23:12+0000\n" "Last-Translator: FULL NAME \n" "Language-Team: Walloon \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n!=1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:32+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:55+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -929,26 +929,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1123,14 +1123,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1178,10 +1178,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12038,6 +12038,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13331,7 +13335,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16682,7 +16686,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17273,39 +17277,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18909,17 +18913,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/yi.po b/src/calibre/translations/yi.po index 935c0a947d..113575c57c 100644 --- a/src/calibre/translations/yi.po +++ b/src/calibre/translations/yi.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2009-09-04 22:02+0000\n" "Last-Translator: Kovid Goyal \n" "Language-Team: Yiddish \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:32+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:55+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -929,26 +929,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1123,14 +1123,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1178,10 +1178,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12038,6 +12038,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13331,7 +13335,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16682,7 +16686,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17273,39 +17277,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18909,17 +18913,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/zh_CN.po b/src/calibre/translations/zh_CN.po index f6fbdf5170..b297490273 100644 --- a/src/calibre/translations/zh_CN.po +++ b/src/calibre/translations/zh_CN.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-10-15 05:31+0000\n" "Last-Translator: mozillazg \n" "Language-Team: Simplified Chinese \n" @@ -17,8 +17,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:34+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:57+0000\n" +"X-Generator: Launchpad (build 16194)\n" "X-Poedit-Country: CHINA\n" "X-Poedit-Language: Chinese\n" @@ -179,12 +179,12 @@ msgstr "不做任何处理" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -939,26 +939,26 @@ msgstr "书库的路径太长。路径长度必须小于 %d 个字符。" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "是" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "主" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "存储卡A" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "存储卡B" @@ -1148,14 +1148,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "新闻" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "分类" @@ -1205,10 +1205,10 @@ msgstr "锦书" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12389,6 +12389,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13712,7 +13716,7 @@ msgstr "书籍添加处理(&P)" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -17214,7 +17218,7 @@ msgid "Options to customize the ebook viewer" msgstr "定制电子书查看器的选项" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "记住上次使用窗口大小" @@ -17809,39 +17813,39 @@ msgstr "管理书签" msgid "Loading ebook..." msgstr "正在加载电子书..." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "无法打开电子书" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "电子书查看器控制选项" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "若指定,查看器窗口在打开时将试图转到前面。" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "若选定,查看窗口开启时试图全屏。" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "在控制台显示 javascript 警告以及控制台信息" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -19551,17 +19555,17 @@ msgstr "" msgid "creating custom column " msgstr "创建自定义列 " -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "

正在将旧数据库转移到位于 %s 的新数据库

" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "正在复制%s" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "正在压缩数据库" diff --git a/src/calibre/translations/zh_HK.po b/src/calibre/translations/zh_HK.po index 7aba5cae2f..3d79f33a47 100644 --- a/src/calibre/translations/zh_HK.po +++ b/src/calibre/translations/zh_HK.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2011-07-11 08:59+0000\n" "Last-Translator: Nader stouhy \n" "Language-Team: Chinese (Hong Kong) \n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:32+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:55+0000\n" +"X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -175,12 +175,12 @@ msgstr "是否絕對沒有" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -929,26 +929,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "" @@ -1123,14 +1123,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "" @@ -1178,10 +1178,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12038,6 +12038,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13331,7 +13335,7 @@ msgstr "" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" @@ -16682,7 +16686,7 @@ msgid "Options to customize the ebook viewer" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "" @@ -17273,39 +17277,39 @@ msgstr "" msgid "Loading ebook..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -18909,17 +18913,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "" diff --git a/src/calibre/translations/zh_TW.po b/src/calibre/translations/zh_TW.po index 419cc02eaf..ade34de334 100644 --- a/src/calibre/translations/zh_TW.po +++ b/src/calibre/translations/zh_TW.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" -"POT-Creation-Date: 2012-10-24 04:12+0000\n" +"POT-Creation-Date: 2012-10-26 05:12+0000\n" "PO-Revision-Date: 2012-10-19 08:56+0000\n" "Last-Translator: Chao-Hsiung Liao \n" "Language-Team: Chinese (traditional)\n" @@ -15,8 +15,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Launchpad-Export-Date: 2012-10-25 05:33+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-10-27 04:57+0000\n" +"X-Generator: Launchpad (build 16194)\n" "Language: zh_TW\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 @@ -176,12 +176,12 @@ msgstr "完全不做任何事" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -937,26 +937,26 @@ msgstr "書庫的路徑太長。必須少於 %d 字元。" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1062 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 msgid "Yes" msgstr "是" #: /home/kovid/work/calibre/src/calibre/db/fields.py:163 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1217 msgid "Main" msgstr "主要" #: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1219 msgid "Card A" msgstr "記憶卡 A" #: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1221 msgid "Card B" msgstr "記憶卡 B" @@ -1144,14 +1144,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "新聞" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 msgid "Catalog" msgstr "分類" @@ -1201,10 +1201,10 @@ msgstr "Bambook" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -12294,6 +12294,10 @@ msgstr "" msgid "Choose &font family" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +msgid "Clear the font family" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 msgid "Cover Browser" @@ -13596,13 +13600,9 @@ msgstr "加入程序(&P)" msgid "" "If set, this option will causes calibre to check if a file\n" " being auto-added is already in the calibre library.\n" -" If it is, a meesage will pop up asking you whether\n" +" If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" -"如果設定,這個選項會讓 calibre 檢查要\n" -" 自動加入的檔案是否已在 calibre 書庫中。\n" -" 如果是,會彈出視窗詢問您是否要強制\n" -" 加入它。" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/adding_ui.py:152 msgid "Check for &duplicates when auto-adding files" @@ -17001,7 +17001,7 @@ msgid "Options to customize the ebook viewer" msgstr "用來自訂電子書檢視器的選項" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107 msgid "Remember last used window size" msgstr "記住上次使用的視窗大小" @@ -17596,39 +17596,39 @@ msgstr "管理書籤" msgid "Loading ebook..." msgstr "正在載入電子書..." -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 msgid "Could not open ebook" msgstr "無法開啟電子書" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" msgstr "用來控制電子書檢視器的選項" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101 msgid "" "If specified, viewer window will try to come to the front when started." msgstr "如果指定了,檢視器視窗在啟動時會嘗試移至最上層。" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104 msgid "" "If specified, viewer window will try to open full screen when started." msgstr "如果指定,檢視器視窗會在啟動時嘗試開啟全螢幕。" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109 msgid "Print javascript alert and console messages to the console" msgstr "在主控台中顯示 javascript 警示及主控台訊息" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111 msgid "" "The position at which to open the specified book. The position is a location " "as displayed in the top left corner of the viewer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118 msgid "" "%prog [options] file\n" "\n" @@ -19309,17 +19309,17 @@ msgstr "" msgid "creating custom column " msgstr "建立自訂欄 " -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "

將舊的資料庫轉移到 %s 的電子書庫

" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 #, python-format msgid "Copying %s" msgstr "正在複製 %s" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 msgid "Compacting database" msgstr "正在壓實資料庫" From d545fe19c1906c221d9f4f864bf88f29b7687325 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 27 Oct 2012 16:27:38 +0530 Subject: [PATCH 010/107] Fix #1072031 (Info not complete to read) --- src/calibre/gui2/dialogs/metadata_bulk.ui | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/calibre/gui2/dialogs/metadata_bulk.ui b/src/calibre/gui2/dialogs/metadata_bulk.ui index 2c4a409a22..917dfbb159 100644 --- a/src/calibre/gui2/dialogs/metadata_bulk.ui +++ b/src/calibre/gui2/dialogs/metadata_bulk.ui @@ -504,7 +504,11 @@ from the value in the box - When doing a same format to same format conversion, for e.g., EPUB to EPUB, calibre saves the original EPUB as ORIGINAL_EPUB. This option tells calibre to restore the EPUB from ORIGINAL_EPUB. Useful if you did a bulk conversion of a large number of books and something went wrong. + When doing a same format to same format conversion, +for e.g., EPUB to EPUB, calibre saves the original EPUB + as ORIGINAL_EPUB. This option tells calibre to restore + the EPUB from ORIGINAL_EPUB. Useful if you did a bulk + conversion of a large number of books and something went wrong. Restore pre conversion &originals, if available From f4e790893664758141133c2c8363faa874dadf67 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 27 Oct 2012 19:20:51 +0530 Subject: [PATCH 011/107] Update The Atlantic --- recipes/atlantic.recipe | 51 ++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/recipes/atlantic.recipe b/recipes/atlantic.recipe index 928f1343b3..55e02b2ad1 100644 --- a/recipes/atlantic.recipe +++ b/recipes/atlantic.recipe @@ -38,8 +38,10 @@ class TheAtlantic(BasicNewsRecipe): self.timefmt = ' [%s]'%ds cover = soup.find('img', src=True, attrs={'class':'cover'}) + if cover is not None: - self.cover_url = cover['src'].replace(' ', '%20') + self.cover_url = re.sub('\s','%20',re.sub('jpg.*','jpg',cover['src'])) + self.log(self.cover_url) feeds = [] seen_titles = set([]) @@ -47,18 +49,16 @@ class TheAtlantic(BasicNewsRecipe): section_title = self.tag_to_string(section.find('h2')) self.log('Found section:', section_title) articles = [] - for post in section.findAll('div', attrs={'class':lambda x : x and - 'post' in x}): - h = post.find(['h3', 'h4']) - title = self.tag_to_string(h) + for post in section.findAll('h3', attrs={'class':'headline'}): + a = post.find('a', href=True) + title = self.tag_to_string(a) if title in seen_titles: continue seen_titles.add(title) - a = post.find('a', href=True) url = a['href'] if url.startswith('/'): url = 'http://www.theatlantic.com'+url - p = post.find('p', attrs={'class':'dek'}) + p = post.parent.find('p', attrs={'class':'dek'}) desc = None self.log('\tFound article:', title, 'at', url) if p is not None: @@ -69,19 +69,29 @@ class TheAtlantic(BasicNewsRecipe): if articles: feeds.append((section_title, articles)) - poems = [] - self.log('Found section: Poems') - pd = soup.find('h2', text='Poetry').parent.parent - for poem in pd.findAll('h4'): - title = self.tag_to_string(poem) - url = poem.find('a')['href'] - if url.startswith('/'): - url = 'http://www.theatlantic.com' + url - self.log('\tFound article:', title, 'at', url) - poems.append({'title':title, 'url':url, 'description':'', - 'date':''}) - if poems: - feeds.append(('Poems', poems)) + rightContent=soup.find('div', attrs = {'class':'rightContent'}) + for module in rightContent.findAll('div', attrs={'class':'module'}): + section_title = self.tag_to_string(module.find('h2')) + articles = [] + for post in module.findAll('div', attrs={'class':'post'}): + a = post.find('a', href=True) + title = self.tag_to_string(a) + if title in seen_titles: + continue + seen_titles.add(title) + url = a['href'] + if url.startswith('/'): + url = 'http://www.theatlantic.com'+url + p = post.parent.find('p', attrs={'class':'dek'}) + desc = None + self.log('\tFound article:', title, 'at', url) + if p is not None: + desc = self.tag_to_string(p) + self.log('\t\t', desc) + articles.append({'title':title, 'url':url, 'description':desc, 'date':''}) + if articles: + feeds.append((section_title, articles)) + return feeds @@ -100,4 +110,3 @@ class TheAtlantic(BasicNewsRecipe): table.replaceWith(div) return soup - From 792901d690a206f470143a27e077bf87b8a3a5c4 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 27 Oct 2012 19:24:57 +0530 Subject: [PATCH 012/107] Update Financial Times (UK) --- recipes/financial_times_uk.recipe | 77 ++++++++++++++++--------------- 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/recipes/financial_times_uk.recipe b/recipes/financial_times_uk.recipe index 4e5b522ae9..e2b69f4987 100644 --- a/recipes/financial_times_uk.recipe +++ b/recipes/financial_times_uk.recipe @@ -1,5 +1,5 @@ __license__ = 'GPL v3' -__copyright__ = '2010-2012, Darko Miletic ' +__copyright__ = '2010-2011, Darko Miletic ' ''' www.ft.com/uk-edition ''' @@ -42,24 +42,18 @@ class FinancialTimes(BasicNewsRecipe): def get_browser(self): br = BasicNewsRecipe.get_browser() br.open(self.INDEX) - if self.username is not None and self.password is not None: - br.open(self.LOGIN2) - br.select_form(name='loginForm') - br['username'] = self.username - br['password'] = self.password - br.submit() + br.open(self.LOGIN) + br.select_form(name='loginForm') + br['username'] = self.username + br['password'] = self.password + br.submit() return br keep_only_tags = [ - dict(name='div' , attrs={'class':['fullstory fullstoryHeader', 'ft-story-header']}) - ,dict(name='div' , attrs={'class':'standfirst'}) - ,dict(name='div' , attrs={'id' :'storyContent'}) - ,dict(name='div' , attrs={'class':['ft-story-body','index-detail']}) - ,dict(name='div' , attrs={'class':['ft-story-body','index-detail']}) - ,dict(name='h2' , attrs={'class':'entry-title'} ) - ,dict(name='span', attrs={'class':lambda x: x and 'posted-on' in x.split()} ) - ,dict(name='span', attrs={'class':'author_byline'} ) - ,dict(name='div' , attrs={'class':'entry-content'} ) + dict(name='div', attrs={'class':['fullstory fullstoryHeader', 'ft-story-header']}) + ,dict(name='div', attrs={'class':'standfirst'}) + ,dict(name='div', attrs={'id' :'storyContent'}) + ,dict(name='div', attrs={'class':['ft-story-body','index-detail']}) ] remove_tags = [ dict(name='div', attrs={'id':'floating-con'}) @@ -88,17 +82,21 @@ class FinancialTimes(BasicNewsRecipe): if self.test and count > 2: return articles rawlink = item['href'] - url = rawlink - if not rawlink.startswith('http://'): - url = self.PREFIX + rawlink - urlverified = self.browser.open_novisit(url).geturl() # resolve redirect. + if rawlink.startswith('http://'): + url = rawlink + else: + url = self.PREFIX + rawlink + try: + urlverified = self.browser.open_novisit(url).geturl() # resolve redirect. + except: + continue title = self.tag_to_string(item) date = strftime(self.timefmt) articles.append({ - 'title' :title - ,'date' :date - ,'url' :urlverified - ,'description':'' + 'title' :title + ,'date' :date + ,'url' :urlverified + ,'description':'' }) return articles @@ -110,20 +108,21 @@ class FinancialTimes(BasicNewsRecipe): wide = soup.find('div',attrs={'class':'wide'}) if not wide: return feeds - allsections = wide.findAll(attrs={'class':lambda x: x and 'footwell' in x.split()}) - if not allsections: + strest = wide.findAll('h3', attrs={'class':'section'}) + if not strest: return feeds + st = wide.findAll('h4',attrs={'class':'section-no-arrow'}) + if st: + st.extend(strest) count = 0 - for item in allsections: + for item in st: count = count + 1 if self.test and count > 2: return feeds - fitem = item.h3 - if not fitem: - fitem = item.h4 - ftitle = self.tag_to_string(fitem) + ftitle = self.tag_to_string(item) self.report_progress(0, _('Fetching feed')+' %s...'%(ftitle)) - feedarts = self.get_artlinks(item.ul) + if item.parent.ul is not None: + feedarts = self.get_artlinks(item.parent.ul) feeds.append((ftitle,feedarts)) return feeds @@ -157,7 +156,7 @@ class FinancialTimes(BasicNewsRecipe): def get_cover_url(self): cdate = datetime.date.today() if cdate.isoweekday() == 7: - cdate -= datetime.timedelta(days=1) + cdate -= datetime.timedelta(days=1) return cdate.strftime('http://specials.ft.com/vtf_pdf/%d%m%y_FRONT1_LON.pdf') def get_obfuscated_article(self, url): @@ -170,8 +169,10 @@ class FinancialTimes(BasicNewsRecipe): except: print "Retrying download..." count += 1 - tfile = PersistentTemporaryFile('_fa.html') - tfile.write(html) - tfile.close() - self.temp_files.append(tfile) - return tfile.name + self.temp_files.append(PersistentTemporaryFile('_fa.html')) + self.temp_files[-1].write(html) + self.temp_files[-1].close() + return self.temp_files[-1].name + + def cleanup(self): + self.browser.open('https://registration.ft.com/registration/login/logout?location=') From 56bc2dd61963e082a60d33a2fe7d3dc66d1fe7dd Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 27 Oct 2012 19:37:53 +0530 Subject: [PATCH 013/107] ... --- manual/images/sg_pref.jpg | Bin 87492 -> 0 bytes manual/images/sg_pref.png | Bin 0 -> 71326 bytes manual/sub_groups.rst | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 manual/images/sg_pref.jpg create mode 100644 manual/images/sg_pref.png diff --git a/manual/images/sg_pref.jpg b/manual/images/sg_pref.jpg deleted file mode 100644 index 8bab672c2583b58a610615bdf9aca25f7ae55f1b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 87492 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 diff --git a/manual/images/sg_pref.png b/manual/images/sg_pref.png new file mode 100644 index 0000000000000000000000000000000000000000..59faa5f3e93d116de4c213b7b2e5c672de37767b GIT binary patch literal 71326 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 Gm;4O@iGn=< literal 0 HcmV?d00001 diff --git a/manual/sub_groups.rst b/manual/sub_groups.rst index 2b5c3b3856..c08df9a901 100644 --- a/manual/sub_groups.rst +++ b/manual/sub_groups.rst @@ -65,7 +65,7 @@ You create the custom column in the usual way, using Preferences -> Add your own Then after restarting |app|, you must tell |app| that the column is to be treated as a hierarchy. Go to Preferences -> Look and Feel -> Tag Browser and enter the lookup name "#genre" into the "Categories with hierarchical items" box. Press Apply, and you are done with setting up. -.. image:: images/sg_pref.jpg +.. image:: images/sg_pref.png :align: center At the point there are no genres in the column. We are left with the last step: how to apply a genre to a book. A genre does not exist in |app| until it appears on at least one book. To learn how to apply a genre for the first time, we must go into some detail about what a genre looks like in the metadata for a book. From e9ff5e25994d85f02eefd55b069b682adbf35761 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 27 Oct 2012 22:15:10 +0530 Subject: [PATCH 014/107] Update New York Times Book Review --- recipes/nytimesbook.recipe | 51 ++++++-------------------------------- 1 file changed, 8 insertions(+), 43 deletions(-) diff --git a/recipes/nytimesbook.recipe b/recipes/nytimesbook.recipe index 686f30b69a..5388da9dcb 100644 --- a/recipes/nytimesbook.recipe +++ b/recipes/nytimesbook.recipe @@ -1,5 +1,4 @@ from calibre.web.feeds.news import BasicNewsRecipe -from calibre.ebooks.BeautifulSoup import BeautifulSoup class NewYorkTimesBookReview(BasicNewsRecipe): title = u'New York Times Book Review' @@ -7,50 +6,16 @@ class NewYorkTimesBookReview(BasicNewsRecipe): __author__ = 'Krittika Goyal' oldest_article = 8 #days max_articles_per_feed = 1000 - recursions = 2 + #recursions = 2 #encoding = 'latin1' + use_embedded_content = False + + no_stylesheets = True + auto_cleanup = True - remove_stylesheets = True - #remove_tags_before = dict(name='h1', attrs={'class':'heading'}) - remove_tags_after = dict(name='div', attrs={'id':'authorId'}) - remove_tags = [ - dict(name='iframe'), - dict(name=['div', 'a'], attrs={'class':['enlargeThis', 'jumpLink']}), - dict(name='div', attrs={'id':['sidebarArticles', 'toolsRight']}), - #dict(name='ul', attrs={'class':'article-tools'}), - #dict(name='ul', attrs={'class':'articleTools'}), - ] - match_regexps = [ - r'http://www.nytimes.com/.+pagewanted=[2-9]+' - ] feeds = [ -('New York Times Sunday Book Review', - 'http://feeds.nytimes.com/nyt/rss/SundayBookReview'), -] + ('New York Times Sunday Book Review', + 'http://feeds.nytimes.com/nyt/rss/SundayBookReview'), + ] - - def preprocess_html(self, soup): - story = soup.find(name='div', attrs={'id':'article'}) - #td = heading.findParent(name='td') - #td.extract() - soup = BeautifulSoup('t') - body = soup.find(name='body') - body.insert(0, story) - #for x in soup.findAll(name='p', text=lambda x:x and '-->' in x): - #p = x.findParent('p') - #if p is not None: - #p.extract() - return soup - - def postprocess_html(self, soup, first): - for div in soup.findAll(id='pageLinks'): - div.extract() - if not first: - h1 = soup.find('h1') - if h1 is not None: - h1.extract() - t = soup.find(attrs={'class':'timestamp'}) - if t is not None: - t.extract() - return soup From 6deb1383200e4decf25a5f770a2fb30e4b8911eb Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 28 Oct 2012 08:13:27 +0530 Subject: [PATCH 015/107] ... --- src/calibre/devices/mtp/driver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/devices/mtp/driver.py b/src/calibre/devices/mtp/driver.py index 1584a3bf93..bc55654b1e 100644 --- a/src/calibre/devices/mtp/driver.py +++ b/src/calibre/devices/mtp/driver.py @@ -114,7 +114,7 @@ class MTP_DEVICE(BASE): except: prints('Failed to load existing driveinfo.calibre file, with error:') traceback.print_exc() - dinfo = None + dinfo = {} if dinfo.get('device_store_uuid', None) is None: dinfo['device_store_uuid'] = unicode(uuid.uuid4()) if dinfo.get('device_name', None) is None: From fefbd78ed33cae2f00a61f7db404a0ec89486dbc Mon Sep 17 00:00:00 2001 From: Translators <> Date: Sun, 28 Oct 2012 04:42:00 +0000 Subject: [PATCH 016/107] Launchpad automatic translations update. --- setup/iso_639/ca.po | 6 +- src/calibre/translations/ca.po | 46 ++++- src/calibre/translations/hu.po | 57 ++++--- src/calibre/translations/sk.po | 295 ++++++++++++++++++++------------- 4 files changed, 256 insertions(+), 148 deletions(-) diff --git a/setup/iso_639/ca.po b/setup/iso_639/ca.po index 5012e48969..b0ea4bffe5 100644 --- a/setup/iso_639/ca.po +++ b/setup/iso_639/ca.po @@ -12,13 +12,13 @@ msgstr "" "Report-Msgid-Bugs-To: Debian iso-codes team \n" "POT-Creation-Date: 2011-11-25 14:01+0000\n" -"PO-Revision-Date: 2012-10-26 17:42+0000\n" +"PO-Revision-Date: 2012-10-27 12:46+0000\n" "Last-Translator: Ferran Rius \n" "Language-Team: Catalan \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-27 04:58+0000\n" +"X-Launchpad-Export-Date: 2012-10-28 04:41+0000\n" "X-Generator: Launchpad (build 16194)\n" "Language: ca\n" @@ -10536,7 +10536,7 @@ msgstr "Izere" #. name for jaa msgid "Jamamadí" -msgstr "" +msgstr "Jamamadí" #. name for jab msgid "Hyam" diff --git a/src/calibre/translations/ca.po b/src/calibre/translations/ca.po index 2521ce5943..37d2258927 100644 --- a/src/calibre/translations/ca.po +++ b/src/calibre/translations/ca.po @@ -11,14 +11,14 @@ msgstr "" "Project-Id-Version: ca\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-10-26 05:12+0000\n" -"PO-Revision-Date: 2012-10-21 14:25+0000\n" +"PO-Revision-Date: 2012-10-27 12:43+0000\n" "Last-Translator: Ferran Rius \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-27 04:40+0000\n" +"X-Launchpad-Export-Date: 2012-10-28 04:40+0000\n" "X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 @@ -3788,6 +3788,12 @@ msgid "" "to remove fonts from the input document. Note that font embedding only works " "with some output formats, principally EPUB and AZW3." msgstr "" +"Incrusta la família de tipus de lletra al llibre. Especifica la lletra " +"«base» que s'utilitza per al llibre. Si el document d'entrada especifica els " +"seus tipus de lletra pot substituir aquesta lletra base. Podeu utilitzar " +"l'opció de la informació del filtre d'estils per suprimir tipus de lletra " +"del document d'entrada. Tingueu en compte que la incrustació de lletra només " +"funciona amb alguns formats de sortida, principalment EPUB i AZW3." #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:209 msgid "" @@ -8711,7 +8717,7 @@ msgstr "Alçada de la &línia:" #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:237 msgid "&Embed font family:" -msgstr "" +msgstr "&Incrusta els tipus de lletra" #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:238 msgid "&Disable font size rescaling" @@ -9142,6 +9148,7 @@ msgstr "Obre un llibre" #: /home/kovid/work/calibre/src/calibre/gui2/convert/regex_builder.py:215 msgid "Click the Open button below to open a ebook to use for testing." msgstr "" +"Feu clic al botó «Obre» per obrir un llibre per utilitzar-lo com a proba." #: /home/kovid/work/calibre/src/calibre/gui2/convert/regex_builder_ui.py:90 msgid "Regex Builder" @@ -13563,7 +13570,7 @@ msgstr "Expressió regular (?P)" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:122 msgid "Choose font family" -msgstr "" +msgstr "Tria el tipus de lletra" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:137 #: /home/kovid/work/calibre/src/calibre/gui2/keyboard.py:377 @@ -13583,15 +13590,15 @@ msgstr "Cap" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:159 msgid "Choose a font family from the list below:" -msgstr "" +msgstr "Trieu un tipus de lletra la la llista següent:" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:187 msgid "Choose &font family" -msgstr "" +msgstr "Tria el &tipus de lletra" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 msgid "Clear the font family" -msgstr "" +msgstr "Elimina el tipus de lletra" #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 @@ -14311,7 +14318,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:273 #, python-format msgid "Could not open \"%s\". Is it being used by another program?" -msgstr "" +msgstr "No s'ha pogut obrir «%s». L'està utilitzant un altre programa?" #: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:306 msgid "" @@ -15020,6 +15027,10 @@ msgid "" " If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" +"Si s'estableix fa que el calibre comprovi si un fitxer\n" +" que s'està afegint automàticament ja està a la biblioteca.\n" +" Si hi és, un missatge emergent us pregunarà si voleu\n" +" afegir-lo igualment." #: /home/kovid/work/calibre/src/calibre/gui2/preferences/adding_ui.py:152 msgid "Check for &duplicates when auto-adding files" @@ -21160,6 +21171,23 @@ msgid "" "that a new OPF has been createdsince the column was added). You will see the " "JSON for the\"display\" for the new column in the OPF." msgstr "" +"Un diccionari d'opcions per personalitzar com s'interpretaran les dades de " +"la columna. És una cadena JSON. Per a columnes d'enumeració utilitzeu --" +"display=\"{\\\"enum_values\\\":[\\\"val1\\\", \\\"val2\\\"]}\"\n" +"Hi ha moltes opcions que poden estar amb la variable «display». Les opcions " +"per tipus de columna són:\n" +"composite: composite_template, composite_sort, make_category,contains_html, " +"use_decorations\n" +"datetime: date_format\n" +"enumeration: enum_values, enum_colors, use_decorations\n" +"int, float: number_format\n" +"text: is_names, use_decorations\n" +"\n" +"La millor manera de trobar combinacions vàlides és crear una columna " +"personalitzada del tipus adequat a la interfície gràfica i mirar la còpia de " +"seguretat OPF per a un llibre (assegureu-vos que es crea un nou OPF després " +"de crear la columna). Veureu la cadena JSON per a «display» de la nova " +"columna al fitxer OPF." #: /home/kovid/work/calibre/src/calibre/library/cli.py:721 msgid "You must specify label, name and datatype" @@ -22231,7 +22259,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/utils/filenames.py:284 msgid "File is open in another process" -msgstr "" +msgstr "El fitxer està obert en un altre procés" #: /home/kovid/work/calibre/src/calibre/utils/formatter.py:31 #: /home/kovid/work/calibre/src/calibre/utils/formatter.py:182 diff --git a/src/calibre/translations/hu.po b/src/calibre/translations/hu.po index 204617bb46..4555eb40ad 100644 --- a/src/calibre/translations/hu.po +++ b/src/calibre/translations/hu.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-10-26 05:12+0000\n" -"PO-Revision-Date: 2012-08-25 19:23+0000\n" +"PO-Revision-Date: 2012-10-27 16:49+0000\n" "Last-Translator: Devilinside \n" "Language-Team: Hungarian \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-27 04:45+0000\n" +"X-Launchpad-Export-Date: 2012-10-28 04:41+0000\n" "X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 @@ -634,13 +634,15 @@ msgstr "A calibre e-book metaadatainak letöltési beállításai" #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1125 #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/mtp_config.py:392 msgid "Ignored devices" -msgstr "" +msgstr "Figyelmen kívül hagyott eszközök" #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1131 msgid "" "Control which devices calibre will ignore when they are connected to the " "computer." msgstr "" +"Állítsa be, hogy a calibre melyik eszközöket hagyja figyelmen kívül azok " +"csatlakozásakor." #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1138 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins.py:295 @@ -871,7 +873,7 @@ msgstr "Ez az Amazon Kindle DX profilja." #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:661 msgid "This profile is intended for the Amazon Kindle PaperWhite" -msgstr "" +msgstr "Az Amazon Kindle PaperWhite profilja" #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:672 msgid "This profile is intended for the Amazon Kindle Fire." @@ -1560,7 +1562,7 @@ msgstr "Hely %(dl)d • %(typ)s
" #: /home/kovid/work/calibre/src/calibre/devices/kindle/driver.py:289 msgid "Communicate with the Kindle 2/3/4/Touch/PaperWhite eBook reader." -msgstr "" +msgstr "Kapcsolódás a Kindle 2/3/4/Touch/PaperWhite ebook olvasókhoz." #: /home/kovid/work/calibre/src/calibre/devices/kindle/driver.py:301 msgid "Send page number information when sending books" @@ -1911,7 +1913,7 @@ msgstr "Kommunikáció Ex124G-vel" #: /home/kovid/work/calibre/src/calibre/devices/misc.py:414 msgid "Communicate with the WayteQ Reader" -msgstr "" +msgstr "Kapcsolódás a WayteQ ebook olvasóhoz" #: /home/kovid/work/calibre/src/calibre/devices/mtp/base.py:29 msgid "MTP Device" @@ -1929,16 +1931,16 @@ msgstr "Eszköz-információ lekérdezése…" #: /home/kovid/work/calibre/src/calibre/devices/mtp/driver.py:166 msgid "Listing files, this can take a while" -msgstr "" +msgstr "Fájlok listázása, ez eltarthat egy ideig" #: /home/kovid/work/calibre/src/calibre/devices/mtp/driver.py:181 msgid "Reading ebook metadata" -msgstr "" +msgstr "Ebook meaadatok olvasása" #: /home/kovid/work/calibre/src/calibre/devices/mtp/driver.py:214 #, python-format msgid "Reading metadata from %s" -msgstr "" +msgstr "Metaadatok olvasása a következő eszközről: %s" #: /home/kovid/work/calibre/src/calibre/devices/mtp/driver.py:233 msgid "Updating metadata cache on device" @@ -1946,7 +1948,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/mtp/driver.py:235 msgid "Finished reading metadata from device" -msgstr "" +msgstr "Metaadatok olvasása az eszközről kész" #: /home/kovid/work/calibre/src/calibre/devices/mtp/driver.py:393 #, python-format @@ -1955,29 +1957,29 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/mtp/driver.py:395 msgid "Transfer to device finished..." -msgstr "" +msgstr "Az eszközre küldés kész..." #: /home/kovid/work/calibre/src/calibre/devices/mtp/driver.py:416 #, python-format msgid "Added %s" -msgstr "" +msgstr "Hozzáadva: %s" #: /home/kovid/work/calibre/src/calibre/devices/mtp/driver.py:418 msgid "Adding complete" -msgstr "" +msgstr "Hozzáadás kész" #: /home/kovid/work/calibre/src/calibre/devices/mtp/driver.py:434 msgid "Deleting books from device..." -msgstr "" +msgstr "Könyvek törlése az eszközről..." #: /home/kovid/work/calibre/src/calibre/devices/mtp/driver.py:440 #, python-format msgid "Deleted %s" -msgstr "" +msgstr "Törölve: %s" #: /home/kovid/work/calibre/src/calibre/devices/mtp/driver.py:441 msgid "All books deleted" -msgstr "" +msgstr "Minden könyv törölve" #: /home/kovid/work/calibre/src/calibre/devices/mtp/driver.py:444 msgid "Removing books from metadata" @@ -1986,11 +1988,11 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/mtp/driver.py:456 #, python-format msgid "Removed %s" -msgstr "" +msgstr "Eltávolítva: %s" #: /home/kovid/work/calibre/src/calibre/devices/mtp/driver.py:458 msgid "All books removed" -msgstr "" +msgstr "Minden könyv eltávolítva" #: /home/kovid/work/calibre/src/calibre/devices/mtp/unix/driver.py:198 #: /home/kovid/work/calibre/src/calibre/devices/mtp/windows/driver.py:313 @@ -3660,6 +3662,11 @@ msgid "" "to remove fonts from the input document. Note that font embedding only works " "with some output formats, principally EPUB and AZW3." msgstr "" +"A megadott betűtípus beágyazása a könyvbe. Ez lesz a könyv alap betűtípusa. " +"Amennyiben a bemeneti fájl tartalmaz már saját betűtípust, az felülírja ezt " +"a beállítást. A Stílus információk szűrésénél ezeket a már beágyazott " +"betűtípusokat eltávolíthatja. Vegye figyelembe, hogy a betűtípus beágyazása " +"csak bizonyos formátumoknál, alapvetően az EPUB-nál és AZW3-nál működik." #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:209 msgid "" @@ -5518,11 +5525,11 @@ msgstr "Nem találhatóak könyvfájlok" #: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:406 msgid "Downloading books" -msgstr "" +msgstr "Könyvek letöltése" #: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:407 msgid "Downloading books from device" -msgstr "" +msgstr "Könyvek letöltése az eszközről" #: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:426 msgid "Could not download files from the device" @@ -8527,7 +8534,7 @@ msgstr "&Sorméret:" #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:237 msgid "&Embed font family:" -msgstr "" +msgstr "B&etűtípus beágyazása:" #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:238 msgid "&Disable font size rescaling" @@ -13277,7 +13284,7 @@ msgstr "Reguláris kifejezés (?P)" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:122 msgid "Choose font family" -msgstr "" +msgstr "Betűtípus kiválasztása" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:137 #: /home/kovid/work/calibre/src/calibre/gui2/keyboard.py:377 @@ -13297,15 +13304,15 @@ msgstr "Nincs" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:159 msgid "Choose a font family from the list below:" -msgstr "" +msgstr "Válasszon betűtípust az alábbi listából:" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:187 msgid "Choose &font family" -msgstr "" +msgstr "Betűtípus &kiválasztása" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 msgid "Clear the font family" -msgstr "" +msgstr "Betűtípus törlése" #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 diff --git a/src/calibre/translations/sk.po b/src/calibre/translations/sk.po index f7e8cc53a6..d69b3aa313 100644 --- a/src/calibre/translations/sk.po +++ b/src/calibre/translations/sk.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-10-26 05:12+0000\n" -"PO-Revision-Date: 2012-05-31 10:38+0000\n" -"Last-Translator: Michal Kaliňák \n" +"PO-Revision-Date: 2012-10-27 16:58+0000\n" +"Last-Translator: viktorc \n" "Language-Team: Slovak \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 1 : (n>=2 && n<=4) ? 2 : 0;\n" -"X-Launchpad-Export-Date: 2012-10-27 04:52+0000\n" +"X-Launchpad-Export-Date: 2012-10-28 04:41+0000\n" "X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 @@ -630,13 +630,14 @@ msgstr "Nastavenie spôsobu, akým Calibre sťahuje metadáta kníh z Internetu. #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1125 #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/mtp_config.py:392 msgid "Ignored devices" -msgstr "" +msgstr "Ignorované zariadenia" #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1131 msgid "" "Control which devices calibre will ignore when they are connected to the " "computer." msgstr "" +"Nastavenie zariadení, ktoré bude Calibre po pripojení k počítaču ignorovať." #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1138 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins.py:295 @@ -866,7 +867,7 @@ msgstr "Tento profil je určený pre zariadenie Amazon Kindle DX." #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:661 msgid "This profile is intended for the Amazon Kindle PaperWhite" -msgstr "" +msgstr "Tento profil je určený pre Amazon Kindle PaperWhite" #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:672 msgid "This profile is intended for the Amazon Kindle Fire." @@ -932,6 +933,8 @@ msgid "" "plugin. This command will automatically zip up the plugin and update it in " "calibre." msgstr "" +"Pre vývojárov modulov: Cesta k adresáru v ktorom vyvýjate modul. Tento " +"príkaz modul automaticky zbalí a aktualizuje ho v Calibre." #: /home/kovid/work/calibre/src/calibre/customize/ui.py:603 msgid "Remove a custom plugin by name. Has no effect on builtin plugins" @@ -1017,12 +1020,16 @@ msgid "" "Comma separated list of directories to send e-books to on the device's " "main memory. The first one that exists will be used" msgstr "" +"Zoznam adresárov oddelených čiarkou. Do prvého z nich, ktorý bude existovať " +"sa uložia e-booky pri odoslaní do hlavnej pamäte zariadenia." #: /home/kovid/work/calibre/src/calibre/devices/android/driver.py:201 msgid "" "Comma separated list of directories to send e-books to on the device's " "storage cards. The first one that exists will be used" msgstr "" +"Zoznam adresárov oddelených čiarkou. Do prvého z nich, ktorý bude existovať " +"sa uložia e-booky pri odoslaní na pamäťovú kartu zariadenia." #: /home/kovid/work/calibre/src/calibre/devices/android/driver.py:316 msgid "Communicate with S60 phones." @@ -1136,6 +1143,9 @@ msgid "" "href=\"http://www.mobileread.com/forums/showpost.php?p=2113958&postcount=3\">" "forum post for more information.

" msgstr "" +"

Nedokážem komunikovať s iTunes.

Pre viac informácií si pozrite " +"príspevok na fóre (v angličtine).

" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:381 #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:384 @@ -1379,7 +1389,7 @@ msgstr "Komunikácia s čítačkou PocketBook 602/603/902/903." #: /home/kovid/work/calibre/src/calibre/devices/eb600/driver.py:257 msgid "Communicate with the PocketBook 622 reader." -msgstr "" +msgstr "Komunikácia s čítačkou PocketBook 622." #: /home/kovid/work/calibre/src/calibre/devices/eb600/driver.py:270 msgid "Communicate with the PocketBook 360+ reader." @@ -1549,7 +1559,7 @@ msgstr "Pozícia %(dl)d • %(typ)s
" #: /home/kovid/work/calibre/src/calibre/devices/kindle/driver.py:289 msgid "Communicate with the Kindle 2/3/4/Touch/PaperWhite eBook reader." -msgstr "" +msgstr "Komunikácia s čítačkou Kindle 2/3/4/Touch/PaperWhite" #: /home/kovid/work/calibre/src/calibre/devices/kindle/driver.py:301 msgid "Send page number information when sending books" @@ -1688,7 +1698,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:88 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1240 msgid "Attempt to support newer firmware" -msgstr "" +msgstr "Podporovať novšie firmwéry" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:89 msgid "" @@ -1697,10 +1707,14 @@ msgid "" "be Dragons!! Enable only if you are comfortable with restoring your kobo to " "factory defaults and testing software" msgstr "" +"Kobo pravidelne aktualizuje firmware a verziu databázy. Táto voľba umožní " +"Calibre, aby sa pokúsil o plnú funkčnosť (čítanie aj zápis). Nebezpečné " +"teritórium. Povoľte len v prípade ak ste zvyknutí obnovovať Kobo do " +"továrenských nastavení a testovať software." #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:617 msgid "Kobo database version unsupported - See details" -msgstr "" +msgstr "Verzia databázy Kobo nie je podporovaná - viď. podrobnosti" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:618 msgid "" @@ -1714,6 +1728,15 @@ msgid "" "firmware\" option. Doing so may require you to perform a factory reset of " "your Kobo." msgstr "" +"Vaše Kobo beží na aktualizovanej verzii firmware/databázy. Calibre túto " +"verziu nepozná a preto z dôvodu ochrany pred poškodením je úprava databázu " +"zakázaná. Aj naďalej môžete pomocou Calibre odosielať knihy do Vášho Koba, " +"ale odstraňovanie a správa zbierok sú zakázané. Ak máte chuť experimentovať " +"a viete, ako obnoviť Vaše Kobo do továrenských nastavení, môžete toto " +"obmedzenie prekonať pravým kliknutím na ikonu zariadenia v Calibre a " +"vybraním \"Konfigurovať toto zariadenie\" a následne voľbou \"Podporovať " +"novšie firmwéry\". Ak tak urobíte, môže sa stať, že budete musieť Vaše Kobo " +"obnoviť do továrenských nastavení." #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:646 #: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:393 @@ -1774,7 +1797,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1211 msgid "The Kobo Touch from firmware V2.0.0 supports bookshelves." -msgstr "" +msgstr "Kobo Touch od firmware V2.0.0 podporuje regály." #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1213 msgid "Specify a tags type column for automatic management" @@ -1782,31 +1805,35 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1214 msgid "Create Bookshelves" -msgstr "" +msgstr "Vytvoriť regály" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1215 msgid "" "Create new bookshelves on the Kobo Touch if they do not exist. This is only " "for firmware V2.0.0 or later." msgstr "" +"Vytvoriť nové knižné regály na Kobo Touch - ak neexistujú. Určené len pre " +"firmware V2.0.0 a novšie." #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1216 msgid "Delete Empty Bookshelves" -msgstr "" +msgstr "Odstrániť prázdne regály" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1217 msgid "" "Delete any empty bookshelves from the Kobo Touch when syncing is finished. " "This is only for firmware V2.0.0 or later." msgstr "" +"Odstrániť na záver synchronizácie z Kobo Touch všetky prázdne knižné regály. " +"Určené len pre firmware V2.0.0 a novšie." #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1218 msgid "Upload covers for books" -msgstr "" +msgstr "Odoslať obálky kníh" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1224 msgid "Always upload covers" -msgstr "" +msgstr "Vždy odosielať obálky" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1225 msgid "" @@ -1823,6 +1850,11 @@ msgid "" "factory defaults and testing software. This driver supports firmware V2.0.x " "and DBVersion up to " msgstr "" +"Kobo pravidelne aktualizuje firmware a verziu databázy. Táto voľba umožní " +"Calibre, aby sa pokúsil o plnú funkčnosť (čítanie aj zápis). Nebezpečné " +"teritórium. Povoľte len v prípade ak ste zvyknutí obnovovať Kobo do " +"továrenských nastavení a testovať software. Tento ovládač podporuje firmware " +"V2.0.x a DBVersion až do " #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1247 msgid "Title to test when debugging" @@ -1898,15 +1930,15 @@ msgstr "Komunikácia so zariadením Ex124G" #: /home/kovid/work/calibre/src/calibre/devices/misc.py:414 msgid "Communicate with the WayteQ Reader" -msgstr "" +msgstr "Komunikácia s čítačkou WayteQ" #: /home/kovid/work/calibre/src/calibre/devices/mtp/base.py:29 msgid "MTP Device" -msgstr "" +msgstr "Zariadenie MTP" #: /home/kovid/work/calibre/src/calibre/devices/mtp/base.py:31 msgid "Communicate with MTP devices" -msgstr "" +msgstr "Komunikácia so zariadeniami MTP" #: /home/kovid/work/calibre/src/calibre/devices/mtp/driver.py:143 #: /home/kovid/work/calibre/src/calibre/devices/smart_device_app/driver.py:912 @@ -1916,83 +1948,83 @@ msgstr "Preberám informácie o zariadení..." #: /home/kovid/work/calibre/src/calibre/devices/mtp/driver.py:166 msgid "Listing files, this can take a while" -msgstr "" +msgstr "Listujem súbory, chvíľu to môže trvať" #: /home/kovid/work/calibre/src/calibre/devices/mtp/driver.py:181 msgid "Reading ebook metadata" -msgstr "" +msgstr "Čítam metadáta e-booku" #: /home/kovid/work/calibre/src/calibre/devices/mtp/driver.py:214 #, python-format msgid "Reading metadata from %s" -msgstr "" +msgstr "Čítam metadáta z %s" #: /home/kovid/work/calibre/src/calibre/devices/mtp/driver.py:233 msgid "Updating metadata cache on device" -msgstr "" +msgstr "Aktualizujem vyrovnávaciu pamäť metadát v zariadení" #: /home/kovid/work/calibre/src/calibre/devices/mtp/driver.py:235 msgid "Finished reading metadata from device" -msgstr "" +msgstr "Čítanie metadát zo zariadenia skončilo" #: /home/kovid/work/calibre/src/calibre/devices/mtp/driver.py:393 #, python-format msgid "Transferred %s to device" -msgstr "" +msgstr "%s prenesených do zariadenia" #: /home/kovid/work/calibre/src/calibre/devices/mtp/driver.py:395 msgid "Transfer to device finished..." -msgstr "" +msgstr "Prenos do zariadenia skončil..." #: /home/kovid/work/calibre/src/calibre/devices/mtp/driver.py:416 #, python-format msgid "Added %s" -msgstr "" +msgstr "%s pridané" #: /home/kovid/work/calibre/src/calibre/devices/mtp/driver.py:418 msgid "Adding complete" -msgstr "" +msgstr "Pridávanie dokončené" #: /home/kovid/work/calibre/src/calibre/devices/mtp/driver.py:434 msgid "Deleting books from device..." -msgstr "" +msgstr "Odstraňujem knihy zo zariadenia..." #: /home/kovid/work/calibre/src/calibre/devices/mtp/driver.py:440 #, python-format msgid "Deleted %s" -msgstr "" +msgstr "%s odstránené" #: /home/kovid/work/calibre/src/calibre/devices/mtp/driver.py:441 msgid "All books deleted" -msgstr "" +msgstr "Všetky knihy boli odstránené" #: /home/kovid/work/calibre/src/calibre/devices/mtp/driver.py:444 msgid "Removing books from metadata" -msgstr "" +msgstr "Odstraňovanie kníh z metadát" #: /home/kovid/work/calibre/src/calibre/devices/mtp/driver.py:456 #, python-format msgid "Removed %s" -msgstr "" +msgstr "%s bola odstránená" #: /home/kovid/work/calibre/src/calibre/devices/mtp/driver.py:458 msgid "All books removed" -msgstr "" +msgstr "Všetky knihy boli odstránené" #: /home/kovid/work/calibre/src/calibre/devices/mtp/unix/driver.py:198 #: /home/kovid/work/calibre/src/calibre/devices/mtp/windows/driver.py:313 msgid "Unknown MTP device" -msgstr "" +msgstr "Neznáme zariadenie MTP" #: /home/kovid/work/calibre/src/calibre/devices/mtp/unix/driver.py:216 #: /home/kovid/work/calibre/src/calibre/devices/mtp/windows/driver.py:220 #, python-format msgid "Found object: %s" -msgstr "" +msgstr "Bol nájdený objekt: %s" #: /home/kovid/work/calibre/src/calibre/devices/mtp/windows/driver.py:61 msgid "MTP devices are not supported on Windows XP" -msgstr "" +msgstr "MTP zariadenia nie sú podporované vo Windows XP" #: /home/kovid/work/calibre/src/calibre/devices/mtp/windows/driver.py:69 msgid "" @@ -2000,11 +2032,14 @@ msgid "" "may need to install Windows Media Player 11 or newer and/or restart your " "computer" msgstr "" +"Služba Prenosných zariadení vo Windows nie je na Vašom počítači dostupná. " +"Mali by ste inštalovať Windows Media Player 11 alebo novší a/alebo " +"reštartovať Váš počítač" #: /home/kovid/work/calibre/src/calibre/devices/mtp/windows/driver.py:222 #, python-format msgid "Found id: %s" -msgstr "" +msgstr "Bolo nájdené id: %s" #: /home/kovid/work/calibre/src/calibre/devices/nokia/driver.py:17 msgid "Communicate with the Nokia 770 internet tablet." @@ -2181,11 +2216,11 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/smart_device_app/driver.py:174 msgid "Wireless Device" -msgstr "" +msgstr "Bezdrôtové zariadenie" #: /home/kovid/work/calibre/src/calibre/devices/smart_device_app/driver.py:178 msgid "Communicate with Smart Device apps" -msgstr "" +msgstr "Komunikujem s aplikáciami Smart zariadenia" #: /home/kovid/work/calibre/src/calibre/devices/smart_device_app/driver.py:264 msgid "All by something" @@ -2193,61 +2228,68 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/smart_device_app/driver.py:267 msgid "Enable connections at startup" -msgstr "" +msgstr "Povoliť pripojenia po spustení" #: /home/kovid/work/calibre/src/calibre/devices/smart_device_app/driver.py:268 msgid "Check this box to allow connections when calibre starts" -msgstr "" +msgstr "Ak chcete povoliť pripojenia po spustení calibre, označte túto voľbu" #: /home/kovid/work/calibre/src/calibre/devices/smart_device_app/driver.py:270 msgid "Security password" -msgstr "" +msgstr "Bezpečnostné heslo" #: /home/kovid/work/calibre/src/calibre/devices/smart_device_app/driver.py:271 msgid "Enter a password that the device app must use to connect to calibre" msgstr "" +"Zadajte heslo, ktoré musí aplikácia zariadenia použiť pri pripojení ku " +"Calibre" #: /home/kovid/work/calibre/src/calibre/devices/smart_device_app/driver.py:273 msgid "Use fixed network port" -msgstr "" +msgstr "Použiť pevný sieťový port" #: /home/kovid/work/calibre/src/calibre/devices/smart_device_app/driver.py:274 msgid "" "If checked, use the port number in the \"Port\" box, otherwise the driver " "will pick a random port" msgstr "" +"Ak označíte, použije sa číslo portu z poľa \"Port\", inak ovládač vyberie " +"náhodný port" #: /home/kovid/work/calibre/src/calibre/devices/smart_device_app/driver.py:276 msgid "Port number: " -msgstr "" +msgstr "Čislo portu: " #: /home/kovid/work/calibre/src/calibre/devices/smart_device_app/driver.py:277 msgid "" "Enter the port number the driver is to use if the \"fixed port\" box is " "checked" msgstr "" +"Zadajte číslo portu, ktoré ovládač použije ak zaškrtnete \"Použiť pevný " +"sieťový port\"" #: /home/kovid/work/calibre/src/calibre/devices/smart_device_app/driver.py:278 msgid "Print extra debug information" -msgstr "" +msgstr "Vypisovať ďalšie ladiace informácie" #: /home/kovid/work/calibre/src/calibre/devices/smart_device_app/driver.py:279 msgid "Check this box if requested when reporting problems" -msgstr "" +msgstr "Označte, ak vás o to pri oznamovaní problémov požiadajú" #: /home/kovid/work/calibre/src/calibre/devices/smart_device_app/driver.py:281 msgid "" "Comma separated list of metadata fields to turn into collections on the " "device." msgstr "" +"Zoznam metadát oddelených čiarkou, ktorý sa v zariadení zmení na zbierky." #: /home/kovid/work/calibre/src/calibre/devices/smart_device_app/driver.py:283 msgid "Possibilities include: series, tags, authors, etc" -msgstr "" +msgstr "Možnosti zahŕňajú: series, tags, authors, atď." #: /home/kovid/work/calibre/src/calibre/devices/smart_device_app/driver.py:291 msgid "Enable the no-activity timeout" -msgstr "" +msgstr "Povoliť časovač bez aktivity" #: /home/kovid/work/calibre/src/calibre/devices/smart_device_app/driver.py:292 #, python-format @@ -2256,10 +2298,13 @@ msgid "" "device does nothing for %d minutes. Unchecking this box disables this " "timeout, so calibre will never automatically disconnect." msgstr "" +"Ak je táto voľba označená, Calibre sa automaticky odpojí od zariadenia, " +"ktoré bolo bez aktivity počas %d minút. Odznačenie tejto voľby zakáže " +"sledovanie neaktivity zariadenia, teda Calibre sa nikdy aktomaticky neodpojí." #: /home/kovid/work/calibre/src/calibre/devices/smart_device_app/driver.py:296 msgid "Use this IP address" -msgstr "" +msgstr "Použiť túto IP adresu" #: /home/kovid/work/calibre/src/calibre/devices/smart_device_app/driver.py:297 msgid "" @@ -2267,25 +2312,28 @@ msgid "" "address. The driver will listen only on the entered address, and this " "address will be the one advertized over mDNS (bonjour)." msgstr "" +"Použite túto voľbu ak chcete ovládaču vynútiť počúvanie na konkrétnej IP " +"adrese. Ovládač bude počúvať len na zadanej adrese a táto bude jediná, ktorú " +"bude propagovať cez mDNS (bonjour)." #: /home/kovid/work/calibre/src/calibre/devices/smart_device_app/driver.py:766 #, python-format msgid "Too many connection attempts from %s" -msgstr "" +msgstr "Príliš veľa pokusov o pripojenie z %s" #: /home/kovid/work/calibre/src/calibre/devices/smart_device_app/driver.py:1271 #, python-format msgid "Invalid port in options: %s" -msgstr "" +msgstr "Neplatný port vo voľbách: %s" #: /home/kovid/work/calibre/src/calibre/devices/smart_device_app/driver.py:1279 #, python-format msgid "Failed to connect to port %d. Try a different value." -msgstr "" +msgstr "Pripojenie k portu %d zlyhalo. Skúste inú hodnotu." #: /home/kovid/work/calibre/src/calibre/devices/smart_device_app/driver.py:1291 msgid "Failed to allocate a random port" -msgstr "" +msgstr "Použitie náhodného portu zlyhalo" #: /home/kovid/work/calibre/src/calibre/devices/sne/driver.py:17 msgid "Communicate with the Samsung SNE eBook reader." @@ -2509,13 +2557,15 @@ msgstr "Priečinok karty A" #: /home/kovid/work/calibre/src/calibre/devices/user_defined/driver.py:69 msgid "Swap main and card A" -msgstr "" +msgstr "Vymeniť hlavú pamäť a kartu A" #: /home/kovid/work/calibre/src/calibre/devices/user_defined/driver.py:70 msgid "" "Check this box if the device's main memory is being seen as card a and the " "card is being seen as main memory" msgstr "" +"Označte túto voľbu ak sa hlavná pamäť zariadenia zobrazuje ako karta a karta " +"ako hlavná pamäť" #: /home/kovid/work/calibre/src/calibre/devices/utils.py:18 #: /home/kovid/work/calibre/src/calibre/devices/utils.py:24 @@ -2525,6 +2575,9 @@ msgid "" "device action. Right click on the send to device button and reset the " "default action to be \"Send to main memory\"." msgstr "" +"Čítačka nemá pamäťovú kartu %s. Mali by ste zmeniť predvolenú akciu pre " +"odoslanie do zariadenia. Kliknite pravým tlačidlom na ikonu odoslať do " +"zariadenia a obnovte predvolenú akciu na \"Odoslať do hlavnej pamäte\"." #: /home/kovid/work/calibre/src/calibre/devices/utils.py:29 #, python-format @@ -3017,6 +3070,8 @@ msgid "" "If set this option causes the file name of the html file inside the htmlz " "archive to be based on the book title." msgstr "" +"Ak je voľba zapnutá, spôsobí že názov html súboru vo vnútri archívu htmlz " +"bude tvorený podľa názvu knihy." #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plugins/lrf_output.py:95 msgid "Enable autorotation of images that are wider than the screen width." @@ -3174,6 +3229,11 @@ msgid "" "6 and the new KF8 format, or only the new KF8 format. KF8 has more features " "than MOBI 6, but only works with newer Kindles." msgstr "" +"Štandardne Calibre generuje súbory MOBI, ktoré obsahujú starý formát MOBI 6. " +"Tento formát je kompatibilný so všetkými zariadeniami. Zmenou tejto voľby " +"nastavíte, aby Calibre generoval súbory MOBI, ktoré budú obsahovať formáty " +"MOBI 6 aj nový KF8, alebo len nový formát KF8. KF8 má viac funkcií, ako MOBI " +"6, ale funguje len na novších Kindle." #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plugins/mobi_output.py:136 #: /home/kovid/work/calibre/src/calibre/ebooks/epub/periodical.py:125 @@ -3258,24 +3318,24 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plugins/pdf_output.py:94 msgid "The font family used to render serif fonts" -msgstr "" +msgstr "Font na vykreslenie pätkových písiem" #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plugins/pdf_output.py:97 msgid "The font family used to render sans-serif fonts" -msgstr "" +msgstr "Font na vykreslenie bezpätkových písiem" #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plugins/pdf_output.py:100 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plugins/pdf_output.py:104 msgid "The font family used to render monospaced fonts" -msgstr "" +msgstr "Font na vykreslenie neproporcionálnych písiem" #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plugins/pdf_output.py:107 msgid "The default font size" -msgstr "" +msgstr "Štandardná veľkosť písma" #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plugins/pdf_output.py:110 msgid "The default font size for monospaced text" -msgstr "" +msgstr "Štandardná veľkosť písma neproporcionálneho textu" #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plugins/pml_output.py:22 msgid "" @@ -3626,6 +3686,12 @@ msgid "" "to remove fonts from the input document. Note that font embedding only works " "with some output formats, principally EPUB and AZW3." msgstr "" +"Pripojiť ku knihe určenú triedu fontov. Toto určuje \"základné\" písmo " +"použité v knihe. Ak vstupný dokument špecifikuje vlastné písma, môže " +"prepísať toto základné písmo. Zo vstupného dokumentu môžete niektoré písma " +"odstrániť pomocou voľby filtrovať informácie štýlov. Uvedomte si, že " +"pripojenie funguje len pri niektorých výstupných formátoch, hlavne EPUB a " +"AZW3." #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:209 msgid "" @@ -4193,7 +4259,7 @@ msgstr "Prebieha transformácia e-knihy..." #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:1136 #, python-format msgid "Running %s plugin" -msgstr "" +msgstr "Spúšťam modul %s" #: /home/kovid/work/calibre/src/calibre/ebooks/epub/fix/__init__.py:20 #, python-format @@ -4401,7 +4467,7 @@ msgstr "Výstupný LRS súbor" #: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrfparser.py:140 msgid "Do not save embedded image and font files to disk" -msgstr "Neukladať vsadené obrazové súbory a súbory písiem na disk" +msgstr "Neukladať pripojené obrazové súbory a súbory písiem na disk" #: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrfparser.py:159 msgid "Parsing LRF..." @@ -5058,7 +5124,7 @@ msgstr "Bočný panel" #: /home/kovid/work/calibre/src/calibre/ebooks/pdf/outline_writer.py:60 #, python-format msgid "Page %d" -msgstr "" +msgstr "Strana %d" #: /home/kovid/work/calibre/src/calibre/ebooks/pdf/pdftohtml.py:71 msgid "Could not find pdftohtml, check it is in your PATH" @@ -5419,6 +5485,9 @@ msgid "" "processed and merged into your Calibre database according to your automerge " "settings:" msgstr "" +"Bolo nájdených nasledujúcich %d duplicitných kníh. Vstupné formáty kníh boli " +"spracované a zlúčené do Vašej databázy Calibre podľa Vašich nastavení " +"automatického pridávania:" #: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:354 msgid "Failed to read metadata" @@ -5457,23 +5526,23 @@ msgstr "Neboli nájdené žiadne súbory kníh" #: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:406 msgid "Downloading books" -msgstr "" +msgstr "Sťahujem knihy" #: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:407 msgid "Downloading books from device" -msgstr "" +msgstr "Sťahujem knihy zo zariadenia" #: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:426 msgid "Could not download files from the device" -msgstr "" +msgstr "Nemôžem stiahnuť súbory zo zariadenia" #: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:429 msgid "Could not download some files from the device" -msgstr "" +msgstr "Nemôžem stiahnuť niektoré súbory zo zariadenia" #: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:433 msgid "Could not download files" -msgstr "" +msgstr "Nemôžem stiahnuť súbory" #: /home/kovid/work/calibre/src/calibre/gui2/actions/add_to_library.py:13 msgid "Add books to library" @@ -5902,6 +5971,9 @@ msgid "" "library. Click Show details to see which ones. This behavior is controlled " "by the Auto merge option in Preferences->Adding books." msgstr "" +"Niektoré knihy boli automaticky zlúčené do existujúcich záznamov v cieľovej " +"knižnici. Kliknutie na Ukáž detaily zobrazí ktoré. Toto chovanie je " +"ovplyvnené voľbou Automaticky zlúčiť v Nastavenia -> Vloženie kníh." #: /home/kovid/work/calibre/src/calibre/gui2/actions/copy_to_library.py:226 msgid "" @@ -5996,6 +6068,7 @@ msgid "" "The %(fmt)s format will be permanently deleted from %(title)s. Are " "you sure?" msgstr "" +"Formát %(fmt)s bude natrvalo odstránený z %(title)s. Ste si istý?" #: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:162 msgid "Choose formats to be deleted" @@ -6080,11 +6153,11 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:33 msgid "Start wireless device connection" -msgstr "" +msgstr "Spustiť pripojenie bezdrôtového zariadenia" #: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:34 msgid "Stop wireless device connection" -msgstr "" +msgstr "Zastaviť pripojenie bezdrôtového zariadenia" #: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:38 msgid "Connect to folder" @@ -6110,7 +6183,7 @@ msgstr "Spustiť/zastaviť server obsahu" #: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:96 #, python-format msgid " [%(ip)s, port %(port)d]" -msgstr "" +msgstr " [%(ip)s, port %(port)d]" #: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:100 msgid "Stop Content Server" @@ -6157,17 +6230,19 @@ msgstr "Zastavujem server, môže to trvať až minútu, čakajte prosím..." #: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:236 msgid "Disable autostart" -msgstr "" +msgstr "Zakázať automatické spustenie" #: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:237 msgid "" "Do you want wireless device connections to be started automatically when " "calibre starts?" msgstr "" +"Chcete, aby boli pripojenia bezdrôtového zariadenia automaticky spustené pri " +"spustení Calibre?" #: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:260 msgid "Many IP addresses. See Start/Stop dialog." -msgstr "" +msgstr "Veľa IP adries. Viď. dialóg Štart/Stop." #: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_collections.py:13 msgid "Manage collections" @@ -6262,6 +6337,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:117 msgid "Show the &failed books in the main book list after updating metadata" msgstr "" +"Po aktualizácii metadát zobraziť &zlyhané knihy v hlavnom zozname kníh" #: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:123 msgid "Download complete" @@ -6521,7 +6597,7 @@ msgstr "Chyba zápisu na disk" #: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:63 msgid "Choose format to save to disk" -msgstr "" +msgstr "Vyberte formát na uloženie na disk" #: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:84 msgid "Choose destination directory" @@ -6638,15 +6714,15 @@ msgstr "Hľadať eknihy" #: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:28 msgid "this author" -msgstr "" +msgstr "tento autor" #: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:28 msgid "this title" -msgstr "" +msgstr "tento titul" #: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:29 msgid "this book" -msgstr "" +msgstr "táto kniha" #: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:32 #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/view.py:469 @@ -6748,31 +6824,14 @@ msgid "" " library.\n" " " msgstr "" -"

O knihe úprav

\n" -"

Kniha úprav umožňuje doladiť výzor e-knihy\n" -" malými zmenami jej vnútra. Na použitie Knihy úprav\n" -" potrebujete vedieť niečo o HTML a CSS, technológiách,\n" -" ktoré sú použité v e-knihách. Nasledujte kroky:

\n" -"
\n" -"
    \n" -"
  1. Kliknite \"Rozbaliť knihu\": toto \"rozbalí\" knihu do jej\n" -" jednotlivých vnútorných zložiek.
  2. \n" -"
  3. Pravým klikom na jednotlivý súbor vyberte \"Otvor s...\"\n" -" a zeditujte ho v obľúbenom textovom editore.
  4. \n" -"
  5. Keď skončíte úpravy: zavrite okno prehliadača súborov\n" -" a okná editora, v ktorom ste robili zmeny. Potom kliknite\n" -" na tlačítko \"Prestavať knihu\", aby sa zaktualizovala kniha v " -"knižnici\n" -" calibre.
  6. \n" -"
" #: /home/kovid/work/calibre/src/calibre/gui2/actions/tweak_epub.py:103 msgid "&Explode Book" -msgstr "" +msgstr "&Rozbaliť knihu" #: /home/kovid/work/calibre/src/calibre/gui2/actions/tweak_epub.py:104 msgid "&Preview Book" -msgstr "" +msgstr "&Náhľad knihy" #: /home/kovid/work/calibre/src/calibre/gui2/actions/tweak_epub.py:105 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comments_dialog.py:25 @@ -6792,49 +6851,53 @@ msgstr "Na editáciu zložiek knihy ju rozbaľte." #: /home/kovid/work/calibre/src/calibre/gui2/actions/tweak_epub.py:111 msgid "Preview the result of your tweaks" -msgstr "" +msgstr "Náhľad výsledku Vašich vylepšení" #: /home/kovid/work/calibre/src/calibre/gui2/actions/tweak_epub.py:113 msgid "Abort without saving any changes" -msgstr "" +msgstr "Prerušiť bez zapísania zmien" #: /home/kovid/work/calibre/src/calibre/gui2/actions/tweak_epub.py:115 msgid "Save your changes and update the book in the calibre library" -msgstr "" +msgstr "Uloží Vaše zmeny a aktualizuje knihu v knižnici Calibre" #: /home/kovid/work/calibre/src/calibre/gui2/actions/tweak_epub.py:155 msgid "Exploding, please wait..." -msgstr "" +msgstr "Rozbaľujem, prosím počkajte..." #: /home/kovid/work/calibre/src/calibre/gui2/actions/tweak_epub.py:177 #: /home/kovid/work/calibre/src/calibre/gui2/actions/tweak_epub.py:187 msgid "Failed to unpack" -msgstr "" +msgstr "Rozbalenie zlyhalo" #: /home/kovid/work/calibre/src/calibre/gui2/actions/tweak_epub.py:178 #, python-format msgid "Could not explode the %s file." -msgstr "" +msgstr "Nemôžem rozbaliť súbor %s." #: /home/kovid/work/calibre/src/calibre/gui2/actions/tweak_epub.py:188 #, python-format msgid "" "Could not explode the %s file. Click \"Show Details\" for more information." msgstr "" +"Nemôžem rozbaliť súbor %s. Pre viac informácií kliknite na \"Zobraziť " +"podrobnosti\"." #: /home/kovid/work/calibre/src/calibre/gui2/actions/tweak_epub.py:222 msgid "Failed to rebuild file" -msgstr "" +msgstr "Znovuvytvorenie súboru zlyhalo" #: /home/kovid/work/calibre/src/calibre/gui2/actions/tweak_epub.py:223 #, python-format msgid "Failed to rebuild %s. For more information, click \"Show details\"." msgstr "" +"Znovuvytvorenie %s zlyhalo. Pre viac informácií kliknite na \"Zobraziť " +"podrobnosti\"." #: /home/kovid/work/calibre/src/calibre/gui2/actions/tweak_epub.py:231 #: /home/kovid/work/calibre/src/calibre/gui2/actions/tweak_epub.py:240 msgid "Rebuilding, please wait..." -msgstr "" +msgstr "Znovuvytváram, prosím čakajte..." #: /home/kovid/work/calibre/src/calibre/gui2/actions/tweak_epub.py:289 msgid "Make small changes to ePub, HTMLZ or AZW3 format books" @@ -6850,7 +6913,7 @@ msgstr "Nemôžem vylepšiť knihu" #: /home/kovid/work/calibre/src/calibre/gui2/actions/tweak_epub.py:310 msgid "Cannot Tweak Book" -msgstr "" +msgstr "Nemôžem vylepšiť knihu" #: /home/kovid/work/calibre/src/calibre/gui2/actions/tweak_epub.py:311 msgid "" @@ -6858,6 +6921,9 @@ msgid "" "\n" "First convert the book to one of these formats." msgstr "" +"Na vylepšenie musí byť kniha vo formáte ePub, HTMLZ, alebo AZW3.\n" +"\n" +"Knihu najprv skonverujte do jedného z týchto formátov." #: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:37 msgid "V" @@ -6997,11 +7063,11 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/add.py:387 msgid "Already in calibre:" -msgstr "" +msgstr "V Calibre už existuje:" #: /home/kovid/work/calibre/src/calibre/gui2/add.py:395 msgid "You are trying to add:" -msgstr "" +msgstr "Pokúšate sa pridať:" #: /home/kovid/work/calibre/src/calibre/gui2/add.py:400 #: /home/kovid/work/calibre/src/calibre/gui2/auto_add.py:223 @@ -7013,6 +7079,8 @@ msgid "" "Books with the same title as the following already exist in calibre. Add " "them anyway?" msgstr "" +"Knihy s rovnakým názvom ako nasledujúci už v Calibre existujú. Napriek tomu " +"pridať?" #: /home/kovid/work/calibre/src/calibre/gui2/add.py:404 msgid "Adding duplicates..." @@ -7256,12 +7324,12 @@ msgstr "Veľkosť obálky: %(width)d x %(height)d" #: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:469 #, python-format msgid "Delete the %s format" -msgstr "" +msgstr "Vymazať formát %s" #: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:470 #, python-format msgid "Save the %s format to disk" -msgstr "" +msgstr "Uložiť formát %s na disk" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_bibtex.py:16 msgid "BibTeX Options" @@ -7425,7 +7493,7 @@ msgstr "Voľby E-book" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:90 msgid "Catalogs" -msgstr "" +msgstr "Katalógy" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:99 msgid "Read book" @@ -8430,7 +8498,7 @@ msgstr "Výška &riadka:" #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:237 msgid "&Embed font family:" -msgstr "" +msgstr "&Pripojiť triedu fontov:" #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:238 msgid "&Disable font size rescaling" @@ -8474,7 +8542,7 @@ msgstr "Formát &hlavičky:" #: /home/kovid/work/calibre/src/calibre/gui2/convert/lrf_output_ui.py:132 msgid "&Embed fonts" -msgstr "&Vložené písma" +msgstr "&Pripojené písma" #: /home/kovid/work/calibre/src/calibre/gui2/convert/lrf_output_ui.py:133 msgid "&Serif font family:" @@ -11800,6 +11868,11 @@ msgid "" "has been corrupted and you get a blank list of books.

Do you want to " "restore the database?" msgstr "" +"Váš zoznam kníh spolu so všetkými metadátami je uložený v jednom súbore, " +"nazvanom databáza. Naviac sú metadáta pre každú jednotlivú knihu uložené, " +"ako záloha, v adresári knihy.

Táto operácia znovu vytvorí databázu z " +"metadát jednotlivých kníh. To je užitočné v prípade, ak bola databáza " +"poškodená a Vy vidíte prázdny zoznam kníh.

Chcete obnoviť databázu?" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/restore_library.py:115 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/restore_library.py:129 @@ -18404,7 +18477,7 @@ msgstr "Nastaviť prehliadač elektronických kníh" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config_ui.py:371 msgid "&Default font size:" -msgstr "Štandardná veľkosť &písma" +msgstr "Štandardná veľkosť &písma:" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config_ui.py:376 msgid "Serif" From 488b82b6ff10e01ee8c19a5c466eb3e2c10d0c35 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 28 Oct 2012 10:25:58 +0530 Subject: [PATCH 017/107] Add CSS3 Fonts support to the fontconfig plugin --- src/calibre/utils/fonts/fc.py | 79 +++++++++++++++++++++++++--- src/calibre/utils/fonts/fontconfig.c | 77 ++++++++++++++++++--------- 2 files changed, 123 insertions(+), 33 deletions(-) diff --git a/src/calibre/utils/fonts/fc.py b/src/calibre/utils/fonts/fc.py index 73800d1193..3e6ae844bc 100644 --- a/src/calibre/utils/fonts/fc.py +++ b/src/calibre/utils/fonts/fc.py @@ -8,7 +8,7 @@ __docformat__ = 'restructuredtext en' import os, sys -from calibre.constants import plugins, islinux, isbsd, isosx +from calibre.constants import plugins, islinux, isbsd, isosx, preferred_encoding _fc, _fc_err = plugins['fontconfig'] @@ -26,6 +26,33 @@ class FontConfig(Thread): Thread.__init__(self) self.daemon = True self.failed = False + self.css_weight_map = { + _fc.FC_WEIGHT_THIN : u'100', + _fc.FC_WEIGHT_EXTRALIGHT : u'200', _fc.FC_WEIGHT_ULTRALIGHT : u'200', + _fc.FC_WEIGHT_LIGHT : u'300', + _fc.FC_WEIGHT_BOOK : u'normal', _fc.FC_WEIGHT_BOOK : u'normal', _fc.FC_WEIGHT_REGULAR : u'normal', + _fc.FC_WEIGHT_MEDIUM : u'500', + _fc.FC_WEIGHT_DEMIBOLD : u'600', _fc.FC_WEIGHT_SEMIBOLD : u'600', + _fc.FC_WEIGHT_BOLD : u'bold', + _fc.FC_WEIGHT_EXTRABOLD : u'800', _fc.FC_WEIGHT_ULTRABOLD : u'800', + _fc.FC_WEIGHT_HEAVY : u'900', _fc.FC_WEIGHT_BLACK : u'900', _fc.FC_WEIGHT_EXTRABLACK : u'900', _fc.FC_WEIGHT_ULTRABLACK : u'900' + } + self.css_slant_map = { + _fc.FC_SLANT_ROMAN : u'normal', + _fc.FC_SLANT_ITALIC : u'italic', + _fc.FC_SLANT_OBLIQUE : u'oblique' + } + self.css_stretch_map = { + _fc.FC_WIDTH_ULTRACONDENSED: u'ultra-condensed', + _fc.FC_WIDTH_EXTRACONDENSED : u'extra-condensed', + _fc.FC_WIDTH_CONDENSED: u'condensed', + _fc.FC_WIDTH_SEMICONDENSED: u'semi-condensed', + _fc.FC_WIDTH_NORMAL: u'normal', + _fc.FC_WIDTH_SEMIEXPANDED: u'semi-expanded', + _fc.FC_WIDTH_EXPANDED: u'expanded', + _fc.FC_WIDTH_EXTRAEXPANDED: u'extra-expanded', + _fc.FC_WIDTH_ULTRAEXPANDED: u'ultra-expanded', + } def run(self): config = None @@ -83,12 +110,13 @@ class FontConfig(Thread): `('normal', 'bold', 'italic', 'bi', 'light', 'li')` ''' self.wait() - if isinstance(family, unicode): - family = family.encode('utf-8') + if not isinstance(family, unicode): + family = family.decode(preferred_encoding) fonts = {} - ofamily = str(family).decode('utf-8') - for fullname, path, style, nfamily, weight, slant in \ - _fc.files_for_family(str(family)): + for entry in _fc.files_for_family(family): + slant, weight = entry['slant'], entry['weight'] + fullname, path = entry['fullname'], entry['path'] + nfamily = entry['family'] style = (slant, weight) if normalize: italic = slant > 0 @@ -104,7 +132,7 @@ class FontConfig(Thread): except UnicodeDecodeError: continue if style in fonts: - if nfamily.lower().strip() == ofamily.lower().strip() \ + if nfamily.lower().strip() == family.lower().strip() \ and 'Condensed' not in fullname and 'ExtraLight' not in fullname: fonts[style] = (path, fullname) else: @@ -112,6 +140,41 @@ class FontConfig(Thread): return fonts + def faces_for_family(self, family): + ''' + Return all the faces in a font family in a manner suitable for CSS 3. + ''' + self.wait() + if not isinstance(family, unicode): + family = family.decode(preferred_encoding) + seen = set() + for entry in _fc.files_for_family(family): + slant, weight = entry['slant'], entry['weight'] + fullname, path = entry['fullname'], entry['path'] + nfamily, width = entry['family'], entry['width'] + fingerprint = (slant, weight, width, nfamily) + if fingerprint in seen: + # Fontconfig returns the same font multiple times if it is + # present in multiple locations + continue + seen.add(fingerprint) + + try: + nfamily = nfamily.decode('UTF-8') + fullname = fullname.decode('utf-8') + path = path.decode('utf-8') + except UnicodeDecodeError: + continue + + face = { + 'font-weight': self.css_weight_map[weight], + 'font-style': self.css_slant_map[slant], + 'font-stretch': self.css_stretch_map[width], + 'font-family': nfamily, + 'fullname': fullname, 'path':path + } + yield face + def match(self, name, all=False, verbose=False): ''' Find the system font that most closely matches `name`, where `name` is a specification @@ -162,7 +225,7 @@ else: def test(): from pprint import pprint; pprint(fontconfig.find_font_families()) - pprint(fontconfig.files_for_family('liberation serif')) + pprint(tuple(fontconfig.faces_for_family('liberation serif'))) m = 'liberation serif' pprint(fontconfig.match(m+':slant=italic:weight=bold', verbose=True)) diff --git a/src/calibre/utils/fonts/fontconfig.c b/src/calibre/utils/fonts/fontconfig.c index be1cbdce13..b66aba4b08 100644 --- a/src/calibre/utils/fonts/fontconfig.c +++ b/src/calibre/utils/fonts/fontconfig.c @@ -141,10 +141,10 @@ fontconfig_files_for_family(PyObject *self, PyObject *args) { FcPattern *pat, *tp; FcObjectSet *oset; FcFontSet *fs; - FcValue file, weight, fullname, style, slant, family2; - PyObject *ans, *temp, *t; + FcValue file, weight, fullname, style, slant, family2, width; + PyObject *ans, *temp; - if (!PyArg_ParseTuple(args, "s", &family)) + if (!PyArg_ParseTuple(args, "es", "UTF-8", &family)) return NULL; ans = PyList_New(0); @@ -154,6 +154,7 @@ fontconfig_files_for_family(PyObject *self, PyObject *args) { pat = FcPatternBuild(0, FC_FAMILY, FcTypeString, family, (char *) 0); if (pat == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } + PyMem_Free(family); family = NULL; oset = FcObjectSetCreate(); if (oset == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } @@ -161,8 +162,9 @@ fontconfig_files_for_family(PyObject *self, PyObject *args) { if (!FcObjectSetAdd(oset, FC_STYLE)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } if (!FcObjectSetAdd(oset, FC_SLANT)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } if (!FcObjectSetAdd(oset, FC_WEIGHT)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } + if (!FcObjectSetAdd(oset, FC_WIDTH)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } if (!FcObjectSetAdd(oset, FC_FAMILY)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - if (!FcObjectSetAdd(oset, "fullname")) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } + if (!FcObjectSetAdd(oset, FC_FULLNAME)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } fs = FcFontList(FcConfigGetCurrent(), pat, oset); if (fs == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } @@ -174,30 +176,21 @@ fontconfig_files_for_family(PyObject *self, PyObject *args) { if (FcPatternGet(tp, FC_FILE, 0, &file) != FcResultMatch) continue; if (FcPatternGet(tp, FC_STYLE, 0, &style) != FcResultMatch) continue; if (FcPatternGet(tp, FC_WEIGHT, 0, &weight) != FcResultMatch) continue; + if (FcPatternGet(tp, FC_WIDTH, 0, &width) != FcResultMatch) continue; if (FcPatternGet(tp, FC_SLANT, 0, &slant) != FcResultMatch) continue; if (FcPatternGet(tp, FC_FAMILY, 0, &family2) != FcResultMatch) continue; - if (FcPatternGet(tp, "fullname", 0, &fullname) != FcResultMatch) continue; + if (FcPatternGet(tp, FC_FULLNAME, 0, &fullname) != FcResultMatch) continue; - temp = PyTuple_New(6); - if(temp == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - t = PyBytes_FromString((char *)fullname.u.s); - if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - PyTuple_SET_ITEM(temp, 0, t); - t = PyBytes_FromString((char *)file.u.s); - if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - PyTuple_SET_ITEM(temp, 1, t); - t = PyBytes_FromString((char *)style.u.s); - if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - PyTuple_SET_ITEM(temp, 2, t); - t = PyBytes_FromString((char *)family2.u.s); - if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - PyTuple_SET_ITEM(temp, 3, t); - t = PyInt_FromLong((long)weight.u.i); - if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - PyTuple_SET_ITEM(temp, 4, t); - t = PyInt_FromLong((long)slant.u.i); - if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - PyTuple_SET_ITEM(temp, 5, t); + temp = Py_BuildValue("{s:s, s:s, s:s, s:s, s:l, s:l, s:l}", + "fullname", (char*)fullname.u.s, + "path", (char*)file.u.s, + "style", (char*)style.u.s, + "family", (char*)family2.u.s, + "weight", (long)weight.u.i, + "slant", (long)slant.u.i, + "width", (long)width.u.i + ); + if (temp == NULL) { fontconfig_cleanup_find(pat, oset, fs); return NULL; } if (PyList_Append(ans, temp) != 0) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } } @@ -343,5 +336,39 @@ initfontconfig(void) { "Find fonts." ); if (m == NULL) return; + + PyModule_AddIntMacro(m, FC_WEIGHT_THIN); + PyModule_AddIntMacro(m, FC_WEIGHT_EXTRALIGHT); + PyModule_AddIntMacro(m, FC_WEIGHT_ULTRALIGHT); + PyModule_AddIntMacro(m, FC_WEIGHT_LIGHT); + PyModule_AddIntMacro(m, FC_WEIGHT_BOOK); + PyModule_AddIntMacro(m, FC_WEIGHT_REGULAR); + PyModule_AddIntMacro(m, FC_WEIGHT_NORMAL); + PyModule_AddIntMacro(m, FC_WEIGHT_MEDIUM); + PyModule_AddIntMacro(m, FC_WEIGHT_DEMIBOLD); + PyModule_AddIntMacro(m, FC_WEIGHT_SEMIBOLD); + PyModule_AddIntMacro(m, FC_WEIGHT_BOLD); + PyModule_AddIntMacro(m, FC_WEIGHT_EXTRABOLD); + PyModule_AddIntMacro(m, FC_WEIGHT_ULTRABOLD); + PyModule_AddIntMacro(m, FC_WEIGHT_BLACK); + PyModule_AddIntMacro(m, FC_WEIGHT_HEAVY); + PyModule_AddIntMacro(m, FC_WEIGHT_EXTRABLACK); + PyModule_AddIntMacro(m, FC_WEIGHT_ULTRABLACK); + + PyModule_AddIntMacro(m, FC_SLANT_ROMAN); + PyModule_AddIntMacro(m, FC_SLANT_ITALIC); + PyModule_AddIntMacro(m, FC_SLANT_OBLIQUE); + + PyModule_AddIntMacro(m, FC_WIDTH_ULTRACONDENSED); + PyModule_AddIntMacro(m, FC_WIDTH_EXTRACONDENSED); + PyModule_AddIntMacro(m, FC_WIDTH_CONDENSED); + PyModule_AddIntMacro(m, FC_WIDTH_SEMICONDENSED); + PyModule_AddIntMacro(m, FC_WIDTH_NORMAL); + PyModule_AddIntMacro(m, FC_WIDTH_SEMIEXPANDED); + PyModule_AddIntMacro(m, FC_WIDTH_EXPANDED); + PyModule_AddIntMacro(m, FC_WIDTH_EXTRAEXPANDED); + PyModule_AddIntMacro(m, FC_WIDTH_ULTRAEXPANDED); + +# } From 6d355b82b81575d45639d041f598b593ee8daa01 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 28 Oct 2012 16:11:24 +0530 Subject: [PATCH 018/107] Fix a potential crash in the FreeType bindings, if the string object passed in from python is deleted before the face oject. --- src/calibre/utils/fonts/freetype.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/calibre/utils/fonts/freetype.cpp b/src/calibre/utils/fonts/freetype.cpp index e4e30000a0..9086ae0377 100644 --- a/src/calibre/utils/fonts/freetype.cpp +++ b/src/calibre/utils/fonts/freetype.cpp @@ -22,6 +22,7 @@ typedef struct { // ensure it is garbage collected before the library object, to prevent // segfaults. PyObject *library; + PyObject *data; } Face; typedef struct { @@ -40,9 +41,12 @@ Face_dealloc(Face* self) } self->face = NULL; - Py_DECREF(self->library); + Py_XDECREF(self->library); self->library = NULL; + Py_XDECREF(self->data); + self->data = NULL; + self->ob_type->tp_free((PyObject*)self); } @@ -55,8 +59,6 @@ Face_init(Face *self, PyObject *args, PyObject *kwds) PyObject *ft; if (!PyArg_ParseTuple(args, "Os#", &ft, &data, &sz)) return -1; - self->library = ft; - Py_XINCREF(ft); Py_BEGIN_ALLOW_THREADS; error = FT_New_Memory_Face( ( (FreeType*)ft )->library, @@ -70,6 +72,10 @@ Face_init(Face *self, PyObject *args, PyObject *kwds) PyErr_Format(FreeTypeError, "Failed to initialize the Font with error: 0x%x", error); return -1; } + self->library = ft; + Py_XINCREF(ft); + + self->data = PySequence_GetItem(args, 1); return 0; } From 1af17f0c20388dde0f86a89004706dc7cada947f Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 28 Oct 2012 17:24:00 +0530 Subject: [PATCH 019/107] Font embedding: Add support for the CSS 3 Fonts module, which means you can embed font families that have more that the usual four faces, with the full set of font-stretch and font-weight variations. Of course, whether the fonts actually show up on a reader will depend on the readers support for CSS 3. --- src/calibre/__init__.py | 23 -- src/calibre/ebooks/__init__.py | 10 +- src/calibre/ebooks/lrf/__init__.py | 10 +- src/calibre/ebooks/oeb/transforms/flatcss.py | 57 ++-- src/calibre/gui2/__init__.py | 46 +-- src/calibre/gui2/convert/mobi_output.py | 32 +- src/calibre/gui2/font_family_chooser.py | 26 +- src/calibre/gui2/widgets.py | 9 +- .../library/catalogs/epub_mobi_builder.py | 10 +- src/calibre/test_build.py | 9 - src/calibre/utils/fonts/__init__.py | 117 ------- src/calibre/utils/fonts/free_type.py | 6 +- src/calibre/utils/fonts/metadata.py | 114 +++++++ src/calibre/utils/fonts/scanner.py | 294 ++++++++++++++++++ src/calibre/utils/fonts/utils.py | 65 ++-- 15 files changed, 529 insertions(+), 299 deletions(-) create mode 100644 src/calibre/utils/fonts/metadata.py create mode 100644 src/calibre/utils/fonts/scanner.py diff --git a/src/calibre/__init__.py b/src/calibre/__init__.py index 4b0ba5cf68..b64fd08d0a 100644 --- a/src/calibre/__init__.py +++ b/src/calibre/__init__.py @@ -690,29 +690,6 @@ def remove_bracketed_text(src, buf.append(char) return u''.join(buf) -def load_builtin_fonts(): - # On linux these are loaded by fontconfig which means that - # they are available to Qt as well, since Qt uses fontconfig - from calibre.utils.fonts import fontconfig - fontconfig - - families = {u'Liberation Serif', u'Liberation Sans', u'Liberation Mono'} - - if iswindows or isosx: - import glob - from PyQt4.Qt import QFontDatabase - families = set() - for f in glob.glob(P('fonts/liberation/*.ttf')): - with open(f, 'rb') as s: - # Windows requires font files to be executable for them to be - # loaded successfully, so we use the in memory loader - fid = QFontDatabase.addApplicationFontFromData(s.read()) - if fid > -1: - families |= set(map(unicode, - QFontDatabase.applicationFontFamilies(fid))) - - return families - def ipython(user_ns=None): from calibre.utils.ipython import ipython ipython(user_ns=user_ns) diff --git a/src/calibre/ebooks/__init__.py b/src/calibre/ebooks/__init__.py index 9cf0e51e7e..a5417be220 100644 --- a/src/calibre/ebooks/__init__.py +++ b/src/calibre/ebooks/__init__.py @@ -254,7 +254,6 @@ def unit_convert(value, base, font, dpi): def generate_masthead(title, output_path=None, width=600, height=60): from calibre.ebooks.conversion.config import load_defaults - from calibre.utils.fonts import fontconfig from calibre.utils.config import tweaks fp = tweaks['generate_cover_title_font'] if not fp: @@ -264,11 +263,10 @@ def generate_masthead(title, output_path=None, width=600, height=60): masthead_font_family = recs.get('masthead_font', 'Default') if masthead_font_family != 'Default': - masthead_font = fontconfig.files_for_family(masthead_font_family) - # Assume 'normal' always in dict, else use default - # {'normal': (path_to_font, friendly name)} - if 'normal' in masthead_font: - font_path = masthead_font['normal'][0] + from calibre.utils.fonts.scanner import font_scanner + faces = font_scanner.fonts_for_family(masthead_font_family) + if faces: + font_path = faces[0]['path'] if not font_path or not os.access(font_path, os.R_OK): font_path = default_font diff --git a/src/calibre/ebooks/lrf/__init__.py b/src/calibre/ebooks/lrf/__init__.py index b12c0d6b34..725338ead8 100644 --- a/src/calibre/ebooks/lrf/__init__.py +++ b/src/calibre/ebooks/lrf/__init__.py @@ -34,24 +34,24 @@ class PRS500_PROFILE(object): name = 'prs500' def find_custom_fonts(options, logger): - from calibre.utils.fonts import fontconfig - files_for_family = fontconfig.files_for_family + from calibre.utils.fonts.scanner import font_scanner fonts = {'serif' : None, 'sans' : None, 'mono' : None} def family(cmd): return cmd.split(',')[-1].strip() if options.serif_family: f = family(options.serif_family) - fonts['serif'] = files_for_family(f) + fonts['serif'] = font_scanner.legacy_fonts_for_family(f) + print (111111, fonts['serif']) if not fonts['serif']: logger.warn('Unable to find serif family %s'%f) if options.sans_family: f = family(options.sans_family) - fonts['sans'] = files_for_family(f) + fonts['sans'] = font_scanner.legacy_fonts_for_family(f) if not fonts['sans']: logger.warn('Unable to find sans family %s'%f) if options.mono_family: f = family(options.mono_family) - fonts['mono'] = files_for_family(f) + fonts['mono'] = font_scanner.legacy_fonts_for_family(f) if not fonts['mono']: logger.warn('Unable to find mono family %s'%f) return fonts diff --git a/src/calibre/ebooks/oeb/transforms/flatcss.py b/src/calibre/ebooks/oeb/transforms/flatcss.py index 6aae85d8d1..f963f468aa 100644 --- a/src/calibre/ebooks/oeb/transforms/flatcss.py +++ b/src/calibre/ebooks/oeb/transforms/flatcss.py @@ -178,49 +178,40 @@ class CSSFlattener(object): body_font_family = None if not family: return body_font_family, efi - from calibre.utils.fonts import fontconfig - from calibre.utils.fonts.utils import (get_font_characteristics, - panose_to_css_generic_family, get_font_names) - faces = fontconfig.fonts_for_family(family) - if not faces or not u'normal' in faces: + from calibre.utils.fonts.scanner import font_scanner + from calibre.utils.fonts.utils import panose_to_css_generic_family + faces = font_scanner.fonts_for_family(family) + if not faces: msg = (u'No embeddable fonts found for family: %r'%self.opts.embed_font_family) - if faces: - msg = (u'The selected font %s has no Regular typeface, only' - ' %s faces, it cannot be used.')%( - self.opts.embed_font_family, - ', '.join(faces.iterkeys())) if failure_critical: raise ValueError(msg) self.oeb.log.warn(msg) return body_font_family, efi - for k, v in faces.iteritems(): - ext, data = v[0::2] - weight, is_italic, is_bold, is_regular, fs_type, panose = \ - get_font_characteristics(data) - generic_family = panose_to_css_generic_family(panose) - family_name, subfamily_name, full_name = get_font_names(data) - if k == u'normal': - body_font_family = u"'%s',%s"%(family_name, generic_family) - if family_name.lower() != family.lower(): - self.oeb.log.warn(u'Failed to find an exact match for font:' - u' %r, using %r instead'%(family, family_name)) - else: - self.oeb.log(u'Embedding font: %s'%family_name) - font = {u'font-family':u'"%s"'%family_name} - if is_italic: - font[u'font-style'] = u'italic' - if is_bold: - font[u'font-weight'] = u'bold' + for i, font in enumerate(faces): + ext = 'otf' if font['is_otf'] else 'ttf' fid, href = self.oeb.manifest.generate(id=u'font', - href=u'%s.%s'%(ascii_filename(full_name).replace(u' ', u'-'), ext)) + href=u'%s.%s'%(ascii_filename(font['full_name']).replace(u' ', u'-'), ext)) item = self.oeb.manifest.add(fid, href, - guess_type(full_name+'.'+ext)[0], - data=data) + guess_type('dummy.'+ext)[0], + data=font_scanner.get_font_data(font)) item.unload_data_from_memory() - font[u'src'] = u'url(%s)'%item.href + + cfont = { + u'font-family':u'"%s"'%font['font-family'], + u'panose-1': u' '.join(map(unicode, font['panose'])), + u'src': u'url(%s)'%item.href, + } + + if i == 0: + generic_family = panose_to_css_generic_family(font['panose']) + body_font_family = u"'%s',%s"%(font['font-family'], generic_family) + self.oeb.log(u'Embedding font: %s'%font['font-family']) + for k in (u'font-weight', u'font-style', u'font-stretch'): + if font[k] != u'normal': + cfont[k] = font[k] rule = '@font-face { %s }'%('; '.join(u'%s:%s'%(k, v) for k, v in - font.iteritems())) + cfont.iteritems())) rule = cssutils.parseString(rule) efi.append(rule) diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index 688b134f0e..c1a088bcac 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -1,18 +1,19 @@ __license__ = 'GPL v3' __copyright__ = '2008, Kovid Goyal ' """ The GUI """ -import os, sys, Queue, threading +import os, sys, Queue, threading, glob from threading import RLock from urllib import unquote from PyQt4.Qt import (QVariant, QFileInfo, QObject, SIGNAL, QBuffer, Qt, QByteArray, QTranslator, QCoreApplication, QThread, QEvent, QTimer, pyqtSignal, QDateTime, QDesktopServices, QFileDialog, QFileIconProvider, QSettings, QColor, - QIcon, QApplication, QDialog, QUrl, QFont, QPalette) + QIcon, QApplication, QDialog, QUrl, QFont, QPalette, + QFontDatabase) ORG_NAME = 'KovidsBrain' APP_UID = 'libprs500' -from calibre import prints, load_builtin_fonts +from calibre import prints from calibre.constants import (islinux, iswindows, isbsd, isfrozen, isosx, plugins, config_dir, filesystem_encoding, DEBUG) from calibre.utils.config import Config, ConfigProxy, dynamic, JSONConfig @@ -779,7 +780,7 @@ class Application(QApplication): qt_app = self self._file_open_paths = [] self._file_open_lock = RLock() - load_builtin_fonts() + self.load_builtin_fonts() self.setup_styles(force_calibre_style) if DEBUG: @@ -792,6 +793,28 @@ class Application(QApplication): self.redirect_notify = True return ret + def load_builtin_fonts(self): + global _rating_font + from calibre.utils.fonts.scanner import font_scanner + # Start scanning the users computer for fonts + font_scanner + + # Load the builtin fonts and any fonts added to calibre by the user to + # Qt + for ff in glob.glob(P('fonts/liberation/*.?tf')) + \ + [P('fonts/calibreSymbols.otf')] + \ + glob.glob(os.path.join(config_dir, 'fonts', '*.?tf')): + if ff.rpartition('.')[-1].lower() in {'ttf', 'otf'}: + with open(ff, 'rb') as s: + # Windows requires font files to be executable for them to be + # loaded successfully, so we use the in memory loader + fid = QFontDatabase.addApplicationFontFromData(s.read()) + if fid > -1: + fam = QFontDatabase.applicationFontFamilies(fid) + fam = set(map(unicode, fam)) + if u'calibre Symbols' in fam: + _rating_font = u'calibre Symbols' + def load_calibre_style(self): # On OS X QtCurve resets the palette, so we preserve it explicitly orig_pal = QPalette(self.palette()) @@ -964,22 +987,9 @@ def is_gui_thread(): global gui_thread return gui_thread is QThread.currentThread() -_rating_font = None +_rating_font = 'Arial Unicode MS' if iswindows else 'sans-serif' def rating_font(): global _rating_font - if _rating_font is None: - from PyQt4.Qt import QFontDatabase - _rating_font = 'Arial Unicode MS' if iswindows else 'sans-serif' - fontid = QFontDatabase.addApplicationFont( - #P('fonts/liberation/LiberationSerif-Regular.ttf') - P('fonts/calibreSymbols.otf') - ) - if fontid > -1: - try: - _rating_font = unicode(list( - QFontDatabase.applicationFontFamilies(fontid))[0]) - except: - pass return _rating_font def find_forms(srcdir): diff --git a/src/calibre/gui2/convert/mobi_output.py b/src/calibre/gui2/convert/mobi_output.py index ac2bf15164..6a5c4120a0 100644 --- a/src/calibre/gui2/convert/mobi_output.py +++ b/src/calibre/gui2/convert/mobi_output.py @@ -29,38 +29,8 @@ class PluginWidget(Widget, Ui_Form): ) self.db, self.book_id = db, book_id - ''' - from calibre.utils.fonts import fontconfig - - global font_family_model - if font_family_model is None: - font_family_model = FontFamilyModel() - try: - font_family_model.families = fontconfig.find_font_families(allowed_extensions=['ttf']) - except: - import traceback - font_family_model.families = [] - print 'WARNING: Could not load fonts' - traceback.print_exc() - font_family_model.families.sort() - font_family_model.families[:0] = [_('Default')] - - self.font_family_model = font_family_model - self.opt_masthead_font.setModel(self.font_family_model) - ''' self.opt_mobi_file_type.addItems(['old', 'both', 'new']) self.initialize_options(get_option, get_help, db, book_id) - ''' - def set_value_handler(self, g, val): - if unicode(g.objectName()) in 'opt_masthead_font': - idx = -1 - if val: - idx = g.findText(val, Qt.MatchFixedString) - if idx < 0: - idx = 0 - g.setCurrentIndex(idx) - return True - return False - ''' + diff --git a/src/calibre/gui2/font_family_chooser.py b/src/calibre/gui2/font_family_chooser.py index 5110e92d24..6c3aa4594a 100644 --- a/src/calibre/gui2/font_family_chooser.py +++ b/src/calibre/gui2/font_family_chooser.py @@ -13,9 +13,6 @@ from PyQt4.Qt import (QFontInfo, QFontMetrics, Qt, QFont, QFontDatabase, QPen, QToolButton, QGridLayout, QListView, QWidget, QDialogButtonBox, QIcon, QHBoxLayout, QLabel, QModelIndex) -from calibre.gui2 import error_dialog -from calibre.utils.icu import sort_key - def writing_system_for_font(font): has_latin = True systems = QFontDatabase().writingSystems(font.family()) @@ -122,19 +119,14 @@ class FontFamilyDialog(QDialog): QDialog.__init__(self, parent) self.setWindowTitle(_('Choose font family')) self.setWindowIcon(QIcon(I('font.png'))) - from calibre.utils.fonts import fontconfig + from calibre.utils.fonts.scanner import font_scanner try: - self.families = fontconfig.find_font_families() + self.families = font_scanner.find_font_families() except: self.families = [] print ('WARNING: Could not load fonts') import traceback traceback.print_exc() - # Restrict to Qt families as we need the font to be available in - # QFontDatabase - qt_families = set([unicode(x) for x in QFontDatabase().families()]) - self.families = list(qt_families.intersection(set(self.families))) - self.families.sort(key=sort_key) self.families.insert(0, _('None')) self.l = l = QGridLayout() @@ -174,20 +166,6 @@ class FontFamilyDialog(QDialog): if idx == 0: return None return self.families[idx] - def accept(self): - ff = self.font_family - if ff: - from calibre.utils.fonts import fontconfig - faces = fontconfig.fonts_for_family(ff) or {} - faces = frozenset(faces.iterkeys()) - if 'normal' not in faces: - error_dialog(self, _('Not a useable font'), - _('The %s font family does not have a Regular typeface, so it' - ' cannot be used. It has only the "%s" face(s).')%( - ff, ', '.join(faces)), show=True) - return - QDialog.accept(self) - class FontFamilyChooser(QWidget): family_changed = pyqtSignal(object) diff --git a/src/calibre/gui2/widgets.py b/src/calibre/gui2/widgets.py index a990baaa1e..dfbcbdcbf0 100644 --- a/src/calibre/gui2/widgets.py +++ b/src/calibre/gui2/widgets.py @@ -11,7 +11,7 @@ from PyQt4.Qt import (QIcon, QFont, QLabel, QListWidget, QAction, QAbstractListModel, QVariant, Qt, SIGNAL, pyqtSignal, QRegExp, QSize, QSplitter, QPainter, QLineEdit, QComboBox, QPen, QGraphicsScene, QMenu, QStringListModel, QCompleter, QStringList, QTimer, QRect, - QFontDatabase, QGraphicsView, QByteArray) + QGraphicsView, QByteArray) from calibre.constants import iswindows from calibre.gui2 import (NONE, error_dialog, pixmap_to_data, gprefs, @@ -352,17 +352,14 @@ class FontFamilyModel(QAbstractListModel): # {{{ def __init__(self, *args): QAbstractListModel.__init__(self, *args) - from calibre.utils.fonts import fontconfig + from calibre.utils.fonts.scanner import font_scanner try: - self.families = fontconfig.find_font_families() + self.families = font_scanner.find_font_families() except: self.families = [] print 'WARNING: Could not load fonts' traceback.print_exc() # Restrict to Qt families as Qt tends to crash - qt_families = set([unicode(x) for x in QFontDatabase().families()]) - self.families = list(qt_families.intersection(set(self.families))) - self.families.sort() self.families[:0] = [_('None')] self.font = QFont('Arial' if iswindows else 'sansserif') diff --git a/src/calibre/library/catalogs/epub_mobi_builder.py b/src/calibre/library/catalogs/epub_mobi_builder.py index 48bb634fd6..fb7bda13cf 100644 --- a/src/calibre/library/catalogs/epub_mobi_builder.py +++ b/src/calibre/library/catalogs/epub_mobi_builder.py @@ -2757,7 +2757,6 @@ class CatalogBuilder(object): """ from calibre.ebooks.conversion.config import load_defaults - from calibre.utils.fonts import fontconfig MI_WIDTH = 600 MI_HEIGHT = 60 @@ -2767,11 +2766,10 @@ class CatalogBuilder(object): masthead_font_family = recs.get('masthead_font', 'Default') if masthead_font_family != 'Default': - masthead_font = fontconfig.files_for_family(masthead_font_family) - # Assume 'normal' always in dict, else use default - # {'normal': (path_to_font, friendly name)} - if 'normal' in masthead_font: - font_path = masthead_font['normal'][0] + from calibre.utils.fonts.scanner import font_scanner + faces = font_scanner.fonts_for_family(masthead_font_family) + if faces: + font_path = faces[0]['path'] if not font_path or not os.access(font_path, os.R_OK): font_path = default_font diff --git a/src/calibre/test_build.py b/src/calibre/test_build.py index 8ca0a36528..d6b3c9a400 100644 --- a/src/calibre/test_build.py +++ b/src/calibre/test_build.py @@ -37,14 +37,6 @@ def test_freetype(): test() print ('FreeType OK!') -def test_fontconfig(): - from calibre.utils.fonts import fontconfig - families = fontconfig.find_font_families() - num = len(families) - if num < 10: - raise RuntimeError('Fontconfig found only %d font families'%num) - print ('Fontconfig OK! (%d families)'%num) - def test_winutil(): from calibre.devices.scanner import win_pnp_drives matches = win_pnp_drives.scanner() @@ -123,7 +115,6 @@ def test(): test_plugins() test_lxml() test_freetype() - test_fontconfig() test_sqlite() test_qt() test_imaging() diff --git a/src/calibre/utils/fonts/__init__.py b/src/calibre/utils/fonts/__init__.py index f3fee56033..3af92bd6a0 100644 --- a/src/calibre/utils/fonts/__init__.py +++ b/src/calibre/utils/fonts/__init__.py @@ -6,120 +6,3 @@ __license__ = 'GPL v3' __copyright__ = '2009, Kovid Goyal ' __docformat__ = 'restructuredtext en' -from calibre.constants import iswindows, isosx - -class Fonts(object): - - def __init__(self): - if iswindows: - from calibre.utils.fonts.win_fonts import load_winfonts - self.backend = load_winfonts() - else: - from calibre.utils.fonts.fc import fontconfig - self.backend = fontconfig - - def find_font_families(self, allowed_extensions={'ttf', 'otf'}): - if iswindows: - return self.backend.font_families() - return self.backend.find_font_families(allowed_extensions=allowed_extensions) - - def find_font_families_no_delay(self, allowed_extensions={'ttf', 'otf'}): - if isosx: - if self.backend.is_scanning(): - return False, [] - return True, self.find_font_families(allowed_extensions=allowed_extensions) - - def files_for_family(self, family, normalize=True): - ''' - Find all the variants in the font family `family`. - Returns a dictionary of tuples. Each tuple is of the form (path to font - file, Full font name). - The keys of the dictionary depend on `normalize`. If `normalize` is `False`, - they are a tuple (slant, weight) otherwise they are strings from the set - `('normal', 'bold', 'italic', 'bi', 'light', 'li')` - ''' - if iswindows: - from calibre.ptempfile import PersistentTemporaryFile - fonts = self.backend.fonts_for_family(family, normalize=normalize) - ans = {} - for ft, val in fonts.iteritems(): - ext, name, data = val - pt = PersistentTemporaryFile('.'+ext) - pt.write(data) - pt.close() - ans[ft] = (pt.name, name) - return ans - return self.backend.files_for_family(family, normalize=normalize) - - def fonts_for_family(self, family, normalize=True): - ''' - Just like files for family, except that it returns 3-tuples of the form - (extension, full name, font data). - ''' - if iswindows: - return self.backend.fonts_for_family(family, normalize=normalize) - files = self.backend.files_for_family(family, normalize=normalize) - ans = {} - for ft, val in files.iteritems(): - f, name = val - ext = f.rpartition('.')[-1].lower() - ans[ft] = (ext, name, open(f, 'rb').read()) - return ans - - def find_font_for_text(self, text, allowed_families={'serif', 'sans-serif'}, - preferred_families=('serif', 'sans-serif', 'monospace', 'cursive', 'fantasy')): - ''' - Find a font on the system capable of rendering the given text. - - Returns a font family (as given by fonts_for_family()) that has a - "normal" font and that can render the supplied text. If no such font - exists, returns None. - - :return: (family name, faces) or None, None - ''' - from calibre.utils.fonts.free_type import FreeType, get_printable_characters, FreeTypeError - from calibre.utils.fonts.utils import panose_to_css_generic_family, get_font_characteristics - ft = FreeType() - found = {} - if not isinstance(text, unicode): - raise TypeError(u'%r is not unicode'%text) - text = get_printable_characters(text) - - def filter_faces(faces): - ans = {} - for k, v in faces.iteritems(): - try: - font = ft.load_font(v[2]) - except FreeTypeError: - continue - if font.supports_text(text, has_non_printable_chars=False): - ans[k] = v - return ans - - for family in sorted(self.find_font_families()): - faces = filter_faces(self.fonts_for_family(family)) - if 'normal' not in faces: - continue - panose = get_font_characteristics(faces['normal'][2])[5] - generic_family = panose_to_css_generic_family(panose) - if generic_family in allowed_families or generic_family == preferred_families[0]: - return (family, faces) - elif generic_family not in found: - found[generic_family] = (family, faces) - - for f in preferred_families: - if f in found: - return found[f] - return None, None - -fontconfig = Fonts() - -def test(): - import os - print(fontconfig.find_font_families()) - m = 'Liberation Serif' - for ft, val in fontconfig.files_for_family(m).iteritems(): - print val[0], ft, val[1], os.path.getsize(val[0]) - -if __name__ == '__main__': - test() diff --git a/src/calibre/utils/fonts/free_type.py b/src/calibre/utils/fonts/free_type.py index a2e8eca213..6be782dc79 100644 --- a/src/calibre/utils/fonts/free_type.py +++ b/src/calibre/utils/fonts/free_type.py @@ -83,11 +83,11 @@ def test(): raise RuntimeError('Incorrectly claiming that text is supported') def test_find_font(): - from calibre.utils.fonts import fontconfig + from calibre.utils.fonts.scanner import font_scanner abcd = '诶比西迪' - family = fontconfig.find_font_for_text(abcd)[0] + family = font_scanner.find_font_for_text(abcd)[0] print ('Family for Chinese text:', family) - family = fontconfig.find_font_for_text(abcd)[0] + family = font_scanner.find_font_for_text(abcd)[0] abcd = 'لوحة المفاتيح العربية' print ('Family for Arabic text:', family) diff --git a/src/calibre/utils/fonts/metadata.py b/src/calibre/utils/fonts/metadata.py new file mode 100644 index 0000000000..4907678c21 --- /dev/null +++ b/src/calibre/utils/fonts/metadata.py @@ -0,0 +1,114 @@ +#!/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 ' +__docformat__ = 'restructuredtext en' + +from io import BytesIO +from struct import calcsize, unpack, unpack_from +from collections import namedtuple + +from calibre.utils.fonts.utils import get_font_names2, get_font_characteristics + +class UnsupportedFont(ValueError): + pass + +FontCharacteristics = namedtuple('FontCharacteristics', + 'weight, is_italic, is_bold, is_regular, fs_type, panose, width, is_oblique, is_wws, os2_version') +FontNames = namedtuple('FontNames', + 'family_name, subfamily_name, full_name, preferred_family_name, preferred_subfamily_name, wws_family_name, wws_subfamily_name') + +class FontMetadata(object): + + def __init__(self, bytes_or_stream): + if not hasattr(bytes_or_stream, 'read'): + bytes_or_stream = BytesIO(bytes_or_stream) + f = bytes_or_stream + f.seek(0) + header = f.read(4) + if header not in {b'\x00\x01\x00\x00', b'OTTO'}: + raise UnsupportedFont('Not a supported sfnt variant') + + self.is_otf = header == b'OTTO' + self.read_table_metadata(f) + self.read_names(f) + self.read_characteristics(f) + + f.seek(0) + self.font_family = (self.names.wws_family_name or + self.names.preferred_family_name or self.names.family_name) + wt = self.characteristics.weight + if wt == 400: + wt = 'normal' + elif wt == 700: + wt = 'bold' + else: + wt = type(u'')(wt) + self.font_weight = wt + + self.font_stretch = ('ultra-condensed', 'extra-condensed', + 'condensed', 'semi-condensed', 'normal', 'semi-expanded', + 'expanded', 'extra-expanded', 'ultra-expanded')[ + self.characteristics.width-1] + if self.characteristics.is_oblique: + self.font_style = 'oblique' + elif self.characteristics.is_italic: + self.font_style = 'italic' + else: + self.font_style = 'normal' + + def read_table_metadata(self, f): + f.seek(4) + num_tables = unpack(b'>H', f.read(2))[0] + # Start of table record entries + f.seek(4 + 4*2) + table_record = b'>4s3L' + sz = calcsize(table_record) + self.tables = {} + block = f.read(sz * num_tables) + for i in xrange(num_tables): + table_tag, table_checksum, table_offset, table_length = \ + unpack_from(table_record, block, i*sz) + self.tables[table_tag.lower()] = (table_offset, table_length, + table_checksum) + + def read_names(self, f): + if b'name' not in self.tables: + raise UnsupportedFont('This font has no name table') + toff, tlen = self.tables[b'name'][:2] + f.seek(toff) + table = f.read(tlen) + if len(table) != tlen: + raise UnsupportedFont('This font has a name table of incorrect length') + vals = get_font_names2(table, raw_is_table=True) + self.names = FontNames(*vals) + + def read_characteristics(self, f): + if b'os/2' not in self.tables: + raise UnsupportedFont('This font has no OS/2 table') + toff, tlen = self.tables[b'os/2'][:2] + f.seek(toff) + table = f.read(tlen) + if len(table) != tlen: + raise UnsupportedFont('This font has an OS/2 table of incorrect length') + vals = get_font_characteristics(table, raw_is_table=True) + self.characteristics = FontCharacteristics(*vals) + + def to_dict(self): + ans = { + 'is_otf':self.is_otf, + 'font-family':self.font_family, + 'font-weight':self.font_weight, + 'font-style':self.font_style, + 'font-stretch':self.font_stretch + } + for f in self.names._fields: + ans[f] = getattr(self.names, f) + for f in self.characteristics._fields: + ans[f] = getattr(self.characteristics, f) + return ans + + diff --git a/src/calibre/utils/fonts/scanner.py b/src/calibre/utils/fonts/scanner.py new file mode 100644 index 0000000000..b26525e690 --- /dev/null +++ b/src/calibre/utils/fonts/scanner.py @@ -0,0 +1,294 @@ +#!/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 ' +__docformat__ = 'restructuredtext en' + +import os +from collections import defaultdict +from threading import Thread + +from calibre import walk, prints, as_unicode +from calibre.constants import config_dir, iswindows, isosx, plugins, DEBUG +from calibre.utils.fonts.metadata import FontMetadata +from calibre.utils.fonts.utils import panose_to_css_generic_family +from calibre.utils.icu import sort_key + +class NoFonts(ValueError): + pass + +def font_dirs(): + if iswindows: + winutil, err = plugins['winutil'] + if err: + raise RuntimeError('Failed to load winutil: %s'%err) + return winutil.special_folder_path(winutil.CSIDL_FONTS) + if isosx: + return [ + '/Library/Fonts', + '/System/Library/Fonts', + '/usr/share/fonts', + '/var/root/Library/Fonts', + os.path.expanduser('~/.fonts'), + os.path.expanduser('~/Library/Fonts'), + ] + return [ + '/opt/share/fonts', + '/usr/share/fonts', + '/usr/local/share/fonts', + os.path.expanduser('~/.fonts') + ] + +class Scanner(Thread): + + CACHE_VERSION = 1 + + def __init__(self, folders=[], allowed_extensions={'ttf', 'otf'}): + Thread.__init__(self) + self.folders = folders + font_dirs() + [os.path.join(config_dir, 'fonts'), + P('fonts/liberation')] + self.folders = [os.path.normcase(os.path.abspath(f)) for f in + self.folders] + self.font_families = () + self.allowed_extensions = allowed_extensions + + def find_font_families(self): + self.join() + return self.font_families + + def fonts_for_family(self, family): + ''' + Return a list of the faces belonging to the specified family. The first + face is the "Regular" face of family. Each face is a dictionary with + many keys, the most important of which are: path, font-family, + font-weight, font-style, font-stretch. The font-* properties follow the + CSS 3 Fonts specification. + ''' + self.join() + try: + return self.font_family_map[icu_lower(family)] + except KeyError: + raise NoFonts('No fonts found for the family: %r'%family) + + def legacy_fonts_for_family(self, family): + ''' + Return a simple set of regular, bold, italic and bold-italic faces for + the specified family. Returns a dictionary with each element being a + 2-tuple of (path to font, full font name) and the keys being: normal, + bold, italic, bi. + ''' + ans = {} + try: + faces = self.fonts_for_family(family) + except NoFonts: + return ans + for i, face in enumerate(faces): + if i == 0: + key = 'normal' + elif face['font-style'] in {'italic', 'oblique'}: + key = 'bi' if face['font-weight'] == 'bold' else 'italic' + elif face['font-weight'] == 'bold': + key = 'bold' + else: + continue + ans[key] = (face['path'], face['full_name']) + return ans + + def get_font_data(self, font_or_path): + path = font_or_path + if isinstance(font_or_path, dict): + path = font_or_path['path'] + with lopen(path, 'rb') as f: + return f.read() + + def find_font_for_text(self, text, allowed_families={'serif', 'sans-serif'}, + preferred_families=('serif', 'sans-serif', 'monospace', 'cursive', 'fantasy')): + ''' + Find a font on the system capable of rendering the given text. + + Returns a font family (as given by fonts_for_family()) that has a + "normal" font and that can render the supplied text. If no such font + exists, returns None. + + :return: (family name, faces) or None, None + ''' + from calibre.utils.fonts.free_type import FreeType, get_printable_characters + ft = FreeType() + found = {} + if not isinstance(text, unicode): + raise TypeError(u'%r is not unicode'%text) + text = get_printable_characters(text) + + def filter_faces(font): + try: + ftface = ft.load_font(self.get_font_data(font)) + return ftface.supports_text(text, has_non_printable_chars=False) + except: + pass + return False + + for family in self.find_font_families(): + faces = filter(filter_faces, self.fonts_for_family(family)) + if not faces: continue + generic_family = panose_to_css_generic_family(faces[0]['panose']) + if generic_family in allowed_families or generic_family == preferred_families[0]: + return (family, faces) + elif generic_family not in found: + found[generic_family] = (family, faces) + + for f in preferred_families: + if f in found: + return found[f] + return None, None + + def reload_cache(self): + if not hasattr(self, 'cache'): + from calibre.utils.config import JSONConfig + self.cache = JSONConfig('fonts/scanner_cache') + self.cache.refresh() + if self.cache.get('version', None) != self.CACHE_VERSION: + self.cache.clear() + self.cached_fonts = self.cache.get('fonts', {}) + + def run(self): + self.do_scan() + + def do_scan(self): + self.reload_cache() + num = 0 + for folder in self.folders: + if not os.path.isdir(folder): + continue + try: + files = tuple(walk(folder)) + except EnvironmentError as e: + if DEBUG: + prints('Failed to walk font folder:', folder, + as_unicode(e)) + continue + for candidate in files: + if (candidate.rpartition('.')[-1].lower() not in self.allowed_extensions + or not os.path.isfile(candidate)): + continue + candidate = os.path.normcase(os.path.abspath(candidate)) + try: + s = os.stat(candidate) + except EnvironmentError: + continue + fileid = '{0}||{1}:{2}'.format(candidate, s.st_size, s.st_mtime) + if fileid in self.cached_fonts: + continue + try: + self.read_font_metadata(candidate, fileid) + except Exception as e: + if DEBUG: + prints('Failed to read metadata from font file:', + candidate, as_unicode(e)) + continue + num += 1 + if num >= 10: + num = 0 + self.write_cache() + if num > 0: + self.write_cache() + self.build_families() + + def font_priority(self, font): + ''' + Try to ensure that the "Regular" face is the first font for a given + family. + ''' + style_normal = font['font-style'] == 'normal' + width_normal = font['font-stretch'] == 'normal' + weight_normal = font['font-weight'] == 'normal' + num_normal = sum(filter(None, (style_normal, width_normal, + weight_normal))) + subfamily_name = (font['wws_subfamily_name'] or + font['preferred_subfamily_name'] or font['subfamily_name']) + if num_normal == 3 and subfamily_name == 'Regular': + return 0 + if num_normal == 3: + return 1 + if subfamily_name == 'Regular': + return 2 + return 3 + (3 - num_normal) + + def build_families(self): + families = defaultdict(list) + for f in self.cached_fonts.itervalues(): + lf = icu_lower(f['font-family'] or '') + if lf: + families[lf].append(f) + + for fonts in families.itervalues(): + # Look for duplicate font files and choose the copy that is from a + # more significant font directory (prefer user directories over + # system directories). + fmap = {} + remove = [] + for f in fonts: + fingerprint = (icu_lower(f['font-family']), f['font-weight'], + f['font-stretch'], f['font-style']) + if fingerprint in fmap: + opath = fmap[fingerprint]['path'] + npath = f['path'] + if self.path_significance(npath) >= self.path_significance(opath): + remove.append(fmap[fingerprint]) + fmap[fingerprint] = f + else: + remove.append(f) + else: + fmap[fingerprint] = f + for font in remove: + fonts.remove(font) + fonts.sort(key=self.font_priority) + + self.font_family_map = dict.copy(families) + self.font_families = tuple(sorted((f[0]['font-family'] for f in + self.font_family_map.itervalues()), key=sort_key)) + + def path_significance(self, path): + path = os.path.normcase(os.path.abspath(path)) + for i, q in enumerate(self.folders): + if path.startswith(q): + return i + return -1 + + def write_cache(self): + with self.cache: + self.cache['version'] = self.CACHE_VERSION + self.cache['fonts'] = self.cached_fonts + + def read_font_metadata(self, path, fileid): + with lopen(path, 'rb') as f: + fm = FontMetadata(f) + data = fm.to_dict() + data['path'] = path + self.cached_fonts[fileid] = data + + def dump_fonts(self): + self.join() + for family in self.font_families: + prints(family) + for font in self.fonts_for_family(family): + prints('\t%s: %s'%(font['full_name'], font['path'])) + prints(end='\t') + for key in ('font-stretch', 'font-weight', 'font-style'): + prints('%s: %s'%(key, font[key]), end=' ') + prints() + prints('\tSub-family:', font['wws_subfamily_name'] or + font['preferred_subfamily_name'] or + font['subfamily_name']) + prints() + prints() + +font_scanner = Scanner() +font_scanner.start() + +if __name__ == '__main__': + font_scanner.dump_fonts() + + diff --git a/src/calibre/utils/fonts/utils.py b/src/calibre/utils/fonts/utils.py index 4fcaa20c44..29b39bbefd 100644 --- a/src/calibre/utils/fonts/utils.py +++ b/src/calibre/utils/fonts/utils.py @@ -36,15 +36,19 @@ def get_table(raw, name): return table, table_index, table_offset, table_checksum return None, None, None, None -def get_font_characteristics(raw): +def get_font_characteristics(raw, raw_is_table=False): ''' - Return (weight, is_italic, is_bold, is_regular, fs_type, panose). These + Return (weight, is_italic, is_bold, is_regular, fs_type, panose, width, + is_oblique, is_wws). These values are taken from the OS/2 table of the font. See http://www.microsoft.com/typography/otspec/os2.htm for details ''' - os2_table = get_table(raw, 'os/2')[0] - if os2_table is None: - raise UnsupportedFont('Not a supported font, has no OS/2 table') + if raw_is_table: + os2_table = raw + else: + os2_table = get_table(raw, 'os/2')[0] + if os2_table is None: + raise UnsupportedFont('Not a supported font, has no OS/2 table') common_fields = b'>Hh3H11h' (version, char_width, weight, width, fs_type, subscript_x_size, @@ -65,10 +69,12 @@ def get_font_characteristics(raw): offset += 4 selection, = struct.unpack_from(b'>H', os2_table, offset) - is_italic = (selection & 0b1) != 0 - is_bold = (selection & 0b100000) != 0 - is_regular = (selection & 0b1000000) != 0 - return weight, is_italic, is_bold, is_regular, fs_type, panose + is_italic = (selection & (1 << 0)) != 0 + is_bold = (selection & (1 << 5)) != 0 + is_regular = (selection & (1 << 6)) != 0 + is_wws = (selection & (1 << 8)) != 0 + is_oblique = (selection & (1 << 9)) != 0 + return weight, is_italic, is_bold, is_regular, fs_type, panose, width, is_oblique, is_wws, version def panose_to_css_generic_family(panose): proportion = panose[3] @@ -142,10 +148,13 @@ def decode_name_record(recs): return None -def get_font_names(raw): - table = get_table(raw, 'name')[0] - if table is None: - raise UnsupportedFont('Not a supported font, has no name table') +def _get_font_names(raw, raw_is_table=False): + if raw_is_table: + table = raw + else: + table = get_table(raw, 'name')[0] + if table is None: + raise UnsupportedFont('Not a supported font, has no name table') table_type, count, string_offset = struct.unpack_from(b'>3H', table) records = defaultdict(list) @@ -161,12 +170,32 @@ def get_font_names(raw): records[name_id].append((platform_id, encoding_id, language_id, src)) + return records + +def get_font_names(raw, raw_is_table=False): + records = _get_font_names(raw, raw_is_table) family_name = decode_name_record(records[1]) subfamily_name = decode_name_record(records[2]) full_name = decode_name_record(records[4]) return family_name, subfamily_name, full_name +def get_font_names2(raw, raw_is_table=False): + records = _get_font_names(raw, raw_is_table) + + family_name = decode_name_record(records[1]) + subfamily_name = decode_name_record(records[2]) + full_name = decode_name_record(records[4]) + + preferred_family_name = decode_name_record(records[16]) + preferred_subfamily_name = decode_name_record(records[17]) + + wws_family_name = decode_name_record(records[21]) + wws_subfamily_name = decode_name_record(records[22]) + + return (family_name, subfamily_name, full_name, preferred_family_name, + preferred_subfamily_name, wws_family_name, wws_subfamily_name) + def checksum_of_block(raw): extra = 4 - len(raw)%4 raw += b'\0'*extra @@ -249,11 +278,11 @@ def get_font_for_text(text, candidate_font_data=None): except FreeTypeError: ok = True if not ok: - from calibre.utils.fonts import fontconfig - family, faces = fontconfig.find_font_for_text(text) - if family is not None: - f = faces.get('bold', faces['normal']) - candidate_font_data = f[2] + from calibre.utils.fonts.scanner import font_scanner + family, faces = font_scanner.find_font_for_text(text) + if faces: + with lopen(faces[0]['path'], 'rb') as f: + candidate_font_data = f.read() return candidate_font_data def test(): From 9c62f0a21c51587f7dae3acf50e8f653a5381802 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 28 Oct 2012 17:37:02 +0530 Subject: [PATCH 020/107] Remove the unused fontconfig bindings --- setup/build_environment.py | 13 - setup/extensions.py | 12 +- setup/installer/osx/app/main.py | 27 +- setup/installer/windows/freeze.py | 2 - setup/installer/windows/notes.rst | 21 -- src/calibre/constants.py | 1 - src/calibre/utils/fonts/fc.py | 233 ----------------- src/calibre/utils/fonts/fontconfig.c | 374 --------------------------- 8 files changed, 5 insertions(+), 678 deletions(-) delete mode 100644 src/calibre/utils/fonts/fc.py delete mode 100644 src/calibre/utils/fonts/fontconfig.c diff --git a/setup/build_environment.py b/setup/build_environment.py index 6601578345..492eca0697 100644 --- a/setup/build_environment.py +++ b/setup/build_environment.py @@ -87,8 +87,6 @@ ft_libs = [] ft_inc_dirs = [] jpg_libs = [] jpg_lib_dirs = [] -fc_inc = '/usr/include/fontconfig' -fc_lib = '/usr/lib' podofo_inc = '/usr/include/podofo' podofo_lib = '/usr/lib' chmlib_inc_dirs = chmlib_lib_dirs = [] @@ -107,8 +105,6 @@ if iswindows: 'source', 'i18n')] icu_lib_dirs = [os.path.join(ICU, 'source', 'lib')] sqlite_inc_dirs = [sw_inc_dir] - fc_inc = os.path.join(sw_inc_dir, 'fontconfig') - fc_lib = sw_lib_dir chmlib_inc_dirs = consolidate('CHMLIB_INC_DIR', os.path.join(prefix, 'build', 'chmlib-0.40', 'src')) chmlib_lib_dirs = consolidate('CHMLIB_LIB_DIR', os.path.join(prefix, @@ -131,8 +127,6 @@ if iswindows: podofo_inc = os.path.join(sw_inc_dir, 'podofo') podofo_lib = sw_lib_dir elif isosx: - fc_inc = '/sw/include/fontconfig' - fc_lib = '/sw/lib' podofo_inc = '/sw/podofo' podofo_lib = '/sw/lib' magick_inc_dirs = consolidate('MAGICK_INC', @@ -166,13 +160,6 @@ else: ft_libs = pkgconfig_libs('freetype2', '', '') -fc_inc = os.environ.get('FC_INC_DIR', fc_inc) -fc_lib = os.environ.get('FC_LIB_DIR', fc_lib) -fc_error = None if os.path.exists(os.path.join(fc_inc, 'fontconfig.h')) else \ - ('fontconfig header files not found on your system. ' - 'Try setting the FC_INC_DIR and FC_LIB_DIR environment ' - 'variables.') - magick_error = None if not magick_inc_dirs or not os.path.exists(os.path.join(magick_inc_dirs[0], 'wand')): diff --git a/setup/extensions.py b/setup/extensions.py index 989a9ddbe9..cfbb148873 100644 --- a/setup/extensions.py +++ b/setup/extensions.py @@ -13,7 +13,7 @@ from multiprocessing import cpu_count from PyQt4.pyqtconfig import QtGuiModuleMakefile from setup import Command, islinux, isbsd, isosx, SRC, iswindows -from setup.build_environment import (fc_inc, fc_lib, chmlib_inc_dirs, fc_error, +from setup.build_environment import (chmlib_inc_dirs, podofo_inc, podofo_lib, podofo_error, pyqt, OSX_SDK, NMAKE, QMAKE, msvc, MT, win_inc, win_lib, win_ddk, magick_inc_dirs, magick_lib_dirs, magick_libs, chmlib_lib_dirs, sqlite_inc_dirs, icu_inc_dirs, @@ -122,13 +122,6 @@ extensions = [ libraries=ft_libs, lib_dirs=ft_lib_dirs), - Extension('fontconfig', - ['calibre/utils/fonts/fontconfig.c'], - inc_dirs = [fc_inc], - libraries=['fontconfig'], - lib_dirs=[fc_lib], - error=fc_error), - Extension('woff', ['calibre/utils/fonts/woff/main.c', 'calibre/utils/fonts/woff/woff.c'], @@ -305,9 +298,6 @@ class Build(Command): CFLAGS - Extra compiler flags LDFLAGS - Extra linker flags - FC_INC_DIR - fontconfig header files - FC_LIB_DIR - fontconfig library - POPPLER_INC_DIR - poppler header files POPPLER_LIB_DIR - poppler-qt4 library diff --git a/setup/installer/osx/app/main.py b/setup/installer/osx/app/main.py index 14df94f4ba..a101c574b7 100644 --- a/setup/installer/osx/app/main.py +++ b/setup/installer/osx/app/main.py @@ -15,8 +15,6 @@ from setup import __version__ as VERSION, __appname__ as APPNAME, basenames, \ LICENSE = open('LICENSE', 'rb').read() MAGICK_HOME='@executable_path/../Frameworks/ImageMagick' ENV = dict( - FC_CONFIG_DIR='@executable_path/../Resources/fonts', - FC_CONFIG_FILE='@executable_path/../Resources/fonts/fonts.conf', MAGICK_CONFIGURE_PATH=MAGICK_HOME+'/config', MAGICK_CODER_MODULE_PATH=MAGICK_HOME+'/modules-Q16/coders', MAGICK_CODER_FILTER_PATH=MAGICK_HOME+'/modules-Q16/filter', @@ -180,7 +178,7 @@ class Py2App(object): self.add_poppler() self.add_libjpeg() self.add_libpng() - self.add_fontconfig() + self.add_freetype() self.add_imagemagick() self.add_misc_libraries() @@ -397,28 +395,11 @@ class Py2App(object): @flush - def add_fontconfig(self): - info('\nAdding fontconfig') - for x in ('fontconfig.1', 'freetype.6', 'expat.1'): + def add_freetype(self): + info('\nAdding freetype') + for x in ('freetype.6', 'expat.1'): src = os.path.join(SW, 'lib', 'lib'+x+'.dylib') self.install_dylib(src) - dst = os.path.join(self.resources_dir, 'fonts') - if os.path.exists(dst): - shutil.rmtree(dst) - src = os.path.join(SW, 'etc', 'fonts') - shutil.copytree(src, dst, symlinks=False) - fc = os.path.join(dst, 'fonts.conf') - raw = open(fc, 'rb').read() - raw = raw.replace('

/usr/share/fonts', '''\ - /Library/Fonts - /Network/Library/Fonts - /System/Library/Fonts - /usr/X11R6/lib/X11/fonts - /usr/share/fonts - /var/root/Library/Fonts - /usr/share/fonts - ''') - open(fc, 'wb').write(raw) @flush def add_imagemagick(self): diff --git a/setup/installer/windows/freeze.py b/setup/installer/windows/freeze.py index 12443b4898..e578d64607 100644 --- a/setup/installer/windows/freeze.py +++ b/setup/installer/windows/freeze.py @@ -281,8 +281,6 @@ class Win32Freeze(Command, WixMixIn): for x in ('zlib1.dll', 'libxml2.dll'): shutil.copy2(self.j(bindir, x+'.manifest'), self.dll_dir) - shutil.copytree(os.path.join(SW, 'etc', 'fonts'), - os.path.join(self.base, 'fontconfig')) # Copy ImageMagick for pat in ('*.dll', '*.xml'): for f in glob.glob(self.j(IMAGEMAGICK, pat)): diff --git a/setup/installer/windows/notes.rst b/setup/installer/windows/notes.rst index 9502135f6e..fe0d8380e0 100644 --- a/setup/installer/windows/notes.rst +++ b/setup/installer/windows/notes.rst @@ -276,27 +276,6 @@ cp build/kdewin32-msvc-0.3.9/build/bin/Release/*.exp lib/ cp -r build/kdewin32-msvc-0.3.9/include/msvc/ include/ cp build/kdewin32-msvc-0.3.9/include/*.h include/ -fontconfig ---------------- - -Get it from http://www.winkde.org/pub/kde/ports/win32/repository/win32libs/ -mkdir build -Remove subdirectory test from the bottom of CMakeLists.txt -run cmake - -Set build type to release and project config to dll -Right click on the fontconfig project and select properties. Add sw/include/msvc to the include paths -Build only fontconfig - -cp build/fontconfig-msvc-2.4.2-3/build/src/Release/*.dll bin -cp build/fontconfig-msvc-2.4.2-3/build/src/Release/*.lib lib -cp build/fontconfig-msvc-2.4.2-3/build/src/Release/*.exp lib -cp -r build/fontconfig-msvc-2.4.2-3/fontconfig/ include/ - -Also install the etc files from the font-config-bin archive from kde win32libs -It contains correct fonts.conf etc. - - poppler ------------- diff --git a/src/calibre/constants.py b/src/calibre/constants.py index f098b77f9a..3c89db2d1a 100644 --- a/src/calibre/constants.py +++ b/src/calibre/constants.py @@ -83,7 +83,6 @@ class Plugins(collections.Mapping): 'magick', 'podofo', 'cPalmdoc', - 'fontconfig', 'progress_indicator', 'chmlib', 'chm_extra', diff --git a/src/calibre/utils/fonts/fc.py b/src/calibre/utils/fonts/fc.py deleted file mode 100644 index 3e6ae844bc..0000000000 --- a/src/calibre/utils/fonts/fc.py +++ /dev/null @@ -1,233 +0,0 @@ -#!/usr/bin/env python -# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai -from __future__ import with_statement - -__license__ = 'GPL v3' -__copyright__ = '2009, Kovid Goyal ' -__docformat__ = 'restructuredtext en' - -import os, sys - -from calibre.constants import plugins, islinux, isbsd, isosx, preferred_encoding - -_fc, _fc_err = plugins['fontconfig'] - -if _fc is None: - raise RuntimeError('Failed to load fontconfig with error:'+_fc_err) - -if islinux or isbsd: - Thread = object -else: - from threading import Thread - -class FontConfig(Thread): - - def __init__(self): - Thread.__init__(self) - self.daemon = True - self.failed = False - self.css_weight_map = { - _fc.FC_WEIGHT_THIN : u'100', - _fc.FC_WEIGHT_EXTRALIGHT : u'200', _fc.FC_WEIGHT_ULTRALIGHT : u'200', - _fc.FC_WEIGHT_LIGHT : u'300', - _fc.FC_WEIGHT_BOOK : u'normal', _fc.FC_WEIGHT_BOOK : u'normal', _fc.FC_WEIGHT_REGULAR : u'normal', - _fc.FC_WEIGHT_MEDIUM : u'500', - _fc.FC_WEIGHT_DEMIBOLD : u'600', _fc.FC_WEIGHT_SEMIBOLD : u'600', - _fc.FC_WEIGHT_BOLD : u'bold', - _fc.FC_WEIGHT_EXTRABOLD : u'800', _fc.FC_WEIGHT_ULTRABOLD : u'800', - _fc.FC_WEIGHT_HEAVY : u'900', _fc.FC_WEIGHT_BLACK : u'900', _fc.FC_WEIGHT_EXTRABLACK : u'900', _fc.FC_WEIGHT_ULTRABLACK : u'900' - } - self.css_slant_map = { - _fc.FC_SLANT_ROMAN : u'normal', - _fc.FC_SLANT_ITALIC : u'italic', - _fc.FC_SLANT_OBLIQUE : u'oblique' - } - self.css_stretch_map = { - _fc.FC_WIDTH_ULTRACONDENSED: u'ultra-condensed', - _fc.FC_WIDTH_EXTRACONDENSED : u'extra-condensed', - _fc.FC_WIDTH_CONDENSED: u'condensed', - _fc.FC_WIDTH_SEMICONDENSED: u'semi-condensed', - _fc.FC_WIDTH_NORMAL: u'normal', - _fc.FC_WIDTH_SEMIEXPANDED: u'semi-expanded', - _fc.FC_WIDTH_EXPANDED: u'expanded', - _fc.FC_WIDTH_EXTRAEXPANDED: u'extra-expanded', - _fc.FC_WIDTH_ULTRAEXPANDED: u'ultra-expanded', - } - - def run(self): - config = None - if getattr(sys, 'frameworks_dir', False): - config_dir = os.path.join(os.path.dirname( - getattr(sys, 'frameworks_dir')), 'Resources', 'fonts') - if isinstance(config_dir, unicode): - config_dir = config_dir.encode(sys.getfilesystemencoding()) - config = os.path.join(config_dir, 'fonts.conf') - try: - _fc.initialize(config) - except: - import traceback - traceback.print_exc() - self.failed = True - if not self.failed and hasattr(_fc, 'add_font_dir'): - _fc.add_font_dir(P('fonts/liberation')) - - def is_scanning(self): - if isosx: - return self.is_alive() - return False - - def wait(self): - if not (islinux or isbsd): - self.join() - if self.failed: - raise RuntimeError('Failed to initialize fontconfig') - - def find_font_families(self, allowed_extensions={'ttf', 'otf'}): - ''' - Return an alphabetically sorted list of font families available on the system. - - `allowed_extensions`: A list of allowed extensions for font file types. Defaults to - `['ttf', 'otf']`. If it is empty, it is ignored. - ''' - self.wait() - ans = _fc.find_font_families([bytes('.'+x) for x in allowed_extensions]) - ans = sorted(set(ans), cmp=lambda x,y:cmp(x.lower(), y.lower())) - ans2 = [] - for x in ans: - try: - ans2.append(x.decode('utf-8')) - except UnicodeDecodeError: - continue - return ans2 - - def files_for_family(self, family, normalize=True): - ''' - Find all the variants in the font family `family`. - Returns a dictionary of tuples. Each tuple is of the form (path to font - file, Full font name). - The keys of the dictionary depend on `normalize`. If `normalize` is `False`, - they are a tuple (slant, weight) otherwise they are strings from the set - `('normal', 'bold', 'italic', 'bi', 'light', 'li')` - ''' - self.wait() - if not isinstance(family, unicode): - family = family.decode(preferred_encoding) - fonts = {} - for entry in _fc.files_for_family(family): - slant, weight = entry['slant'], entry['weight'] - fullname, path = entry['fullname'], entry['path'] - nfamily = entry['family'] - style = (slant, weight) - if normalize: - italic = slant > 0 - normal = weight == 80 - bold = weight > 80 - if italic: - style = 'italic' if normal else 'bi' if bold else 'li' - else: - style = 'normal' if normal else 'bold' if bold else 'light' - try: - fullname, path = fullname.decode('utf-8'), path.decode('utf-8') - nfamily = nfamily.decode('utf-8') - except UnicodeDecodeError: - continue - if style in fonts: - if nfamily.lower().strip() == family.lower().strip() \ - and 'Condensed' not in fullname and 'ExtraLight' not in fullname: - fonts[style] = (path, fullname) - else: - fonts[style] = (path, fullname) - - return fonts - - def faces_for_family(self, family): - ''' - Return all the faces in a font family in a manner suitable for CSS 3. - ''' - self.wait() - if not isinstance(family, unicode): - family = family.decode(preferred_encoding) - seen = set() - for entry in _fc.files_for_family(family): - slant, weight = entry['slant'], entry['weight'] - fullname, path = entry['fullname'], entry['path'] - nfamily, width = entry['family'], entry['width'] - fingerprint = (slant, weight, width, nfamily) - if fingerprint in seen: - # Fontconfig returns the same font multiple times if it is - # present in multiple locations - continue - seen.add(fingerprint) - - try: - nfamily = nfamily.decode('UTF-8') - fullname = fullname.decode('utf-8') - path = path.decode('utf-8') - except UnicodeDecodeError: - continue - - face = { - 'font-weight': self.css_weight_map[weight], - 'font-style': self.css_slant_map[slant], - 'font-stretch': self.css_stretch_map[width], - 'font-family': nfamily, - 'fullname': fullname, 'path':path - } - yield face - - def match(self, name, all=False, verbose=False): - ''' - Find the system font that most closely matches `name`, where `name` is a specification - of the form:: - familyname-::... - - For example, `verdana:weight=bold:slant=italic` - - Returns a list of dictionaries, or a single dictionary. - Each dictionary has the keys: - 'weight', 'slant', 'family', 'file', 'fullname', 'style' - - `all`: If `True` return a sorted list of matching fonts, where the sort - is in order of decreasing closeness of matching. If `False` only the - best match is returned. ''' - self.wait() - if isinstance(name, unicode): - name = name.encode('utf-8') - fonts = [] - for fullname, path, style, family, weight, slant in \ - _fc.match(str(name), bool(all), bool(verbose)): - try: - fullname = fullname.decode('utf-8') - path = path.decode('utf-8') - style = style.decode('utf-8') - family = family.decode('utf-8') - fonts.append({ - 'fullname' : fullname, - 'path' : path, - 'style' : style, - 'family' : family, - 'weight' : weight, - 'slant' : slant - }) - except UnicodeDecodeError: - continue - return fonts if all else (fonts[0] if fonts else None) - -fontconfig = FontConfig() -if islinux or isbsd: - # On X11 Qt also uses fontconfig, so initialization must happen in the - # main thread. In any case on X11 initializing fontconfig should be very - # fast - fontconfig.run() -else: - fontconfig.start() - -def test(): - from pprint import pprint; - pprint(fontconfig.find_font_families()) - pprint(tuple(fontconfig.faces_for_family('liberation serif'))) - m = 'liberation serif' - pprint(fontconfig.match(m+':slant=italic:weight=bold', verbose=True)) - -if __name__ == '__main__': - test() diff --git a/src/calibre/utils/fonts/fontconfig.c b/src/calibre/utils/fonts/fontconfig.c deleted file mode 100644 index b66aba4b08..0000000000 --- a/src/calibre/utils/fonts/fontconfig.c +++ /dev/null @@ -1,374 +0,0 @@ -/* -:mod:`fontconfig` -- Pythonic interface to fontconfig -===================================================== - -.. module:: fontconfig - :platform: All - :synopsis: Pythonic interface to the fontconfig library - -.. moduleauthor:: Kovid Goyal Copyright 2009 - -*/ - -#define PY_SSIZE_T_CLEAN -#include -#include -#include -#include - -static PyObject * -fontconfig_initialize(PyObject *self, PyObject *args) { - FcChar8 *path; - FcBool ok; - FcConfig *config; - PyThreadState *_save; - - if (!PyArg_ParseTuple(args, "z", &path)) - return NULL; - if (path == NULL) { - _save = PyEval_SaveThread(); - ok = FcInit(); - PyEval_RestoreThread(_save); - } else { - config = FcConfigCreate(); - if (config == NULL) return PyErr_NoMemory(); - _save = PyEval_SaveThread(); - ok = FcConfigParseAndLoad(config, path, FcTrue); - if (ok) ok = FcConfigBuildFonts(config); - if (ok) ok = FcConfigSetCurrent(config); - PyEval_RestoreThread(_save); - if (!ok) return PyErr_NoMemory(); - ok = 1; - } - if (ok) Py_RETURN_TRUE; - Py_RETURN_FALSE; -} - -static PyObject* -fontconfig_add_font_dir(PyObject *self, PyObject *args) { - FcChar8 *path; - - if (!PyArg_ParseTuple(args, "s", &path)) return NULL; - - if (FcConfigAppFontAddDir(NULL, path)) - Py_RETURN_TRUE; - Py_RETURN_FALSE; -} - -static void -fontconfig_cleanup_find(FcPattern *p, FcObjectSet *oset, FcFontSet *fs) { - if (p != NULL) FcPatternDestroy(p); - if (oset != NULL) FcObjectSetDestroy(oset); - if (fs != NULL) FcFontSetDestroy(fs); -} - - -static PyObject * -fontconfig_find_font_families(PyObject *self, PyObject *args) { - int i; - size_t flen; - char *ext; - Py_ssize_t l, j, extlen; - FcBool ok; - FcPattern *pat, *temp; - FcObjectSet *oset; - FcFontSet *fs; - FcValue v, w; - PyObject *ans, *exts, *t; - - ans = PyList_New(0); - fs = NULL; oset = NULL; pat = NULL; - - if (ans == NULL) return PyErr_NoMemory(); - - if (!PyArg_ParseTuple(args, "O", &exts)) - return NULL; - - if (!PySequence_Check(exts)) { - PyErr_SetString(PyExc_ValueError, "Must pass sequence of extensions"); - return NULL; - } - l = PySequence_Size(exts); - - - pat = FcPatternCreate(); - if (pat == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - - oset = FcObjectSetCreate(); - if (oset == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - if (!FcObjectSetAdd(oset, FC_FILE)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - if (!FcObjectSetAdd(oset, FC_FAMILY)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - - fs = FcFontList(FcConfigGetCurrent(), pat, oset); - if (fs == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - - for (i = 0; i < fs->nfont; i++) { - temp = fs->fonts[i]; - - if (temp == NULL) continue; - if (FcPatternGet(temp, FC_FILE, 0, &v) != FcResultMatch) continue; - - if (v.type == FcTypeString) { - flen = strlen((char *)v.u.s); - ok = FcFalse; - if (l == 0) ok = FcTrue; - for ( j = 0; j < l && !ok; j++) { - ext = PyBytes_AS_STRING(PySequence_ITEM(exts, j)); - extlen = PyBytes_GET_SIZE(PySequence_ITEM(exts, j)); - ok = flen > extlen && extlen > 0 && - PyOS_strnicmp(ext, ((char *)v.u.s) + (flen - extlen), extlen) == 0; - } - - if (ok) { - if (FcPatternGet(temp, FC_FAMILY, 0, &w) != FcResultMatch) continue; - if (w.type != FcTypeString) continue; - t = PyString_FromString((char *)w.u.s); - if (t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - if (PyList_Append(ans, t) != 0) - { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - } - } - - } - fontconfig_cleanup_find(pat, oset, fs); - Py_INCREF(ans); - return ans; -} - -static PyObject * -fontconfig_files_for_family(PyObject *self, PyObject *args) { - char *family; int i; - FcPattern *pat, *tp; - FcObjectSet *oset; - FcFontSet *fs; - FcValue file, weight, fullname, style, slant, family2, width; - PyObject *ans, *temp; - - if (!PyArg_ParseTuple(args, "es", "UTF-8", &family)) - return NULL; - - ans = PyList_New(0); - if (ans == NULL) return PyErr_NoMemory(); - - fs = NULL; oset = NULL; pat = NULL; - - pat = FcPatternBuild(0, FC_FAMILY, FcTypeString, family, (char *) 0); - if (pat == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - PyMem_Free(family); family = NULL; - - oset = FcObjectSetCreate(); - if (oset == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - if (!FcObjectSetAdd(oset, FC_FILE)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - if (!FcObjectSetAdd(oset, FC_STYLE)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - if (!FcObjectSetAdd(oset, FC_SLANT)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - if (!FcObjectSetAdd(oset, FC_WEIGHT)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - if (!FcObjectSetAdd(oset, FC_WIDTH)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - if (!FcObjectSetAdd(oset, FC_FAMILY)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - if (!FcObjectSetAdd(oset, FC_FULLNAME)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - - fs = FcFontList(FcConfigGetCurrent(), pat, oset); - if (fs == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - - for (i = 0; i < fs->nfont; i++) { - tp = fs->fonts[i]; - - if (tp == NULL) continue; - if (FcPatternGet(tp, FC_FILE, 0, &file) != FcResultMatch) continue; - if (FcPatternGet(tp, FC_STYLE, 0, &style) != FcResultMatch) continue; - if (FcPatternGet(tp, FC_WEIGHT, 0, &weight) != FcResultMatch) continue; - if (FcPatternGet(tp, FC_WIDTH, 0, &width) != FcResultMatch) continue; - if (FcPatternGet(tp, FC_SLANT, 0, &slant) != FcResultMatch) continue; - if (FcPatternGet(tp, FC_FAMILY, 0, &family2) != FcResultMatch) continue; - if (FcPatternGet(tp, FC_FULLNAME, 0, &fullname) != FcResultMatch) continue; - - temp = Py_BuildValue("{s:s, s:s, s:s, s:s, s:l, s:l, s:l}", - "fullname", (char*)fullname.u.s, - "path", (char*)file.u.s, - "style", (char*)style.u.s, - "family", (char*)family2.u.s, - "weight", (long)weight.u.i, - "slant", (long)slant.u.i, - "width", (long)width.u.i - ); - if (temp == NULL) { fontconfig_cleanup_find(pat, oset, fs); return NULL; } - if (PyList_Append(ans, temp) != 0) - { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - } - fontconfig_cleanup_find(pat, oset, fs); - Py_INCREF(ans); - return ans; -} - -static PyObject * -fontconfig_match(PyObject *self, PyObject *args) { - FcChar8 *namespec; int i; - FcPattern *pat, *tp; - FcObjectSet *oset; - FcFontSet *fs, *fs2; - FcValue file, weight, fullname, style, slant, family; - FcResult res; - PyObject *ans, *temp, *t, *all, *verbose; - - if (!PyArg_ParseTuple(args, "sOO", &namespec, &all, &verbose)) - return NULL; - - ans = PyList_New(0); - if (ans == NULL) return PyErr_NoMemory(); - - fs = NULL; oset = NULL; pat = NULL; fs2 = NULL; - - pat = FcNameParse(namespec); - if (pat == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - if (PyObject_IsTrue(verbose)) FcPatternPrint(pat); - - if (!FcConfigSubstitute(FcConfigGetCurrent(), pat, FcMatchPattern)) - { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - FcDefaultSubstitute(pat); - - fs = FcFontSetCreate(); - if (fs == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - if (PyObject_IsTrue(all)) { - fs2 = FcFontSort(FcConfigGetCurrent(), pat, FcTrue, NULL, &res); - if (fs2 == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - - for (i = 0; i < fs2->nfont; i++) { - tp = fs2->fonts[i]; - if (tp == NULL) continue; - tp = FcFontRenderPrepare(FcConfigGetCurrent(), pat, tp); - if (tp == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - if (!FcFontSetAdd(fs, tp)) - { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - } - if (fs2 != NULL) FcFontSetDestroy(fs2); - } else { - tp = FcFontMatch(FcConfigGetCurrent(), pat, &res); - if (tp == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - if (!FcFontSetAdd(fs, tp)) - { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - } - - for (i = 0; i < fs->nfont; i++) { - tp = fs->fonts[i]; - if (tp == NULL) continue; - if (FcPatternGet(tp, FC_FILE, 0, &file) != FcResultMatch) continue; - if (FcPatternGet(tp, FC_STYLE, 0, &style) != FcResultMatch) continue; - if (FcPatternGet(tp, FC_WEIGHT, 0, &weight) != FcResultMatch) continue; - if (FcPatternGet(tp, FC_SLANT, 0, &slant) != FcResultMatch) continue; - if (FcPatternGet(tp, FC_FAMILY, 0, &family) != FcResultMatch) continue; - if (FcPatternGet(tp, "fullname", 0, &fullname) != FcResultMatch) continue; - - temp = PyTuple_New(6); - if(temp == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - t = PyBytes_FromString((char *)fullname.u.s); - if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - PyTuple_SET_ITEM(temp, 0, t); - t = PyBytes_FromString((char *)file.u.s); - if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - PyTuple_SET_ITEM(temp, 1, t); - t = PyBytes_FromString((char *)style.u.s); - if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - PyTuple_SET_ITEM(temp, 2, t); - t = PyBytes_FromString((char *)family.u.s); - if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - PyTuple_SET_ITEM(temp, 3, t); - t = PyInt_FromLong((long)weight.u.i); - if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - PyTuple_SET_ITEM(temp, 4, t); - t = PyInt_FromLong((long)slant.u.i); - if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - PyTuple_SET_ITEM(temp, 5, t); - if (PyList_Append(ans, temp) != 0) - { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } - - } - fontconfig_cleanup_find(pat, oset, fs); - Py_INCREF(ans); - return ans; -} - - - -static -PyMethodDef fontconfig_methods[] = { - {"initialize", fontconfig_initialize, METH_VARARGS, - "initialize(path_to_config_file)\n\n" - "Initialize the library. If path to config file is specified it is used instead of the " - "default configuration. Returns True iff the initialization succeeded." - }, - - {"find_font_families", fontconfig_find_font_families, METH_VARARGS, - "find_font_families(allowed_extensions)\n\n" - "Find all font families on the system for fonts of the specified types. If no " - "types are specified all font families are returned." - }, - - {"files_for_family", fontconfig_files_for_family, METH_VARARGS, - "files_for_family(family, normalize)\n\n" - "Find all the variants in the font family `family`. " - "Returns a list of tuples. Each tuple is of the form " - "(fullname, path, style, family, weight, slant). " - }, - - {"match", fontconfig_match, METH_VARARGS, - "match(namespec,all,verbose)\n\n" - "Find all system fonts that match namespec, in decreasing order " - "of closeness. " - "Returns a list of tuples. Each tuple is of the form " - "(fullname, path, style, family, weight, slant). " - - }, - - {"add_font_dir", fontconfig_add_font_dir, METH_VARARGS, - "add_font_dir(path_to_dir)\n\n" - "Add the fonts in the specified directory to the list of application specific fonts." - }, - - {NULL, NULL, 0, NULL} -}; - - - -PyMODINIT_FUNC -initfontconfig(void) { - PyObject *m; - m = Py_InitModule3( - "fontconfig", fontconfig_methods, - "Find fonts." - ); - if (m == NULL) return; - - PyModule_AddIntMacro(m, FC_WEIGHT_THIN); - PyModule_AddIntMacro(m, FC_WEIGHT_EXTRALIGHT); - PyModule_AddIntMacro(m, FC_WEIGHT_ULTRALIGHT); - PyModule_AddIntMacro(m, FC_WEIGHT_LIGHT); - PyModule_AddIntMacro(m, FC_WEIGHT_BOOK); - PyModule_AddIntMacro(m, FC_WEIGHT_REGULAR); - PyModule_AddIntMacro(m, FC_WEIGHT_NORMAL); - PyModule_AddIntMacro(m, FC_WEIGHT_MEDIUM); - PyModule_AddIntMacro(m, FC_WEIGHT_DEMIBOLD); - PyModule_AddIntMacro(m, FC_WEIGHT_SEMIBOLD); - PyModule_AddIntMacro(m, FC_WEIGHT_BOLD); - PyModule_AddIntMacro(m, FC_WEIGHT_EXTRABOLD); - PyModule_AddIntMacro(m, FC_WEIGHT_ULTRABOLD); - PyModule_AddIntMacro(m, FC_WEIGHT_BLACK); - PyModule_AddIntMacro(m, FC_WEIGHT_HEAVY); - PyModule_AddIntMacro(m, FC_WEIGHT_EXTRABLACK); - PyModule_AddIntMacro(m, FC_WEIGHT_ULTRABLACK); - - PyModule_AddIntMacro(m, FC_SLANT_ROMAN); - PyModule_AddIntMacro(m, FC_SLANT_ITALIC); - PyModule_AddIntMacro(m, FC_SLANT_OBLIQUE); - - PyModule_AddIntMacro(m, FC_WIDTH_ULTRACONDENSED); - PyModule_AddIntMacro(m, FC_WIDTH_EXTRACONDENSED); - PyModule_AddIntMacro(m, FC_WIDTH_CONDENSED); - PyModule_AddIntMacro(m, FC_WIDTH_SEMICONDENSED); - PyModule_AddIntMacro(m, FC_WIDTH_NORMAL); - PyModule_AddIntMacro(m, FC_WIDTH_SEMIEXPANDED); - PyModule_AddIntMacro(m, FC_WIDTH_EXPANDED); - PyModule_AddIntMacro(m, FC_WIDTH_EXTRAEXPANDED); - PyModule_AddIntMacro(m, FC_WIDTH_ULTRAEXPANDED); - -# -} - From 8d34fbcf2abe751e19033d79cdf3044318684734 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 28 Oct 2012 17:45:20 +0530 Subject: [PATCH 021/107] ... --- src/calibre/utils/fonts/scanner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/utils/fonts/scanner.py b/src/calibre/utils/fonts/scanner.py index b26525e690..a4dbd60a5f 100644 --- a/src/calibre/utils/fonts/scanner.py +++ b/src/calibre/utils/fonts/scanner.py @@ -25,7 +25,7 @@ def font_dirs(): winutil, err = plugins['winutil'] if err: raise RuntimeError('Failed to load winutil: %s'%err) - return winutil.special_folder_path(winutil.CSIDL_FONTS) + return [winutil.special_folder_path(winutil.CSIDL_FONTS)] if isosx: return [ '/Library/Fonts', From c4b6ab96b202ce8938037dd4b1c604ab21889e7b Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 28 Oct 2012 17:46:47 +0530 Subject: [PATCH 022/107] ... --- src/calibre/gui2/font_family_chooser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/gui2/font_family_chooser.py b/src/calibre/gui2/font_family_chooser.py index 6c3aa4594a..065ca9f472 100644 --- a/src/calibre/gui2/font_family_chooser.py +++ b/src/calibre/gui2/font_family_chooser.py @@ -121,7 +121,7 @@ class FontFamilyDialog(QDialog): self.setWindowIcon(QIcon(I('font.png'))) from calibre.utils.fonts.scanner import font_scanner try: - self.families = font_scanner.find_font_families() + self.families = list(font_scanner.find_font_families()) except: self.families = [] print ('WARNING: Could not load fonts') From 5b70d13765e62b4f16769161809768b019fe5701 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 28 Oct 2012 18:14:43 +0530 Subject: [PATCH 023/107] ... --- src/calibre/utils/fonts/metadata.py | 7 ++++++- src/calibre/utils/fonts/scanner.py | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/calibre/utils/fonts/metadata.py b/src/calibre/utils/fonts/metadata.py index 4907678c21..b85a65a9d2 100644 --- a/src/calibre/utils/fonts/metadata.py +++ b/src/calibre/utils/fonts/metadata.py @@ -111,4 +111,9 @@ class FontMetadata(object): ans[f] = getattr(self.characteristics, f) return ans - +if __name__ == '__main__': + import sys + with open(sys.argv[-1], 'rb') as f: + fm = FontMetadata(f) + import pprint + pprint.pprint(fm.to_dict()) diff --git a/src/calibre/utils/fonts/scanner.py b/src/calibre/utils/fonts/scanner.py index a4dbd60a5f..c7317ee563 100644 --- a/src/calibre/utils/fonts/scanner.py +++ b/src/calibre/utils/fonts/scanner.py @@ -55,6 +55,7 @@ class Scanner(Thread): self.font_families = () self.allowed_extensions = allowed_extensions + # API {{{ def find_font_families(self): self.join() return self.font_families @@ -143,6 +144,7 @@ class Scanner(Thread): if f in found: return found[f] return None, None + # }}} def reload_cache(self): if not hasattr(self, 'cache'): From 2844f87ba8bf42037cd16510d22b039aab7693b9 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 28 Oct 2012 18:19:46 +0530 Subject: [PATCH 024/107] Do not retry unsupported fonts every time the scanner is run --- src/calibre/utils/fonts/scanner.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/calibre/utils/fonts/scanner.py b/src/calibre/utils/fonts/scanner.py index c7317ee563..e90448726d 100644 --- a/src/calibre/utils/fonts/scanner.py +++ b/src/calibre/utils/fonts/scanner.py @@ -13,7 +13,7 @@ from threading import Thread from calibre import walk, prints, as_unicode from calibre.constants import config_dir, iswindows, isosx, plugins, DEBUG -from calibre.utils.fonts.metadata import FontMetadata +from calibre.utils.fonts.metadata import FontMetadata, UnsupportedFont from calibre.utils.fonts.utils import panose_to_css_generic_family from calibre.utils.icu import sort_key @@ -221,6 +221,7 @@ class Scanner(Thread): def build_families(self): families = defaultdict(list) for f in self.cached_fonts.itervalues(): + if not f: continue lf = icu_lower(f['font-family'] or '') if lf: families[lf].append(f) @@ -266,10 +267,14 @@ class Scanner(Thread): def read_font_metadata(self, path, fileid): with lopen(path, 'rb') as f: - fm = FontMetadata(f) - data = fm.to_dict() - data['path'] = path - self.cached_fonts[fileid] = data + try: + fm = FontMetadata(f) + except UnsupportedFont: + self.cached_fonts[fileid] = {} + else: + data = fm.to_dict() + data['path'] = path + self.cached_fonts[fileid] = data def dump_fonts(self): self.join() From faea33fc569b8a008204aa74b9bf73811aeb859a Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 28 Oct 2012 18:58:13 +0530 Subject: [PATCH 025/107] Font family chooser: Show the faces available for a family when clicking on the family --- src/calibre/gui2/font_family_chooser.py | 70 +++++++++++++++++++++---- 1 file changed, 60 insertions(+), 10 deletions(-) diff --git a/src/calibre/gui2/font_family_chooser.py b/src/calibre/gui2/font_family_chooser.py index 065ca9f472..93682e3966 100644 --- a/src/calibre/gui2/font_family_chooser.py +++ b/src/calibre/gui2/font_family_chooser.py @@ -110,8 +110,54 @@ class FontFamilyDelegate(QStyledItemDelegate): r.setLeft(r.left() + w) painter.drawText(r, Qt.AlignVCenter|Qt.AlignLeading|Qt.TextSingleLine, sample) -class Typefaces(QWidget): - pass +class Typefaces(QLabel): + + def __init__(self, parent=None): + QLabel.__init__(self, parent) + self.setMinimumWidth(400) + self.base_msg = '

'+_('Choose a font family')+'

' + self.setText(self.base_msg) + self.setWordWrap(True) + + def show_family(self, family, faces): + if not family: + self.setText(self.base_msg) + return + msg = ''' +

%s

+
+ {0} +
+ '''%(_('Available faces for %s')%family) + entries = [] + for font in faces: + sf = (font['wws_subfamily_name'] or font['preferred_subfamily_name'] + or font['subfamily_name']) + entries.append(''' +
{sf}
+
font-stretch: {width} font-weight: {weight} font-style: + {style}
+ + '''.format(sf=sf, width=font['font-stretch'], + weight=font['font-weight'], style=font['font-style'])) + msg = msg.format('\n\n'.join(entries)) + self.setText(msg) + +class FontsView(QListView): + + changed = pyqtSignal() + + def __init__(self, parent): + QListView.__init__(self, parent) + self.setSelectionMode(self.SingleSelection) + self.setAlternatingRowColors(True) + self.d = FontFamilyDelegate(self) + self.setItemDelegate(self.d) + + def currentChanged(self, current, previous): + self.changed.emit() + QListView.currentChanged(self, current, previous) + class FontFamilyDialog(QDialog): @@ -120,6 +166,7 @@ class FontFamilyDialog(QDialog): self.setWindowTitle(_('Choose font family')) self.setWindowIcon(QIcon(I('font.png'))) from calibre.utils.fonts.scanner import font_scanner + self.font_scanner = font_scanner try: self.families = list(font_scanner.find_font_families()) except: @@ -131,11 +178,9 @@ class FontFamilyDialog(QDialog): self.l = l = QGridLayout() self.setLayout(l) - self.view = QListView(self) + self.view = FontsView(self) self.m = QStringListModel(self.families) self.view.setModel(self.m) - self.d = FontFamilyDelegate(self) - self.view.setItemDelegate(self.d) self.view.setCurrentIndex(self.m.index(0)) if current_family: for i, val in enumerate(self.families): @@ -143,22 +188,22 @@ class FontFamilyDialog(QDialog): self.view.setCurrentIndex(self.m.index(i)) break self.view.doubleClicked.connect(self.accept, type=Qt.QueuedConnection) - self.view.setSelectionMode(self.view.SingleSelection) - self.view.setAlternatingRowColors(True) - + self.view.changed.connect(self.current_changed, + type=Qt.QueuedConnection) + self.faces = Typefaces(self) self.bb = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel) self.bb.accepted.connect(self.accept) self.bb.rejected.connect(self.reject) self.ml = QLabel(_('Choose a font family from the list below:')) - self.faces = Typefaces(self) l.addWidget(self.ml, 0, 0, 1, 2) l.addWidget(self.view, 1, 0, 1, 1) l.addWidget(self.faces, 1, 1, 1, 1) l.addWidget(self.bb, 2, 0, 1, 2) + l.setAlignment(self.faces, Qt.AlignTop) - self.resize(600, 500) + self.resize(800, 600) @property def font_family(self): @@ -166,6 +211,11 @@ class FontFamilyDialog(QDialog): if idx == 0: return None return self.families[idx] + def current_changed(self): + fam = self.font_family + self.faces.show_family(fam, self.font_scanner.fonts_for_family(fam) + if fam else None) + class FontFamilyChooser(QWidget): family_changed = pyqtSignal(object) From 2bfc897266f8189a4977f700af73762565fc46fe Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 29 Oct 2012 01:52:26 +0530 Subject: [PATCH 026/107] Windows: Workaround for error while changing title/author with calibre library on a network share. Also explicitly close file handles in samefile() instead of relying on garbage collection. --- src/calibre/utils/filenames.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/calibre/utils/filenames.py b/src/calibre/utils/filenames.py index 5c31c92c33..3a327b214c 100644 --- a/src/calibre/utils/filenames.py +++ b/src/calibre/utils/filenames.py @@ -208,17 +208,22 @@ def samefile_windows(src, dst): if samestring: return True + handles = [] + def get_fileid(x): if isbytestring(x): x = x.decode(filesystem_encoding) try: h = win32file.CreateFile(x, 0, 0, None, win32file.OPEN_EXISTING, win32file.FILE_FLAG_BACKUP_SEMANTICS, 0) + handles.append(h) data = win32file.GetFileInformationByHandle(h) except (error, EnvironmentError): return None return (data[4], data[8], data[9]) a, b = get_fileid(src), get_fileid(dst) + for h in handles: + win32file.CloseHandle(h) if a is None and b is None: return False return a == b @@ -302,6 +307,8 @@ class WindowsAtomicFolderMove(object): ' operation was started'%path) try: win32file.CreateHardLink(dest, path) + if not os.path.exists(dest): + raise Exception('This apparently can happen on network shares. Sigh.') return except: pass @@ -341,6 +348,8 @@ def hardlink_file(src, dest): if iswindows: import win32file win32file.CreateHardLink(dest, src) + if not os.path.exists(dest): + raise Exception('This apparently can happen on network shares. Sigh.') return os.link(src, dest) From 7a174b5bc81e7ef8a0155388dc731c8a8524dd85 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 29 Oct 2012 08:58:23 +0530 Subject: [PATCH 027/107] Template editor: Use dummy metadata instead of blank/unknown values --- src/calibre/gui2/dialogs/template_dialog.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/calibre/gui2/dialogs/template_dialog.py b/src/calibre/gui2/dialogs/template_dialog.py index a395ecf6b9..ef95b03fc2 100644 --- a/src/calibre/gui2/dialogs/template_dialog.py +++ b/src/calibre/gui2/dialogs/template_dialog.py @@ -219,7 +219,13 @@ class TemplateDialog(QDialog, Ui_TemplateDialog): if mi: self.mi = mi else: - self.mi = Metadata(None, None) + self.mi = Metadata(_('Title'), [_('Author')]) + self.mi.author_sort = _('Author Sort') + self.mi.series = _('Series') + self.mi.series_index = 3 + self.mi.rating = 4.0 + self.mi.tags = [_('Tag 1'), _('Tag 2')] + self.mi.language = ['eng'] # Remove help icon on title bar icon = self.windowIcon() From 88620ed588de3c6ef7df25bc8a2bd2325f5c152f Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 29 Oct 2012 09:01:28 +0530 Subject: [PATCH 028/107] Compare filesizes to verify the hardlinking worked on windows, more robust --- src/calibre/utils/filenames.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/calibre/utils/filenames.py b/src/calibre/utils/filenames.py index 3a327b214c..0960a50c1c 100644 --- a/src/calibre/utils/filenames.py +++ b/src/calibre/utils/filenames.py @@ -307,7 +307,7 @@ class WindowsAtomicFolderMove(object): ' operation was started'%path) try: win32file.CreateHardLink(dest, path) - if not os.path.exists(dest): + if os.path.getsize(dest) != os.path.getsize(path): raise Exception('This apparently can happen on network shares. Sigh.') return except: @@ -348,7 +348,7 @@ def hardlink_file(src, dest): if iswindows: import win32file win32file.CreateHardLink(dest, src) - if not os.path.exists(dest): + if os.path.getsize(dest) != os.path.getsize(src): raise Exception('This apparently can happen on network shares. Sigh.') return os.link(src, dest) From 268ad8ec7783e978fce2c3e792f3d742efdbac0b Mon Sep 17 00:00:00 2001 From: Translators <> Date: Mon, 29 Oct 2012 04:59:56 +0000 Subject: [PATCH 029/107] Launchpad automatic translations update. --- setup/iso_639/ca.po | 24 +- src/calibre/translations/de.po | 67 +++-- src/calibre/translations/fr.po | 8 +- src/calibre/translations/sk.po | 437 ++++++++++++++++++++++----------- 4 files changed, 358 insertions(+), 178 deletions(-) diff --git a/setup/iso_639/ca.po b/setup/iso_639/ca.po index b0ea4bffe5..f4e26346d5 100644 --- a/setup/iso_639/ca.po +++ b/setup/iso_639/ca.po @@ -12,13 +12,13 @@ msgstr "" "Report-Msgid-Bugs-To: Debian iso-codes team \n" "POT-Creation-Date: 2011-11-25 14:01+0000\n" -"PO-Revision-Date: 2012-10-27 12:46+0000\n" +"PO-Revision-Date: 2012-10-28 09:28+0000\n" "Last-Translator: Ferran Rius \n" "Language-Team: Catalan \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-28 04:41+0000\n" +"X-Launchpad-Export-Date: 2012-10-29 04:59+0000\n" "X-Generator: Launchpad (build 16194)\n" "Language: ca\n" @@ -10540,23 +10540,23 @@ msgstr "Jamamadí" #. name for jab msgid "Hyam" -msgstr "" +msgstr "Ham" #. name for jac msgid "Popti'" -msgstr "" +msgstr "Jacaltec" #. name for jad msgid "Jahanka" -msgstr "" +msgstr "Jahanka" #. name for jae msgid "Yabem" -msgstr "" +msgstr "Yabem" #. name for jaf msgid "Jara" -msgstr "" +msgstr "Jara" #. name for jah msgid "Jah Hut" @@ -10660,23 +10660,23 @@ msgstr "Jad" #. name for jdg msgid "Jadgali" -msgstr "" +msgstr "Jadgali" #. name for jdt msgid "Judeo-Tat" -msgstr "" +msgstr "Judeotat" #. name for jeb msgid "Jebero" -msgstr "" +msgstr "Jebero" #. name for jee msgid "Jerung" -msgstr "" +msgstr "Jerung" #. name for jeg msgid "Jeng" -msgstr "" +msgstr "Jeng" #. name for jeh msgid "Jeh" diff --git a/src/calibre/translations/de.po b/src/calibre/translations/de.po index c5e2cb6a62..c937fa38e9 100644 --- a/src/calibre/translations/de.po +++ b/src/calibre/translations/de.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: de\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-10-26 05:12+0000\n" -"PO-Revision-Date: 2012-10-20 14:01+0000\n" -"Last-Translator: SimonFS \n" +"PO-Revision-Date: 2012-10-28 20:09+0000\n" +"Last-Translator: Patrick Haake \n" "Language-Team: American English \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-27 04:43+0000\n" +"X-Launchpad-Export-Date: 2012-10-29 04:59+0000\n" "X-Generator: Launchpad (build 16194)\n" "X-Poedit-Bookmarks: 3327,-1,-1,-1,-1,-1,-1,-1,-1,-1\n" "Generated-By: pygettext.py 1.5\n" @@ -885,7 +885,7 @@ msgstr "Dieses Profil ist geeignet für den Amazon Kindle DX." #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:661 msgid "This profile is intended for the Amazon Kindle PaperWhite" -msgstr "" +msgstr "Dieses Profil ist für den Amazon Kindle PaperWhite gedacht" #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:672 msgid "This profile is intended for the Amazon Kindle Fire." @@ -1589,7 +1589,7 @@ msgstr "Ort %(dl)d • %(typ)s
" #: /home/kovid/work/calibre/src/calibre/devices/kindle/driver.py:289 msgid "Communicate with the Kindle 2/3/4/Touch/PaperWhite eBook reader." -msgstr "" +msgstr "Kommuniziere mit dem Kindle 2/3/4/Touch/PaperWhite eBook-Reader" #: /home/kovid/work/calibre/src/calibre/devices/kindle/driver.py:301 msgid "Send page number information when sending books" @@ -1842,7 +1842,7 @@ msgstr "Der Kobo Touch ab Firmware V2.0.0 unterstützt Bücherregale" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1213 msgid "Specify a tags type column for automatic management" -msgstr "" +msgstr "Bestimmen Sie eine Tag-Typ-Spalte für automatische Verwaltung" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1214 msgid "Create Bookshelves" @@ -1882,6 +1882,10 @@ msgid "" "already on the device. Select this option if you want covers uploaded the " "first time you send the book to the device." msgstr "" +"Wenn die \"Buchcover hochladen\" Option ausgewählt ist, wird der Treiber nur " +"die Cover ersetzen, die bereits auf dem Gerät vorhanden sind. Wählen Sie " +"diese Option wenn beim erstmaligen Senden eines Buches ein Cover hochgeladen " +"werden soll." #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1241 msgid "" @@ -1891,10 +1895,16 @@ msgid "" "factory defaults and testing software. This driver supports firmware V2.0.x " "and DBVersion up to " msgstr "" +"Kobo macht regelmäßig Updates der Firmware und der Datenbankversion. Mit " +"dieser Option wird Calibre versuchen volle Lese- und Schreibberechtigungen " +"zu erhalten. Hic sunt dracones!! Nur einschalten, wenn Sie sich sicher sind, " +"dass Sie Ihren Kobo auf Werkszustand zurücksetzen und die Software testen " +"wollen. Dieser Treiber unterstützt die Firmware V2.0.x und die DBVersion bis " +"zu " #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1247 msgid "Title to test when debugging" -msgstr "" +msgstr "Titel für Fehlerbehebung" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1248 msgid "" @@ -1902,6 +1912,9 @@ msgid "" "debugging. The test is to see if the string is contained in the title of a " "book. The better the match, the less extraneous output." msgstr "" +"Teil des Titels eines Buches, der während Fehlerbehebungen genutzt werden " +"kann. Der Test prüft, ob die Zeichenkette in dem Buchtitel vorhanden ist. Je " +"besser die Übereinstimmung, desto weniger Fehlausgaben." #: /home/kovid/work/calibre/src/calibre/devices/misc.py:19 msgid "Communicate with the Palm Pre" @@ -1966,7 +1979,7 @@ msgstr "Kommuniziere mit dem Ex124G" #: /home/kovid/work/calibre/src/calibre/devices/misc.py:414 msgid "Communicate with the WayteQ Reader" -msgstr "" +msgstr "Mit dem WayteQ Reader kommunizieren" #: /home/kovid/work/calibre/src/calibre/devices/mtp/base.py:29 msgid "MTP Device" @@ -6363,7 +6376,7 @@ msgstr "Den Inhalte-Server starten/anhalten" #: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:96 #, python-format msgid " [%(ip)s, port %(port)d]" -msgstr "" +msgstr " [%(ip)s, port %(port)d]" #: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:100 msgid "Stop Content Server" @@ -8760,7 +8773,7 @@ msgstr "&Zeilenabstand" #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:237 msgid "&Embed font family:" -msgstr "" +msgstr "&Einschließen der Schriftfamilie:" #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:238 msgid "&Disable font size rescaling" @@ -9138,6 +9151,9 @@ msgid "" "the output profile to the default output profile. Otherwise the output " "profile will override these settings." msgstr "" +"Hinweis: Die Einstellungen zur Seitengröße greifen nur, wenn Sie das " +"Ausgabeprofil auf das Standardprofil gestellt haben. Ansonsten wird das " +"Ausgabeprofil diese Einstellungen überschreiben." #: /home/kovid/work/calibre/src/calibre/gui2/convert/pml_output.py:14 msgid "PMLZ Output" @@ -9190,6 +9206,7 @@ msgstr "Buch öffnen" #: /home/kovid/work/calibre/src/calibre/gui2/convert/regex_builder.py:215 msgid "Click the Open button below to open a ebook to use for testing." msgstr "" +"Klicken Sie unten auf den Öffnen-Button, um ein e-Book zum Testen zu öffnen." #: /home/kovid/work/calibre/src/calibre/gui2/convert/regex_builder_ui.py:90 msgid "Regex Builder" @@ -13650,7 +13667,7 @@ msgstr "Regulärer Ausdruck (?P)" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:122 msgid "Choose font family" -msgstr "" +msgstr "Wähle Schriftfamilie" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:137 #: /home/kovid/work/calibre/src/calibre/gui2/keyboard.py:377 @@ -13670,15 +13687,15 @@ msgstr "Keine" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:159 msgid "Choose a font family from the list below:" -msgstr "" +msgstr "Wähle eine Schriftfamilie aus der untenstehenden Liste:" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:187 msgid "Choose &font family" -msgstr "" +msgstr "Wähle &Schriftfamilie" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 msgid "Clear the font family" -msgstr "" +msgstr "Schriftfamilie zurücksetzen" #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 @@ -14399,6 +14416,8 @@ msgstr "" #, python-format msgid "Could not open \"%s\". Is it being used by another program?" msgstr "" +"Konnte \"%s\" nicht öffnen. Wird es gerade von einem anderen Programm " +"benutzt?" #: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:306 msgid "" @@ -15110,6 +15129,11 @@ msgid "" " If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" +"Wenn gesetzt, wird calibre überprüfen, ob eine Datei\n" +" schon in der calibre-Bibliothek vorhanden ist, wenn diese automatisch " +"hinzugefügt wurde.\n" +" Wenn dies zutrifft, wird ein Pop-Up erscheinen und fragen, ob Sie \n" +" die Datei trotzdem hinzufügen wollen." #: /home/kovid/work/calibre/src/calibre/gui2/preferences/adding_ui.py:152 msgid "Check for &duplicates when auto-adding files" @@ -22368,7 +22392,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/utils/filenames.py:284 msgid "File is open in another process" -msgstr "" +msgstr "Datei ist in einem anderen Prozess geöffnet" #: /home/kovid/work/calibre/src/calibre/utils/formatter.py:31 #: /home/kovid/work/calibre/src/calibre/utils/formatter.py:182 @@ -22796,6 +22820,11 @@ msgid "" "template program mode using the template \"{:'approximate_formats()'}\". " "Note that format names are always uppercase, as in EPUB." msgstr "" +"approximate_formats() -- gibt eine kommagetrennte Liste der Formate, die " +"einem Buch einmal zugewiesen waren. Es gibt keine Garantie, dass diese Liste " +"korrekt ist, obwohl sie es wahrscheinlich ist. Diese Funktion kann im " +"Vorlagen Programmiermodus ausgeführt werden: \"{:'approximate_formats()'}\". " +"Beachten Sie, dass die Formatnamen immer in Großbuchstaben sind, wie in EPUB." #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:620 msgid "" @@ -23025,6 +23054,11 @@ msgid "" "list1 and list2 are separated by separator, as are the items in the returned " "list." msgstr "" +"list_union(list1, list2, separator) -- gibt eine Liste mit den " +"zusammengeführten Elementen aus list1 und list2 zurück, wobei Duplikate " +"durch schreibungsunabhängigen Vergleich entfernt werden. Wenn Elemente sich " +"in der Schreibweise unterscheiden, dann wird das aus list1 verwendet. Die " +"Elemente in list1 und list2 werden durch den separator getrennt." #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:1004 msgid "" @@ -23152,6 +23186,9 @@ msgid "" "This function can be called in template program mode using the template " "\"{:'current_library_path()'}\"." msgstr "" +"current_library_path() -- gibt den Pfad der aktuellen calibe-Datenbank " +"zurück. Diese Funktion dann im Vorlagen Programmiermodus verwendet werden: " +"\"{:'current_library_path()'}\"." #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:1200 msgid "" diff --git a/src/calibre/translations/fr.po b/src/calibre/translations/fr.po index cbd899bb35..ff050ef1c4 100644 --- a/src/calibre/translations/fr.po +++ b/src/calibre/translations/fr.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: calibre 0.4.22\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-10-26 05:12+0000\n" -"PO-Revision-Date: 2012-10-25 06:36+0000\n" -"Last-Translator: Franck \n" +"PO-Revision-Date: 2012-10-28 13:56+0000\n" +"Last-Translator: sengian \n" "Language-Team: PCGen\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Launchpad-Export-Date: 2012-10-27 04:42+0000\n" +"X-Launchpad-Export-Date: 2012-10-29 04:58+0000\n" "X-Generator: Launchpad (build 16194)\n" "Language: fr\n" "X-Poedit-Bookmarks: 1177,1104,-1,-1,-1,-1,-1,-1,-1,-1\n" @@ -13773,7 +13773,7 @@ msgstr "Choisir la &famille de polices" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 msgid "Clear the font family" -msgstr "" +msgstr "Supprimer la famille de polices" #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 diff --git a/src/calibre/translations/sk.po b/src/calibre/translations/sk.po index d69b3aa313..806b6350e7 100644 --- a/src/calibre/translations/sk.po +++ b/src/calibre/translations/sk.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-10-26 05:12+0000\n" -"PO-Revision-Date: 2012-10-27 16:58+0000\n" +"PO-Revision-Date: 2012-10-28 16:21+0000\n" "Last-Translator: viktorc \n" "Language-Team: Slovak \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 1 : (n>=2 && n<=4) ? 2 : 0;\n" -"X-Launchpad-Export-Date: 2012-10-28 04:41+0000\n" +"X-Launchpad-Export-Date: 2012-10-29 04:59+0000\n" "X-Generator: Launchpad (build 16194)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 @@ -350,7 +350,7 @@ msgstr "Upraviť metadata kníh vo vašej Calibre knižnici" #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:805 msgid "Read books in your calibre library" -msgstr "Čítať knihy vo vašej Calibre knižnici" +msgstr "Prečítané knihy vo vašej knižnici Calibre" #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:810 msgid "Download news from the internet in ebook form" @@ -4230,10 +4230,10 @@ msgid "" "pattern (which can be an empty line). The regular expression must be in the " "python regex syntax and the file must be UTF-8 encoded." msgstr "" -"Cesta k súboru obsahujúcom vyhľadanie a nahradenie regulárnych výrazov. " -"Súbor musí obsahovať striedajúce sa riadky regulárnych výrazov nasledované " -"nahradzujúcim vzorom (môže byť prázdny riadok). Regulárne výrazy musia byť v " -"python-ovom regex syntaxe a súbor musí byť kódovaný v UTF-8." +"Cesta k súboru obsahujúcom regulárne výrazy hľadania a nahradenia. Súbor " +"musí obsahovať striedajúce sa riadky regulárnych výrazov nasledované " +"nahradzujúcim vzorom (môže byť prázdny riadok). Regulárne výrazy musia byť " +"podľa syntaxu pythonu a súbor musí byť kódovaný v UTF-8." #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:767 msgid "Could not find an ebook inside the archive" @@ -6824,6 +6824,26 @@ msgid "" " library.\n" " " msgstr "" +"

O vylepšení knihy

\n" +"

Vylepšenie knihy Vám umožňuje detailne doladiť\n" +" vzhľad e-booku drobnými zmenami vnútorných nastavení.\n" +" Pred použitím Vylepšenia knihy by ste mali niečo málo\n" +" vedieť o technológiách HTML a CSS, ktoré sú v e-bookoch\n" +" použité. Postupujte nasledovne:

\n" +"
\n" +"
    \n" +"
  1. Kliknite na \"Rozbaliť knihu\": Tým \"rozbalíte\" knihu na " +"jej \n" +" jednotlivé vnútorné komponenty.
  2. \n" +"
  3. Na úpravu jednotlivých súborov Vaším obľúbeným \n" +" editorom, kliknite na ne pravým tlačidlom myši a vyberte\n" +" \"Otvoriť v...\".
  4. \n" +"
  5. Keď s vylepšovaním skončíte: zatvorte okno prehliadača\n" +" súborov a okná editorov ktoré ste použili na vylepšenia.\n" +" Následne kliknite na tlačidlo \"Znovuvytvoriť knihu\", aby sa " +"kniha\n" +" aktualizovala v knižnici Calibre.
  6. \n" +"
" #: /home/kovid/work/calibre/src/calibre/gui2/actions/tweak_epub.py:103 msgid "&Explode Book" @@ -6843,7 +6863,7 @@ msgstr "&Zrušiť" #: /home/kovid/work/calibre/src/calibre/gui2/actions/tweak_epub.py:106 msgid "&Rebuild Book" -msgstr "" +msgstr "Znovu&vytvoriť knihu" #: /home/kovid/work/calibre/src/calibre/gui2/actions/tweak_epub.py:109 msgid "Explode the book to edit its components" @@ -6901,7 +6921,7 @@ msgstr "Znovuvytváram, prosím čakajte..." #: /home/kovid/work/calibre/src/calibre/gui2/actions/tweak_epub.py:289 msgid "Make small changes to ePub, HTMLZ or AZW3 format books" -msgstr "" +msgstr "Urobiť drobné zmeny vo formátoch kníh ePub, HTMLZ, alebo AZW3" #: /home/kovid/work/calibre/src/calibre/gui2/actions/tweak_epub.py:290 msgid "T" @@ -7497,65 +7517,65 @@ msgstr "Katalógy" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:99 msgid "Read book" -msgstr "" +msgstr "Prečítaná kniha" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:105 msgid "Wishlist item" -msgstr "" +msgstr "Položka zoznamu želaní" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:133 #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:795 msgid "any date" -msgstr "" +msgstr "nejaký dátum" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:133 #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:793 msgid "any value" -msgstr "" +msgstr "nejaká hodnota" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:135 #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:791 #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:793 #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:795 msgid "unspecified" -msgstr "" +msgstr "neuvedené" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:185 msgid "No genres will be excluded" -msgstr "" +msgstr "Žiadne žánre nebudú vyňaté" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:194 #, python-format msgid "regex error: %s" -msgstr "" +msgstr "chyba regulárneho výrazu: %s" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:203 msgid "All genres will be excluded" -msgstr "" +msgstr "Všetky žánre budú vyňaté" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:639 #, python-format msgid "Are you sure you want to delete '%s'?" -msgstr "" +msgstr "Ste si istý, že chcete odstrániť '%s'?" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:641 #, python-format msgid "Are you sure you want to delete rules #%(first)d-%(last)d?" -msgstr "" +msgstr "Ste si istý, že chcete odstrániť pravidlá #%(first)d-%(last)d?" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:642 msgid "Delete Rule" -msgstr "" +msgstr "Odstrániť pravidlo" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:791 #: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:601 #: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:4665 msgid "False" -msgstr "" +msgstr "Nepravda" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:791 msgid "True" -msgstr "" +msgstr "Pravda" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:816 #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:907 @@ -7569,20 +7589,20 @@ msgstr "Názov" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:817 #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:909 msgid "Field" -msgstr "" +msgstr "Pole" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:818 #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:910 msgid "Value" -msgstr "" +msgstr "Hodnota" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:908 msgid "Prefix" -msgstr "" +msgstr "Titul pred" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:266 msgid "Enabled sections will be included in the generated catalog." -msgstr "" +msgstr "Povolené sekcie budú zahrnuté do generovaného katalógu" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:267 msgid "Included sections" @@ -7590,23 +7610,23 @@ msgstr "Zahrnuté sekcie" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:268 msgid "&Authors" -msgstr "" +msgstr "&Autori" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:269 msgid "&Titles" -msgstr "" +msgstr "&Tituly" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:270 msgid "&Series" -msgstr "" +msgstr "&Série" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:271 msgid "&Genres" -msgstr "" +msgstr "Žá&nre" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:272 msgid "&Recently Added" -msgstr "" +msgstr "&Naposledy pridané" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:273 msgid "&Descriptions" @@ -7620,13 +7640,15 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:275 msgid "Prefixes" -msgstr "" +msgstr "Prefixy" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:276 msgid "" "Books matching any of the exclusion rules will be excluded from the " "generated catalog. " msgstr "" +"Knihy vyhovujúce pravidlám pre vyňatie nebudú zahrnuté do generovaného " +"katalógu. " #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:277 msgid "Excluded books" @@ -7639,6 +7661,10 @@ msgid "" "The default pattern \\[.+\\]|\\+ excludes tags of the form [tag], e.g., " "[Test book], and '+', the default tag for a read book." msgstr "" +"Regulárny výraz popisujúci žánre, ktoré nemajú byť zaradené do generovaného " +"katalógu. Žánre sú odvodené od značiek priradených k Vaším knihám.\n" +"Štandardná maska \\[.+\\]|\\+ vyníma značky v tvare [značka], napr. " +"[Testovacia kniha], a '+', štandardná značka pre čítanú knihu." #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:280 msgid "Excluded genres" @@ -7646,19 +7672,19 @@ msgstr "Vynechané žánre" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:281 msgid "Tags to &exclude (regex):" -msgstr "" +msgstr "&Vyňať značky (regulárny výraz):" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:282 msgid "Reset to default" -msgstr "" +msgstr "Obnoviť na východzie" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:284 msgid "Results of regex:" -msgstr "" +msgstr "Výsledky regulárneho výrazu:" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:285 msgid "Tags that will be excluded as genres" -msgstr "" +msgstr "Značky, ktoré budú vyňaté z žánrov" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:286 msgid "Other options" @@ -7669,10 +7695,12 @@ msgid "" "Custom column containing additional content to be merged with Comments " "metadata." msgstr "" +"Užívateľské pole obsahujúce doplnkový obsah, ktorý sa má pripojiť k " +"metadátam Komentáre." #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:288 msgid "Merge additional content before Comments metadata." -msgstr "" +msgstr "Pripojiť doplnkový obsah pred metadáta Komentáre" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:289 msgid "&Before" @@ -7680,7 +7708,7 @@ msgstr "&Pred" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:290 msgid "Merge additional content after Comments metadata." -msgstr "" +msgstr "Pripojiť doplnkový obsah za metadáta Komentáre" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:291 msgid "&After" @@ -7693,11 +7721,11 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:293 msgid "Include &Separator" -msgstr "" +msgstr "Vložiť &oddeľovač" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:294 msgid "&Merge with Comments:" -msgstr "" +msgstr "&Zlúčiť s komentármi:" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:295 msgid "Catalog cover:" @@ -7705,11 +7733,11 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:296 msgid "Generate new cover" -msgstr "" +msgstr "Generovať novú obálku" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:297 msgid "Use existing cover" -msgstr "" +msgstr "Použiť existujúcu obálku" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:298 msgid "E&xtra Description note:" @@ -7890,11 +7918,11 @@ msgstr "Vytvoriť odkaz" #: /home/kovid/work/calibre/src/calibre/gui2/comments_editor.py:215 msgid "Enter &URL:" -msgstr "" +msgstr "Zadajte &URL:" #: /home/kovid/work/calibre/src/calibre/gui2/comments_editor.py:216 msgid "Enter name (optional):" -msgstr "" +msgstr "Zadajte názov (voliteľné):" #: /home/kovid/work/calibre/src/calibre/gui2/comments_editor.py:577 msgid "Normal view" @@ -7906,7 +7934,7 @@ msgstr "HTML zdroj" #: /home/kovid/work/calibre/src/calibre/gui2/convert/azw3_output.py:17 msgid "AZW3 Output" -msgstr "" +msgstr "Výstup AZW3" #: /home/kovid/work/calibre/src/calibre/gui2/convert/azw3_output_ui.py:53 #: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output_ui.py:84 @@ -8322,7 +8350,7 @@ msgstr "Spôsob spracovania s triedami v CSS" #: /home/kovid/work/calibre/src/calibre/gui2/convert/htmlz_output_ui.py:50 msgid "Use book &title as the filename for the HTML file inside the archive" -msgstr "" +msgstr "Použiť &názov knihy pre názov HTML súboru vo vnútri archívu" #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel.py:16 msgid "Look & Feel" @@ -8498,7 +8526,7 @@ msgstr "Výška &riadka:" #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:237 msgid "&Embed font family:" -msgstr "&Pripojiť triedu fontov:" +msgstr "&Pripojiť písmo:" #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:238 msgid "&Disable font size rescaling" @@ -8703,6 +8731,8 @@ msgid "" "Do not convert all images to &JPEG (may result in images not working in " "older viewers)" msgstr "" +"Nekonvertovať všetky obrázky do &JPEG (môže spôsobiť, že staršie prehliadače " +"ich nezobrazia)" #: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output_ui.py:87 msgid "Kindle options" @@ -8710,7 +8740,7 @@ msgstr "Voľby Kindle" #: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output_ui.py:88 msgid "MOBI file &type:" -msgstr "" +msgstr "&Typ súboru MOBI:" #: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output_ui.py:89 msgid "Personal Doc tag:" @@ -8722,6 +8752,9 @@ msgid "" "both MOBI filetypes. If you wish to use the new format on your device, " "convert to AZW3 instead of MOBI." msgstr "" +"UPOZORNENIE: Mnohé zariadenia Kindle majú problém so zobrazením " +"nového, alebo oboch typov súborov MOBI. Ak si želáte použiť vo Vašom " +"zariadení nový formát, skonvertujte ho na AZW3, namiesto MOBI." #: /home/kovid/work/calibre/src/calibre/gui2/convert/page_setup.py:35 msgid "Page Setup" @@ -8752,7 +8785,7 @@ msgstr "V&ľavo:" #: /home/kovid/work/calibre/src/calibre/gui2/convert/page_setup_ui.py:136 #: /home/kovid/work/calibre/src/calibre/gui2/convert/page_setup_ui.py:139 msgid "No margin" -msgstr "" +msgstr "Bez okraja" #: /home/kovid/work/calibre/src/calibre/gui2/convert/page_setup_ui.py:132 msgid "&Top:" @@ -8782,7 +8815,7 @@ msgstr "&Formát:" #: /home/kovid/work/calibre/src/calibre/gui2/convert/rb_output_ui.py:34 #: /home/kovid/work/calibre/src/calibre/gui2/convert/txt_output_ui.py:95 msgid "&Inline TOC" -msgstr "" +msgstr "&Vložený obsah" #: /home/kovid/work/calibre/src/calibre/gui2/convert/pdb_output_ui.py:50 #: /home/kovid/work/calibre/src/calibre/gui2/convert/pmlz_output_ui.py:49 @@ -8843,7 +8876,7 @@ msgstr "Š&tandardné písmo:" #: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:109 msgid "Default font si&ze:" -msgstr "" +msgstr "Štandardná &veľkosť písma:" #: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:110 #: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:112 @@ -8904,7 +8937,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/convert/regex_builder.py:181 #: /home/kovid/work/calibre/src/calibre/gui2/convert/regex_builder.py:185 msgid "Failed to generate preview" -msgstr "" +msgstr "Vytvorenie náhľadu zlyhalo" #: /home/kovid/work/calibre/src/calibre/gui2/convert/regex_builder.py:191 msgid "Open book" @@ -8977,37 +9010,39 @@ msgstr "Regulárny výraz pre &hľadanie" #: /home/kovid/work/calibre/src/calibre/gui2/convert/search_and_replace.py:56 msgid "Replacement Text" -msgstr "" +msgstr "Nahradzovaný text" #: /home/kovid/work/calibre/src/calibre/gui2/convert/search_and_replace.py:56 msgid "Search Regular Expression" -msgstr "" +msgstr "Regulárny výraz hľadania" #: /home/kovid/work/calibre/src/calibre/gui2/convert/search_and_replace.py:102 msgid "Load Calibre Search-Replace definitions file" -msgstr "" +msgstr "Načítať definičný súbor Calibre pre hľadanie-náhradu" #: /home/kovid/work/calibre/src/calibre/gui2/convert/search_and_replace.py:104 #: /home/kovid/work/calibre/src/calibre/gui2/convert/search_and_replace.py:122 msgid "Calibre Search-Replace definitions file" -msgstr "" +msgstr "Definičný súbor Calibre pre hľadanie-náhradu" #: /home/kovid/work/calibre/src/calibre/gui2/convert/search_and_replace.py:113 msgid "Failed to read" -msgstr "" +msgstr "Nepodarilo sa prečítať" #: /home/kovid/work/calibre/src/calibre/gui2/convert/search_and_replace.py:114 #, python-format msgid "Failed to load patterns from %s, click Show details to learn more." msgstr "" +"Zlyhalo načítanie vzorov z %s. Viac sa dozviete po kliknutí na Zobraziť " +"podrobnosti." #: /home/kovid/work/calibre/src/calibre/gui2/convert/search_and_replace.py:120 msgid "Save Calibre Search-Replace definitions file" -msgstr "" +msgstr "Uložiť definičný súbor Calibre pre hľadanie-náhradu" #: /home/kovid/work/calibre/src/calibre/gui2/convert/search_and_replace.py:196 msgid "Unused Search & Replace definition" -msgstr "" +msgstr "Nepoužitá definícia Hľadať a Nahradiť" #: /home/kovid/work/calibre/src/calibre/gui2/convert/search_and_replace.py:197 msgid "" @@ -9015,6 +9050,8 @@ msgid "" "of definitions. Do you wish to continue with the conversion (the definition " "will not be used)?" msgstr "" +"Upravovaná definícia pre hľadanie / náhradu nebola doplnená do zoznamu " +"definícií. Želáte si pokračovať v konverzii (táto definícia sa nepoužije)?" #: /home/kovid/work/calibre/src/calibre/gui2/convert/search_and_replace.py:208 #: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:110 @@ -9032,10 +9069,12 @@ msgid "" "The list of search/replace definitions that will be applied to this " "conversion." msgstr "" +"Zoznam definícií pre hľadanie / náhradu, ktorý bude použitý pri tejto " +"konverzii." #: /home/kovid/work/calibre/src/calibre/gui2/convert/search_and_replace_ui.py:146 msgid "Search/Replace Definition Edit" -msgstr "" +msgstr "Úprava definície hľadať/nahradiť" #: /home/kovid/work/calibre/src/calibre/gui2/convert/search_and_replace_ui.py:147 msgid "&Replacement Text" @@ -9044,15 +9083,15 @@ msgstr "&Nahradiť za" #: /home/kovid/work/calibre/src/calibre/gui2/convert/search_and_replace_ui.py:148 msgid "" "Add the current expression to the list of expressions that will be applied" -msgstr "" +msgstr "Pridať aktuálny výraz do zoznamu výrazov ktoré sa použijú" #: /home/kovid/work/calibre/src/calibre/gui2/convert/search_and_replace_ui.py:149 msgid "&Add" -msgstr "" +msgstr "&Pridať" #: /home/kovid/work/calibre/src/calibre/gui2/convert/search_and_replace_ui.py:150 msgid "Edit the currently selected expression" -msgstr "" +msgstr "Upraviť aktuálne vybraný výraz" #: /home/kovid/work/calibre/src/calibre/gui2/convert/search_and_replace_ui.py:151 #: /home/kovid/work/calibre/src/calibre/gui2/wizard/library_ui.py:59 @@ -9061,7 +9100,7 @@ msgstr "&Zmeniť" #: /home/kovid/work/calibre/src/calibre/gui2/convert/search_and_replace_ui.py:152 msgid "Remove the currently selected expression" -msgstr "" +msgstr "Odstrániť aktuálne vybraný výraz" #: /home/kovid/work/calibre/src/calibre/gui2/convert/search_and_replace_ui.py:153 #: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:871 @@ -9070,16 +9109,16 @@ msgstr "&Odstrániť" #: /home/kovid/work/calibre/src/calibre/gui2/convert/search_and_replace_ui.py:154 msgid "Load a list of expressions from a previously saved file" -msgstr "" +msgstr "Načítať zoznam výrazov z predtým uloženého súboru" #: /home/kovid/work/calibre/src/calibre/gui2/convert/search_and_replace_ui.py:155 #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config_ui.py:433 msgid "&Load" -msgstr "" +msgstr "&Načítať" #: /home/kovid/work/calibre/src/calibre/gui2/convert/search_and_replace_ui.py:156 msgid "Save this list of expressions so that you can re-use it easily" -msgstr "" +msgstr "Uložiť zoznam výrazov pre jednoduchšie opakované použitie" #: /home/kovid/work/calibre/src/calibre/gui2/convert/search_and_replace_ui.py:157 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/search_ui.py:188 @@ -9090,11 +9129,11 @@ msgstr "&Uložiť" #: /home/kovid/work/calibre/src/calibre/gui2/convert/search_and_replace_ui.py:158 msgid "Move expression up." -msgstr "" +msgstr "Posunúť výraz hore." #: /home/kovid/work/calibre/src/calibre/gui2/convert/search_and_replace_ui.py:159 msgid "Move expression down." -msgstr "" +msgstr "Posunúť výraz dolu." #: /home/kovid/work/calibre/src/calibre/gui2/convert/search_and_replace_ui.py:160 msgid "" @@ -9105,6 +9144,12 @@ msgid "" "the current input document. When you are happy with an expression, click the " "Add button to add it to the list of expressions." msgstr "" +"

Hľadať a nahradiť využíva regulárne výrazy. S regulárnymi výrazmi " +"sa môžete oboznámiť v príručke regulárnych výrazov. Kliknutím na " +"tlačidlo sprievodcu Vám umožní otestovať Váš regulárny výraz v aktoálnom " +"vstupnom dokumente. Ak ste s výrazom spokojní, pridajte ho do zoznamu " +"výrazov tlačidlom Pridať." #: /home/kovid/work/calibre/src/calibre/gui2/convert/single.py:184 msgid "Convert" @@ -9664,12 +9709,12 @@ msgstr "Chyba komunikácie so zariadením" #: /home/kovid/work/calibre/src/calibre/gui2/device.py:860 #, python-format msgid "Manage the %s?" -msgstr "" +msgstr "Spravovať %s?" #: /home/kovid/work/calibre/src/calibre/gui2/device.py:861 #, python-format msgid "Detected the %s. Do you want calibre to manage it?" -msgstr "" +msgstr "Bol detekovaný %s. Želáte si, aby ho Calibre spravovala?" #: /home/kovid/work/calibre/src/calibre/gui2/device.py:884 #: /home/kovid/work/calibre/src/calibre/gui2/device.py:1460 @@ -9698,7 +9743,7 @@ msgstr "Konfigurovať %s" #: /home/kovid/work/calibre/src/calibre/gui2/device.py:939 #, python-format msgid "Restart calibre for the changes to %s to be applied." -msgstr "" +msgstr "Aby sa zmeny %s prejavili, treba Calibre reštartovať." #: /home/kovid/work/calibre/src/calibre/gui2/device.py:981 msgid "Error talking to device" @@ -9731,7 +9776,7 @@ msgstr "Žiadne zariadenie" #: /home/kovid/work/calibre/src/calibre/gui2/device.py:1140 msgid "No device connected" -msgstr "" +msgstr "Žiadne zariadenie nie je pripojené" #: /home/kovid/work/calibre/src/calibre/gui2/device.py:1156 #, python-format @@ -9802,7 +9847,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/device.py:1540 msgid "Incorrect destination" -msgstr "" +msgstr "Nesprávny cieľ" #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/configwidget.py:142 msgid "Unknown formats" @@ -9860,21 +9905,23 @@ msgstr "Uložiť &šablónu:" #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/mtp_config.py:57 msgid "No formats selected" -msgstr "" +msgstr "Nie sú vybrané žiadne formáty" #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/mtp_config.py:58 msgid "You must choose at least one format to send to the device" -msgstr "" +msgstr "Musíte zvoliť aspoň jeden formát, ktorý chcete poslať do zariadenia" #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/mtp_config.py:86 msgid "" "Save &template to control the filename and\n" " location of files sent to the device:" msgstr "" +"Uložiť šab&lónu na určujúcu názov súboru a\n" +" umiestnenia súborov posielaných do zariadenia:" #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/mtp_config.py:92 msgid "&Template editor" -msgstr "" +msgstr "Editor šab&lón" #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/mtp_config.py:102 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_line_editor.py:41 @@ -9888,30 +9935,34 @@ msgid "" "A list of &folders on the device to\n" " which to send ebooks. The first one that exists will be used:" msgstr "" +"A zoznam &priečinkov v zariadení do\n" +" ktorých posielať e-booky. Použije sa prvý existujúci:" #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/mtp_config.py:139 #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/mtp_config.py:226 msgid "Browse for a folder on the device" -msgstr "" +msgstr "Vybrať priečinok v zariadení" #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/mtp_config.py:167 msgid "" "Select the devices to be ignored. calibre will not\n" " connect to devices with a checkmark next to their names." msgstr "" +"Výber zariadení, ktoré sa majú ignorovať. Calibre sa\n" +" k označeným zariadeniam nebude pripájať." #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/mtp_config.py:212 #, python-format msgid "Send the %s format to the folder:" -msgstr "" +msgstr "Odoslať formát %s do priečinka:" #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/mtp_config.py:220 msgid "Folder on the device" -msgstr "" +msgstr "Priečinok v zariadení" #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/mtp_config.py:228 msgid "&Remove rule" -msgstr "" +msgstr "Odst&rániť pravidlo" #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/mtp_config.py:273 msgid "Format specific sending" @@ -9924,41 +9975,48 @@ msgid "" "over\n" " the folders specified above." msgstr "" +"Môžete vytvoriť pravidlá, ktoré budú ovplyvňovať kam do zariadenia\n" +" sa e-booky určitého formátu budú posielať. Tieto majú prednosť\n" +" pred priečinkami zadanými vyššie." #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/mtp_config.py:300 msgid "Add a &new rule" -msgstr "" +msgstr "Pridať &nové pravidlo" #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/mtp_config.py:338 #, python-format msgid "The %s device has no serial number, it cannot be configured" -msgstr "" +msgstr "Zariadenie %s nemá sériové číslo a nemôže byť nastavované" #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/mtp_config.py:343 msgid "" "No MTP device connected.

You can only configure the MTP device " "plugin when a device is connected." msgstr "" +"Nie je pripojené žiadne MTP zariadenie.

Modul MTP zariadenia " +"môžete nastavovať len ak je zariadenie pripojené." #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/mtp_config.py:350 msgid "" "If you want to un-ignore a previously ignored MTP device, use the \"Ignored " "devices\" tab." msgstr "" +"Ak chcete aby sa MTP zariadenie, ktoré bolo doteraz ignorované, prestalo " +"ignorovať, použite záložku \"Ignorované zariadenia\"." #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/mtp_config.py:370 #, python-format msgid "Choose the formats to send to the %s" -msgstr "" +msgstr "Vyberte formáty na posielanie do %s" #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/mtp_config.py:373 #, python-format msgid "&Ignore the %s in calibre" -msgstr "" +msgstr "&Ignorovať %s v Calibre" #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/mtp_config.py:377 msgid "Show device information" -msgstr "" +msgstr "Zobraziť informácie o zariadení" #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/mtp_config.py:411 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/message_box.py:141 @@ -9971,11 +10029,11 @@ msgstr "Kopírovať do schránky" #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/mtp_config.py:419 #, python-format msgid "The %s will be ignored in calibre" -msgstr "" +msgstr "%s bude v Calibre ignorované" #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/mtp_folder_browser.py:91 msgid "Choose folder on device" -msgstr "" +msgstr "Vyberte priečinok v zariadení" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/add_empty_book.py:19 msgid "How many empty books?" @@ -10055,11 +10113,11 @@ msgstr "Moje knihy" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/catalog.py:190 msgid "No help available" -msgstr "" +msgstr "Nápoveda nie je dispozícii" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/catalog.py:191 msgid "No help available for this output format." -msgstr "" +msgstr "Pre tento výstupný formát nie je nápoveda k dispozícii" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/catalog_ui.py:92 #: /home/kovid/work/calibre/src/calibre/gui2/tools.py:331 @@ -10360,12 +10418,15 @@ msgid "" "You should not create a library inside the Calibre folder as this folder is " "automatically deleted during upgrades." msgstr "" +"V priečinku Calibre by ste nemali vytvárať knižnicu, pretože tento priečinok " +"sa pri aktualizáciách automaticky vymazáva." #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_library.py:78 #, python-format msgid "" "You can only create libraries inside %s at the top level, not in sub-folders" msgstr "" +"Knižnice môžete vytvárať len v najvyššej úrovni %s, nie v jeho podpriečinkoch" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_library.py:84 msgid "No existing library found" @@ -10842,7 +10903,7 @@ msgstr "Zobraziť protokol" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/message_box.py:322 #, python-format msgid "Hide the remaining %d error messages" -msgstr "" +msgstr "Skryť zostávajúcich %d chybových správ" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:60 msgid "Title/Author" @@ -11012,7 +11073,7 @@ msgstr "Názov hľadania/náhrady:" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:1052 msgid "You must provide a name." -msgstr "" +msgstr "Musíte poskytnúť meno" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:1057 msgid "" @@ -12388,7 +12449,7 @@ msgstr "&Názov/Autor/Séria ..." #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/select_formats.py:38 #, python-format msgid "There are %(count)d book(s) with the %(fmt)s format" -msgstr "" +msgstr "Existuje %(count)d kníh vo formáte %(fmt)s" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/select_formats.py:55 msgid "Choose formats" @@ -12400,6 +12461,9 @@ msgid "" "example, if you run calibre on a laptop, use that laptop in an airport, and " "want to connect your smart device to calibre, you should use a password." msgstr "" +"Ak beží Calibre v sieti, ktorá nie je bezpečná, použite heslo. Napr. ak " +"bežíte Calibre na notebooku, ktorý používate na letisku a chcete sa k nemu " +"pripojiť svojím smart zariadením, mali by ste použiť heslo." #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/smartdevice.py:51 msgid "" @@ -12407,6 +12471,9 @@ msgid "" "interface when calibre starts. You should not do this if you are using a " "network that is not secure and you are not setting a password." msgstr "" +"Označte túto voľbu ak chcete aby Calibre automaticky po štarte spúšťalo " +"rozhranie pre smart zariadenia. Ak používate nezabezpečenú sieť a nemáte " +"nastavené heslo, nemali by ste to robiť." #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/smartdevice.py:57 msgid "" @@ -12414,12 +12481,17 @@ msgid "" "will not need to do this. However, if your device consistently fails to " "connect to calibre, try checking this box and entering a number." msgstr "" +"Označte túto voľbu, ak chcete aby Calibre použila pevný sieťový port. " +"Obvykle to nemusíte robiť. Ak sa však Vaše zariadenie opakovane nemôže ku " +"Calibre pripojoť, skúste túto voľbu označiť a zadajte číslo portu." #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/smartdevice.py:63 msgid "" "Try 9090. If calibre says that it fails to connect to the port, try another " "number. You can use any number between 8,000 and 32,000." msgstr "" +"Vyskúšajte 9090. Ak Calibre oznámi, že sa k tomuto portu nemôže pripojiť, " +"skúste iné číslo. Môžete použiť akékoľvek číslo medzi 8.000 and 32.000." #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/smartdevice.py:69 msgid "" @@ -12430,36 +12502,41 @@ msgid "" "computer's control panel to get a complete list of your computer's network " "interfaces and IP addresses." msgstr "" +"Toto sú IP adresy tohoto počítača. Ak sa rozhodnete, že sa má Vaše " +"zariadenie pripájať cez pevnú IP adresu, mala by to byť jedna z nich. Je " +"nepravdepodobné, ale možné, že správna IP adresa v zozname nie je. V takom " +"prípade budete musieť otvoriť ovládacie panely počítača, kde nájdete úplný " +"zoznam jeho sieťových rozhraní a IP adries." #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/smartdevice.py:118 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/smartdevice.py:124 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/smartdevice.py:129 msgid "Invalid port number" -msgstr "" +msgstr "Neplatné číslo portu" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/smartdevice.py:119 msgid "You must provide a port number." -msgstr "" +msgstr "Musíte zadať číslo portu." #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/smartdevice.py:125 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/smartdevice.py:130 msgid "The port must be a number between 8000 and 32000." -msgstr "" +msgstr "Číslo portu musí byť medzi 8000 a 32000." #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/smartdevice.py:145 #: /home/kovid/work/calibre/src/calibre/gui2/ui.py:390 msgid "Problem starting the wireless device" -msgstr "" +msgstr "Pri spustení bezdrôtového zariadenia sa vyskytol problém" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/smartdevice.py:146 #: /home/kovid/work/calibre/src/calibre/gui2/ui.py:391 #, python-format msgid "The wireless device driver did not start. It said \"%s\"" -msgstr "" +msgstr "Ovládač bezdrôtového zariadenia sa nespustil. Vypísal \"%s\"" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/smartdevice_ui.py:86 msgid "Smart device control" -msgstr "" +msgstr "Ovládanie smart zariadenia" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/smartdevice_ui.py:87 msgid "" @@ -12470,38 +12547,44 @@ msgid "" "virus manager asking you if it is OK for calibre to connect to the network. " "Please answer yes. If you do not, wireless connections will not work." msgstr "" +"

Spustiť pripojenia bezdrôtového zariadenia. V súčasnosti používané len\n" +" aplikáciou Calibre Companion.\n" +"

Môžu sa zobraziť dotazy firewallu, alebo antivíru Vášho počítača, " +"či je v poriadku, aby sa Calibre pripojila k sieti. Odpovedzte prosím " +"áno. V opačnom prípade nebudú bezdrôtové priopjenia fungovať." #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/smartdevice_ui.py:90 msgid "Calibre IP addresses:" -msgstr "" +msgstr "IP adresy Calibre:" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/smartdevice_ui.py:91 msgid "Possibe IP addresses:" -msgstr "" +msgstr "Možné IP adresy:" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/smartdevice_ui.py:92 msgid "Optional &password:" -msgstr "" +msgstr "Voliteľné &heslo:" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/smartdevice_ui.py:93 msgid "Optional password for security" -msgstr "" +msgstr "Voliteľné bezpečnostné heslo" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/smartdevice_ui.py:95 msgid "Optional &fixed port:" -msgstr "" +msgstr "Voliteľný &pevný port:" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/smartdevice_ui.py:96 msgid "Optional port number" -msgstr "" +msgstr "Voliteľné číslo portu" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/smartdevice_ui.py:97 msgid "&Use a fixed port" -msgstr "" +msgstr "Po&užiť pevný port" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/smartdevice_ui.py:98 msgid "&Automatically allow connections at calibre startup" -msgstr "" +msgstr "Po štarte Calibre &automaticky povoliť pripojenia" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories.py:60 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:164 @@ -12672,19 +12755,19 @@ msgstr "Bolo" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor.py:182 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor_ui.py:75 msgid "Find" -msgstr "" +msgstr "Nájsť" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor.py:167 msgid "You must enter some text to search for" -msgstr "" +msgstr "Musíte zadať nejaký hľadaný text" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor.py:182 msgid "No tag found" -msgstr "" +msgstr "Značka nebola nájdená" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor_ui.py:74 msgid "Search for an item in the Tag column" -msgstr "" +msgstr "Hľadať položku v stĺpci značka" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor_ui.py:76 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog_ui.py:112 @@ -13181,7 +13264,7 @@ msgstr "Regulárny výraz (?P)" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:122 msgid "Choose font family" -msgstr "" +msgstr "Vyberte písmo" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:137 #: /home/kovid/work/calibre/src/calibre/gui2/keyboard.py:377 @@ -13201,15 +13284,15 @@ msgstr "Žiadne" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:159 msgid "Choose a font family from the list below:" -msgstr "" +msgstr "Vyberte písmo zo zoznamu nižšie:" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:187 msgid "Choose &font family" -msgstr "" +msgstr "Vyberte &písmo" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 msgid "Clear the font family" -msgstr "" +msgstr "Vymažte písmo" #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 @@ -13721,13 +13804,15 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/main.py:75 msgid "Path too long" -msgstr "" +msgstr "Cesta je príliš dlhá" #: /home/kovid/work/calibre/src/calibre/gui2/main.py:76 #, python-format msgid "" "Path to Calibre Portable (%s) too long. Must be less than 59 characters." msgstr "" +"Cesta ku Calibre Portable (%s) je príliš dlhá. Musí byť kratšia ako 59 " +"znakov." #: /home/kovid/work/calibre/src/calibre/gui2/main.py:105 #: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:777 @@ -13838,15 +13923,15 @@ msgstr "%s je už spustený." #: /home/kovid/work/calibre/src/calibre/gui2/main.py:370 msgid "No running calibre found" -msgstr "" +msgstr "Nebolo nájdené bežiace Calibre" #: /home/kovid/work/calibre/src/calibre/gui2/main.py:374 msgid "Shutdown command sent, waiting for shutdown..." -msgstr "" +msgstr "Odoslaný príkaz na ukončenie, čakám na ukončenie..." #: /home/kovid/work/calibre/src/calibre/gui2/main.py:379 msgid "Failed to shutdown running calibre instance" -msgstr "" +msgstr "Ukončenie bežiacej inštancie Calibre zlyhalo" #: /home/kovid/work/calibre/src/calibre/gui2/main_window.py:25 msgid "" @@ -13918,7 +14003,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:273 #, python-format msgid "Could not open \"%s\". Is it being used by another program?" -msgstr "" +msgstr "Nemôžem otvoriť \"%s\". Používa ho iný program?" #: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:306 msgid "" @@ -14189,7 +14274,7 @@ msgstr "(Zlyhala obálka)" #: /home/kovid/work/calibre/src/calibre/gui2/metadata/bulk_download.py:200 #, python-format msgid "Processed %s" -msgstr "" +msgstr "Spracované %s" #: /home/kovid/work/calibre/src/calibre/gui2/metadata/config.py:61 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/metadata_sources_ui.py:124 @@ -14266,11 +14351,11 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:162 msgid "Clear series" -msgstr "" +msgstr "Vyčistiť série" #: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:197 msgid "Clear Ids" -msgstr "" +msgstr "Vyčistiť Id" #: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:201 msgid "" @@ -14616,6 +14701,10 @@ msgid "" " If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" +"Ak je voľba nastavená spôsobí, že Calibre bude pri\n" +" automatickom pridávaní kontrolovať, či už súbor\n" +" v knižnici Calibre nie je. Ak je, zobrazí sa otázka,\n" +" či ho má napriek tomu pridať." #: /home/kovid/work/calibre/src/calibre/gui2/preferences/adding_ui.py:152 msgid "Check for &duplicates when auto-adding files" @@ -14640,6 +14729,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/adding_ui.py:155 msgid "Ignore files with the following extensions when automatically adding " msgstr "" +"Pri automatickom pridávaní ignorovať súbory s nasledujúcimi príponami " #: /home/kovid/work/calibre/src/calibre/gui2/preferences/adding_ui.py:156 msgid "Folder to auto-add files from" @@ -14652,6 +14742,7 @@ msgstr "Vyhľadajte priečinok" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/adding_ui.py:159 msgid "Automatically &convert added files to the current output format" msgstr "" +"Pridávané súbory automaticky &konvertovať do aktuálneho výstupného formátu" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/adding_ui.py:160 msgid "&Automatic Adding" @@ -14670,7 +14761,7 @@ msgstr "Nízka" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior.py:36 msgid "Very low" -msgstr "" +msgstr "Veľmi nízka" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior.py:64 msgid "Compact Metadata" @@ -14868,6 +14959,9 @@ msgid "" "eng for English. You can also use the full language name, in which case " "calibre will try to automatically convert it to the language code." msgstr "" +"Zadajte 3-znakový ISO kód jazyka, napr. fra pre Francúzštinu, deu pre " +"Nemčinu, alebo eng pre Angličtinu. Môžete použiť aj plný názov jazyka a v " +"takom prípade sa ho Calibre automaticky pokúsi skonvertovať na kód jazyka." #: /home/kovid/work/calibre/src/calibre/gui2/preferences/coloring.py:225 msgid "Enter a number" @@ -14916,7 +15010,7 @@ msgstr "Podmienku môžete vypnúť vymazaním všetkých jej polí" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/coloring.py:338 msgid "Sample Text" -msgstr "" +msgstr "Vzorka textu" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/coloring.py:380 msgid "Invalid condition" @@ -15465,7 +15559,7 @@ msgstr "Farby" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/device_debug.py:24 msgid "Getting debug information, please wait" -msgstr "" +msgstr "Získavam ladiace informácie, prosím čakajte" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/device_debug.py:25 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/device_user_defined.py:32 @@ -15474,7 +15568,7 @@ msgstr "&Kopírovať do schránky" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/device_debug.py:43 msgid "Device already detected" -msgstr "" +msgstr "Zariadenie už bolo detekované" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/device_debug.py:44 #, python-format @@ -15482,16 +15576,20 @@ msgid "" "A device (%s) is already detected by calibre. If you wish to debug the " "detection of another device, first disconnect this device." msgstr "" +"Zadiadenie (%s) už bolo detekované programom Calibre. Ak chcete ladiť " +"detekciu iného zariadenia, najprv odpojte toto." #: /home/kovid/work/calibre/src/calibre/gui2/preferences/device_debug.py:57 msgid "Debugging failed" -msgstr "" +msgstr "Ladenie zlyhalo" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/device_debug.py:58 msgid "" "Running debug device detection failed. Click Show Details for more " "information." msgstr "" +"Spustenie ladenia detekcie zariadenia zlyhalo. Pre viac informácií kliknite " +"na Zobraziť podrobnosti." #: /home/kovid/work/calibre/src/calibre/gui2/preferences/device_user_defined.py:31 msgid "Getting device information" @@ -15595,6 +15693,8 @@ msgid "" "The list of devices that you have asked calibre to ignore. Uncheck a device " "to have calibre stop ignoring it." msgstr "" +"Zoznam zariadení, ktoré ste chceli, aby Calibre ignorovalo. Odznačte " +"zariadenie, ktoré sa má prestať ignorovať." #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel.py:103 msgid "Narrow" @@ -15606,11 +15706,11 @@ msgstr "Široké" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel.py:105 msgid "Calibre style" -msgstr "" +msgstr "Štýl Calibre" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel.py:105 msgid "System default" -msgstr "" +msgstr "Predvolené nastavenie" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel.py:140 msgid "Off" @@ -15714,11 +15814,11 @@ msgstr "Zmeniť &písmo (vyžaduje reštart)" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:251 msgid "User interface &style (needs restart):" -msgstr "" +msgstr "Š&týl užívateľského rozhrania (vyžaduje reštart):" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:252 msgid "Show &tooltips in the book list" -msgstr "" +msgstr "Zobraziť &tooltipy v zozname kníh" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:253 msgid "Main Interface" @@ -15768,7 +15868,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:265 msgid "Show &cover in the book details panel" -msgstr "" +msgstr "Zobraziť &obálku v paneli podrobností knihy" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:267 msgid "" @@ -15849,7 +15949,7 @@ msgstr "Kategórie s &hiererchickými položkami:" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:290 msgid "Use &alternating row colors in the Tag Browser" -msgstr "" +msgstr "Použiť &striedavú farbu riadkov v Prehliadači značiek" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:292 msgid "Show cover &browser in a separate window (needs restart)" @@ -15905,6 +16005,8 @@ msgid "" "The changes you have made require calibre be restarted immediately. You will " "not be allowed to set any more preferences, until you restart." msgstr "" +"Zmeny, ktoré ste vykonali vyžadujú okamžitý reštart Calibre. Dovtedy " +"nebudete môcť nastavovať žiadne ďalšie predvoľby." #: /home/kovid/work/calibre/src/calibre/gui2/preferences/metadata_sources.py:48 msgid "Source" @@ -16059,7 +16161,7 @@ msgstr "Uprednostniť &menej značiek" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/metadata_sources_ui.py:142 msgid "Use published date of \"first edition\" (from worldcat.org)" -msgstr "" +msgstr "Použite dátum \"prvého vydania\" (z worldcat.org)" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/misc.py:36 msgid "" @@ -16067,6 +16169,9 @@ msgid "" "This refers to CPU intensive tasks like conversion. Lower this number if " "you want calibre to use less CPU." msgstr "" +"Maximálny počet úloh, ktoré budú bežať na pozadí súčasne. Toto platí pre " +"úlohy náročné na CPU, medzi ktoré patrí napr. konverzia. Ak chcete, aby " +"Calibre využívala menej CPU, toto číslo znížte." #: /home/kovid/work/calibre/src/calibre/gui2/preferences/misc.py:46 msgid "No proxies used" @@ -16194,7 +16299,7 @@ msgstr "Zariadenie {0} nepodporuje formát {1}." #: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugboard.py:261 msgid "The {0} device supports only the {1} format(s)." -msgstr "" +msgstr "Zariadenie {0} podporuje len formáť(y) {1}." #: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugboard.py:294 msgid "Invalid destination" @@ -16299,6 +16404,9 @@ msgid "" "\n" "This plugin has been disabled" msgstr "" +"\n" +"\n" +"Tento modul bol zakázaný" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins.py:237 msgid "Search for plugin" @@ -16383,7 +16491,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/save_template.py:66 msgid "Constant template" -msgstr "" +msgstr "Konštantná šablóna" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/save_template.py:67 msgid "" @@ -16487,6 +16595,29 @@ msgid "" "check for duplicates, to find which column contains a particular item, or to " "have hierarchical categories (categories that contain categories)." msgstr "" +"Združené vyhľadávacie termíny sú názvy vyhľadávania, ktoré umožňujú " +"dotazy na automatické prehľadávanie viac ako jedného poľa. Napr. ak " +"vytvoríte združený vyhľadávací termín všetkysérie s hodnotou " +"series, #myseries, #myseries2, potom dotaz " +"všetkysérie:adhoc nájde 'adhoc' v ktoromkoľvek z polí " +"series, #myseries, a #myseries2.

" +"Názov združeného vyhľadávacieho termínu zadajte do vyskakovacieho zoznamu, " +"zoznam polí do zapíšte do poľa hodnota a stlačte tlačidlo Uložiť. " +"

Upozornenie: Názvy vyhľadávacích termínov sú upravené na malé písmená; " +"MojeHľadanie a mojehľadanie označujú rovnaký " +"termín.

Vaše združené vyhľadávacie termíny si môžete nechať zobraziť ako " +"užívateľské kategórie v Prehliadači značiek. Stačí pridať názvy združených " +"vyhľadávacích termínov do poľa Vytvoriť užívateľské kategórie z. Môžete " +"pridať viacero termínov oddelených čiarkami. Nové užívateľské kategórie budú " +"automaticky zaplnené všetkými položkami z polí začlenených do združeného " +"vyhľadávacieho termínu.

Automatické užívateľské polia umožňujú jednoducho " +"vidieť všetky položky z polí obsiahnutých v združenom vyhľadávacom termíne. " +"Pomocou vyššie spomenutého príkladu všetkysérie, bude " +"automaticky generovaná užívateľská kategória obsahovať všetky série, " +"spomenuté v series, #myseries, a " +"#myseries2. To môže byť užitočné pri hľadaní duplikátov, " +"hľadaní ktoré pole obsahuje príslušnú položku, alebo mať hierarchické " +"kategórie (kategórie obsahujúce kategórie)." #: /home/kovid/work/calibre/src/calibre/gui2/preferences/search.py:77 #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:419 @@ -16505,7 +16636,7 @@ msgstr "Nájsť ktorékoľvek" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/search.py:172 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/search_ui.py:176 msgid "Grouped Search Terms" -msgstr "" +msgstr "Združené vyhľadávacie termíny" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/search.py:140 msgid "The search term cannot be blank" @@ -16514,6 +16645,7 @@ msgstr "Hľadaný výraz nemôže byť prázdny" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/search.py:150 msgid "That name is already used for a column or grouped search term" msgstr "" +"Tento názov už bol použitý pre pole, alebo združený vyhľadávací termín" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/search.py:154 msgid "That name is already used for user category" @@ -16525,7 +16657,7 @@ msgstr "Pole hodnoty nemôže byť prázdne" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/search.py:173 msgid "The empty grouped search term cannot be deleted" -msgstr "" +msgstr "Prázdny združený vyhľadávací termín nemôže byť odstránený" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/search_ui.py:168 msgid "Search as you &type" @@ -16615,6 +16747,8 @@ msgid "" "Enter the names of any grouped search terms you wish\n" "to be shown as user categories" msgstr "" +"Zadajte názvy združených vyhľadávacích termínov,\n" +"ktoré chcete zobraziť ako užívateľské kategórie" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/search_ui.py:192 msgid "" @@ -16630,7 +16764,7 @@ msgstr "Vymazať &históriu hľadania" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/search_ui.py:194 msgid "What to search when searching similar books" -msgstr "" +msgstr "Čo porovnávať pri hľadaní podobných kníh" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/search_ui.py:195 msgid "" @@ -16641,22 +16775,27 @@ msgid "" " By changing the lookup name to a grouped search term you can\n" " search multiple columns at once.

" msgstr "" +"

Ak hľadáte podobné knihy pravým kliknutím na knihu a vybraním\n" +" \"Podobné knihy...\", Calibre vytvorí vyhľadávanie pomocou\n" +" vyhľadávacích názvov stĺpcov zvolených nižšie.\n" +" Zmenou vyhľadávacieho názvu na združený vyhľadávací termín\n" +" môžete prehľadávať viacero stĺpcov naraz.

" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/search_ui.py:200 msgid "Similar authors: " -msgstr "" +msgstr "Podobní autori: " #: /home/kovid/work/calibre/src/calibre/gui2/preferences/search_ui.py:201 msgid "Similar series: " -msgstr "" +msgstr "Podobné série: " #: /home/kovid/work/calibre/src/calibre/gui2/preferences/search_ui.py:202 msgid "Similar tags: " -msgstr "" +msgstr "Podobné značky: " #: /home/kovid/work/calibre/src/calibre/gui2/preferences/search_ui.py:203 msgid "Similar publishers: " -msgstr "" +msgstr "Podobní vydavatelia: " #: /home/kovid/work/calibre/src/calibre/gui2/preferences/sending.py:28 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/sending_ui.py:70 @@ -17736,7 +17875,7 @@ msgstr "%p%" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:307 msgid "The grouped search term name is \"{0}\"" -msgstr "" +msgstr "Názov združeného vyhľadávacieho termínu je \"{0}\"" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:766 msgid "" @@ -17900,7 +18039,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:391 msgid "Alter Tag Browser" -msgstr "" +msgstr "Upraviť prehliadač značiek" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:397 #: /home/kovid/work/calibre/src/calibre/library/server/browse.py:276 @@ -19729,6 +19868,10 @@ msgid "" "'+', the default tag for read books.\n" "Applies to: AZW3, ePub, MOBI output formats" msgstr "" +"Regulárny výraz popisujúci značky, ktoré budú odstránené z žánrov.\n" +"Štandardne: '%default' odstráni značky v zátvorkách, napr. '[Projekt " +"Gutenberg]', a '+', štandardnú značku pre čítané knihy.\n" +"Platí pre: výstupné formáty AZW3, ePub a MOBI" #: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi.py:66 msgid "" @@ -19867,7 +20010,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:282 msgid "Check 'Excluded genres' regex in E-book options.\n" -msgstr "" +msgstr "Označte regulárny výraz 'Vynechať žánre' z volieb e-booku.\n" #: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:284 msgid "No books available to catalog" From f4485b5e02d1829fa3e0a1b3260a631b57e06826 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 29 Oct 2012 11:13:55 +0530 Subject: [PATCH 030/107] Windows: Do not change title/author if book files are in use, to prevent (a harmless) mismatch between title/author anf on disk path --- src/calibre/gui2/library/models.py | 10 +++- src/calibre/gui2/metadata/basic_widgets.py | 66 ++++++++++++---------- src/calibre/gui2/metadata/single.py | 10 ++-- src/calibre/library/database2.py | 27 ++++++++- 4 files changed, 75 insertions(+), 38 deletions(-) diff --git a/src/calibre/gui2/library/models.py b/src/calibre/gui2/library/models.py index 641ac23611..49e5c497fe 100644 --- a/src/calibre/gui2/library/models.py +++ b/src/calibre/gui2/library/models.py @@ -871,12 +871,18 @@ class BooksModel(QAbstractTableModel): # {{{ try: return self._set_data(index, value) except (IOError, OSError) as err: + import traceback if getattr(err, 'errno', None) == errno.EACCES: # Permission denied - import traceback + fname = getattr(err, 'filename', None) + p = 'Locked file: %s\n\n'%fname if fname else '' error_dialog(get_gui(), _('Permission denied'), _('Could not change the on disk location of this' ' book. Is it open in another program?'), - det_msg=traceback.format_exc(), show=True) + det_msg=p+traceback.format_exc(), show=True) + return False + error_dialog(get_gui(), _('Failed to set data'), + _('Could not set data, click Show Details to see why.'), + det_msg=traceback.format_exc(), show=True) except: import traceback traceback.print_exc() diff --git a/src/calibre/gui2/metadata/basic_widgets.py b/src/calibre/gui2/metadata/basic_widgets.py index 0da9b1bcf4..409088d315 100644 --- a/src/calibre/gui2/metadata/basic_widgets.py +++ b/src/calibre/gui2/metadata/basic_widgets.py @@ -91,22 +91,26 @@ class TitleEdit(EnLineEdit): def commit(self, db, id_): title = self.current_val - try: - if self.COMMIT: - getattr(db, 'set_'+ self.TITLE_ATTR)(id_, title, notify=False) - else: - getattr(db, 'set_'+ self.TITLE_ATTR)(id_, title, notify=False, - commit=False) - except (IOError, OSError) as err: - if getattr(err, 'errno', -1) == errno.EACCES: # Permission denied - import traceback - fname = err.filename if err.filename else 'file' - error_dialog(self, _('Permission denied'), - _('Could not open %s. Is it being used by another' - ' program?')%fname, det_msg=traceback.format_exc(), - show=True) - return False - raise + if title != self.original_val: + # Only try to commit if changed. This allow setting of other fields + # to work even if some of the book files are opened in windows. + try: + if self.COMMIT: + getattr(db, 'set_'+ self.TITLE_ATTR)(id_, title, notify=False) + else: + getattr(db, 'set_'+ self.TITLE_ATTR)(id_, title, notify=False, + commit=False) + except (IOError, OSError) as err: + if getattr(err, 'errno', None) == errno.EACCES: # Permission denied + import traceback + fname = getattr(err, 'filename', None) + p = 'Locked file: %s\n\n'%fname if fname else '' + error_dialog(self, _('Permission denied'), + _('Could not change the on disk location of this' + ' book. Is it open in another program?'), + det_msg=p+traceback.format_exc(), show=True) + return False + raise return True @dynamic_property @@ -262,19 +266,23 @@ class AuthorsEdit(EditWithComplete): def commit(self, db, id_): authors = self.current_val - try: - self.books_to_refresh |= db.set_authors(id_, authors, notify=False, - allow_case_change=True) - except (IOError, OSError) as err: - if getattr(err, 'errno', -1) == errno.EACCES: # Permission denied - import traceback - fname = err.filename if err.filename else 'file' - error_dialog(self, _('Permission denied'), - _('Could not open "%s". Is it being used by another' - ' program?')%fname, det_msg=traceback.format_exc(), - show=True) - return False - raise + if authors != self.original_val: + # Only try to commit if changed. This allow setting of other fields + # to work even if some of the book files are opened in windows. + try: + self.books_to_refresh |= db.set_authors(id_, authors, notify=False, + allow_case_change=True) + except (IOError, OSError) as err: + if getattr(err, 'errno', None) == errno.EACCES: # Permission denied + import traceback + fname = getattr(err, 'filename', None) + p = 'Locked file: %s\n\n'%fname if fname else '' + error_dialog(self, _('Permission denied'), + _('Could not change the on disk location of this' + ' book. Is it open in another program?'), + det_msg=p+traceback.format_exc(), show=True) + return False + raise return True @dynamic_property diff --git a/src/calibre/gui2/metadata/single.py b/src/calibre/gui2/metadata/single.py index 54067f4c0f..af56e2e657 100644 --- a/src/calibre/gui2/metadata/single.py +++ b/src/calibre/gui2/metadata/single.py @@ -322,6 +322,7 @@ class MetadataSingleDialogBase(ResizableDialog): ' program?')%fname, det_msg=traceback.format_exc(), show=True) return + raise if mi is None: return cdata = None @@ -444,11 +445,12 @@ class MetadataSingleDialogBase(ResizableDialog): except (IOError, OSError) as err: if getattr(err, 'errno', None) == errno.EACCES: # Permission denied import traceback - fname = err.filename if err.filename else 'file' + fname = getattr(err, 'filename', None) + p = 'Locked file: %s\n\n'%fname if fname else '' error_dialog(self, _('Permission denied'), - _('Could not open %s. Is it being used by another' - ' program?')%fname, det_msg=traceback.format_exc(), - show=True) + _('Could not change the on disk location of this' + ' book. Is it open in another program?'), + det_msg=p+traceback.format_exc(), show=True) return False raise for widget in getattr(self, 'custom_metadata_widgets', []): diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py index d4cdf8cc1f..5952e11e57 100644 --- a/src/calibre/library/database2.py +++ b/src/calibre/library/database2.py @@ -2205,13 +2205,14 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): def set(self, row, column, val, allow_case_change=False): ''' - Convenience method for setting the title, authors, publisher or rating + Convenience method for setting the title, authors, publisher, tags or + rating ''' id = self.data[row][0] - col = {'title':1, 'authors':2, 'publisher':3, 'rating':4, 'tags':7}[column] + col = self.FIELD_MAP[column] books_to_refresh = set() - self.data.set(row, col, val) + set_args = (row, col, val) if column == 'authors': val = string_to_authors(val) books_to_refresh |= self.set_authors(id, val, notify=False, @@ -2227,6 +2228,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): books_to_refresh |= \ self.set_tags(id, [x.strip() for x in val.split(',') if x.strip()], append=False, notify=False, allow_case_change=allow_case_change) + self.data.set(*set_args) self.data.refresh_ids(self, [id]) self.set_path(id, True) self.notify('metadata', [id]) @@ -2474,6 +2476,23 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): self.clean_standard_field('authors', commit=True) return books_to_refresh + def windows_check_if_files_in_use(self, book_id): + ''' + Raises an EACCES IOError if any of the files in the folder of book_id + are opened in another program on windows. + ''' + if iswindows: + path = self.path(book_id, index_is_id=True) + if path: + spath = os.path.join(self.library_path, *path.split('/')) + wam = None + if os.path.exists(spath): + try: + wam = WindowsAtomicFolderMove(spath) + finally: + if wam is not None: + wam.close_handles() + def set_authors(self, id, authors, notify=True, commit=True, allow_case_change=False): ''' @@ -2482,6 +2501,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): :param authors: A list of authors. ''' + self.windows_check_if_files_in_use(id) books_to_refresh = self._set_authors(id, authors, allow_case_change=allow_case_change) self.dirtied(set([id])|books_to_refresh, commit=False) @@ -2532,6 +2552,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): Note that even if commit is False, the db will still be committed to because this causes the location of files to change ''' + self.windows_check_if_files_in_use(id) if not self._set_title(id, title): return self.set_path(id, index_is_id=True) From 9c9f0e350c93ba0b5d3af11d890da60afd6ab3a8 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 29 Oct 2012 19:06:33 +0530 Subject: [PATCH 031/107] Fix Science AAAS --- recipes/science_aas.recipe | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipes/science_aas.recipe b/recipes/science_aas.recipe index f94ab1eb99..2d486e4458 100644 --- a/recipes/science_aas.recipe +++ b/recipes/science_aas.recipe @@ -27,7 +27,7 @@ class ScienceAAS(BasicNewsRecipe): br = BasicNewsRecipe.get_browser() if self.username is not None and self.password is not None: br.open(self.LOGIN) - br.select_form(nr=1) + br.select_form(nr=0) br['username'] = self.username br['code' ] = self.password br.submit() From b859653724be604219b9904ea72e2725ee25573f Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 29 Oct 2012 23:25:34 +0530 Subject: [PATCH 032/107] Fix #1072822 (Updated recipe for Financial Times UK edition) --- recipes/financial_times_uk.recipe | 72 ++++++++++++++++--------------- 1 file changed, 38 insertions(+), 34 deletions(-) diff --git a/recipes/financial_times_uk.recipe b/recipes/financial_times_uk.recipe index e2b69f4987..6af000d990 100644 --- a/recipes/financial_times_uk.recipe +++ b/recipes/financial_times_uk.recipe @@ -1,5 +1,5 @@ __license__ = 'GPL v3' -__copyright__ = '2010-2011, Darko Miletic ' +__copyright__ = '2010-2012, Darko Miletic ' ''' www.ft.com/uk-edition ''' @@ -42,18 +42,23 @@ class FinancialTimes(BasicNewsRecipe): def get_browser(self): br = BasicNewsRecipe.get_browser() br.open(self.INDEX) - br.open(self.LOGIN) - br.select_form(name='loginForm') - br['username'] = self.username - br['password'] = self.password - br.submit() + if self.username is not None and self.password is not None: + br.open(self.LOGIN2) + br.select_form(name='loginForm') + br['username'] = self.username + br['password'] = self.password + br.submit() return br keep_only_tags = [ - dict(name='div', attrs={'class':['fullstory fullstoryHeader', 'ft-story-header']}) - ,dict(name='div', attrs={'class':'standfirst'}) - ,dict(name='div', attrs={'id' :'storyContent'}) - ,dict(name='div', attrs={'class':['ft-story-body','index-detail']}) + dict(name='div' , attrs={'class':['fullstory fullstoryHeader', 'ft-story-header']}) + ,dict(name='div' , attrs={'class':'standfirst'}) + ,dict(name='div' , attrs={'id' :'storyContent'}) + ,dict(name='div' , attrs={'class':['ft-story-body','index-detail']}) + ,dict(name='h2' , attrs={'class':'entry-title'} ) + ,dict(name='span', attrs={'class':lambda x: x and 'posted-on' in x.split()} ) + ,dict(name='span', attrs={'class':'author_byline'} ) + ,dict(name='div' , attrs={'class':'entry-content'} ) ] remove_tags = [ dict(name='div', attrs={'id':'floating-con'}) @@ -82,21 +87,20 @@ class FinancialTimes(BasicNewsRecipe): if self.test and count > 2: return articles rawlink = item['href'] - if rawlink.startswith('http://'): - url = rawlink - else: - url = self.PREFIX + rawlink + url = rawlink + if not rawlink.startswith('http://'): + url = self.PREFIX + rawlink try: urlverified = self.browser.open_novisit(url).geturl() # resolve redirect. except: - continue + continue title = self.tag_to_string(item) date = strftime(self.timefmt) articles.append({ - 'title' :title - ,'date' :date - ,'url' :urlverified - ,'description':'' + 'title' :title + ,'date' :date + ,'url' :urlverified + ,'description':'' }) return articles @@ -108,21 +112,20 @@ class FinancialTimes(BasicNewsRecipe): wide = soup.find('div',attrs={'class':'wide'}) if not wide: return feeds - strest = wide.findAll('h3', attrs={'class':'section'}) - if not strest: + allsections = wide.findAll(attrs={'class':lambda x: x and 'footwell' in x.split()}) + if not allsections: return feeds - st = wide.findAll('h4',attrs={'class':'section-no-arrow'}) - if st: - st.extend(strest) count = 0 - for item in st: + for item in allsections: count = count + 1 if self.test and count > 2: return feeds - ftitle = self.tag_to_string(item) + fitem = item.h3 + if not fitem: + fitem = item.h4 + ftitle = self.tag_to_string(fitem) self.report_progress(0, _('Fetching feed')+' %s...'%(ftitle)) - if item.parent.ul is not None: - feedarts = self.get_artlinks(item.parent.ul) + feedarts = self.get_artlinks(item.ul) feeds.append((ftitle,feedarts)) return feeds @@ -156,7 +159,7 @@ class FinancialTimes(BasicNewsRecipe): def get_cover_url(self): cdate = datetime.date.today() if cdate.isoweekday() == 7: - cdate -= datetime.timedelta(days=1) + cdate -= datetime.timedelta(days=1) return cdate.strftime('http://specials.ft.com/vtf_pdf/%d%m%y_FRONT1_LON.pdf') def get_obfuscated_article(self, url): @@ -169,10 +172,11 @@ class FinancialTimes(BasicNewsRecipe): except: print "Retrying download..." count += 1 - self.temp_files.append(PersistentTemporaryFile('_fa.html')) - self.temp_files[-1].write(html) - self.temp_files[-1].close() - return self.temp_files[-1].name + tfile = PersistentTemporaryFile('_fa.html') + tfile.write(html) + tfile.close() + self.temp_files.append(tfile) + return tfile.name def cleanup(self): - self.browser.open('https://registration.ft.com/registration/login/logout?location=') + self.browser.open('https://registration.ft.com/registration/login/logout?location=') \ No newline at end of file From a3e8511e680505c9607e04e09157cc86e2703d05 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 30 Oct 2012 07:54:53 +0530 Subject: [PATCH 033/107] ... --- manual/faq.rst | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/manual/faq.rst b/manual/faq.rst index c8a7b67d27..d7d6367f69 100644 --- a/manual/faq.rst +++ b/manual/faq.rst @@ -674,7 +674,20 @@ If you still cannot get the installer to work and you are on windows, you can us My antivirus program claims |app| is a virus/trojan? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Your antivirus program is wrong. Antivirus programs use heuristics, patterns of code that "looks suspicuous" to detect viruses. It's rather like racial profiling. |app| is a completely open source product. You can actually browse the source code yourself (or hire someone to do it for you) to verify that it is not a virus. Please report the false identification to whatever company you buy your antivirus software from. If the antivirus program is preventing you from downloading/installing |app|, disable it temporarily, install |app| and then re-enable it. +The first thing to check is that you are downloading |app| from the official +website: ``_. |app| is a very popular program +and unscrupulous people try to setup websites offering it for download to fool +the unwary. + +If you have the official download and your antivirus program is still claiming +|app| is a virus, then, your antivirus program is wrong. Antivirus programs use +heuristics, patterns of code that "look suspicious" to detect viruses. It's +rather like racial profiling. |app| is a completely open source product. You +can actually browse the source code yourself (or hire someone to do it for you) +to verify that it is not a virus. Please report the false identification to +whatever company you buy your antivirus software from. If the antivirus program +is preventing you from downloading/installing |app|, disable it temporarily, +install |app| and then re-enable it. How do I backup |app|? ~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 24134a5d5cd85f3dc7ad6568d5c0117800f4d5bf Mon Sep 17 00:00:00 2001 From: Translators <> Date: Tue, 30 Oct 2012 04:44:11 +0000 Subject: [PATCH 034/107] Launchpad automatic translations update. --- setup/iso_639/eu.po | 23 +++++++++--------- src/calibre/translations/eu.po | 14 ++++++----- src/calibre/translations/fr.po | 44 +++++++++++++++++++++++++++------- src/calibre/translations/pl.po | 43 ++++++++++++++++++++------------- 4 files changed, 83 insertions(+), 41 deletions(-) diff --git a/setup/iso_639/eu.po b/setup/iso_639/eu.po index a262c93085..92b3057e51 100644 --- a/setup/iso_639/eu.po +++ b/setup/iso_639/eu.po @@ -9,14 +9,14 @@ msgstr "" "Report-Msgid-Bugs-To: Debian iso-codes team \n" "POT-Creation-Date: 2011-11-25 14:01+0000\n" -"PO-Revision-Date: 2012-04-18 13:08+0000\n" -"Last-Translator: Asier Iturralde Sarasola \n" +"PO-Revision-Date: 2012-10-29 14:16+0000\n" +"Last-Translator: gorkaazk \n" "Language-Team: Euskara \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-04-19 04:36+0000\n" -"X-Generator: Launchpad (build 15108)\n" +"X-Launchpad-Export-Date: 2012-10-30 04:44+0000\n" +"X-Generator: Launchpad (build 16206)\n" "Language: eu\n" #. name for aaa @@ -73,7 +73,7 @@ msgstr "Anambé" #. name for aao msgid "Arabic; Algerian Saharan" -msgstr "" +msgstr "Arabiera, Aljeriako Saharakoa" #. name for aap msgid "Arára; Pará" @@ -181,31 +181,32 @@ msgstr "Abazera" #. name for abr msgid "Abron" -msgstr "" +msgstr "Abron; (bono hizkuntza, Ghana)" #. name for abs msgid "Malay; Ambonese" -msgstr "" +msgstr "Malaysiera; (\"ambonese\" hizkuntza)" #. name for abt msgid "Ambulas" -msgstr "" +msgstr "Ambulas hizkuntza" #. name for abu msgid "Abure" msgstr "" +"Abure hizkuntza (edo abonwa; edo akaplass) (Niger, Kongo, Boli-kosta)" #. name for abv msgid "Arabic; Baharna" -msgstr "" +msgstr "Arabiera; baharna" #. name for abw msgid "Pal" -msgstr "" +msgstr "Pal hizkuntza (Papua)" #. name for abx msgid "Inabaknon" -msgstr "" +msgstr "Inabaknon hizkuntza (edo abaknon, Filipina uharteak)" #. name for aby msgid "Aneme Wake" diff --git a/src/calibre/translations/eu.po b/src/calibre/translations/eu.po index 5db051499c..be2940448a 100644 --- a/src/calibre/translations/eu.po +++ b/src/calibre/translations/eu.po @@ -8,15 +8,15 @@ msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-10-26 05:12+0000\n" -"PO-Revision-Date: 2012-09-19 22:56+0000\n" +"PO-Revision-Date: 2012-10-29 14:23+0000\n" "Last-Translator: gorkaazk \n" "Language-Team: http://librezale.org/wiki/Calibre\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-27 04:38+0000\n" -"X-Generator: Launchpad (build 16194)\n" +"X-Launchpad-Export-Date: 2012-10-30 04:43+0000\n" +"X-Generator: Launchpad (build 16206)\n" "Language: eu\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 @@ -649,7 +649,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1125 #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/mtp_config.py:392 msgid "Ignored devices" -msgstr "" +msgstr "Kontuan hartu ez diren gailuak" #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1131 msgid "" @@ -897,7 +897,7 @@ msgstr "Profil hau Amazon Kindle DX-arentzat zuzendua dago." #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:661 msgid "This profile is intended for the Amazon Kindle PaperWhite" -msgstr "" +msgstr "Profil hau honerako: the Amazon Kindle PaperWhite" #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:672 msgid "This profile is intended for the Amazon Kindle Fire." @@ -1595,7 +1595,7 @@ msgstr "Kokapena %(dl)d • %(typ)s
" #: /home/kovid/work/calibre/src/calibre/devices/kindle/driver.py:289 msgid "Communicate with the Kindle 2/3/4/Touch/PaperWhite eBook reader." -msgstr "" +msgstr "Komunikatu honekin: the Kindle 2/3/4/Touch/PaperWhite eBook reader." #: /home/kovid/work/calibre/src/calibre/devices/kindle/driver.py:301 msgid "Send page number information when sending books" @@ -1827,6 +1827,8 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1211 msgid "The Kobo Touch from firmware V2.0.0 supports bookshelves." msgstr "" +"\" Kobo Touch inprimaki firmwarea\"-ren V2.0.0 bertsioak liburu-apalategiak " +"onartzen ditu." #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1213 msgid "Specify a tags type column for automatic management" diff --git a/src/calibre/translations/fr.po b/src/calibre/translations/fr.po index ff050ef1c4..a435e699e4 100644 --- a/src/calibre/translations/fr.po +++ b/src/calibre/translations/fr.po @@ -8,15 +8,15 @@ msgstr "" "Project-Id-Version: calibre 0.4.22\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-10-26 05:12+0000\n" -"PO-Revision-Date: 2012-10-28 13:56+0000\n" -"Last-Translator: sengian \n" +"PO-Revision-Date: 2012-10-29 20:09+0000\n" +"Last-Translator: Arnaud \n" "Language-Team: PCGen\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Launchpad-Export-Date: 2012-10-29 04:58+0000\n" -"X-Generator: Launchpad (build 16194)\n" +"X-Launchpad-Export-Date: 2012-10-30 04:43+0000\n" +"X-Generator: Launchpad (build 16206)\n" "Language: fr\n" "X-Poedit-Bookmarks: 1177,1104,-1,-1,-1,-1,-1,-1,-1,-1\n" "Generated-By: pygettext.py 1.5\n" @@ -7126,6 +7126,29 @@ msgid "" " library.\n" " " msgstr "" +"

A propos de Tweak Book

\n" +"

Tweak Book vous permet d'ajuster finement l'apparence d'un " +"livre numérique en\n" +" faisant de légères modifications dans sa structure. Pour " +"utiliser Tweak Book,\n" +" yous devez avoir des connaissances en HTML etCSS, technologies " +"utilisées dans\n" +" les livres numériques. Veuillez suivre ces étapes:

\n" +"
\n" +"
    \n" +"
  1. Cliquer sur \"Explode Book\": Ceci va \"séparer\" les " +"différents \n" +" composants interne du livre..
  2. \n" +"
  3. Faire un click droit sur un des fichiers et sélectionner " +"\"Ouvrir avec...\" pour\n" +" l'éditer dans votre éditeur de texte favori.
  4. \n" +"
  5. Quand vous en avez fini avec vos modifications: fermer " +"l'explorateur de fichiers \n" +" et l'éditeur ayant été utilisé pour faire vos modifications. " +"Cliquer alors sur le bouton\n" +" \"Rebuild Book\" pour mettre à jour le livre dans la librairie " +"calibre.
  6. \n" +"
" #: /home/kovid/work/calibre/src/calibre/gui2/actions/tweak_epub.py:103 msgid "&Explode Book" @@ -14543,7 +14566,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:503 msgid "&Number:" -msgstr "&Nombre:" +msgstr "&Numéro :" #: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:603 #, python-format @@ -15215,6 +15238,11 @@ msgid "" " If it is, a message will pop up asking you whether\n" " you want to add it anyway." msgstr "" +"Quand cette option est sélectionnée et qu'un fichier \n" +"a été automatiquement ajouté, Calibre vérifie \n" +"préalablement si ce fichier existe déjà dans la librairie calibre.\n" +"Si c'est le cas, un message vous demandera si vous souhaitez \n" +"tout de même l'ajouter." #: /home/kovid/work/calibre/src/calibre/gui2/preferences/adding_ui.py:152 msgid "Check for &duplicates when auto-adding files" @@ -15768,7 +15796,7 @@ msgstr "Le nom des gens" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/create_custom_column.py:76 msgid "Number" -msgstr "Nombre" +msgstr "Numéro" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/create_custom_column.py:76 msgid "Text" @@ -16693,7 +16721,7 @@ msgstr "Echanger les noms des auteurs de PR. NOM à NOM, PR." #: /home/kovid/work/calibre/src/calibre/gui2/preferences/metadata_sources_ui.py:134 msgid "Max. number of &tags to download:" -msgstr "Nombre max. d’étiquettes à télécharger:" +msgstr "Nombre max. d’étiquettes à télécharger :" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/metadata_sources_ui.py:135 msgid "Max. &time to wait after first match is found:" @@ -21166,7 +21194,7 @@ msgstr "Définir les séries du(es) livre(s) ajouté(s)" #: /home/kovid/work/calibre/src/calibre/library/cli.py:328 msgid "Set the series number of the added book(s)" -msgstr "Assigne le numéro de la série des livres ajoutés" +msgstr "Assigne le numéro de la série de(s) livre(s) ajoutés" #: /home/kovid/work/calibre/src/calibre/library/cli.py:363 msgid "You must specify at least one file to add" diff --git a/src/calibre/translations/pl.po b/src/calibre/translations/pl.po index 5126cc3c5f..e1aa0ae91a 100644 --- a/src/calibre/translations/pl.po +++ b/src/calibre/translations/pl.po @@ -8,16 +8,16 @@ msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-10-26 05:12+0000\n" -"PO-Revision-Date: 2012-09-29 16:04+0000\n" -"Last-Translator: Piotr Parafiniuk \n" +"PO-Revision-Date: 2012-10-29 17:08+0000\n" +"Last-Translator: Marcin Ostajewski (panszpik) \n" "Language-Team: Polish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " "|| n%100>=20) ? 1 : 2;\n" -"X-Launchpad-Export-Date: 2012-10-27 04:50+0000\n" -"X-Generator: Launchpad (build 16194)\n" +"X-Launchpad-Export-Date: 2012-10-30 04:43+0000\n" +"X-Generator: Launchpad (build 16206)\n" "X-Poedit-Bookmarks: -1,3588,-1,-1,-1,-1,-1,-1,-1,-1\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 @@ -633,13 +633,15 @@ msgstr "Kontroluj sposób, w jaki calibre pobiera metadane z Sieci" #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1125 #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/mtp_config.py:392 msgid "Ignored devices" -msgstr "" +msgstr "Ignorowane urządzenia" #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1131 msgid "" "Control which devices calibre will ignore when they are connected to the " "computer." msgstr "" +"Konfiguruje urządzenia ignorowane przez calibre przy podłączeniu do " +"komputera." #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1138 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins.py:295 @@ -1838,11 +1840,11 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1218 msgid "Upload covers for books" -msgstr "" +msgstr "Wgraj okładki książek" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1224 msgid "Always upload covers" -msgstr "" +msgstr "Zawsze wgrywaj okładki książek" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1225 msgid "" @@ -6774,15 +6776,15 @@ msgstr "Szukaj ebooków" #: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:28 msgid "this author" -msgstr "ten autor" +msgstr "tego autora" #: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:28 msgid "this title" -msgstr "ten tytuł" +msgstr "tego tytułu" #: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:29 msgid "this book" -msgstr "ta książka" +msgstr "tej książki" #: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:32 #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/view.py:469 @@ -7143,11 +7145,11 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/add.py:387 msgid "Already in calibre:" -msgstr "" +msgstr "Już obecne w calibre:" #: /home/kovid/work/calibre/src/calibre/gui2/add.py:395 msgid "You are trying to add:" -msgstr "" +msgstr "Próbujesz dodać:" #: /home/kovid/work/calibre/src/calibre/gui2/add.py:400 #: /home/kovid/work/calibre/src/calibre/gui2/auto_add.py:223 @@ -7159,6 +7161,7 @@ msgid "" "Books with the same title as the following already exist in calibre. Add " "them anyway?" msgstr "" +"Książki o podanych poniżej tytułach już figurują w calibre. Dodać je mimo to?" #: /home/kovid/work/calibre/src/calibre/gui2/add.py:404 msgid "Adding duplicates..." @@ -9786,7 +9789,7 @@ msgstr "Błąd podczas komunikacji z urządzeniem" #: /home/kovid/work/calibre/src/calibre/gui2/device.py:860 #, python-format msgid "Manage the %s?" -msgstr "" +msgstr "Zarządzać %s?" #: /home/kovid/work/calibre/src/calibre/gui2/device.py:861 #, python-format @@ -10026,6 +10029,9 @@ msgid "" "Select the devices to be ignored. calibre will not\n" " connect to devices with a checkmark next to their names." msgstr "" +"Wybierz urządzenia, które calibre ma ignorować. Calibre nie " +"połączy\n" +" się z urządzeniami z zaznaczeniem obok nazwy." #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/mtp_config.py:212 #, python-format @@ -13383,7 +13389,7 @@ msgstr "Wyrażenie regularne (?P)" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:122 msgid "Choose font family" -msgstr "" +msgstr "Wybór rodziny czcionek" #: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:137 #: /home/kovid/work/calibre/src/calibre/gui2/keyboard.py:377 @@ -15829,6 +15835,8 @@ msgid "" "The list of devices that you have asked calibre to ignore. Uncheck a device " "to have calibre stop ignoring it." msgstr "" +"Lista urządzeń, które oznaczono jako ignorowane. Wyczyść pole przy " +"urządzeniu jeśli calibre nie powinien już go ignorować." #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel.py:103 msgid "Narrow" @@ -16543,6 +16551,9 @@ msgid "" "\n" "This plugin has been disabled" msgstr "" +"\n" +"\n" +"Ta wtyczka została wyłączona" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins.py:237 msgid "Search for plugin" @@ -19283,7 +19294,7 @@ msgstr "Nie można otworzyć książki" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979 msgid "Unknown error" -msgstr "" +msgstr "Nieznany błąd" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094 msgid "Options to control the ebook viewer" @@ -21934,7 +21945,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/utils/filenames.py:284 msgid "File is open in another process" -msgstr "" +msgstr "Plik jest otwarty przez inny proces" #: /home/kovid/work/calibre/src/calibre/utils/formatter.py:31 #: /home/kovid/work/calibre/src/calibre/utils/formatter.py:182 From 1156e2f0d3197f66ee93d1db399aebbabce797cf Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 30 Oct 2012 11:04:06 +0530 Subject: [PATCH 035/107] Import sfntly into the calibre source tree --- src/sfntly/COPYING.txt | 203 +++ src/sfntly/src/sfntly/data/byte_array.cc | 199 +++ src/sfntly/src/sfntly/data/byte_array.h | 201 +++ src/sfntly/src/sfntly/data/font_data.cc | 82 ++ src/sfntly/src/sfntly/data/font_data.h | 135 ++ .../src/sfntly/data/font_input_stream.cc | 141 ++ .../src/sfntly/data/font_input_stream.h | 97 ++ .../src/sfntly/data/font_output_stream.cc | 130 ++ .../src/sfntly/data/font_output_stream.h | 79 + .../sfntly/data/growable_memory_byte_array.cc | 82 ++ .../sfntly/data/growable_memory_byte_array.h | 66 + .../src/sfntly/data/memory_byte_array.cc | 93 ++ .../src/sfntly/data/memory_byte_array.h | 81 ++ .../src/sfntly/data/readable_font_data.cc | 336 +++++ .../src/sfntly/data/readable_font_data.h | 308 ++++ .../src/sfntly/data/writable_font_data.cc | 201 +++ .../src/sfntly/data/writable_font_data.h | 211 +++ src/sfntly/src/sfntly/font.cc | 557 +++++++ src/sfntly/src/sfntly/font.h | 352 +++++ src/sfntly/src/sfntly/font_factory.cc | 214 +++ src/sfntly/src/sfntly/font_factory.h | 140 ++ src/sfntly/src/sfntly/math/fixed1616.h | 41 + src/sfntly/src/sfntly/math/font_math.h | 49 + src/sfntly/src/sfntly/port/atomic.h | 71 + src/sfntly/src/sfntly/port/config.h | 28 + src/sfntly/src/sfntly/port/endian.h | 77 + src/sfntly/src/sfntly/port/exception_type.h | 125 ++ .../src/sfntly/port/file_input_stream.cc | 169 +++ .../src/sfntly/port/file_input_stream.h | 57 + src/sfntly/src/sfntly/port/input_stream.h | 49 + src/sfntly/src/sfntly/port/java_iterator.h | 94 ++ src/sfntly/src/sfntly/port/lock.cc | 72 + src/sfntly/src/sfntly/port/lock.h | 76 + .../src/sfntly/port/memory_input_stream.cc | 147 ++ .../src/sfntly/port/memory_input_stream.h | 57 + .../src/sfntly/port/memory_output_stream.cc | 72 + .../src/sfntly/port/memory_output_stream.h | 51 + src/sfntly/src/sfntly/port/output_stream.h | 46 + src/sfntly/src/sfntly/port/refcount.h | 277 ++++ src/sfntly/src/sfntly/port/type.h | 102 ++ .../sfntly/table/bitmap/big_glyph_metrics.cc | 171 +++ .../sfntly/table/bitmap/big_glyph_metrics.h | 96 ++ .../src/sfntly/table/bitmap/bitmap_glyph.cc | 101 ++ .../src/sfntly/table/bitmap/bitmap_glyph.h | 119 ++ .../sfntly/table/bitmap/bitmap_glyph_info.cc | 68 + .../sfntly/table/bitmap/bitmap_glyph_info.h | 85 ++ .../sfntly/table/bitmap/bitmap_size_table.cc | 604 ++++++++ .../sfntly/table/bitmap/bitmap_size_table.h | 173 +++ .../table/bitmap/composite_bitmap_glyph.cc | 109 ++ .../table/bitmap/composite_bitmap_glyph.h | 75 + .../src/sfntly/table/bitmap/ebdt_table.cc | 236 +++ .../src/sfntly/table/bitmap/ebdt_table.h | 108 ++ .../src/sfntly/table/bitmap/eblc_table.cc | 313 ++++ .../src/sfntly/table/bitmap/eblc_table.h | 194 +++ .../src/sfntly/table/bitmap/ebsc_table.cc | 107 ++ .../src/sfntly/table/bitmap/ebsc_table.h | 101 ++ .../src/sfntly/table/bitmap/glyph_metrics.cc | 39 + .../src/sfntly/table/bitmap/glyph_metrics.h | 43 + .../sfntly/table/bitmap/index_sub_table.cc | 278 ++++ .../src/sfntly/table/bitmap/index_sub_table.h | 178 +++ .../table/bitmap/index_sub_table_format1.cc | 299 ++++ .../table/bitmap/index_sub_table_format1.h | 116 ++ .../table/bitmap/index_sub_table_format2.cc | 272 ++++ .../table/bitmap/index_sub_table_format2.h | 106 ++ .../table/bitmap/index_sub_table_format3.cc | 295 ++++ .../table/bitmap/index_sub_table_format3.h | 113 ++ .../table/bitmap/index_sub_table_format4.cc | 381 +++++ .../table/bitmap/index_sub_table_format4.h | 135 ++ .../table/bitmap/index_sub_table_format5.cc | 344 +++++ .../table/bitmap/index_sub_table_format5.h | 118 ++ .../table/bitmap/simple_bitmap_glyph.cc | 45 + .../sfntly/table/bitmap/simple_bitmap_glyph.h | 44 + .../table/bitmap/small_glyph_metrics.cc | 126 ++ .../sfntly/table/bitmap/small_glyph_metrics.h | 79 + .../sfntly/table/byte_array_table_builder.cc | 70 + .../sfntly/table/byte_array_table_builder.h | 53 + .../src/sfntly/table/core/cmap_table.cc | 1288 +++++++++++++++++ src/sfntly/src/sfntly/table/core/cmap_table.h | 711 +++++++++ .../sfntly/table/core/font_header_table.cc | 265 ++++ .../src/sfntly/table/core/font_header_table.h | 168 +++ .../core/horizontal_device_metrics_table.cc | 124 ++ .../core/horizontal_device_metrics_table.h | 82 ++ .../table/core/horizontal_header_table.cc | 213 +++ .../table/core/horizontal_header_table.h | 111 ++ .../table/core/horizontal_metrics_table.cc | 138 ++ .../table/core/horizontal_metrics_table.h | 87 ++ .../table/core/maximum_profile_table.cc | 240 +++ .../sfntly/table/core/maximum_profile_table.h | 120 ++ .../src/sfntly/table/core/name_table.cc | 721 +++++++++ src/sfntly/src/sfntly/table/core/name_table.h | 744 ++++++++++ src/sfntly/src/sfntly/table/core/os2_table.cc | 608 ++++++++ src/sfntly/src/sfntly/table/core/os2_table.h | 508 +++++++ .../src/sfntly/table/font_data_table.cc | 193 +++ src/sfntly/src/sfntly/table/font_data_table.h | 123 ++ .../src/sfntly/table/generic_table_builder.cc | 49 + .../src/sfntly/table/generic_table_builder.h | 42 + src/sfntly/src/sfntly/table/header.cc | 66 + src/sfntly/src/sfntly/table/header.h | 114 ++ src/sfntly/src/sfntly/table/subtable.cc | 64 + src/sfntly/src/sfntly/table/subtable.h | 73 + .../sfntly/table/subtable_container_table.h | 48 + src/sfntly/src/sfntly/table/table.cc | 162 +++ src/sfntly/src/sfntly/table/table.h | 119 ++ .../sfntly/table/table_based_table_builder.cc | 69 + .../sfntly/table/table_based_table_builder.h | 48 + .../src/sfntly/table/truetype/glyph_table.cc | 679 +++++++++ .../src/sfntly/table/truetype/glyph_table.h | 335 +++++ .../src/sfntly/table/truetype/loca_table.cc | 246 ++++ .../src/sfntly/table/truetype/loca_table.h | 183 +++ src/sfntly/src/sfntly/tag.cc | 110 ++ src/sfntly/src/sfntly/tag.h | 123 ++ .../tools/subsetter/glyph_table_subsetter.cc | 90 ++ .../tools/subsetter/glyph_table_subsetter.h | 37 + .../src/sfntly/tools/subsetter/subsetter.cc | 102 ++ .../src/sfntly/tools/subsetter/subsetter.h | 72 + .../sfntly/tools/subsetter/table_subsetter.h | 39 + .../tools/subsetter/table_subsetter_impl.cc | 38 + .../tools/subsetter/table_subsetter_impl.h | 37 + 118 files changed, 20751 insertions(+) create mode 100644 src/sfntly/COPYING.txt create mode 100644 src/sfntly/src/sfntly/data/byte_array.cc create mode 100644 src/sfntly/src/sfntly/data/byte_array.h create mode 100644 src/sfntly/src/sfntly/data/font_data.cc create mode 100644 src/sfntly/src/sfntly/data/font_data.h create mode 100644 src/sfntly/src/sfntly/data/font_input_stream.cc create mode 100644 src/sfntly/src/sfntly/data/font_input_stream.h create mode 100644 src/sfntly/src/sfntly/data/font_output_stream.cc create mode 100644 src/sfntly/src/sfntly/data/font_output_stream.h create mode 100644 src/sfntly/src/sfntly/data/growable_memory_byte_array.cc create mode 100644 src/sfntly/src/sfntly/data/growable_memory_byte_array.h create mode 100644 src/sfntly/src/sfntly/data/memory_byte_array.cc create mode 100644 src/sfntly/src/sfntly/data/memory_byte_array.h create mode 100644 src/sfntly/src/sfntly/data/readable_font_data.cc create mode 100644 src/sfntly/src/sfntly/data/readable_font_data.h create mode 100644 src/sfntly/src/sfntly/data/writable_font_data.cc create mode 100644 src/sfntly/src/sfntly/data/writable_font_data.h create mode 100644 src/sfntly/src/sfntly/font.cc create mode 100644 src/sfntly/src/sfntly/font.h create mode 100644 src/sfntly/src/sfntly/font_factory.cc create mode 100644 src/sfntly/src/sfntly/font_factory.h create mode 100644 src/sfntly/src/sfntly/math/fixed1616.h create mode 100644 src/sfntly/src/sfntly/math/font_math.h create mode 100644 src/sfntly/src/sfntly/port/atomic.h create mode 100644 src/sfntly/src/sfntly/port/config.h create mode 100644 src/sfntly/src/sfntly/port/endian.h create mode 100644 src/sfntly/src/sfntly/port/exception_type.h create mode 100644 src/sfntly/src/sfntly/port/file_input_stream.cc create mode 100644 src/sfntly/src/sfntly/port/file_input_stream.h create mode 100644 src/sfntly/src/sfntly/port/input_stream.h create mode 100644 src/sfntly/src/sfntly/port/java_iterator.h create mode 100644 src/sfntly/src/sfntly/port/lock.cc create mode 100644 src/sfntly/src/sfntly/port/lock.h create mode 100755 src/sfntly/src/sfntly/port/memory_input_stream.cc create mode 100755 src/sfntly/src/sfntly/port/memory_input_stream.h create mode 100644 src/sfntly/src/sfntly/port/memory_output_stream.cc create mode 100644 src/sfntly/src/sfntly/port/memory_output_stream.h create mode 100644 src/sfntly/src/sfntly/port/output_stream.h create mode 100644 src/sfntly/src/sfntly/port/refcount.h create mode 100644 src/sfntly/src/sfntly/port/type.h create mode 100644 src/sfntly/src/sfntly/table/bitmap/big_glyph_metrics.cc create mode 100644 src/sfntly/src/sfntly/table/bitmap/big_glyph_metrics.h create mode 100644 src/sfntly/src/sfntly/table/bitmap/bitmap_glyph.cc create mode 100644 src/sfntly/src/sfntly/table/bitmap/bitmap_glyph.h create mode 100644 src/sfntly/src/sfntly/table/bitmap/bitmap_glyph_info.cc create mode 100644 src/sfntly/src/sfntly/table/bitmap/bitmap_glyph_info.h create mode 100644 src/sfntly/src/sfntly/table/bitmap/bitmap_size_table.cc create mode 100644 src/sfntly/src/sfntly/table/bitmap/bitmap_size_table.h create mode 100644 src/sfntly/src/sfntly/table/bitmap/composite_bitmap_glyph.cc create mode 100644 src/sfntly/src/sfntly/table/bitmap/composite_bitmap_glyph.h create mode 100644 src/sfntly/src/sfntly/table/bitmap/ebdt_table.cc create mode 100644 src/sfntly/src/sfntly/table/bitmap/ebdt_table.h create mode 100644 src/sfntly/src/sfntly/table/bitmap/eblc_table.cc create mode 100644 src/sfntly/src/sfntly/table/bitmap/eblc_table.h create mode 100644 src/sfntly/src/sfntly/table/bitmap/ebsc_table.cc create mode 100644 src/sfntly/src/sfntly/table/bitmap/ebsc_table.h create mode 100644 src/sfntly/src/sfntly/table/bitmap/glyph_metrics.cc create mode 100644 src/sfntly/src/sfntly/table/bitmap/glyph_metrics.h create mode 100644 src/sfntly/src/sfntly/table/bitmap/index_sub_table.cc create mode 100644 src/sfntly/src/sfntly/table/bitmap/index_sub_table.h create mode 100644 src/sfntly/src/sfntly/table/bitmap/index_sub_table_format1.cc create mode 100644 src/sfntly/src/sfntly/table/bitmap/index_sub_table_format1.h create mode 100644 src/sfntly/src/sfntly/table/bitmap/index_sub_table_format2.cc create mode 100644 src/sfntly/src/sfntly/table/bitmap/index_sub_table_format2.h create mode 100644 src/sfntly/src/sfntly/table/bitmap/index_sub_table_format3.cc create mode 100644 src/sfntly/src/sfntly/table/bitmap/index_sub_table_format3.h create mode 100644 src/sfntly/src/sfntly/table/bitmap/index_sub_table_format4.cc create mode 100644 src/sfntly/src/sfntly/table/bitmap/index_sub_table_format4.h create mode 100644 src/sfntly/src/sfntly/table/bitmap/index_sub_table_format5.cc create mode 100644 src/sfntly/src/sfntly/table/bitmap/index_sub_table_format5.h create mode 100644 src/sfntly/src/sfntly/table/bitmap/simple_bitmap_glyph.cc create mode 100644 src/sfntly/src/sfntly/table/bitmap/simple_bitmap_glyph.h create mode 100644 src/sfntly/src/sfntly/table/bitmap/small_glyph_metrics.cc create mode 100644 src/sfntly/src/sfntly/table/bitmap/small_glyph_metrics.h create mode 100644 src/sfntly/src/sfntly/table/byte_array_table_builder.cc create mode 100644 src/sfntly/src/sfntly/table/byte_array_table_builder.h create mode 100644 src/sfntly/src/sfntly/table/core/cmap_table.cc create mode 100644 src/sfntly/src/sfntly/table/core/cmap_table.h create mode 100644 src/sfntly/src/sfntly/table/core/font_header_table.cc create mode 100644 src/sfntly/src/sfntly/table/core/font_header_table.h create mode 100644 src/sfntly/src/sfntly/table/core/horizontal_device_metrics_table.cc create mode 100644 src/sfntly/src/sfntly/table/core/horizontal_device_metrics_table.h create mode 100644 src/sfntly/src/sfntly/table/core/horizontal_header_table.cc create mode 100644 src/sfntly/src/sfntly/table/core/horizontal_header_table.h create mode 100644 src/sfntly/src/sfntly/table/core/horizontal_metrics_table.cc create mode 100644 src/sfntly/src/sfntly/table/core/horizontal_metrics_table.h create mode 100644 src/sfntly/src/sfntly/table/core/maximum_profile_table.cc create mode 100644 src/sfntly/src/sfntly/table/core/maximum_profile_table.h create mode 100644 src/sfntly/src/sfntly/table/core/name_table.cc create mode 100644 src/sfntly/src/sfntly/table/core/name_table.h create mode 100644 src/sfntly/src/sfntly/table/core/os2_table.cc create mode 100644 src/sfntly/src/sfntly/table/core/os2_table.h create mode 100644 src/sfntly/src/sfntly/table/font_data_table.cc create mode 100644 src/sfntly/src/sfntly/table/font_data_table.h create mode 100644 src/sfntly/src/sfntly/table/generic_table_builder.cc create mode 100644 src/sfntly/src/sfntly/table/generic_table_builder.h create mode 100644 src/sfntly/src/sfntly/table/header.cc create mode 100644 src/sfntly/src/sfntly/table/header.h create mode 100644 src/sfntly/src/sfntly/table/subtable.cc create mode 100644 src/sfntly/src/sfntly/table/subtable.h create mode 100644 src/sfntly/src/sfntly/table/subtable_container_table.h create mode 100644 src/sfntly/src/sfntly/table/table.cc create mode 100644 src/sfntly/src/sfntly/table/table.h create mode 100644 src/sfntly/src/sfntly/table/table_based_table_builder.cc create mode 100644 src/sfntly/src/sfntly/table/table_based_table_builder.h create mode 100644 src/sfntly/src/sfntly/table/truetype/glyph_table.cc create mode 100644 src/sfntly/src/sfntly/table/truetype/glyph_table.h create mode 100644 src/sfntly/src/sfntly/table/truetype/loca_table.cc create mode 100644 src/sfntly/src/sfntly/table/truetype/loca_table.h create mode 100644 src/sfntly/src/sfntly/tag.cc create mode 100644 src/sfntly/src/sfntly/tag.h create mode 100644 src/sfntly/src/sfntly/tools/subsetter/glyph_table_subsetter.cc create mode 100644 src/sfntly/src/sfntly/tools/subsetter/glyph_table_subsetter.h create mode 100644 src/sfntly/src/sfntly/tools/subsetter/subsetter.cc create mode 100644 src/sfntly/src/sfntly/tools/subsetter/subsetter.h create mode 100644 src/sfntly/src/sfntly/tools/subsetter/table_subsetter.h create mode 100644 src/sfntly/src/sfntly/tools/subsetter/table_subsetter_impl.cc create mode 100644 src/sfntly/src/sfntly/tools/subsetter/table_subsetter_impl.h diff --git a/src/sfntly/COPYING.txt b/src/sfntly/COPYING.txt new file mode 100644 index 0000000000..c61423cfed --- /dev/null +++ b/src/sfntly/COPYING.txt @@ -0,0 +1,203 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2011 Google Inc. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/src/sfntly/src/sfntly/data/byte_array.cc b/src/sfntly/src/sfntly/data/byte_array.cc new file mode 100644 index 0000000000..915a40c035 --- /dev/null +++ b/src/sfntly/src/sfntly/data/byte_array.cc @@ -0,0 +1,199 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/data/byte_array.h" + +#include + +#include "sfntly/port/exception_type.h" + +namespace sfntly { + +const int32_t ByteArray::COPY_BUFFER_SIZE = 8192; + +ByteArray::~ByteArray() {} + +int32_t ByteArray::Length() { return filled_length_; } +int32_t ByteArray::Size() { return storage_length_; } + +int32_t ByteArray::SetFilledLength(int32_t filled_length) { + filled_length_ = std::min(filled_length, storage_length_); + return filled_length_; +} + +int32_t ByteArray::Get(int32_t index) { + return InternalGet(index) & 0xff; +} + +int32_t ByteArray::Get(int32_t index, ByteVector* b) { + assert(b); + return Get(index, &((*b)[0]), 0, b->size()); +} + +int32_t ByteArray::Get(int32_t index, + byte_t* b, + int32_t offset, + int32_t length) { + assert(b); + if (index < 0 || index >= filled_length_) { + return 0; + } + int32_t actual_length = std::min(length, filled_length_ - index); + return InternalGet(index, b, offset, actual_length); +} + +void ByteArray::Put(int32_t index, byte_t b) { + if (index < 0 || index >= Size()) { +#if defined (SFNTLY_NO_EXCEPTION) + return; +#else + throw IndexOutOfBoundException( + "Attempt to write outside the bounds of the data"); +#endif + } + InternalPut(index, b); + filled_length_ = std::max(filled_length_, index + 1); +} + +int32_t ByteArray::Put(int index, ByteVector* b) { + assert(b); + return Put(index, &((*b)[0]), 0, b->size()); +} + +int32_t ByteArray::Put(int32_t index, + byte_t* b, + int32_t offset, + int32_t length) { + assert(b); + if (index < 0 || index >= Size()) { +#if defined (SFNTLY_NO_EXCEPTION) + return 0; +#else + throw IndexOutOfBoundException( + "Attempt to write outside the bounds of the data"); +#endif + } + int32_t actual_length = std::min(length, Size() - index); + int32_t bytes_written = InternalPut(index, b, offset, actual_length); + filled_length_ = std::max(filled_length_, index + bytes_written); + return bytes_written; +} + +int32_t ByteArray::CopyTo(ByteArray* array) { + return CopyTo(array, 0, Length()); +} + +int32_t ByteArray::CopyTo(ByteArray* array, int32_t offset, int32_t length) { + return CopyTo(0, array, offset, length); +} + +int32_t ByteArray::CopyTo(int32_t dst_offset, ByteArray* array, + int32_t src_offset, int32_t length) { + assert(array); + if (array->Size() < dst_offset + length) { // insufficient space + return -1; + } + + ByteVector b(COPY_BUFFER_SIZE); + int32_t bytes_read = 0; + int32_t index = 0; + int32_t remaining_length = length; + int32_t buffer_length = std::min(COPY_BUFFER_SIZE, length); + while ((bytes_read = + Get(index + src_offset, &(b[0]), 0, buffer_length)) > 0) { + int bytes_written = array->Put(index + dst_offset, &(b[0]), 0, bytes_read); + UNREFERENCED_PARAMETER(bytes_written); + index += bytes_read; + remaining_length -= bytes_read; + buffer_length = std::min(b.size(), remaining_length); + } + return index; +} + +int32_t ByteArray::CopyTo(OutputStream* os) { + return CopyTo(os, 0, Length()); +} + +int32_t ByteArray::CopyTo(OutputStream* os, int32_t offset, int32_t length) { + ByteVector b(COPY_BUFFER_SIZE); + int32_t bytes_read = 0; + int32_t index = 0; + int32_t buffer_length = std::min(COPY_BUFFER_SIZE, length); + while ((bytes_read = Get(index + offset, &(b[0]), 0, buffer_length)) > 0) { + os->Write(&b, 0, bytes_read); + index += bytes_read; + buffer_length = std::min(b.size(), length - index); + } + return index; +} + +bool ByteArray::CopyFrom(InputStream* is, int32_t length) { + ByteVector b(COPY_BUFFER_SIZE); + int32_t bytes_read = 0; + int32_t index = 0; + int32_t buffer_length = std::min(COPY_BUFFER_SIZE, length); + while ((bytes_read = is->Read(&b, 0, buffer_length)) > 0) { + if (Put(index, &(b[0]), 0, bytes_read) != bytes_read) { +#if defined (SFNTLY_NO_EXCEPTION) + return 0; +#else + throw IOException("Error writing bytes."); +#endif + } + index += bytes_read; + length -= bytes_read; + buffer_length = std::min(b.size(), length); + } + return true; +} + +bool ByteArray::CopyFrom(InputStream* is) { + ByteVector b(COPY_BUFFER_SIZE); + int32_t bytes_read = 0; + int32_t index = 0; + int32_t buffer_length = COPY_BUFFER_SIZE; + while ((bytes_read = is->Read(&b, 0, buffer_length)) > 0) { + if (Put(index, &b[0], 0, bytes_read) != bytes_read) { +#if defined (SFNTLY_NO_EXCEPTION) + return 0; +#else + throw IOException("Error writing bytes."); +#endif + } + index += bytes_read; + } + return true; +} + +ByteArray::ByteArray(int32_t filled_length, + int32_t storage_length, + bool growable) { + Init(filled_length, storage_length, growable); +} + +ByteArray::ByteArray(int32_t filled_length, int32_t storage_length) { + Init(filled_length, storage_length, false); +} + +void ByteArray::Init(int32_t filled_length, + int32_t storage_length, + bool growable) { + storage_length_ = storage_length; + growable_ = growable; + SetFilledLength(filled_length); +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/data/byte_array.h b/src/sfntly/src/sfntly/data/byte_array.h new file mode 100644 index 0000000000..70dc92f51a --- /dev/null +++ b/src/sfntly/src/sfntly/data/byte_array.h @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2011 The sfntly Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_BYTE_ARRAY_H_ +#define SFNTLY_CPP_SRC_SFNTLY_DATA_BYTE_ARRAY_H_ + +#include "sfntly/port/refcount.h" +#include "sfntly/port/type.h" +#include "sfntly/port/input_stream.h" +#include "sfntly/port/output_stream.h" + +namespace sfntly { + +// An abstraction to a contiguous array of bytes. +// C++ port of this class assumes that the data are stored in a linear region +// like std::vector. +class ByteArray : virtual public RefCount { + public: + virtual ~ByteArray(); + + // Gets the current filled and readable length of the array. + int32_t Length(); + + // Gets the maximum size of the array. This is the maximum number of bytes that + // the array can hold and all of it may not be filled with data or even fully + // allocated yet. + int32_t Size(); + + // Determines whether or not this array is growable or of fixed size. + bool growable() { return growable_; } + + int32_t SetFilledLength(int32_t filled_length); + + // Gets the byte from the given index. + // @param index the index into the byte array + // @return the byte or -1 if reading beyond the bounds of the data + virtual int32_t Get(int32_t index); + + // Gets the bytes from the given index and fill the buffer with them. As many + // bytes as will fit into the buffer are read unless that would go past the + // end of the array. + // @param index the index into the byte array + // @param b the buffer to put the bytes read into + // @return the number of bytes read from the buffer + virtual int32_t Get(int32_t index, ByteVector* b); + + // Gets the bytes from the given index and fill the buffer with them starting + // at the offset given. As many bytes as the specified length are read unless + // that would go past the end of the array. + // @param index the index into the byte array + // @param b the buffer to put the bytes read into + // @param offset the location in the buffer to start putting the bytes + // @param length the number of bytes to put into the buffer + // @return the number of bytes read from the buffer + virtual int32_t Get(int32_t index, + byte_t* b, + int32_t offset, + int32_t length); + + // Puts the specified byte into the array at the given index unless that would + // be beyond the length of the array and it isn't growable. + virtual void Put(int32_t index, byte_t b); + + // Puts the specified bytes into the array at the given index. The entire + // buffer is put into the array unless that would extend beyond the length and + // the array isn't growable. + virtual int32_t Put(int32_t index, ByteVector* b); + + // Puts the specified bytes into the array at the given index. All of the bytes + // specified are put into the array unless that would extend beyond the length + // and the array isn't growable. The bytes to be put into the array are those + // in the buffer from the given offset and for the given length. + // @param index the index into the ByteArray + // @param b the bytes to put into the array + // @param offset the offset in the bytes to start copying from + // @param length the number of bytes to copy into the array + // @return the number of bytes actually written + virtual int32_t Put(int32_t index, + byte_t* b, + int32_t offset, + int32_t length); + + // Fully copies this ByteArray to another ByteArray to the extent that the + // destination array has storage for the data copied. + virtual int32_t CopyTo(ByteArray* array); + + // Copies a segment of this ByteArray to another ByteArray. + // @param array the destination + // @param offset the offset in this ByteArray to start copying from + // @param length the maximum length in bytes to copy + // @return the number of bytes copied + virtual int32_t CopyTo(ByteArray* array, int32_t offset, int32_t length); + + // Copies this ByteArray to another ByteArray. + // @param dstOffset the offset in the destination array to start copying to + // @param array the destination + // @param srcOffset the offset in this ByteArray to start copying from + // @param length the maximum length in bytes to copy + // @return the number of bytes copied + virtual int32_t CopyTo(int32_t dst_offset, + ByteArray* array, + int32_t src_offset, + int32_t length); + + // Copies this ByteArray to an OutputStream. + // @param os the destination + // @return the number of bytes copied + virtual int32_t CopyTo(OutputStream* os); + + // Copies this ByteArray to an OutputStream. + // @param os the destination + // @param offset + // @param length + // @return the number of bytes copied + virtual int32_t CopyTo(OutputStream* os, int32_t offset, int32_t length); + + // Copies from the InputStream into this ByteArray. + // @param is the source + // @param length the number of bytes to copy + virtual bool CopyFrom(InputStream* is, int32_t length); + + // Copies everything from the InputStream into this ByteArray. + // @param is the source + virtual bool CopyFrom(InputStream* is); + + protected: + // filledLength the length that is "filled" and readable counting from offset. + // storageLength the maximum storage size of the underlying data. + // growable is the storage growable - storageLength is the max growable size. + ByteArray(int32_t filled_length, int32_t storage_length, bool growable); + ByteArray(int32_t filled_length, int32_t storage_length); + void Init(int32_t filled_length, int32_t storage_length, bool growable); + + // Internal subclass API + + // Stores the byte at the index given. + // @param index the location to store at + // @param b the byte to store + virtual void InternalPut(int32_t index, byte_t b) = 0; + + // Stores the array of bytes at the given index. + // @param index the location to store at + // @param b the bytes to store + // @param offset the offset to start from in the byte array + // @param length the length of the byte array to store from the offset + // @return the number of bytes actually stored + virtual int32_t InternalPut(int32_t index, + byte_t* b, + int32_t offset, + int32_t length) = 0; + + // Gets the byte at the index given. + // @param index the location to get from + // @return the byte stored at the index + virtual byte_t InternalGet(int32_t index) = 0; + + // Gets the bytes at the index given of the given length. + // @param index the location to start getting from + // @param b the array to put the bytes into + // @param offset the offset in the array to put the bytes into + // @param length the length of bytes to read + // @return the number of bytes actually ready + virtual int32_t InternalGet(int32_t index, + byte_t* b, + int32_t offset, + int32_t length) = 0; + + // Close this instance of the ByteArray. + virtual void Close() = 0; + + // C++ port only, raw pointer to the first element of storage. + virtual byte_t* Begin() = 0; + + // Java toString() not ported. + + static const int32_t COPY_BUFFER_SIZE; + + private: + //bool bound_; // unused, comment out + int32_t filled_length_; + int32_t storage_length_; + bool growable_; +}; +typedef Ptr ByteArrayPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_DATA_BYTE_ARRAY_H_ diff --git a/src/sfntly/src/sfntly/data/font_data.cc b/src/sfntly/src/sfntly/data/font_data.cc new file mode 100644 index 0000000000..d2b95eac1b --- /dev/null +++ b/src/sfntly/src/sfntly/data/font_data.cc @@ -0,0 +1,82 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "sfntly/data/font_data.h" + +namespace sfntly { + +int32_t FontData::Size() const { + return std::min(array_->Size() - bound_offset_, bound_length_); +} + +bool FontData::Bound(int32_t offset, int32_t length) { + if (offset + length > Size() || offset < 0 || length < 0) + return false; + + bound_offset_ += offset; + bound_length_ = length; + return true; +} + +bool FontData::Bound(int32_t offset) { +if (offset > Size() || offset < 0) + return false; + + bound_offset_ += offset; + return true; +} + +int32_t FontData::Length() const { + return std::min(array_->Length() - bound_offset_, bound_length_); +} + +FontData::FontData(ByteArray* ba) { + Init(ba); +} + +FontData::FontData(FontData* data, int32_t offset, int32_t length) { + Init(data->array_); + Bound(data->bound_offset_ + offset, length); +} + +FontData::FontData(FontData* data, int32_t offset) { + Init(data->array_); + Bound(data->bound_offset_ + offset, + (data->bound_length_ == GROWABLE_SIZE) + ? GROWABLE_SIZE : data->bound_length_ - offset); +} + +FontData::~FontData() {} + +void FontData::Init(ByteArray* ba) { + array_ = ba; + bound_offset_ = 0; + bound_length_ = GROWABLE_SIZE; +} + +int32_t FontData::BoundOffset(int32_t offset) { + return offset + bound_offset_; +} + +int32_t FontData::BoundLength(int32_t offset, int32_t length) { + return std::min(length, bound_length_ - offset); +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/data/font_data.h b/src/sfntly/src/sfntly/data/font_data.h new file mode 100644 index 0000000000..d02e8b75db --- /dev/null +++ b/src/sfntly/src/sfntly/data/font_data.h @@ -0,0 +1,135 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_DATA_H_ +#define SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_DATA_H_ + +#include + +#include + +#include "sfntly/port/type.h" +#include "sfntly/data/byte_array.h" +#include "sfntly/port/refcount.h" + +namespace sfntly { + +struct DataSize { + enum { + kBYTE = 1, + kCHAR = 1, + kUSHORT = 2, + kSHORT = 2, + kUINT24 = 3, + kULONG = 4, + kLONG = 4, + kFixed = 4, + kFUNIT = 4, + kFWORD = 2, + kUFWORD = 2, + kF2DOT14 = 2, + kLONGDATETIME = 8, + kTag = 4, + kGlyphID = 2, + kOffset = 2 + }; +}; + +class FontData : virtual public RefCount { + public: + // Gets the maximum size of the FontData. This is the maximum number of bytes + // that the font data can hold and all of it may not be filled with data or + // even fully allocated yet. + // @return the maximum size of this font data + virtual int32_t Size() const; + + // Sets limits on the size of the FontData. The FontData is then only + // visible within the bounds set. + // @param offset the start of the new bounds + // @param length the number of bytes in the bounded array + // @return true if the bounding range was successful; false otherwise + virtual bool Bound(int32_t offset, int32_t length); + + // Sets limits on the size of the FontData. This is a offset bound only so if + // the FontData is writable and growable then there is no limit to that growth + // from the bounding operation. + // @param offset the start of the new bounds which must be within the current + // size of the FontData + // @return true if the bounding range was successful; false otherwise + virtual bool Bound(int32_t offset); + + // Makes a slice of this FontData. The returned slice will share the data with + // the original FontData. + // @param offset the start of the slice + // @param length the number of bytes in the slice + // @return a slice of the original FontData + virtual CALLER_ATTACH FontData* Slice(int32_t offset, int32_t length) = 0; + + // Makes a bottom bound only slice of this array. The returned slice will + // share the data with the original FontData. + // @param offset the start of the slice + // @return a slice of the original FontData + virtual CALLER_ATTACH FontData* Slice(int32_t offset) = 0; + + // Gets the length of the data. + virtual int32_t Length() const; + + protected: + // Constructor. + // @param ba the byte array to use for the backing data + explicit FontData(ByteArray* ba); + + // Constructor. + // @param data the data to wrap + // @param offset the offset to start the wrap from + // @param length the length of the data wrapped + FontData(FontData* data, int32_t offset, int32_t length); + + // Constructor. + // @param data the data to wrap + // @param offset the offset to start the wrap from + FontData(FontData* data, int32_t offset); + virtual ~FontData(); + + void Init(ByteArray* ba); + + // Gets the offset in the underlying data taking into account any bounds on + // the data. + // @param offset the offset to get the bound compensated offset for + // @return the bound compensated offset + int32_t BoundOffset(int32_t offset); + + // Gets the length in the underlying data taking into account any bounds on + // the data. + // @param offset the offset that the length is being used at + // @param length the length to get the bound compensated length for + // @return the bound compensated length + int32_t BoundLength(int32_t offset, int32_t length); + + static const int32_t GROWABLE_SIZE = INT_MAX; + + // TODO(arthurhsu): style guide violation: refactor this protected member + ByteArrayPtr array_; + + private: + int32_t bound_offset_; + int32_t bound_length_; +}; +typedef Ptr FontDataPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_DATA_H_ diff --git a/src/sfntly/src/sfntly/data/font_input_stream.cc b/src/sfntly/src/sfntly/data/font_input_stream.cc new file mode 100644 index 0000000000..dcf8be35f9 --- /dev/null +++ b/src/sfntly/src/sfntly/data/font_input_stream.cc @@ -0,0 +1,141 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/data/font_input_stream.h" + +#include + +namespace sfntly { + +FontInputStream::FontInputStream(InputStream* is) + : stream_(is), position_(0), length_(0), bounded_(false) { +} + +FontInputStream::FontInputStream(InputStream* is, size_t length) + : stream_(is), position_(0), length_(length), bounded_(true) { +} + +FontInputStream::~FontInputStream() { + // Do not close here, underlying InputStream will close themselves. +} + +int32_t FontInputStream::Available() { + if (stream_) { + return stream_->Available(); + } + return 0; +} + +void FontInputStream::Close() { + if (stream_) { + stream_->Close(); + } +} + +void FontInputStream::Mark(int32_t readlimit) { + if (stream_) { + stream_->Mark(readlimit); + } +} + +bool FontInputStream::MarkSupported() { + if (stream_) { + return stream_->MarkSupported(); + } + return false; +} + +void FontInputStream::Reset() { + if (stream_) { + stream_->Reset(); + } +} + +int32_t FontInputStream::Read() { + if (!stream_ || (bounded_ && position_ >= length_)) { + return -1; + } + int32_t b = stream_->Read(); + if (b >= 0) { + position_++; + } + return b; +} + +int32_t FontInputStream::Read(ByteVector* b, int32_t offset, int32_t length) { + if (!stream_ || offset < 0 || length < 0 || + (bounded_ && position_ >= length_)) { + return -1; + } + int32_t bytes_to_read = + bounded_ ? std::min(length, (int32_t)(length_ - position_)) : + length; + int32_t bytes_read = stream_->Read(b, offset, bytes_to_read); + position_ += bytes_read; + return bytes_read; +} + +int32_t FontInputStream::Read(ByteVector* b) { + return Read(b, 0, b->size()); +} + +int32_t FontInputStream::ReadChar() { + return Read(); +} + +int32_t FontInputStream::ReadUShort() { + return 0xffff & (Read() << 8 | Read()); +} + +int32_t FontInputStream::ReadShort() { + return ((Read() << 8 | Read()) << 16) >> 16; +} + +int32_t FontInputStream::ReadUInt24() { + return 0xffffff & (Read() << 16 | Read() << 8 | Read()); +} + +int64_t FontInputStream::ReadULong() { + return 0xffffffffL & ReadLong(); +} + +int32_t FontInputStream::ReadULongAsInt() { + int64_t ulong = ReadULong(); + return ((int32_t)ulong) & ~0x80000000; +} + +int32_t FontInputStream::ReadLong() { + return Read() << 24 | Read() << 16 | Read() << 8 | Read(); +} + +int32_t FontInputStream::ReadFixed() { + return ReadLong(); +} + +int64_t FontInputStream::ReadDateTimeAsLong() { + return (int64_t)ReadULong() << 32 | ReadULong(); +} + +int64_t FontInputStream::Skip(int64_t n) { + if (stream_) { + int64_t skipped = stream_->Skip(n); + position_ += skipped; + return skipped; + } + return 0; +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/data/font_input_stream.h b/src/sfntly/src/sfntly/data/font_input_stream.h new file mode 100644 index 0000000000..9992b0753f --- /dev/null +++ b/src/sfntly/src/sfntly/data/font_input_stream.h @@ -0,0 +1,97 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_INPUT_STREAM_H_ +#define SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_INPUT_STREAM_H_ + +#include "sfntly/port/type.h" +#include "sfntly/port/input_stream.h" + +namespace sfntly { + +// An input stream for reading font data. +// The data types used are as listed: +// BYTE 8-bit unsigned integer. +// CHAR 8-bit signed integer. +// USHORT 16-bit unsigned integer. +// SHORT 16-bit signed integer. +// UINT24 24-bit unsigned integer. +// ULONG 32-bit unsigned integer. +// LONG 32-bit signed integer. +// Fixed 32-bit signed fixed-point number (16.16) +// FUNIT Smallest measurable distance in the em space. +// FWORD 16-bit signed integer (SHORT) that describes a quantity in FUnits. +// UFWORD 16-bit unsigned integer (USHORT) that describes a quantity in +// FUnits. +// F2DOT14 16-bit signed fixed number with the low 14 bits of fraction (2.14) +// LONGDATETIME Date represented in number of seconds since 12:00 midnight, +// January 1, 1904. The value is represented as a signed 64-bit +// integer. + +// Note: Original class inherits from Java's FilterOutputStream, which wraps +// an InputStream within. In C++, we directly do the wrapping without +// defining another layer of abstraction. The wrapped output stream is +// *NOT* reference counted (because it's meaningless to ref-count an I/O +// stream). +class FontInputStream : public InputStream { + public: + // Constructor. + // @param is input stream to wrap + explicit FontInputStream(InputStream* is); + + // Constructor for a bounded font input stream. + // @param is input stream to wrap + // @param length the maximum length of bytes to read + FontInputStream(InputStream* is, size_t length); + + virtual ~FontInputStream(); + + + virtual int32_t Available(); + virtual void Close(); + virtual void Mark(int32_t readlimit); + virtual bool MarkSupported(); + virtual void Reset(); + + virtual int32_t Read(); + virtual int32_t Read(ByteVector* buffer); + virtual int32_t Read(ByteVector* buffer, int32_t offset, int32_t length); + + // Get the current position in the stream in bytes. + // @return the current position in bytes + virtual int64_t position() { return position_; } + + virtual int32_t ReadChar(); + virtual int32_t ReadUShort(); + virtual int32_t ReadShort(); + virtual int32_t ReadUInt24(); + virtual int64_t ReadULong(); + virtual int32_t ReadULongAsInt(); + virtual int32_t ReadLong(); + virtual int32_t ReadFixed(); + virtual int64_t ReadDateTimeAsLong(); + virtual int64_t Skip(int64_t n); // n can be negative. + + private: + InputStream* stream_; + int64_t position_; + int64_t length_; // Bound on length of data to read. + bool bounded_; +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_INPUT_STREAM_H_ diff --git a/src/sfntly/src/sfntly/data/font_output_stream.cc b/src/sfntly/src/sfntly/data/font_output_stream.cc new file mode 100644 index 0000000000..3422a22827 --- /dev/null +++ b/src/sfntly/src/sfntly/data/font_output_stream.cc @@ -0,0 +1,130 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/data/font_output_stream.h" + +#include + +namespace sfntly { + +FontOutputStream::FontOutputStream(OutputStream* os) + : stream_(os), + position_(0) { +} + +FontOutputStream::~FontOutputStream() { + // Do not close, underlying stream shall clean up themselves. +} + +void FontOutputStream::Write(byte_t b) { + if (stream_) { + stream_->Write(b); + position_++; + } +} + +void FontOutputStream::Write(ByteVector* b) { + if (b) { + Write(b, 0, b->size()); + position_ += b->size(); + } +} + +void FontOutputStream::Write(ByteVector* b, int32_t off, int32_t len) { + assert(b); + assert(stream_); + if (off < 0 || len < 0 || off + len < 0 || + static_cast(off + len) > b->size()) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundException(); +#else + return; +#endif + } + + stream_->Write(b, off, len); + position_ += len; +} + +void FontOutputStream::Write(byte_t* b, int32_t off, int32_t len) { + assert(b); + assert(stream_); + if (off < 0 || len < 0 || off + len < 0) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundException(); +#else + return; +#endif + } + + stream_->Write(b, off, len); + position_ += len; +} + +void FontOutputStream::WriteChar(byte_t c) { + Write(c); +} + +void FontOutputStream::WriteUShort(int32_t us) { + Write((byte_t)((us >> 8) & 0xff)); + Write((byte_t)(us & 0xff)); +} + +void FontOutputStream::WriteShort(int32_t s) { + WriteUShort(s); +} + +void FontOutputStream::WriteUInt24(int32_t ui) { + Write((byte_t)(ui >> 16) & 0xff); + Write((byte_t)(ui >> 8) & 0xff); + Write((byte_t)ui & 0xff); +} + +void FontOutputStream::WriteULong(int64_t ul) { + Write((byte_t)((ul >> 24) & 0xff)); + Write((byte_t)((ul >> 16) & 0xff)); + Write((byte_t)((ul >> 8) & 0xff)); + Write((byte_t)(ul & 0xff)); +} + +void FontOutputStream::WriteLong(int64_t l) { + WriteULong(l); +} + +void FontOutputStream::WriteFixed(int32_t f) { + WriteULong(f); +} + +void FontOutputStream::WriteDateTime(int64_t date) { + WriteULong((date >> 32) & 0xffffffff); + WriteULong(date & 0xffffffff); +} + +void FontOutputStream::Flush() { + if (stream_) { + stream_->Flush(); + } +} + +void FontOutputStream::Close() { + if (stream_) { + stream_->Flush(); + stream_->Close(); + position_ = 0; + } +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/data/font_output_stream.h b/src/sfntly/src/sfntly/data/font_output_stream.h new file mode 100644 index 0000000000..fcd48e8aaa --- /dev/null +++ b/src/sfntly/src/sfntly/data/font_output_stream.h @@ -0,0 +1,79 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_OUTPUT_STREAM_H_ +#define SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_OUTPUT_STREAM_H_ + +#include "sfntly/port/type.h" +#include "sfntly/port/output_stream.h" + +namespace sfntly { + +// An output stream for writing font data. +// The data types used are as listed: +// BYTE 8-bit unsigned integer. +// CHAR 8-bit signed integer. +// USHORT 16-bit unsigned integer. +// SHORT 16-bit signed integer. +// UINT24 24-bit unsigned integer. +// ULONG 32-bit unsigned integer. +// LONG 32-bit signed integer. +// Fixed 32-bit signed fixed-point number (16.16) +// FUNIT Smallest measurable distance in the em space. +// FWORD 16-bit signed integer (SHORT) that describes a quantity in FUnits. +// UFWORD 16-bit unsigned integer (USHORT) that describes a quantity in +// FUnits. +// F2DOT14 16-bit signed fixed number with the low 14 bits of fraction (2.14) +// LONGDATETIME Date represented in number of seconds since 12:00 midnight, +// January 1, 1904. The value is represented as a signed 64-bit +// integer. + +// Note: The wrapped output stream is *NOT* reference counted (because it's +// meaningless to ref-count an I/O stream). +class FontOutputStream : public OutputStream { + public: + explicit FontOutputStream(OutputStream* os); + virtual ~FontOutputStream(); + + virtual size_t position() { return position_; } + + virtual void Write(byte_t b); + virtual void Write(ByteVector* b); + virtual void Write(ByteVector* b, int32_t off, int32_t len); + virtual void Write(byte_t* b, int32_t off, int32_t len); + virtual void WriteChar(byte_t c); + virtual void WriteUShort(int32_t us); + virtual void WriteShort(int32_t s); + virtual void WriteUInt24(int32_t ui); + virtual void WriteULong(int64_t ul); + virtual void WriteLong(int64_t l); + virtual void WriteFixed(int32_t l); + virtual void WriteDateTime(int64_t date); + + // Note: C++ port only. + virtual void Flush(); + virtual void Close(); + + private: + // Note: we do not use the variable name out as in Java because it has + // special meaning in VC++ and will be very confusing. + OutputStream* stream_; + size_t position_; +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_OUTPUT_STREAM_H_ diff --git a/src/sfntly/src/sfntly/data/growable_memory_byte_array.cc b/src/sfntly/src/sfntly/data/growable_memory_byte_array.cc new file mode 100644 index 0000000000..c335614d4d --- /dev/null +++ b/src/sfntly/src/sfntly/data/growable_memory_byte_array.cc @@ -0,0 +1,82 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/data/growable_memory_byte_array.h" + +#include +#include + +#include + +namespace sfntly { + +GrowableMemoryByteArray::GrowableMemoryByteArray() + : ByteArray(0, INT_MAX, true) { + // Note: We did not set an initial size of array like Java because STL + // implementation will determine the best strategy. +} + +GrowableMemoryByteArray::~GrowableMemoryByteArray() {} + +int32_t GrowableMemoryByteArray::CopyTo(OutputStream* os, + int32_t offset, + int32_t length) { + assert(os); + os->Write(&b_, offset, length); + return length; +} + +void GrowableMemoryByteArray::InternalPut(int32_t index, byte_t b) { + if ((size_t)index >= b_.size()) { + b_.resize((size_t)(index + 1)); + } + b_[index] = b; +} + +int32_t GrowableMemoryByteArray::InternalPut(int32_t index, + byte_t* b, + int32_t offset, + int32_t length) { + if ((size_t)index + length >= b_.size()) { + // Note: We grow one byte more than Java version. VC debuggers shows + // data better this way. + b_.resize((size_t)(index + length + 1)); + } + std::copy(b + offset, b + offset + length, b_.begin() + index); + return length; +} + +byte_t GrowableMemoryByteArray::InternalGet(int32_t index) { + return b_[index]; +} + +int32_t GrowableMemoryByteArray::InternalGet(int32_t index, + byte_t* b, + int32_t offset, + int32_t length) { + memcpy(b + offset, &(b_[0]) + index, length); + return length; +} + +void GrowableMemoryByteArray::Close() { + b_.clear(); +} + +byte_t* GrowableMemoryByteArray::Begin() { + return &(b_[0]); +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/data/growable_memory_byte_array.h b/src/sfntly/src/sfntly/data/growable_memory_byte_array.h new file mode 100644 index 0000000000..8583a0d645 --- /dev/null +++ b/src/sfntly/src/sfntly/data/growable_memory_byte_array.h @@ -0,0 +1,66 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_GROWABLE_MEMORY_BYTE_ARRAY_H_ +#define SFNTLY_CPP_SRC_SFNTLY_DATA_GROWABLE_MEMORY_BYTE_ARRAY_H_ + +#include "sfntly/data/byte_array.h" + +namespace sfntly { + +// Note: This is not really a port of Java version. Instead, this wraps a +// std::vector inside and let it grow by calling resize(). +class GrowableMemoryByteArray : public ByteArray, + public RefCounted { + public: + GrowableMemoryByteArray(); + virtual ~GrowableMemoryByteArray(); + virtual int32_t CopyTo(OutputStream* os, int32_t offset, int32_t length); + + // Make gcc -Woverloaded-virtual happy. + virtual int32_t CopyTo(ByteArray* array) { return ByteArray::CopyTo(array); } + virtual int32_t CopyTo(ByteArray* array, int32_t offset, int32_t length) { + return ByteArray::CopyTo(array, offset, length); + } + virtual int32_t CopyTo(int32_t dst_offset, + ByteArray* array, + int32_t src_offset, + int32_t length) { + return ByteArray::CopyTo(dst_offset, array, src_offset, length); + } + virtual int32_t CopyTo(OutputStream* os) { return ByteArray::CopyTo(os); } + + protected: + virtual void InternalPut(int32_t index, byte_t b); + virtual int32_t InternalPut(int32_t index, + byte_t* b, + int32_t offset, + int32_t length); + virtual byte_t InternalGet(int32_t index); + virtual int32_t InternalGet(int32_t index, + byte_t* b, + int32_t offset, + int32_t length); + virtual void Close(); + virtual byte_t* Begin(); + + private: + ByteVector b_; +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_DATA_GROWABLE_MEMORY_BYTE_ARRAY_H_ diff --git a/src/sfntly/src/sfntly/data/memory_byte_array.cc b/src/sfntly/src/sfntly/data/memory_byte_array.cc new file mode 100644 index 0000000000..d6c9c4828d --- /dev/null +++ b/src/sfntly/src/sfntly/data/memory_byte_array.cc @@ -0,0 +1,93 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/data/memory_byte_array.h" + +#include + +namespace sfntly { + +MemoryByteArray::MemoryByteArray(int32_t length) + : ByteArray(0, length), b_(NULL), allocated_(true) { +} + +MemoryByteArray::MemoryByteArray(byte_t* b, int32_t filled_length) + : ByteArray(filled_length, filled_length), b_(b), allocated_(false) { + assert(b); +} + +MemoryByteArray::~MemoryByteArray() { + Close(); +} + +int32_t MemoryByteArray::CopyTo(OutputStream* os, + int32_t offset, + int32_t length) { + assert(os); + os->Write(b_, offset, length); + return length; +} + +void MemoryByteArray::Init() { + if (allocated_ && b_ == NULL) { + b_ = new byte_t[Size()]; + memset(b_, 0, Size()); + } +} + +void MemoryByteArray::InternalPut(int32_t index, byte_t b) { + Init(); + b_[index] = b; +} + +int32_t MemoryByteArray::InternalPut(int32_t index, + byte_t* b, + int32_t offset, + int32_t length) { + assert(b); + Init(); + memcpy(b_ + index, b + offset, length); + return length; +} + +byte_t MemoryByteArray::InternalGet(int32_t index) { + Init(); + return b_[index]; +} + +int32_t MemoryByteArray::InternalGet(int32_t index, + byte_t* b, + int32_t offset, + int32_t length) { + assert(b); + Init(); + memcpy(b + offset, b_ + index, length); + return length; +} + +void MemoryByteArray::Close() { + if (allocated_ && b_) { + delete[] b_; + } + b_ = NULL; +} + +byte_t* MemoryByteArray::Begin() { + Init(); + return b_; +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/data/memory_byte_array.h b/src/sfntly/src/sfntly/data/memory_byte_array.h new file mode 100644 index 0000000000..838fd1aca5 --- /dev/null +++ b/src/sfntly/src/sfntly/data/memory_byte_array.h @@ -0,0 +1,81 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_MEMORY_BYTE_ARRAY_H_ +#define SFNTLY_CPP_SRC_SFNTLY_DATA_MEMORY_BYTE_ARRAY_H_ + +#include "sfntly/data/byte_array.h" + +namespace sfntly { + +class MemoryByteArray : public ByteArray, public RefCounted { + public: + // Construct a new MemoryByteArray with a new array of the size given. It is + // assumed that none of the array is filled and readable. + explicit MemoryByteArray(int32_t length); + + // Note: not implemented due to dangerous operations in constructor. + //explicit MemoryByteArray(ByteVector* b); + + // Construct a new MemoryByteArray using byte array. + // @param b the byte array that provides the actual storage + // @param filled_length the index of the last byte in the array has data + // Note: This is different from Java version, it does not take over the + // ownership of b. Caller is responsible for handling the lifetime + // of b. C++ port also assumes filled_length is buffer_length since + // there is not a reliable way to identify the actual size of buffer. + MemoryByteArray(byte_t* b, int32_t filled_length); + + virtual ~MemoryByteArray(); + virtual int32_t CopyTo(OutputStream* os, int32_t offset, int32_t length); + + // Make gcc -Woverloaded-virtual happy. + virtual int32_t CopyTo(ByteArray* array) { return ByteArray::CopyTo(array); } + virtual int32_t CopyTo(ByteArray* array, int32_t offset, int32_t length) { + return ByteArray::CopyTo(array, offset, length); + } + virtual int32_t CopyTo(int32_t dst_offset, + ByteArray* array, + int32_t src_offset, + int32_t length) { + return ByteArray::CopyTo(dst_offset, array, src_offset, length); + } + virtual int32_t CopyTo(OutputStream* os) { return ByteArray::CopyTo(os); } + + protected: + virtual void InternalPut(int32_t index, byte_t b); + virtual int32_t InternalPut(int32_t index, + byte_t* b, + int32_t offset, + int32_t length); + virtual byte_t InternalGet(int32_t index); + virtual int32_t InternalGet(int32_t index, + byte_t* b, + int32_t offset, + int32_t length); + virtual void Close(); + virtual byte_t* Begin(); + + private: + void Init(); // C++ port only, used to allocate memory outside constructor. + + byte_t* b_; + bool allocated_; +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_DATA_MEMORY_BYTE_ARRAY_H_ diff --git a/src/sfntly/src/sfntly/data/readable_font_data.cc b/src/sfntly/src/sfntly/data/readable_font_data.cc new file mode 100644 index 0000000000..06d783f2e3 --- /dev/null +++ b/src/sfntly/src/sfntly/data/readable_font_data.cc @@ -0,0 +1,336 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/data/readable_font_data.h" + +#include + +#include "sfntly/data/memory_byte_array.h" +#include "sfntly/data/writable_font_data.h" +#include "sfntly/port/exception_type.h" + +namespace sfntly { + +ReadableFontData::ReadableFontData(ByteArray* array) + : FontData(array), + checksum_set_(false), + checksum_(0) { +} + +ReadableFontData::~ReadableFontData() {} + +// TODO(arthurhsu): re-investigate the memory model of this function. It's +// not too useful without copying, but it's not performance +// savvy to do copying. +CALLER_ATTACH +ReadableFontData* ReadableFontData::CreateReadableFontData(ByteVector* b) { + assert(b); + ByteArrayPtr ba = new MemoryByteArray(b->size()); + ba->Put(0, b); + ReadableFontDataPtr wfd = new ReadableFontData(ba); + return wfd.Detach(); +} + +int64_t ReadableFontData::Checksum() { + AutoLock lock(checksum_lock_); + if (!checksum_set_) { + ComputeChecksum(); + } + return checksum_; +} + +void ReadableFontData::SetCheckSumRanges(const IntegerList& ranges) { + checksum_range_ = ranges; + checksum_set_ = false; // UNIMPLEMENTED: atomicity +} + +int32_t ReadableFontData::ReadUByte(int32_t index) { + int32_t b = array_->Get(BoundOffset(index)); +#if !defined (SFNTLY_NO_EXCEPTION) + if (b < 0) { + throw IndexOutOfBoundException( + "Index attempted to be read from is out of bounds", index); + } +#endif + return b; +} + +int32_t ReadableFontData::ReadByte(int32_t index) { + int32_t b = array_->Get(BoundOffset(index)); +#if !defined (SFNTLY_NO_EXCEPTION) + if (b < 0) { + throw IndexOutOfBoundException( + "Index attempted to be read from is out of bounds", index); + } +#endif + return (b << 24) >> 24; +} + +int32_t ReadableFontData::ReadBytes(int32_t index, + byte_t* b, + int32_t offset, + int32_t length) { + return array_->Get(BoundOffset(index), b, offset, BoundLength(index, length)); +} + +int32_t ReadableFontData::ReadChar(int32_t index) { + return ReadUByte(index); +} + +int32_t ReadableFontData::ReadUShort(int32_t index) { + return 0xffff & (ReadUByte(index) << 8 | ReadUByte(index + 1)); +} + +int32_t ReadableFontData::ReadShort(int32_t index) { + return ((ReadByte(index) << 8 | ReadUByte(index + 1)) << 16) >> 16; +} + +int32_t ReadableFontData::ReadUInt24(int32_t index) { + return 0xffffff & (ReadUByte(index) << 16 | + ReadUByte(index + 1) << 8 | + ReadUByte(index + 2)); +} + +int64_t ReadableFontData::ReadULong(int32_t index) { + return 0xffffffffL & (ReadUByte(index) << 24 | + ReadUByte(index + 1) << 16 | + ReadUByte(index + 2) << 8 | + ReadUByte(index + 3)); +} + +int32_t ReadableFontData::ReadULongAsInt(int32_t index) { + int64_t ulong = ReadULong(index); +#if !defined (SFNTLY_NO_EXCEPTION) + if ((ulong & 0x80000000) == 0x80000000) { + throw ArithmeticException("Long value too large to fit into an integer."); + } +#endif + return static_cast(ulong); +} + +int64_t ReadableFontData::ReadULongLE(int32_t index) { + return 0xffffffffL & (ReadUByte(index) | + ReadUByte(index + 1) << 8 | + ReadUByte(index + 2) << 16 | + ReadUByte(index + 3) << 24); +} + +int32_t ReadableFontData::ReadLong(int32_t index) { + return ReadByte(index) << 24 | + ReadUByte(index + 1) << 16 | + ReadUByte(index + 2) << 8 | + ReadUByte(index + 3); +} + +int32_t ReadableFontData::ReadFixed(int32_t index) { + return ReadLong(index); +} + +int64_t ReadableFontData::ReadDateTimeAsLong(int32_t index) { + return (int64_t)ReadULong(index) << 32 | ReadULong(index + 4); +} + +int32_t ReadableFontData::ReadFWord(int32_t index) { + return ReadShort(index); +} + +int32_t ReadableFontData::ReadFUFWord(int32_t index) { + return ReadUShort(index); +} + +int32_t ReadableFontData::CopyTo(OutputStream* os) { + return array_->CopyTo(os, BoundOffset(0), Length()); +} + +int32_t ReadableFontData::CopyTo(WritableFontData* wfd) { + return array_->CopyTo(wfd->BoundOffset(0), + wfd->array_, + BoundOffset(0), + Length()); +} + +int32_t ReadableFontData::CopyTo(ByteArray* ba) { + return array_->CopyTo(ba, BoundOffset(0), Length()); +} + +int32_t ReadableFontData::SearchUShort(int32_t start_index, + int32_t start_offset, + int32_t end_index, + int32_t end_offset, + int32_t length, + int32_t key) { + int32_t location = 0; + int32_t bottom = 0; + int32_t top = length; + while (top != bottom) { + location = (top + bottom) / 2; + int32_t location_start = ReadUShort(start_index + location * start_offset); + if (key < location_start) { + // location is below current location + top = location; + } else { + // is key below the upper bound? + int32_t location_end = ReadUShort(end_index + location * end_offset); +#if defined (SFNTLY_DEBUG_FONTDATA) + fprintf(stderr, "**start: %d; end: %d\n", location_start, location_end); +#endif + if (key <= location_end) { + return location; + } else { + // location is above the current location + bottom = location + 1; + } + } + } + return -1; +} + +int32_t ReadableFontData::SearchUShort(int32_t start_index, + int32_t start_offset, + int32_t length, + int32_t key) { + int32_t location = 0; + int32_t bottom = 0; + int32_t top = length; + while (top != bottom) { + location = (top + bottom) / 2; + int32_t location_start = ReadUShort(start_index + location * start_offset); + if (key < location_start) { + // location is below current location + top = location; + } else if (key > location_start) { + // location is above current location + bottom = location + 1; + } else { + return location; + } + } + return -1; +} + +int32_t ReadableFontData::SearchULong(int32_t start_index, + int32_t start_offset, + int32_t end_index, + int32_t end_offset, + int32_t length, + int32_t key) { + int32_t location = 0; + int32_t bottom = 0; + int32_t top = length; + while (top != bottom) { + location = (top + bottom) / 2; + int32_t location_start = ReadULongAsInt(start_index + + location * start_offset); + if (key < location_start) { + // location is below current location + top = location; + } else { + // is key below the upper bound? + int32_t location_end = ReadULongAsInt(end_index + location * end_offset); +#if defined (SFNTLY_DEBUG_FONTDATA) + fprintf(stderr, "**start: %d; end: %d\n", location_start, location_end); +#endif + if (key <= location_end) { + return location; + } else { + // location is above the current location + bottom = location + 1; + } + } + } + return -1; +} + +CALLER_ATTACH FontData* ReadableFontData::Slice(int32_t offset, + int32_t length) { + if (offset < 0 || offset + length > Size()) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundsException( + "Attempt to bind data outside of its limits"); +#endif + return NULL; + } + FontDataPtr slice = new ReadableFontData(this, offset, length); + return slice.Detach(); +} + +CALLER_ATTACH FontData* ReadableFontData::Slice(int32_t offset) { + if (offset < 0 || offset > Size()) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundsException( + "Attempt to bind data outside of its limits"); +#endif + return NULL; + } + FontDataPtr slice = new ReadableFontData(this, offset); + return slice.Detach(); +} + +ReadableFontData::ReadableFontData(ReadableFontData* data, int32_t offset) + : FontData(data, offset), + checksum_set_(false), + checksum_(0) { +} + +ReadableFontData::ReadableFontData(ReadableFontData* data, + int32_t offset, + int32_t length) + : FontData(data, offset, length), + checksum_set_(false), + checksum_(0) { +} + +void ReadableFontData::ComputeChecksum() { + // TODO(arthurhsu): IMPLEMENT: synchronization/atomicity + int64_t sum = 0; + if (checksum_range_.empty()) { + sum = ComputeCheckSum(0, Length()); + } else { + for (uint32_t low_bound_index = 0; low_bound_index < checksum_range_.size(); + low_bound_index += 2) { + int32_t low_bound = checksum_range_[low_bound_index]; + int32_t high_bound = (low_bound_index == checksum_range_.size() - 1) ? + Length() : + checksum_range_[low_bound_index + 1]; + sum += ComputeCheckSum(low_bound, high_bound); + } + } + + checksum_ = sum & 0xffffffffL; + checksum_set_ = true; +} + +int64_t ReadableFontData::ComputeCheckSum(int32_t low_bound, + int32_t high_bound) { + int64_t sum = 0; + // Checksum all whole 4-byte chunks. + for (int32_t i = low_bound; i <= high_bound - 4; i += 4) { + sum += ReadULong(i); + } + + // Add last fragment if not 4-byte multiple + int32_t off = high_bound & -4; + if (off < high_bound) { + int32_t b3 = ReadUByte(off); + int32_t b2 = (off + 1 < high_bound) ? ReadUByte(off + 1) : 0; + int32_t b1 = (off + 2 < high_bound) ? ReadUByte(off + 2) : 0; + int32_t b0 = 0; + sum += (b3 << 24) | (b2 << 16) | (b1 << 8) | b0; + } + return sum; +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/data/readable_font_data.h b/src/sfntly/src/sfntly/data/readable_font_data.h new file mode 100644 index 0000000000..b43c626041 --- /dev/null +++ b/src/sfntly/src/sfntly/data/readable_font_data.h @@ -0,0 +1,308 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_READABLE_FONT_DATA_H_ +#define SFNTLY_CPP_SRC_SFNTLY_DATA_READABLE_FONT_DATA_H_ + +#include "sfntly/data/font_data.h" +#include "sfntly/port/lock.h" + +namespace sfntly { + +class WritableFontData; +class OutputStream; + +// Writable font data wrapper. Supports reading of data primitives in the +// TrueType / OpenType spec. +// The data types used are as listed: +// BYTE 8-bit unsigned integer. +// CHAR 8-bit signed integer. +// USHORT 16-bit unsigned integer. +// SHORT 16-bit signed integer. +// UINT24 24-bit unsigned integer. +// ULONG 32-bit unsigned integer. +// LONG 32-bit signed integer. +// Fixed 32-bit signed fixed-point number (16.16) +// FUNIT Smallest measurable distance in the em space. +// FWORD 16-bit signed integer (SHORT) that describes a quantity in FUnits. +// UFWORD 16-bit unsigned integer (USHORT) that describes a quantity in +// FUnits. +// F2DOT14 16-bit signed fixed number with the low 14 bits of fraction (2.14) +// LONGDATETIME Date represented in number of seconds since 12:00 midnight, +// January 1, 1904. The value is represented as a signed 64-bit +// integer. + +class ReadableFontData : public FontData, + public RefCounted { + public: + explicit ReadableFontData(ByteArray* array); + virtual ~ReadableFontData(); + + static CALLER_ATTACH ReadableFontData* CreateReadableFontData(ByteVector* b); + + // Gets a computed checksum for the data. This checksum uses the OpenType spec + // calculation. Every ULong value (32 bit unsigned) in the data is summed and + // the resulting value is truncated to 32 bits. If the data length in bytes is + // not an integral multiple of 4 then any remaining bytes are treated as the + // start of a 4 byte sequence whose remaining bytes are zero. + // @return the checksum + int64_t Checksum(); + + // Sets the bounds to use for computing the checksum. These bounds are in + // begin and end pairs. If an odd number is given then the final range is + // assumed to extend to the end of the data. The lengths of each range must be + // a multiple of 4. + // @param ranges the range bounds to use for the checksum + void SetCheckSumRanges(const IntegerList& ranges); + + // Read the UBYTE at the given index. + // @param index index into the font data + // @return the UBYTE; -1 if outside the bounds of the font data + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t ReadUByte(int32_t index); + + // Read the BYTE at the given index. + // @param index index into the font data + // @return the BYTE + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t ReadByte(int32_t index); + + // Read the bytes at the given index into the array. + // @param index index into the font data + // @param b the destination for the bytes read + // @param offset offset in the byte array to place the bytes + // @param length the length of bytes to read + // @return the number of bytes actually read; -1 if the index is outside the + // bounds of the font data + virtual int32_t ReadBytes(int32_t index, + byte_t* b, + int32_t offset, + int32_t length); + + // Read the CHAR at the given index. + // @param index index into the font data + // @return the CHAR + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t ReadChar(int32_t index); + + // Read the USHORT at the given index. + // @param index index into the font data + // @return the USHORT + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t ReadUShort(int32_t index); + + // Read the SHORT at the given index. + // @param index index into the font data + // @return the SHORT + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t ReadShort(int32_t index); + + // Read the UINT24 at the given index. + // @param index index into the font data + // @return the UINT24 + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t ReadUInt24(int32_t index); + + // Read the ULONG at the given index. + // @param index index into the font data + // @return the ULONG + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int64_t ReadULong(int32_t index); + + // Read the ULONG at the given index as int32_t. + // @param index index into the font data + // @return the ULONG + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t ReadULongAsInt(int32_t index); + + // Read the ULONG at the given index, little-endian variant + // @param index index into the font data + // @return the ULONG + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int64_t ReadULongLE(int32_t index); + + // Read the LONG at the given index. + // @param index index into the font data + // @return the LONG + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t ReadLong(int32_t index); + + // Read the Fixed at the given index. + // @param index index into the font data + // @return the Fixed + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t ReadFixed(int32_t index); + + // Read the LONGDATETIME at the given index. + // @param index index into the font data + // @return the LONGDATETIME + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int64_t ReadDateTimeAsLong(int32_t index); + + // Read the FWORD at the given index. + // @param index index into the font data + // @return the FWORD + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t ReadFWord(int32_t index); + + // Read the UFWORD at the given index. + // @param index index into the font data + // @return the UFWORD + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t ReadFUFWord(int32_t index); + + // Note: Not ported because they just throw UnsupportedOperationException() + // in Java. + /* + virtual int32_t ReadFUnit(int32_t index); + virtual int64_t ReadF2Dot14(int32_t index); + */ + + // Copy the FontData to an OutputStream. + // @param os the destination + // @return number of bytes copied + // @throws IOException + virtual int32_t CopyTo(OutputStream* os); + + // Copy the FontData to a WritableFontData. + // @param wfd the destination + // @return number of bytes copied + // @throws IOException + virtual int32_t CopyTo(WritableFontData* wfd); + + // Make gcc -Woverloaded-virtual happy. + virtual int32_t CopyTo(ByteArray* ba); + + // Search for the key value in the range tables provided. + // The search looks through the start-end pairs looking for the key value. It + // is assumed that the start-end pairs are both represented by UShort values, + // ranges do not overlap, and are monotonically increasing. + // @param startIndex the position to read the first start value from + // @param startOffset the offset between subsequent start values + // @param endIndex the position to read the first end value from + // @param endOffset the offset between subsequent end values + // @param length the number of start-end pairs + // @param key the value to search for + // @return the index of the start-end pairs in which the key was found; -1 + // otherwise + int32_t SearchUShort(int32_t start_index, + int32_t start_offset, + int32_t end_index, + int32_t end_offset, + int32_t length, + int32_t key); + + // Search for the key value in the table provided. + // The search looks through the values looking for the key value. It is + // assumed that the are represented by UShort values and are monotonically + // increasing. + // @param startIndex the position to read the first start value from + // @param startOffset the offset between subsequent start values + // @param length the number of start-end pairs + // @param key the value to search for + // @return the index of the start-end pairs in which the key was found; -1 + // otherwise + int32_t SearchUShort(int32_t start_index, + int32_t start_offset, + int32_t length, + int32_t key); + + // Search for the key value in the range tables provided. + // The search looks through the start-end pairs looking for the key value. It + // is assumed that the start-end pairs are both represented by ULong values + // that can be represented within 31 bits, ranges do not overlap, and are + // monotonically increasing. + // @param startIndex the position to read the first start value from + // @param startOffset the offset between subsequent start values + // @param endIndex the position to read the first end value from + // @param endOffset the offset between subsequent end values + // @param length the number of start-end pairs + // @param key the value to search for + // @return the index of the start-end pairs in which the key was found; -1 + // otherwise + int32_t SearchULong(int32_t start_index, + int32_t start_offset, + int32_t end_index, + int32_t end_offset, + int32_t length, + int32_t key); + + + // TODO(arthurhsu): IMPLEMENT + /* + virtual int32_t ReadFUnit(int32_t index); + virtual int64_t ReadF2Dot14(int32_t index); + virtual int64_t ReadLongDateTime(int32_t index); + */ + + // Makes a slice of this FontData. The returned slice will share the data with + // the original FontData. + // @param offset the start of the slice + // @param length the number of bytes in the slice + // @return a slice of the original FontData + // Note: C++ polymorphism requires return type to be consistent + virtual CALLER_ATTACH FontData* Slice(int32_t offset, int32_t length); + + // Makes a bottom bound only slice of this array. The returned slice will + // share the data with the original FontData. + // @param offset the start of the slice + // @return a slice of the original FontData + // Note: C++ polymorphism requires return type to be consistent + virtual CALLER_ATTACH FontData* Slice(int32_t offset); + + // Not Ported: toString() + + protected: + // Constructor. Creates a bounded wrapper of another ReadableFontData from the + // given offset until the end of the original ReadableFontData. + // @param data data to wrap + // @param offset the start of this data's view of the original data + ReadableFontData(ReadableFontData* data, int32_t offset); + + // Constructor. Creates a bounded wrapper of another ReadableFontData from the + // given offset until the end of the original ReadableFontData. + // @param data data to wrap + // @param offset the start of this data's view of the original data + // @param length the length of the other FontData to use + ReadableFontData(ReadableFontData* data, int32_t offset, int32_t length); + + private: + // Compute the checksum for the font data using any ranges set for the + // calculation. + void ComputeChecksum(); + + // Do the actual computation of the checksum for a range using the + // TrueType/OpenType checksum algorithm. The range used is from the low bound + // to the high bound in steps of four bytes. If any of the bytes within that 4 + // byte segment are not readable then it will considered a zero for + // calculation. + // Only called from within a synchronized method so it does not need to be + // synchronized itself. + // @param lowBound first position to start a 4 byte segment on + // @param highBound last possible position to start a 4 byte segment on + // @return the checksum for the total range + int64_t ComputeCheckSum(int32_t low_bound, int32_t high_bound); + + Lock checksum_lock_; + bool checksum_set_; + int64_t checksum_; + IntegerList checksum_range_; +}; +typedef Ptr ReadableFontDataPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_DATA_READABLE_FONT_DATA_H_ diff --git a/src/sfntly/src/sfntly/data/writable_font_data.cc b/src/sfntly/src/sfntly/data/writable_font_data.cc new file mode 100644 index 0000000000..7f6f72f533 --- /dev/null +++ b/src/sfntly/src/sfntly/data/writable_font_data.cc @@ -0,0 +1,201 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/data/writable_font_data.h" + +#include "sfntly/data/memory_byte_array.h" +#include "sfntly/data/growable_memory_byte_array.h" + +namespace sfntly { + +WritableFontData::WritableFontData(ByteArray* ba) : ReadableFontData(ba) { +} + +WritableFontData::~WritableFontData() {} + +// static +CALLER_ATTACH +WritableFontData* WritableFontData::CreateWritableFontData(int32_t length) { + ByteArrayPtr ba; + if (length > 0) { + ba = new MemoryByteArray(length); + ba->SetFilledLength(length); + } else { + ba = new GrowableMemoryByteArray(); + } + WritableFontDataPtr wfd = new WritableFontData(ba); + return wfd.Detach(); +} + +// TODO(arthurhsu): re-investigate the memory model of this function. It's +// not too useful without copying, but it's not performance +// savvy to do copying. +CALLER_ATTACH +WritableFontData* WritableFontData::CreateWritableFontData(ByteVector* b) { + ByteArrayPtr ba = new GrowableMemoryByteArray(); + ba->Put(0, b); + WritableFontDataPtr wfd = new WritableFontData(ba); + return wfd.Detach(); +} + +int32_t WritableFontData::WriteByte(int32_t index, byte_t b) { + array_->Put(BoundOffset(index), b); + return 1; +} + +int32_t WritableFontData::WriteBytes(int32_t index, + byte_t* b, + int32_t offset, + int32_t length) { + return array_->Put(BoundOffset(index), + b, + offset, + BoundLength(index, length)); +} + +int32_t WritableFontData::WriteBytes(int32_t index, ByteVector* b) { + assert(b); + return WriteBytes(index, &((*b)[0]), 0, b->size()); +} + +int32_t WritableFontData::WriteBytesPad(int32_t index, + ByteVector* b, + int32_t offset, + int32_t length, + byte_t pad) { + int32_t written = + array_->Put(BoundOffset(index), + &((*b)[0]), + offset, + BoundLength(index, + std::min(length, b->size() - offset))); + written += WritePadding(written + index, length - written, pad); + return written; +} + +int32_t WritableFontData::WritePadding(int32_t index, int32_t count) { + return WritePadding(index, count, (byte_t)0); +} + +int32_t WritableFontData::WritePadding(int32_t index, int32_t count, + byte_t pad) { + for (int32_t i = 0; i < count; ++i) { + array_->Put(index + i, pad); + } + return count; +} + +int32_t WritableFontData::WriteChar(int32_t index, byte_t c) { + return WriteByte(index, c); +} + +int32_t WritableFontData::WriteUShort(int32_t index, int32_t us) { + WriteByte(index, (byte_t)((us >> 8) & 0xff)); + WriteByte(index + 1, (byte_t)(us & 0xff)); + return 2; +} + +int32_t WritableFontData::WriteUShortLE(int32_t index, int32_t us) { + WriteByte(index, (byte_t)(us & 0xff)); + WriteByte(index + 1, (byte_t)((us >> 8) & 0xff)); + return 2; +} + +int32_t WritableFontData::WriteShort(int32_t index, int32_t s) { + return WriteUShort(index, s); +} + +int32_t WritableFontData::WriteUInt24(int32_t index, int32_t ui) { + WriteByte(index, (byte_t)((ui >> 16) & 0xff)); + WriteByte(index + 1, (byte_t)((ui >> 8) & 0xff)); + WriteByte(index + 2, (byte_t)(ui & 0xff)); + return 3; +} + +int32_t WritableFontData::WriteULong(int32_t index, int64_t ul) { + WriteByte(index, (byte_t)((ul >> 24) & 0xff)); + WriteByte(index + 1, (byte_t)((ul >> 16) & 0xff)); + WriteByte(index + 2, (byte_t)((ul >> 8) & 0xff)); + WriteByte(index + 3, (byte_t)(ul & 0xff)); + return 4; +} + +int32_t WritableFontData::WriteULongLE(int32_t index, int64_t ul) { + WriteByte(index, (byte_t)(ul & 0xff)); + WriteByte(index + 1, (byte_t)((ul >> 8) & 0xff)); + WriteByte(index + 2, (byte_t)((ul >> 16) & 0xff)); + WriteByte(index + 3, (byte_t)((ul >> 24) & 0xff)); + return 4; +} + +int32_t WritableFontData::WriteLong(int32_t index, int64_t l) { + return WriteULong(index, l); +} + +int32_t WritableFontData::WriteFixed(int32_t index, int32_t f) { + return WriteLong(index, f); +} + +int32_t WritableFontData::WriteDateTime(int32_t index, int64_t date) { + WriteULong(index, (date >> 32) & 0xffffffff); + WriteULong(index + 4, date & 0xffffffff); + return 8; +} + +void WritableFontData::CopyFrom(InputStream* is, int32_t length) { + array_->CopyFrom(is, length); +} + +void WritableFontData::CopyFrom(InputStream* is) { + array_->CopyFrom(is); +} + +CALLER_ATTACH FontData* WritableFontData::Slice(int32_t offset, + int32_t length) { + if (offset < 0 || offset + length > Size()) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundsException( + "Attempt to bind data outside of its limits"); +#endif + return NULL; + } + FontDataPtr slice = new WritableFontData(this, offset, length); + return slice.Detach(); +} + +CALLER_ATTACH FontData* WritableFontData::Slice(int32_t offset) { + if (offset > Size()) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundsException( + "Attempt to bind data outside of its limits"); +#endif + return NULL; + } + FontDataPtr slice = new WritableFontData(this, offset); + return slice.Detach(); +} + +WritableFontData::WritableFontData(WritableFontData* data, int32_t offset) + : ReadableFontData(data, offset) { +} + +WritableFontData::WritableFontData(WritableFontData* data, + int32_t offset, + int32_t length) + : ReadableFontData(data, offset, length) { +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/data/writable_font_data.h b/src/sfntly/src/sfntly/data/writable_font_data.h new file mode 100644 index 0000000000..d2a049eb55 --- /dev/null +++ b/src/sfntly/src/sfntly/data/writable_font_data.h @@ -0,0 +1,211 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_WRITABLE_FONT_DATA_H_ +#define SFNTLY_CPP_SRC_SFNTLY_DATA_WRITABLE_FONT_DATA_H_ + +#include "sfntly/data/readable_font_data.h" + +namespace sfntly { + +// Writable font data wrapper. Supports writing of data primitives in the +// TrueType / OpenType spec. +class WritableFontData : public ReadableFontData { + public: + explicit WritableFontData(ByteArray* ba); + virtual ~WritableFontData(); + + // Constructs a writable font data object. If the length is specified as + // positive then a fixed size font data object will be created. If the length + // is zero or less then a growable font data object will be created and the + // size will be used as an estimate to help in allocating the original space. + // @param length if length > 0 create a fixed length font data; otherwise + // create a growable font data + // @return a new writable font data + static CALLER_ATTACH WritableFontData* CreateWritableFontData(int32_t length); + + // Constructs a writable font data object. The new font data object will wrap + // the bytes passed in to the factory and it will take make a copy of those + // bytes. + // @param b the byte vector to wrap + // @return a new writable font data + static CALLER_ATTACH WritableFontData* CreateWritableFontData(ByteVector* b); + + // Write a byte at the given index. + // @param index index into the font data + // @param b the byte to write + // @return the number of bytes written + virtual int32_t WriteByte(int32_t index, byte_t b); + + // Write the bytes from the array. + // @param index index into the font data + // @param b the source for the bytes to be written + // @param offset offset in the byte array + // @param length the length of the bytes to be written + // @return the number of bytes actually written; -1 if the index is outside + // the FontData's range + virtual int32_t WriteBytes(int32_t index, + byte_t* b, + int32_t offset, + int32_t length); + + // Write the bytes from the array. + // @param index index into the font data + // @param b the source for the bytes to be written + // @return the number of bytes actually written; -1 if the index is outside + // the FontData's range + virtual int32_t WriteBytes(int32_t index, ByteVector* b); + + // Write the bytes from the array and pad if necessary. + // Write to the length given using the byte array provided and if there are + // not enough bytes in the array then pad to the requested length using the + // pad byte specified. + // @param index index into the font data + // @param b the source for the bytes to be written + // @param offset offset in the byte array + // @param length the length of the bytes to be written + // @param pad the padding byte to be used if necessary + // @return the number of bytes actually written + virtual int32_t WriteBytesPad(int32_t index, + ByteVector* b, + int32_t offset, + int32_t length, + byte_t pad); + + // Writes padding to the FontData. The padding byte written is 0x00. + // @param index index into the font data + // @param count the number of pad bytes to write + // @return the number of pad bytes written + virtual int32_t WritePadding(int32_t index, int32_t count); + + // Writes padding to the FontData. + // @param index index into the font data + // @param count the number of pad bytes to write + // @param pad the byte value to use as padding + // @return the number of pad bytes written + virtual int32_t WritePadding(int32_t index, int32_t count, byte_t pad); + + // Write the CHAR at the given index. + // @param index index into the font data + // @param c the CHAR + // @return the number of bytes actually written + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t WriteChar(int32_t index, byte_t c); + + // Write the USHORT at the given index. + // @param index index into the font data + // @param us the USHORT + // @return the number of bytes actually written + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t WriteUShort(int32_t index, int32_t us); + + // Write the USHORT at the given index in little endian format. + // @param index index into the font data + // @param us the USHORT + // @return the number of bytes actually written + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t WriteUShortLE(int32_t index, int32_t us); + + // Write the SHORT at the given index. + // @param index index into the font data + // @param s the SHORT + // @return the number of bytes actually written + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t WriteShort(int32_t index, int32_t s); + + // Write the UINT24 at the given index. + // @param index index into the font data + // @param ui the UINT24 + // @return the number of bytes actually written + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t WriteUInt24(int32_t index, int32_t ui); + + // Write the ULONG at the given index. + // @param index index into the font data + // @param ul the ULONG + // @return the number of bytes actually written + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t WriteULong(int32_t index, int64_t ul); + + // Write the ULONG at the given index in little endian format. + // @param index index into the font data + // @param ul the ULONG + // @return the number of bytes actually written + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t WriteULongLE(int32_t index, int64_t ul); + + // Write the LONG at the given index. + // @param index index into the font data + // @param l the LONG + // @return the number of bytes actually written + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t WriteLong(int32_t index, int64_t l); + + // Write the Fixed at the given index. + // @param index index into the font data + // @param f the Fixed + // @return the number of bytes actually written + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t WriteFixed(int32_t index, int32_t f); + + // Write the LONGDATETIME at the given index. + // @param index index into the font data + // @param date the LONGDATETIME + // @return the number of bytes actually written + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t WriteDateTime(int32_t index, int64_t date); + + // Copy from the InputStream into this FontData. + // @param is the source + // @param length the number of bytes to copy + // @throws IOException + virtual void CopyFrom(InputStream* is, int32_t length); + + // Copy everything from the InputStream into this FontData. + // @param is the source + // @throws IOException + virtual void CopyFrom(InputStream* is); + + // Makes a slice of this FontData. The returned slice will share the data with + // the original FontData. + // @param offset the start of the slice + // @param length the number of bytes in the slice + // @return a slice of the original FontData + virtual CALLER_ATTACH FontData* Slice(int32_t offset, int32_t length); + + // Makes a bottom bound only slice of this array. The returned slice will + // share the data with the original FontData. + // @param offset the start of the slice + // @return a slice of the original FontData + virtual CALLER_ATTACH FontData* Slice(int32_t offset); + + private: + // Constructor with a lower bound. + // @param data other WritableFontData object to share data with + // @param offset offset from the other WritableFontData's data + WritableFontData(WritableFontData* data, int32_t offset); + + // Constructor with lower bound and a length bound. + // @param data other WritableFontData object to share data with + // @param offset offset from the other WritableFontData's data + // @param length length of other WritableFontData's data to use + WritableFontData(WritableFontData* data, int32_t offset, int32_t length); +}; +typedef Ptr WritableFontDataPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_DATA_WRITABLE_FONT_DATA_H_ diff --git a/src/sfntly/src/sfntly/font.cc b/src/sfntly/src/sfntly/font.cc new file mode 100644 index 0000000000..347e0c13e9 --- /dev/null +++ b/src/sfntly/src/sfntly/font.cc @@ -0,0 +1,557 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/font.h" + +#include + +#include +#include +#include +#include +#include +#include + +#include "sfntly/data/font_input_stream.h" +#include "sfntly/font_factory.h" +#include "sfntly/math/fixed1616.h" +#include "sfntly/math/font_math.h" +#include "sfntly/port/exception_type.h" +#include "sfntly/table/core/font_header_table.h" +#include "sfntly/table/core/horizontal_device_metrics_table.h" +#include "sfntly/table/core/horizontal_header_table.h" +#include "sfntly/table/core/horizontal_metrics_table.h" +#include "sfntly/table/core/maximum_profile_table.h" +#include "sfntly/table/truetype/loca_table.h" +#include "sfntly/tag.h" + +namespace sfntly { + +const int32_t SFNTVERSION_MAJOR = 1; +const int32_t SFNTVERSION_MINOR = 0; + +/****************************************************************************** + * Font class + ******************************************************************************/ +Font::~Font() {} + +bool Font::HasTable(int32_t tag) { + TableMap::const_iterator result = tables_.find(tag); + TableMap::const_iterator end = tables_.end(); + return (result != end); +} + +Table* Font::GetTable(int32_t tag) { + if (!HasTable(tag)) { + return NULL; + } + return tables_[tag]; +} + +const TableMap* Font::GetTableMap() { + return &tables_; +} + +void Font::Serialize(OutputStream* os, IntegerList* table_ordering) { + assert(table_ordering); + IntegerList final_table_ordering; + GenerateTableOrdering(table_ordering, &final_table_ordering); + TableHeaderList table_records; + BuildTableHeadersForSerialization(&final_table_ordering, &table_records); + + FontOutputStream fos(os); + SerializeHeader(&fos, &table_records); + SerializeTables(&fos, &table_records); +} + +Font::Font(int32_t sfnt_version, ByteVector* digest) + : sfnt_version_(sfnt_version) { + // non-trivial assignments that makes debugging hard if placed in + // initialization list + digest_ = *digest; +} + +void Font::BuildTableHeadersForSerialization(IntegerList* table_ordering, + TableHeaderList* table_headers) { + assert(table_headers); + assert(table_ordering); + + IntegerList final_table_ordering; + GenerateTableOrdering(table_ordering, &final_table_ordering); + int32_t table_offset = Offset::kTableRecordBegin + num_tables() * + Offset::kTableRecordSize; + for (IntegerList::iterator tag = final_table_ordering.begin(), + tag_end = final_table_ordering.end(); + tag != tag_end; ++tag) { + if (tables_.find(*tag) == tables_.end()) { + continue; + } + TablePtr table = tables_[*tag]; + if (table != NULL) { + HeaderPtr header = + new Header(*tag, table->CalculatedChecksum(), table_offset, + table->header()->length()); + table_headers->push_back(header); + table_offset += (table->DataLength() + 3) & ~3; + } + } +} + +void Font::SerializeHeader(FontOutputStream* fos, + TableHeaderList* table_headers) { + fos->WriteFixed(sfnt_version_); + fos->WriteUShort(table_headers->size()); + int32_t log2_of_max_power_of_2 = FontMath::Log2(table_headers->size()); + int32_t search_range = 2 << (log2_of_max_power_of_2 - 1 + 4); + fos->WriteUShort(search_range); + fos->WriteUShort(log2_of_max_power_of_2); + fos->WriteUShort((table_headers->size() * 16) - search_range); + + HeaderTagSortedSet sorted_headers; + std::copy(table_headers->begin(), + table_headers->end(), + std::inserter(sorted_headers, sorted_headers.end())); + + for (HeaderTagSortedSet::iterator record = sorted_headers.begin(), + record_end = sorted_headers.end(); + record != record_end; ++record) { + fos->WriteULong((*record)->tag()); + fos->WriteULong((int32_t)((*record)->checksum())); + fos->WriteULong((*record)->offset()); + fos->WriteULong((*record)->length()); + } +} + +void Font::SerializeTables(FontOutputStream* fos, + TableHeaderList* table_headers) { + assert(fos); + assert(table_headers); + for (TableHeaderList::iterator record = table_headers->begin(), + end_of_headers = table_headers->end(); + record != end_of_headers; ++record) { + TablePtr target_table = GetTable((*record)->tag()); + if (target_table == NULL) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("Table out of sync with font header."); +#endif + return; + } + int32_t table_size = target_table->Serialize(fos); + if (table_size != (*record)->length()) { + assert(false); + } + int32_t filler_size = ((table_size + 3) & ~3) - table_size; + for (int32_t i = 0; i < filler_size; ++i) { + fos->Write(static_cast(0)); + } + } +} + +void Font::GenerateTableOrdering(IntegerList* default_table_ordering, + IntegerList* table_ordering) { + assert(default_table_ordering); + assert(table_ordering); + table_ordering->clear(); + if (default_table_ordering->empty()) { + DefaultTableOrdering(default_table_ordering); + } + + typedef std::map Int2Bool; + typedef std::pair Int2BoolEntry; + Int2Bool tables_in_font; + for (TableMap::iterator table = tables_.begin(), table_end = tables_.end(); + table != table_end; ++table) { + tables_in_font.insert(Int2BoolEntry(table->first, false)); + } + for (IntegerList::iterator tag = default_table_ordering->begin(), + tag_end = default_table_ordering->end(); + tag != tag_end; ++tag) { + if (HasTable(*tag)) { + table_ordering->push_back(*tag); + tables_in_font[*tag] = true; + } + } + for (Int2Bool::iterator table = tables_in_font.begin(), + table_end = tables_in_font.end(); + table != table_end; ++table) { + if (table->second == false) + table_ordering->push_back(table->first); + } +} + +void Font::DefaultTableOrdering(IntegerList* default_table_ordering) { + assert(default_table_ordering); + default_table_ordering->clear(); + if (HasTable(Tag::CFF)) { + default_table_ordering->resize(CFF_TABLE_ORDERING_SIZE); + std::copy(CFF_TABLE_ORDERING, CFF_TABLE_ORDERING + CFF_TABLE_ORDERING_SIZE, + default_table_ordering->begin()); + return; + } + default_table_ordering->resize(TRUE_TYPE_TABLE_ORDERING_SIZE); + std::copy(TRUE_TYPE_TABLE_ORDERING, + TRUE_TYPE_TABLE_ORDERING + TRUE_TYPE_TABLE_ORDERING_SIZE, + default_table_ordering->begin()); +} + +/****************************************************************************** + * Font::Builder class + ******************************************************************************/ +Font::Builder::~Builder() {} + +CALLER_ATTACH Font::Builder* Font::Builder::GetOTFBuilder(FontFactory* factory, + InputStream* is) { + FontBuilderPtr builder = new Builder(factory); + builder->LoadFont(is); + return builder.Detach(); +} + +CALLER_ATTACH Font::Builder* Font::Builder::GetOTFBuilder( + FontFactory* factory, + WritableFontData* wfd, + int32_t offset_to_offset_table) { + FontBuilderPtr builder = new Builder(factory); + builder->LoadFont(wfd, offset_to_offset_table); + return builder.Detach(); +} + +CALLER_ATTACH Font::Builder* Font::Builder::GetOTFBuilder( + FontFactory* factory) { + FontBuilderPtr builder = new Builder(factory); + return builder.Detach(); +} + +bool Font::Builder::ReadyToBuild() { + // just read in data with no manipulation + if (table_builders_.empty() && !data_blocks_.empty()) { + return true; + } + + // TODO(stuartg): font level checks - required tables etc? + for (TableBuilderMap::iterator table_builder = table_builders_.begin(), + table_builder_end = table_builders_.end(); + table_builder != table_builder_end; + ++table_builder) { + if (!table_builder->second->ReadyToBuild()) + return false; + } + return true; +} + +CALLER_ATTACH Font* Font::Builder::Build() { + FontPtr font = new Font(sfnt_version_, &digest_); + + if (!table_builders_.empty()) { + // Note: Different from Java. Directly use font->tables_ here to avoid + // STL container copying. + BuildTablesFromBuilders(font, &table_builders_, &font->tables_); + } + + table_builders_.clear(); + data_blocks_.clear(); + return font.Detach(); +} + +void Font::Builder::SetDigest(ByteVector* digest) { + digest_.clear(); + digest_ = *digest; +} + +void Font::Builder::ClearTableBuilders() { + table_builders_.clear(); +} + +bool Font::Builder::HasTableBuilder(int32_t tag) { + return (table_builders_.find(tag) != table_builders_.end()); +} + +Table::Builder* Font::Builder::GetTableBuilder(int32_t tag) { + if (HasTableBuilder(tag)) + return table_builders_[tag]; + return NULL; +} + +Table::Builder* Font::Builder::NewTableBuilder(int32_t tag) { + HeaderPtr header = new Header(tag); + TableBuilderPtr builder; + builder.Attach(Table::Builder::GetBuilder(header, NULL)); + table_builders_.insert(TableBuilderEntry(header->tag(), builder)); + return builder; +} + +Table::Builder* Font::Builder::NewTableBuilder(int32_t tag, + ReadableFontData* src_data) { + assert(src_data); + WritableFontDataPtr data; + data.Attach(WritableFontData::CreateWritableFontData(src_data->Length())); + // TODO(stuarg): take over original data instead? + src_data->CopyTo(data); + + HeaderPtr header = new Header(tag, data->Length()); + TableBuilderPtr builder; + builder.Attach(Table::Builder::GetBuilder(header, data)); + table_builders_.insert(TableBuilderEntry(tag, builder)); + return builder; +} + +void Font::Builder::RemoveTableBuilder(int32_t tag) { + TableBuilderMap::iterator target = table_builders_.find(tag); + if (target != table_builders_.end()) { + table_builders_.erase(target); + } +} + +Font::Builder::Builder(FontFactory* factory) + : factory_(factory), + sfnt_version_(Fixed1616::Fixed(SFNTVERSION_MAJOR, SFNTVERSION_MINOR)) { +} + +void Font::Builder::LoadFont(InputStream* is) { + // Note: we do not throw exception here for is. This is more of an assertion. + assert(is); + FontInputStream font_is(is); + HeaderOffsetSortedSet records; + ReadHeader(&font_is, &records); + LoadTableData(&records, &font_is, &data_blocks_); + BuildAllTableBuilders(&data_blocks_, &table_builders_); + font_is.Close(); +} + +void Font::Builder::LoadFont(WritableFontData* wfd, + int32_t offset_to_offset_table) { + // Note: we do not throw exception here for is. This is more of an assertion. + assert(wfd); + HeaderOffsetSortedSet records; + ReadHeader(wfd, offset_to_offset_table, &records); + LoadTableData(&records, wfd, &data_blocks_); + BuildAllTableBuilders(&data_blocks_, &table_builders_); +} + +int32_t Font::Builder::SfntWrapperSize() { + return Offset::kSfntHeaderSize + + (Offset::kTableRecordSize * table_builders_.size()); +} + +void Font::Builder::BuildAllTableBuilders(DataBlockMap* table_data, + TableBuilderMap* builder_map) { + for (DataBlockMap::iterator record = table_data->begin(), + record_end = table_data->end(); + record != record_end; ++record) { + TableBuilderPtr builder; + builder.Attach(GetTableBuilder(record->first.p_, record->second.p_)); + builder_map->insert(TableBuilderEntry(record->first->tag(), builder)); + } + InterRelateBuilders(&table_builders_); +} + +CALLER_ATTACH +Table::Builder* Font::Builder::GetTableBuilder(Header* header, + WritableFontData* data) { + return Table::Builder::GetBuilder(header, data); +} + +void Font::Builder::BuildTablesFromBuilders(Font* font, + TableBuilderMap* builder_map, + TableMap* table_map) { + UNREFERENCED_PARAMETER(font); + InterRelateBuilders(builder_map); + + // Now build all the tables. + for (TableBuilderMap::iterator builder = builder_map->begin(), + builder_end = builder_map->end(); + builder != builder_end; ++builder) { + TablePtr table; + if (builder->second && builder->second->ReadyToBuild()) { + table.Attach(down_cast(builder->second->Build())); + } + if (table == NULL) { + table_map->clear(); +#if !defined (SFNTLY_NO_EXCEPTION) + std::string builder_string = "Unable to build table - "; + char* table_name = TagToString(builder->first); + builder_string += table_name; + delete[] table_name; + throw RuntimeException(builder_string.c_str()); +#endif + return; + } + table_map->insert(TableMapEntry(table->header()->tag(), table)); + } +} + +static Table::Builder* GetBuilder(TableBuilderMap* builder_map, int32_t tag) { + if (builder_map) { + TableBuilderMap::iterator target = builder_map->find(tag); + if (target != builder_map->end()) { + return target->second.p_; + } + } + + return NULL; +} + +void Font::Builder::InterRelateBuilders(TableBuilderMap* builder_map) { + Table::Builder* raw_head_builder = GetBuilder(builder_map, Tag::head); + FontHeaderTableBuilderPtr header_table_builder; + if (raw_head_builder != NULL) { + header_table_builder = + down_cast(raw_head_builder); + } + + Table::Builder* raw_hhea_builder = GetBuilder(builder_map, Tag::hhea); + HorizontalHeaderTableBuilderPtr horizontal_header_builder; + if (raw_head_builder != NULL) { + horizontal_header_builder = + down_cast(raw_hhea_builder); + } + + Table::Builder* raw_maxp_builder = GetBuilder(builder_map, Tag::maxp); + MaximumProfileTableBuilderPtr max_profile_builder; + if (raw_maxp_builder != NULL) { + max_profile_builder = + down_cast(raw_maxp_builder); + } + + Table::Builder* raw_loca_builder = GetBuilder(builder_map, Tag::loca); + LocaTableBuilderPtr loca_table_builder; + if (raw_loca_builder != NULL) { + loca_table_builder = down_cast(raw_loca_builder); + } + + Table::Builder* raw_hmtx_builder = GetBuilder(builder_map, Tag::hmtx); + HorizontalMetricsTableBuilderPtr horizontal_metrics_builder; + if (raw_hmtx_builder != NULL) { + horizontal_metrics_builder = + down_cast(raw_hmtx_builder); + } + +#if defined (SFNTLY_EXPERIMENTAL) + Table::Builder* raw_hdmx_builder = GetBuilder(builder_map, Tag::hdmx); + HorizontalDeviceMetricsTableBuilderPtr hdmx_table_builder; + if (raw_hdmx_builder != NULL) { + hdmx_table_builder = + down_cast(raw_hdmx_builder); + } +#endif + + // set the inter table data required to build certain tables + if (horizontal_metrics_builder != NULL) { + if (max_profile_builder != NULL) { + horizontal_metrics_builder->SetNumGlyphs( + max_profile_builder->NumGlyphs()); + } + if (horizontal_header_builder != NULL) { + horizontal_metrics_builder->SetNumberOfHMetrics( + horizontal_header_builder->NumberOfHMetrics()); + } + } + + if (loca_table_builder != NULL) { + if (max_profile_builder != NULL) { + loca_table_builder->SetNumGlyphs(max_profile_builder->NumGlyphs()); + } + if (header_table_builder != NULL) { + loca_table_builder->set_format_version( + header_table_builder->IndexToLocFormat()); + } + } + +#if defined (SFNTLY_EXPERIMENTAL) + // Note: In C++, hdmx_table_builder can be NULL in a subsetter. + if (max_profile_builder != NULL && hdmx_table_builder != NULL) { + hdmx_table_builder->SetNumGlyphs(max_profile_builder->NumGlyphs()); + } +#endif +} + +void Font::Builder::ReadHeader(FontInputStream* is, + HeaderOffsetSortedSet* records) { + assert(records); + sfnt_version_ = is->ReadFixed(); + num_tables_ = is->ReadUShort(); + search_range_ = is->ReadUShort(); + entry_selector_ = is->ReadUShort(); + range_shift_ = is->ReadUShort(); + + for (int32_t table_number = 0; table_number < num_tables_; ++table_number) { + // Need to use temporary vars here. C++ evaluates function parameters from + // right to left and thus breaks the order of input stream. + int32_t tag = is->ReadULongAsInt(); + int64_t checksum = is->ReadULong(); + int32_t offset = is->ReadULongAsInt(); + int32_t length = is->ReadULongAsInt(); + HeaderPtr table = new Header(tag, checksum, offset, length); + records->insert(table); + } +} + +void Font::Builder::ReadHeader(ReadableFontData* fd, + int32_t offset, + HeaderOffsetSortedSet* records) { + assert(records); + sfnt_version_ = fd->ReadFixed(offset + Offset::kSfntVersion); + num_tables_ = fd->ReadUShort(offset + Offset::kNumTables); + search_range_ = fd->ReadUShort(offset + Offset::kSearchRange); + entry_selector_ = fd->ReadUShort(offset + Offset::kEntrySelector); + range_shift_ = fd->ReadUShort(offset + Offset::kRangeShift); + + int32_t table_offset = offset + Offset::kTableRecordBegin; + for (int32_t table_number = 0; + table_number < num_tables_; + table_number++, table_offset += Offset::kTableRecordSize) { + int32_t tag = fd->ReadULongAsInt(table_offset + Offset::kTableTag); + int64_t checksum = fd->ReadULong(table_offset + Offset::kTableCheckSum); + int32_t offset = fd->ReadULongAsInt(table_offset + Offset::kTableOffset); + int32_t length = fd->ReadULongAsInt(table_offset + Offset::kTableLength); + HeaderPtr table = new Header(tag, checksum, offset, length); + records->insert(table); + } +} + +void Font::Builder::LoadTableData(HeaderOffsetSortedSet* headers, + FontInputStream* is, + DataBlockMap* table_data) { + assert(table_data); + for (HeaderOffsetSortedSet::iterator table_header = headers->begin(), + table_end = headers->end(); + table_header != table_end; + ++table_header) { + is->Skip((*table_header)->offset() - is->position()); + FontInputStream table_is(is, (*table_header)->length()); + WritableFontDataPtr data; + data.Attach( + WritableFontData::CreateWritableFontData((*table_header)->length())); + data->CopyFrom(&table_is, (*table_header)->length()); + table_data->insert(DataBlockEntry(*table_header, data)); + } +} + +void Font::Builder::LoadTableData(HeaderOffsetSortedSet* headers, + WritableFontData* fd, + DataBlockMap* table_data) { + for (HeaderOffsetSortedSet::iterator table_header = headers->begin(), + table_end = headers->end(); + table_header != table_end; + ++table_header) { + FontDataPtr sliced_data; + sliced_data.Attach( + fd->Slice((*table_header)->offset(), (*table_header)->length())); + WritableFontDataPtr data = down_cast(sliced_data.p_); + table_data->insert(DataBlockEntry(*table_header, data)); + } +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/font.h b/src/sfntly/src/sfntly/font.h new file mode 100644 index 0000000000..975e8cc52c --- /dev/null +++ b/src/sfntly/src/sfntly/font.h @@ -0,0 +1,352 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_FONT_H_ +#define SFNTLY_CPP_SRC_SFNTLY_FONT_H_ + +#include + +#include "sfntly/port/refcount.h" +#include "sfntly/port/type.h" +#include "sfntly/port/endian.h" +#include "sfntly/data/font_input_stream.h" +#include "sfntly/data/font_output_stream.h" +#include "sfntly/data/writable_font_data.h" +#include "sfntly/table/table.h" + +namespace sfntly { + +// Note: following constants are embedded in Font class in Java. They are +// extracted out for easier reference from other classes. Offset is the +// one that is kept within class. +// Platform ids. These are used in a number of places within the font whenever +// the platform needs to be specified. +struct PlatformId { + enum { + kUnknown = -1, + kUnicode = 0, + kMacintosh = 1, + kISO = 2, + kWindows = 3, + kCustom = 4 + }; +}; + +// Unicode encoding ids. These are used in a number of places within the font +// whenever character encodings need to be specified. +struct UnicodeEncodingId { + enum { + kUnknown = -1, + kUnicode1_0 = 0, + kUnicode1_1 = 1, + kISO10646 = 2, + kUnicode2_0_BMP = 3, + kUnicode2_0 = 4, + kUnicodeVariationSequences = 5 + }; +}; + +// Windows encoding ids. These are used in a number of places within the font +// whenever character encodings need to be specified. +struct WindowsEncodingId { + enum { + kUnknown = 0xffffffff, + kSymbol = 0, + kUnicodeUCS2 = 1, + kShiftJIS = 2, + kPRC = 3, + kBig5 = 4, + kWansung = 5, + kJohab = 6, + kUnicodeUCS4 = 10 + }; +}; + +// Macintosh encoding ids. These are used in a number of places within the +// font whenever character encodings need to be specified. +struct MacintoshEncodingId { + // Macintosh Platform Encodings + enum { + kUnknown = -1, + kRoman = 0, + kJapanese = 1, + kChineseTraditional = 2, + kKorean = 3, + kArabic = 4, + kHebrew = 5, + kGreek = 6, + kRussian = 7, + kRSymbol = 8, + kDevanagari = 9, + kGurmukhi = 10, + kGujarati = 11, + kOriya = 12, + kBengali = 13, + kTamil = 14, + kTelugu = 15, + kKannada = 16, + kMalayalam = 17, + kSinhalese = 18, + kBurmese = 19, + kKhmer = 20, + kThai = 21, + kLaotian = 22, + kGeorgian = 23, + kArmenian = 24, + kChineseSimplified = 25, + kTibetan = 26, + kMongolian = 27, + kGeez = 28, + kSlavic = 29, + kVietnamese = 30, + kSindhi = 31, + kUninterpreted = 32 + }; +}; + +class FontFactory; + +// An sfnt container font object. This object is immutable and thread safe. To +// construct one use an instance of Font::Builder. +class Font : public RefCounted { + public: + // A builder for a font object. The builder allows the for the creation of + // immutable Font objects. The builder is a one use non-thread safe object and + // once the Font object has been created it is no longer usable. To create a + // further Font object new builder will be required. + class Builder : public RefCounted { + public: + virtual ~Builder(); + + static CALLER_ATTACH Builder* + GetOTFBuilder(FontFactory* factory, InputStream* is); + static CALLER_ATTACH Builder* + GetOTFBuilder(FontFactory* factory, + WritableFontData* ba, + int32_t offset_to_offset_table); + static CALLER_ATTACH Builder* GetOTFBuilder(FontFactory* factory); + + // Get the font factory that created this font builder. + FontFactory* GetFontFactory() { return factory_; } + + // Is the font ready to build? + bool ReadyToBuild(); + + // Build the Font. After this call this builder will no longer be usable. + CALLER_ATTACH Font* Build(); + + // Set a unique fingerprint for the font object. + void SetDigest(ByteVector* digest); + + // Clear all table builders. + void ClearTableBuilders(); + + // Does this font builder have the specified table builder. + bool HasTableBuilder(int32_t tag); + + // Get the table builder for the given tag. If there is no builder for that + // tag then return a null. + Table::Builder* GetTableBuilder(int32_t tag); + + // Creates a new table builder for the table type given by the table id tag. + // This new table has been added to the font and will replace any existing + // builder for that table. + // @return new empty table of the type specified by tag; if tag is not known + // then a generic OpenTypeTable is returned + virtual Table::Builder* NewTableBuilder(int32_t tag); + + // Creates a new table builder for the table type given by the table id tag. + // It makes a copy of the data provided and uses that copy for the table. + // This new table has been added to the font and will replace any existing + // builder for that table. + virtual Table::Builder* NewTableBuilder(int32_t tag, + ReadableFontData* src_data); + + // Get a map of the table builders in this font builder accessed by table + // tag. + virtual TableBuilderMap* table_builders() { return &table_builders_; } + + // Remove the specified table builder from the font builder. + // Note: different from Java: we don't return object in removeTableBuilder + virtual void RemoveTableBuilder(int32_t tag); + + // Get the number of table builders in the font builder. + virtual int32_t number_of_table_builders() { + return (int32_t)table_builders_.size(); + } + + private: + explicit Builder(FontFactory* factory); + virtual void LoadFont(InputStream* is); + virtual void LoadFont(WritableFontData* wfd, + int32_t offset_to_offset_table); + int32_t SfntWrapperSize(); + void BuildAllTableBuilders(DataBlockMap* table_data, + TableBuilderMap* builder_map); + CALLER_ATTACH Table::Builder* + GetTableBuilder(Header* header, WritableFontData* data); + void BuildTablesFromBuilders(Font* font, + TableBuilderMap* builder_map, + TableMap* tables); + static void InterRelateBuilders(TableBuilderMap* builder_map); + + void ReadHeader(FontInputStream* is, + HeaderOffsetSortedSet* records); + + void ReadHeader(ReadableFontData* fd, + int32_t offset, + HeaderOffsetSortedSet* records); + + void LoadTableData(HeaderOffsetSortedSet* headers, + FontInputStream* is, + DataBlockMap* table_data); + + void LoadTableData(HeaderOffsetSortedSet* headers, + WritableFontData* fd, + DataBlockMap* table_data); + + TableBuilderMap table_builders_; + FontFactory* factory_; // dumb pointer, avoid circular refcounting + int32_t sfnt_version_; + int32_t num_tables_; + int32_t search_range_; + int32_t entry_selector_; + int32_t range_shift_; + DataBlockMap data_blocks_; + ByteVector digest_; + }; + + virtual ~Font(); + + // Gets the sfnt version set in the sfnt wrapper of the font. + int32_t sfnt_version() { return sfnt_version_; } + + // Gets a copy of the fonts digest that was created when the font was read. If + // no digest was set at creation time then the return result will be null. + ByteVector* digest() { return &digest_; } + + // Get the checksum for this font. + int64_t checksum() { return checksum_; } + + // Get the number of tables in this font. + int32_t num_tables() { return (int32_t)tables_.size(); } + + // Whether the font has a particular table. + bool HasTable(int32_t tag); + + // UNIMPLEMENTED: public Iterator iterator + + // Get the table in this font with the specified id. + // @param tag the identifier of the table + // @return the table specified if it exists; null otherwise + // C++ port: rename table() to GetTable() + Table* GetTable(int32_t tag); + + // Get a map of the tables in this font accessed by table tag. + // @return an unmodifiable view of the tables in this font + // Note: renamed tableMap() to GetTableMap() + const TableMap* GetTableMap(); + + // UNIMPLEMENTED: toString() + + // Serialize the font to the output stream. + // @param os the destination for the font serialization + // @param tableOrdering the table ordering to apply + void Serialize(OutputStream* os, IntegerList* table_ordering); + + private: + // Offsets to specific elements in the underlying data. These offsets are + // relative to the start of the table or the start of sub-blocks within the + // table. + struct Offset { + enum { + // Offsets within the main directory + kSfntVersion = 0, + kNumTables = 4, + kSearchRange = 6, + kEntrySelector = 8, + kRangeShift = 10, + kTableRecordBegin = 12, + kSfntHeaderSize = 12, + + // Offsets within a specific table record + kTableTag = 0, + kTableCheckSum = 4, + kTableOffset = 8, + kTableLength = 12, + kTableRecordSize = 16 + }; + }; + + // Note: the two constants are moved to tag.h to avoid VC++ bug. +// static const int32_t CFF_TABLE_ORDERING[]; +// static const int32_t TRUE_TYPE_TABLE_ORDERING[]; + + // Constructor. + // @param sfntVersion the sfnt version + // @param digest the computed digest for the font; null if digest was not + // computed + // Note: Current C++ port does not support SHA digest validation. + Font(int32_t sfnt_version, ByteVector* digest); + + // Build the table headers to be used for serialization. These headers will be + // filled out with the data required for serialization. The headers will be + // sorted in the order specified and only those specified will have headers + // generated. + // @param tableOrdering the tables to generate headers for and the order to + // sort them + // @return a list of table headers ready for serialization + void BuildTableHeadersForSerialization(IntegerList* table_ordering, + TableHeaderList* table_headers); + + // Searialize the headers. + // @param fos the destination stream for the headers + // @param tableHeaders the headers to serialize + // @throws IOException + void SerializeHeader(FontOutputStream* fos, TableHeaderList* table_headers); + + // Serialize the tables. + // @param fos the destination stream for the headers + // @param tableHeaders the headers for the tables to serialize + // @throws IOException + void SerializeTables(FontOutputStream* fos, TableHeaderList* table_headers); + + // Generate the full table ordering to used for serialization. The full + // ordering uses the partial ordering as a seed and then adds all remaining + // tables in the font in an undefined order. + // @param defaultTableOrdering the partial ordering to be used as a seed for + // the full ordering + // @param (out) table_ordering the full ordering for serialization + void GenerateTableOrdering(IntegerList* default_table_ordering, + IntegerList* table_ordering); + + // Get the default table ordering based on the type of the font. + // @param (out) default_table_ordering the default table ordering + void DefaultTableOrdering(IntegerList* default_table_ordering); + + int32_t sfnt_version_; + ByteVector digest_; + int64_t checksum_; + TableMap tables_; +}; +typedef Ptr FontPtr; +typedef std::vector FontArray; +typedef Ptr FontBuilderPtr; +typedef std::vector FontBuilderArray; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_FONT_H_ diff --git a/src/sfntly/src/sfntly/font_factory.cc b/src/sfntly/src/sfntly/font_factory.cc new file mode 100644 index 0000000000..c162a77af3 --- /dev/null +++ b/src/sfntly/src/sfntly/font_factory.cc @@ -0,0 +1,214 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/font_factory.h" + +#include + +#include "sfntly/tag.h" + +namespace sfntly { + +FontFactory::~FontFactory() { +} + +CALLER_ATTACH FontFactory* FontFactory::GetInstance() { + FontFactoryPtr instance = new FontFactory(); + return instance.Detach(); +} + +void FontFactory::FingerprintFont(bool fingerprint) { + fingerprint_ = fingerprint; +} + +bool FontFactory::FingerprintFont() { + return fingerprint_; +} + +void FontFactory::LoadFonts(InputStream* is, FontArray* output) { + assert(output); + PushbackInputStream* pbis = down_cast(is); + if (IsCollection(pbis)) { + LoadCollection(pbis, output); + return; + } + FontPtr font; + font.Attach(LoadSingleOTF(pbis)); + if (font) { + output->push_back(font); + } +} + +void FontFactory::LoadFonts(ByteVector* b, FontArray* output) { + WritableFontDataPtr wfd; + wfd.Attach(WritableFontData::CreateWritableFontData(b)); + if (IsCollection(wfd)) { + LoadCollection(wfd, output); + return; + } + FontPtr font; + font.Attach(LoadSingleOTF(wfd)); + if (font) { + output->push_back(font); + } +} + +void FontFactory::LoadFontsForBuilding(InputStream* is, + FontBuilderArray* output) { + PushbackInputStream* pbis = down_cast(is); + if (IsCollection(pbis)) { + LoadCollectionForBuilding(pbis, output); + return; + } + FontBuilderPtr builder; + builder.Attach(LoadSingleOTFForBuilding(pbis)); + if (builder) { + output->push_back(builder); + } +} + +void FontFactory::LoadFontsForBuilding(ByteVector* b, + FontBuilderArray* output) { + WritableFontDataPtr wfd; + wfd.Attach(WritableFontData::CreateWritableFontData(b)); + if (IsCollection(wfd)) { + LoadCollectionForBuilding(wfd, output); + return; + } + FontBuilderPtr builder; + builder.Attach(LoadSingleOTFForBuilding(wfd, 0)); + if (builder) { + output->push_back(builder); + } +} + +void FontFactory::SerializeFont(Font* font, OutputStream* os) { + font->Serialize(os, &table_ordering_); +} + +void FontFactory::SetSerializationTableOrdering( + const IntegerList& table_ordering) { + table_ordering_ = table_ordering; +} + +CALLER_ATTACH Font::Builder* FontFactory::NewFontBuilder() { + return Font::Builder::GetOTFBuilder(this); +} + +CALLER_ATTACH Font* FontFactory::LoadSingleOTF(InputStream* is) { + FontBuilderPtr builder; + builder.Attach(LoadSingleOTFForBuilding(is)); + return builder->Build(); +} + +CALLER_ATTACH Font* FontFactory::LoadSingleOTF(WritableFontData* wfd) { + FontBuilderPtr builder; + builder.Attach(LoadSingleOTFForBuilding(wfd, 0)); + return builder->Build(); +} + +void FontFactory::LoadCollection(InputStream* is, FontArray* output) { + FontBuilderArray ba; + LoadCollectionForBuilding(is, &ba); + output->reserve(ba.size()); + for (FontBuilderArray::iterator builder = ba.begin(), builders_end = ba.end(); + builder != builders_end; ++builder) { + FontPtr font; + font.Attach((*builder)->Build()); + output->push_back(font); + } +} + +void FontFactory::LoadCollection(WritableFontData* wfd, FontArray* output) { + FontBuilderArray builders; + LoadCollectionForBuilding(wfd, &builders); + output->reserve(builders.size()); + for (FontBuilderArray::iterator builder = builders.begin(), + builders_end = builders.end(); + builder != builders_end; ++builder) { + FontPtr font; + font.Attach((*builder)->Build()); + output->push_back(font); + } +} + +CALLER_ATTACH +Font::Builder* FontFactory::LoadSingleOTFForBuilding(InputStream* is) { + // UNIMPLEMENTED: SHA-1 hash checking via Java DigestStream + Font::Builder* builder = Font::Builder::GetOTFBuilder(this, is); + // UNIMPLEMENTED: setDigest + return builder; +} + +CALLER_ATTACH Font::Builder* + FontFactory::LoadSingleOTFForBuilding(WritableFontData* wfd, + int32_t offset_to_offset_table) { + // UNIMPLEMENTED: SHA-1 hash checking via Java DigestStream + Font::Builder* builder = + Font::Builder::GetOTFBuilder(this, wfd, offset_to_offset_table); + // UNIMPLEMENTED: setDigest + return builder; +} + +void FontFactory::LoadCollectionForBuilding(InputStream* is, + FontBuilderArray* builders) { + assert(is); + assert(builders); + WritableFontDataPtr wfd; + wfd.Attach(WritableFontData::CreateWritableFontData(is->Available())); + wfd->CopyFrom(is); + LoadCollectionForBuilding(wfd, builders); +} + +void FontFactory::LoadCollectionForBuilding(WritableFontData* wfd, + FontBuilderArray* builders) { + int32_t ttc_tag = wfd->ReadULongAsInt(Offset::kTTCTag); + UNREFERENCED_PARAMETER(ttc_tag); + int32_t version = wfd->ReadFixed(Offset::kVersion); + UNREFERENCED_PARAMETER(version); + int32_t num_fonts = wfd->ReadULongAsInt(Offset::kNumFonts); + + builders->reserve(num_fonts); + int32_t offset_table_offset = Offset::kOffsetTable; + for (int32_t font_number = 0; + font_number < num_fonts; + font_number++, offset_table_offset += DataSize::kULONG) { + int32_t offset = wfd->ReadULongAsInt(offset_table_offset); + FontBuilderPtr builder; + builder.Attach(LoadSingleOTFForBuilding(wfd, offset)); + builders->push_back(builder); + } +} + +bool FontFactory::IsCollection(PushbackInputStream* pbis) { + ByteVector tag(4); + pbis->Read(&tag); + pbis->Unread(&tag); + return Tag::ttcf == GenerateTag(tag[0], tag[1], tag[2], tag[3]); +} + +bool FontFactory::IsCollection(ReadableFontData* rfd) { + ByteVector tag(4); + rfd->ReadBytes(0, &(tag[0]), 0, tag.size()); + return Tag::ttcf == + GenerateTag(tag[0], tag[1], tag[2], tag[3]); +} + +FontFactory::FontFactory() + : fingerprint_(false) { +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/font_factory.h b/src/sfntly/src/sfntly/font_factory.h new file mode 100644 index 0000000000..63deff4abf --- /dev/null +++ b/src/sfntly/src/sfntly/font_factory.h @@ -0,0 +1,140 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_FONT_FACTORY_H_ +#define SFNTLY_CPP_SRC_SFNTLY_FONT_FACTORY_H_ + +#include + +#include "sfntly/port/refcount.h" +#include "sfntly/port/type.h" +#include "sfntly/font.h" + +namespace sfntly { + +class FontFactory : public RefCounted { + public: + virtual ~FontFactory(); + + // Factory method for the construction of a font factory. + static CALLER_ATTACH FontFactory* GetInstance(); + + // Toggle whether fonts that are loaded are fingerprinted with a SHA-1 hash. + // If a font is fingerprinted then a SHA-1 hash is generated at load time and + // stored in the font. This is useful for uniquely identifying fonts. By + // default this is turned on. + // @param fingerprint whether fingerprinting should be turned on or off + // TODO(arthurhsu): IMPLEMENT: C++ port currently don't do any SHA-1 + void FingerprintFont(bool fingerprint); + bool FingerprintFont(); + + // Load the font(s) from the input stream. The current settings on the factory + // are used during the loading process. One or more fonts are returned if the + // stream contains valid font data. Some font container formats may have more + // than one font and in this case multiple font objects will be returned. If + // the data in the stream cannot be parsed or is invalid an array of size zero + // will be returned. + void LoadFonts(InputStream* is, FontArray* output); + + // ByteArray font loading + // Load the font(s) from the byte array. The current settings on the factory + // are used during the loading process. One or more fonts are returned if the + // stream contains valid font data. Some font container formats may have more + // than one font and in this case multiple font objects will be returned. If + // the data in the stream cannot be parsed or is invalid an array of size zero + // will be returned. + void LoadFonts(ByteVector* b, FontArray* output); + + // Load the font(s) from the input stream into font builders. The current + // settings on the factory are used during the loading process. One or more + // font builders are returned if the stream contains valid font data. Some + // font container formats may have more than one font and in this case + // multiple font builder objects will be returned. If the data in the stream + // cannot be parsed or is invalid an array of size zero will be returned. + void LoadFontsForBuilding(InputStream* is, FontBuilderArray* output); + + // Load the font(s) from the byte array into font builders. The current + // settings on the factory are used during the loading process. One or more + // font builders are returned if the stream contains valid font data. Some + // font container formats may have more than one font and in this case + // multiple font builder objects will be returned. If the data in the stream + // cannot be parsed or is invalid an array of size zero will be returned. + void LoadFontsForBuilding(ByteVector* b, FontBuilderArray* output); + + // Font serialization + // Serialize the font to the output stream. + // NOTE: in this port we attempted not to implement I/O stream because dealing + // with cross-platform I/O stream itself is big enough as a project. + // Byte buffer it is. + void SerializeFont(Font* font, OutputStream* os); + + // Set the table ordering to be used in serializing a font. The table ordering + // is an ordered list of table ids and tables will be serialized in the order + // given. Any tables whose id is not listed in the ordering will be placed in + // an unspecified order following those listed. + void SetSerializationTableOrdering(const IntegerList& table_ordering); + + // Get an empty font builder for creating a new font from scratch. + CALLER_ATTACH Font::Builder* NewFontBuilder(); + + private: + // Offsets to specific elements in the underlying data. These offsets are + // relative to the start of the table or the start of sub-blocks within the + // table. + struct Offset { + enum { + // Offsets within the main directory. + kTTCTag = 0, + kVersion = 4, + kNumFonts = 8, + kOffsetTable = 12, + + // TTC Version 2.0 extensions. + // Offsets from end of OffsetTable. + kulDsigTag = 0, + kulDsigLength = 4, + kulDsigOffset = 8 + }; + }; + + FontFactory(); + + CALLER_ATTACH Font* LoadSingleOTF(InputStream* is); + CALLER_ATTACH Font* LoadSingleOTF(WritableFontData* wfd); + + void LoadCollection(InputStream* is, FontArray* output); + void LoadCollection(WritableFontData* wfd, FontArray* output); + + CALLER_ATTACH Font::Builder* LoadSingleOTFForBuilding(InputStream* is); + CALLER_ATTACH Font::Builder* + LoadSingleOTFForBuilding(WritableFontData* wfd, + int32_t offset_to_offset_table); + + void LoadCollectionForBuilding(InputStream* is, FontBuilderArray* builders); + void LoadCollectionForBuilding(WritableFontData* ba, + FontBuilderArray* builders); + + static bool IsCollection(PushbackInputStream* pbis); + static bool IsCollection(ReadableFontData* wfd); + + bool fingerprint_; + IntegerList table_ordering_; +}; +typedef Ptr FontFactoryPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_FONT_FACTORY_H_ diff --git a/src/sfntly/src/sfntly/math/fixed1616.h b/src/sfntly/src/sfntly/math/fixed1616.h new file mode 100644 index 0000000000..4abbe18098 --- /dev/null +++ b/src/sfntly/src/sfntly/math/fixed1616.h @@ -0,0 +1,41 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_MATH_FIXED1616_H_ +#define SFNTLY_CPP_SRC_SFNTLY_MATH_FIXED1616_H_ + +#include "sfntly/port/type.h" + +namespace sfntly { + +class Fixed1616 { + public: + static inline int32_t Integral(int32_t fixed) { + return (fixed >> 16); + } + + static inline int32_t Fractional(int32_t fixed) { + return (fixed & 0xffff); + } + + static inline int32_t Fixed(int32_t integral, int32_t fractional) { + return ((integral & 0xffff) << 16) | (fractional & 0xffff); + } +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_MATH_FIXED1616_H_ diff --git a/src/sfntly/src/sfntly/math/font_math.h b/src/sfntly/src/sfntly/math/font_math.h new file mode 100644 index 0000000000..f1cd2d2a6f --- /dev/null +++ b/src/sfntly/src/sfntly/math/font_math.h @@ -0,0 +1,49 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_MATH_FONT_MATH_H_ +#define SFNTLY_CPP_SRC_SFNTLY_MATH_FONT_MATH_H_ + +#include "sfntly/port/type.h" + +namespace sfntly { + +class FontMath { + public: + static int32_t Log2(int32_t a) { + int r = 0; // r will be lg(a) + while (a != 0) { + a >>= 1; + r++; + } + return r - 1; + } + + // Calculates the amount of padding needed. The values provided need to be in + // the same units. So, if the size is given as the number of bytes then the + // alignment size must also be specified as byte size to align to. + // @param size the size of the data that may need padding + // @param alignmentSize the number of units to align to + // @return the number of units needing to be added for alignment + static int32_t PaddingRequired(int32_t size, int32_t alignment_size) { + int32_t padding = alignment_size - (size % alignment_size); + return padding == alignment_size ? 0 : padding; + } +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_MATH_FONT_MATH_H_ diff --git a/src/sfntly/src/sfntly/port/atomic.h b/src/sfntly/src/sfntly/port/atomic.h new file mode 100644 index 0000000000..b381a52af7 --- /dev/null +++ b/src/sfntly/src/sfntly/port/atomic.h @@ -0,0 +1,71 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_ATOMIC_H_ +#define SFNTLY_CPP_SRC_SFNTLY_PORT_ATOMIC_H_ + +#if defined (WIN32) + +#include + +static inline size_t AtomicIncrement(size_t* address) { +#if defined (_WIN64) + return InterlockedIncrement64(reinterpret_cast(address)); +#else + return InterlockedIncrement(reinterpret_cast(address)); +#endif +} + +static inline size_t AtomicDecrement(size_t* address) { +#if defined (_WIN64) + return InterlockedDecrement64(reinterpret_cast(address)); +#else + return InterlockedDecrement(reinterpret_cast(address)); +#endif +} + +#elif defined (__APPLE__) + +#include + +static inline size_t AtomicIncrement(size_t* address) { + return OSAtomicIncrement32Barrier(reinterpret_cast(address)); +} + +static inline size_t AtomicDecrement(size_t* address) { + return OSAtomicDecrement32Barrier(reinterpret_cast(address)); +} + +// Originally we check __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4, however, there are +// issues that clang not carring over this definition. Therefore we boldly +// assume it's gcc or gcc-compatible here. Compilation shall still fail since +// the intrinsics used are GCC-specific. + +#else + +#include + +static inline size_t AtomicIncrement(size_t* address) { + return __sync_add_and_fetch(address, 1); +} + +static inline size_t AtomicDecrement(size_t* address) { + return __sync_sub_and_fetch(address, 1); +} + +#endif // WIN32 + +#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_ATOMIC_H_ diff --git a/src/sfntly/src/sfntly/port/config.h b/src/sfntly/src/sfntly/port/config.h new file mode 100644 index 0000000000..0fcdffe724 --- /dev/null +++ b/src/sfntly/src/sfntly/port/config.h @@ -0,0 +1,28 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_CONFIG_H_ +#define SFNTLY_CPP_SRC_SFNTLY_PORT_CONFIG_H_ + +#if !defined(SFNTLY_BIG_ENDIAN) && !defined(SFNTLY_LITTLE_ENDIAN) + #if defined (__ppc__) || defined (__ppc64__) + #define SFNTLY_BIG_ENDIAN + #else + #define SFNTLY_LITTLE_ENDIAN + #endif +#endif + +#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_CONFIG_H_ diff --git a/src/sfntly/src/sfntly/port/endian.h b/src/sfntly/src/sfntly/port/endian.h new file mode 100644 index 0000000000..db58f0a307 --- /dev/null +++ b/src/sfntly/src/sfntly/port/endian.h @@ -0,0 +1,77 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_ENDIAN_H_ +#define SFNTLY_CPP_SRC_SFNTLY_PORT_ENDIAN_H_ + +#include "sfntly/port/config.h" +#include "sfntly/port/type.h" + +namespace sfntly { + +static inline uint16_t EndianSwap16(uint16_t value) { + return (uint16_t)((value >> 8) | (value << 8)); +} + +static inline int32_t EndianSwap32(int32_t value) { + return (((value & 0x000000ff) << 24) | + ((value & 0x0000ff00) << 8) | + ((value & 0x00ff0000) >> 8) | + ((value & 0xff000000) >> 24)); +} + +static inline uint64_t EndianSwap64(uint64_t value) { + return (((value & 0x00000000000000ffLL) << 56) | + ((value & 0x000000000000ff00LL) << 40) | + ((value & 0x0000000000ff0000LL) << 24) | + ((value & 0x00000000ff000000LL) << 8) | + ((value & 0x000000ff00000000LL) >> 8) | + ((value & 0x0000ff0000000000LL) >> 24) | + ((value & 0x00ff000000000000LL) >> 40) | + ((value & 0xff00000000000000LL) >> 56)); +} + +#ifdef SFNTLY_LITTLE_ENDIAN + #define ToBE16(n) EndianSwap16(n) + #define ToBE32(n) EndianSwap32(n) + #define ToBE64(n) EndianSwap64(n) + #define ToLE16(n) (n) + #define ToLE32(n) (n) + #define ToLE64(n) (n) + #define FromBE16(n) EndianSwap16(n) + #define FromBE32(n) EndianSwap32(n) + #define FromBE64(n) EndianSwap64(n) + #define FromLE16(n) (n) + #define FromLE32(n) (n) + #define FromLE64(n) (n) +#else // SFNTLY_BIG_ENDIAN + #define ToBE16(n) (n) + #define ToBE32(n) (n) + #define ToBE64(n) (n) + #define ToLE16(n) EndianSwap16(n) + #define ToLE32(n) EndianSwap32(n) + #define ToLE64(n) EndianSwap64(n) + #define FromBE16(n) (n) + #define FromBE32(n) (n) + #define FromBE64(n) (n) + #define FromLE16(n) EndianSwap16(n) + #define FromLE32(n) EndianSwap32(n) + #define FromLE64(n) EndianSwap64(n) +#endif + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_ENDIAN_H_ diff --git a/src/sfntly/src/sfntly/port/exception_type.h b/src/sfntly/src/sfntly/port/exception_type.h new file mode 100644 index 0000000000..b96efcb6c5 --- /dev/null +++ b/src/sfntly/src/sfntly/port/exception_type.h @@ -0,0 +1,125 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Exceptions used in sfntly + +#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_EXCEPTION_TYPE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_PORT_EXCEPTION_TYPE_H_ + +#if !defined (SFNTLY_NO_EXCEPTION) + +#include +#include +#include + +namespace sfntly { + +class Exception : public std::exception { + public: + Exception() : what_("Unknown exception") {} + explicit Exception(const char* message) throw() { SetMessage(message); } + virtual ~Exception() throw() {} + virtual const char* what() const throw() { return what_.c_str(); } + + protected: + void SetMessage(const char* message) throw() { + try { + what_ = message; + } catch (...) {} + } + + private: + std::string what_; +}; + +class IndexOutOfBoundException : public Exception { + public: + IndexOutOfBoundException() throw() : Exception("Index out of bound") {} + explicit IndexOutOfBoundException(const char* message) throw() + : Exception(message) {} + IndexOutOfBoundException(const char* message, int32_t index) throw() { + try { + std::ostringstream msg; + msg << message; + msg << ":"; + msg << index; + SetMessage(msg.str().c_str()); + } catch (...) {} + } + virtual ~IndexOutOfBoundException() throw() {} +}; + +class IOException : public Exception { + public: + IOException() throw() : Exception("I/O exception") {} + explicit IOException(const char* message) throw() : Exception(message) {} + virtual ~IOException() throw() {} +}; + +class ArithmeticException : public Exception { + public: + ArithmeticException() throw() : Exception("Arithmetic exception") {} + explicit ArithmeticException(const char* message) throw() + : Exception(message) {} + virtual ~ArithmeticException() throw() {} +}; + +class UnsupportedOperationException : public Exception { + public: + UnsupportedOperationException() throw() : + Exception("Operation not supported") {} + explicit UnsupportedOperationException(const char* message) throw() + : Exception(message) {} + virtual ~UnsupportedOperationException() throw() {} +}; + +class RuntimeException : public Exception { + public: + RuntimeException() throw() : Exception("Runtime exception") {} + explicit RuntimeException(const char* message) throw() + : Exception(message) {} + virtual ~RuntimeException() throw() {} +}; + +class NoSuchElementException : public Exception { + public: + NoSuchElementException() throw() : Exception("No such element") {} + explicit NoSuchElementException(const char* message) throw() + : Exception(message) {} + virtual ~NoSuchElementException() throw() {} +}; + +class IllegalArgumentException : public Exception { + public: + IllegalArgumentException() throw() : Exception("Illegal argument") {} + explicit IllegalArgumentException(const char* message) throw() + : Exception(message) {} + virtual ~IllegalArgumentException() throw() {} +}; + +class IllegalStateException : public Exception { + public: + IllegalStateException() throw() : Exception("Illegal state") {} + explicit IllegalStateException(const char* message) throw() + : Exception(message) {} + virtual ~IllegalStateException() throw() {} +}; + +} // namespace sfntly + +#endif // #if !defined (SFNTLY_NO_EXCEPTION) + +#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_EXCEPTION_TYPE_H_ diff --git a/src/sfntly/src/sfntly/port/file_input_stream.cc b/src/sfntly/src/sfntly/port/file_input_stream.cc new file mode 100644 index 0000000000..5bcb434af0 --- /dev/null +++ b/src/sfntly/src/sfntly/port/file_input_stream.cc @@ -0,0 +1,169 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if defined (WIN32) +#include +#endif + +#include "sfntly/port/file_input_stream.h" +#include "sfntly/port/exception_type.h" + +namespace sfntly { + +FileInputStream::FileInputStream() + : file_(NULL), + position_(0), + length_(0) { +} + +FileInputStream::~FileInputStream() { + Close(); +} + +int32_t FileInputStream::Available() { + return length_ - position_; +} + +void FileInputStream::Close() { + if (file_) { + fclose(file_); + length_ = 0; + position_ = 0; + file_ = NULL; + } +} + +void FileInputStream::Mark(int32_t readlimit) { + // NOP + UNREFERENCED_PARAMETER(readlimit); +} + +bool FileInputStream::MarkSupported() { + return false; +} + +int32_t FileInputStream::Read() { + if (!file_) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("no opened file"); +#endif + return 0; + } + if (feof(file_)) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("eof reached"); +#endif + return 0; + } + byte_t value; + size_t length = fread(&value, 1, 1, file_); + position_ += length; + return value; +} + +int32_t FileInputStream::Read(ByteVector* b) { + return Read(b, 0, b->size()); +} + +int32_t FileInputStream::Read(ByteVector* b, int32_t offset, int32_t length) { + assert(b); + if (!file_) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("no opened file"); +#endif + return 0; + } + if (feof(file_)) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("eof reached"); +#endif + return 0; + } + size_t read_count = std::min(length_ - position_, length); + if (b->size() < (size_t)(offset + read_count)) { + b->resize((size_t)(offset + read_count)); + } + int32_t actual_read = fread(&((*b)[offset]), 1, read_count, file_); + position_ += actual_read; + return actual_read; +} + +void FileInputStream::Reset() { + // NOP +} + +int64_t FileInputStream::Skip(int64_t n) { + if (!file_) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("no opened file"); +#endif + return 0; + } + int64_t skip_count = 0; + if (n < 0) { // move backwards + skip_count = std::max(0 - (int64_t)position_, n); + position_ -= (size_t)(0 - skip_count); + fseek(file_, position_, SEEK_SET); + } else { + skip_count = std::min(length_ - position_, (size_t)n); + position_ += (size_t)skip_count; + fseek(file_, (size_t)skip_count, SEEK_CUR); + } + return skip_count; +} + +void FileInputStream::Unread(ByteVector* b) { + Unread(b, 0, b->size()); +} + +void FileInputStream::Unread(ByteVector* b, int32_t offset, int32_t length) { + assert(b); + assert(b->size() >= size_t(offset + length)); + if (!file_) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("no opened file"); +#endif + return; + } + size_t unread_count = std::min(position_, length); + fseek(file_, position_ - unread_count, SEEK_SET); + position_ -= unread_count; + Read(b, offset, length); + fseek(file_, position_ - unread_count, SEEK_SET); + position_ -= unread_count; +} + +bool FileInputStream::Open(const char* file_path) { + assert(file_path); + if (file_) { + Close(); + } +#if defined (WIN32) + fopen_s(&file_, file_path, "rb"); +#else + file_ = fopen(file_path, "rb"); +#endif + if (file_ == NULL) { + return false; + } + + fseek(file_, 0, SEEK_END); + length_ = ftell(file_); + fseek(file_, 0, SEEK_SET); + return true; +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/port/file_input_stream.h b/src/sfntly/src/sfntly/port/file_input_stream.h new file mode 100644 index 0000000000..cbca25f7e4 --- /dev/null +++ b/src/sfntly/src/sfntly/port/file_input_stream.h @@ -0,0 +1,57 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_FILE_INPUT_STREAM_H_ +#define SFNTLY_CPP_SRC_SFNTLY_PORT_FILE_INPUT_STREAM_H_ + +#include + +#include "sfntly/port/input_stream.h" + +namespace sfntly { + +class FileInputStream : public PushbackInputStream { + public: + FileInputStream(); + virtual ~FileInputStream(); + + // InputStream methods + virtual int32_t Available(); + virtual void Close(); + virtual void Mark(int32_t readlimit); + virtual bool MarkSupported(); + virtual int32_t Read(); + virtual int32_t Read(ByteVector* b); + virtual int32_t Read(ByteVector* b, int32_t offset, int32_t length); + virtual void Reset(); + virtual int64_t Skip(int64_t n); + + // PushbackInputStream methods + virtual void Unread(ByteVector* b); + virtual void Unread(ByteVector* b, int32_t offset, int32_t length); + + // Own methods + virtual bool Open(const char* file_path); + + private: + FILE* file_; + size_t position_; + size_t length_; +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_FILE_INPUT_STREAM_H_ diff --git a/src/sfntly/src/sfntly/port/input_stream.h b/src/sfntly/src/sfntly/port/input_stream.h new file mode 100644 index 0000000000..5d24036ea7 --- /dev/null +++ b/src/sfntly/src/sfntly/port/input_stream.h @@ -0,0 +1,49 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_INPUT_STREAM_H_ +#define SFNTLY_CPP_SRC_SFNTLY_PORT_INPUT_STREAM_H_ + +#include "sfntly/port/type.h" + +namespace sfntly { + +// C++ equivalent to Java's OutputStream class +class InputStream { + public: + // Make gcc -Wnon-virtual-dtor happy. + virtual ~InputStream() {} + + virtual int32_t Available() = 0; + virtual void Close() = 0; + virtual void Mark(int32_t readlimit) = 0; + virtual bool MarkSupported() = 0; + virtual int32_t Read() = 0; + virtual int32_t Read(ByteVector* b) = 0; + virtual int32_t Read(ByteVector* b, int32_t offset, int32_t length) = 0; + virtual void Reset() = 0; + virtual int64_t Skip(int64_t n) = 0; +}; + +class PushbackInputStream : public InputStream { + public: + virtual void Unread(ByteVector* b) = 0; + virtual void Unread(ByteVector* b, int32_t offset, int32_t length) = 0; +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_INPUT_STREAM_H_ diff --git a/src/sfntly/src/sfntly/port/java_iterator.h b/src/sfntly/src/sfntly/port/java_iterator.h new file mode 100644 index 0000000000..0a99bca1d0 --- /dev/null +++ b/src/sfntly/src/sfntly/port/java_iterator.h @@ -0,0 +1,94 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_JAVA_ITERATOR_H_ +#define SFNTLY_CPP_SRC_SFNTLY_PORT_JAVA_ITERATOR_H_ + +#include "sfntly/port/refcount.h" + +// Interface of Java iterator. +// This is a forward read-only iterator that represents java.util.Iterator + +namespace sfntly { + +template +class Iterator : public virtual RefCount { + public: + virtual ~Iterator() {} + virtual ContainerBase* container_base() = 0; + + protected: + Iterator() {} + NO_COPY_AND_ASSIGN(Iterator); +}; + +template +class PODIterator : public Iterator, + public RefCounted< PODIterator > { + public: + explicit PODIterator(Container* container) : container_(container) {} + virtual ~PODIterator() {} + virtual ContainerBase* container_base() { + return static_cast(container_); + } + + virtual bool HasNext() = 0; + virtual ReturnType Next() = 0; + virtual void Remove() { +#if !defined (SFNTLY_NO_EXCEPTION) + // Default to no support. + throw UnsupportedOperationException(); +#endif + } + + protected: + Container* container() { return container_; } + + private: + Container* container_; // Dumb pointer is used to avoid circular ref-counting +}; + +template +class RefIterator : public Iterator, + public RefCounted< RefIterator > { + public: + explicit RefIterator(Container* container) : container_(container) {} + virtual ~RefIterator() {} + virtual ContainerBase* container_base() { + return static_cast(container_); + } + + virtual bool HasNext() = 0; + CALLER_ATTACH virtual ReturnType* Next() = 0; + virtual void Remove() { +#if !defined (SFNTLY_NO_EXCEPTION) + // Default to no support. + throw UnsupportedOperationException(); +#endif + } + + protected: + Container* container() { return container_; } + + private: + Container* container_; // Dumb pointer is used to avoid circular ref-counting +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_JAVA_ITERATOR_H_ diff --git a/src/sfntly/src/sfntly/port/lock.cc b/src/sfntly/src/sfntly/port/lock.cc new file mode 100644 index 0000000000..6c0c309a94 --- /dev/null +++ b/src/sfntly/src/sfntly/port/lock.cc @@ -0,0 +1,72 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/port/lock.h" + +namespace sfntly { + +#if defined (WIN32) + +Lock::Lock() { + // The second parameter is the spin count, for short-held locks it avoid the + // contending thread from going to sleep which helps performance greatly. + ::InitializeCriticalSectionAndSpinCount(&os_lock_, 2000); +} + +Lock::~Lock() { + ::DeleteCriticalSection(&os_lock_); +} + +bool Lock::Try() { + if (::TryEnterCriticalSection(&os_lock_) != FALSE) { + return true; + } + return false; +} + +void Lock::Acquire() { + ::EnterCriticalSection(&os_lock_); +} + +void Lock::Unlock() { + ::LeaveCriticalSection(&os_lock_); +} + +#else // We assume it's pthread + +Lock::Lock() { + pthread_mutex_init(&os_lock_, NULL); +} + +Lock::~Lock() { + pthread_mutex_destroy(&os_lock_); +} + +bool Lock::Try() { + return (pthread_mutex_trylock(&os_lock_) == 0); +} + +void Lock::Acquire() { + pthread_mutex_lock(&os_lock_); +} + +void Lock::Unlock() { + pthread_mutex_unlock(&os_lock_); +} + +#endif + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/port/lock.h b/src/sfntly/src/sfntly/port/lock.h new file mode 100644 index 0000000000..b2e29bf64f --- /dev/null +++ b/src/sfntly/src/sfntly/port/lock.h @@ -0,0 +1,76 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_LOCK_H_ +#define SFNTLY_CPP_SRC_SFNTLY_PORT_LOCK_H_ + +#if defined (WIN32) +#include +#else // Assume pthread. +#include +#include +#endif + +#include "sfntly/port/type.h" + +namespace sfntly { + +#if defined (WIN32) + typedef CRITICAL_SECTION OSLockType; +#else // Assume pthread. + typedef pthread_mutex_t OSLockType; +#endif + +class Lock { + public: + Lock(); + ~Lock(); + + // If the lock is not held, take it and return true. If the lock is already + // held by something else, immediately return false. + bool Try(); + + // Take the lock, blocking until it is available if necessary. + void Acquire(); + + // Release the lock. This must only be called by the lock's holder: after + // a successful call to Try, or a call to Lock. + void Unlock(); + + private: + OSLockType os_lock_; + NO_COPY_AND_ASSIGN(Lock); +}; + +// A helper class that acquires the given Lock while the AutoLock is in scope. +class AutoLock { + public: + explicit AutoLock(Lock& lock) : lock_(lock) { + lock_.Acquire(); + } + + ~AutoLock() { + lock_.Unlock(); + } + + private: + Lock& lock_; + NO_COPY_AND_ASSIGN(AutoLock); +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_LOCK_H_ diff --git a/src/sfntly/src/sfntly/port/memory_input_stream.cc b/src/sfntly/src/sfntly/port/memory_input_stream.cc new file mode 100755 index 0000000000..56ee81e5dd --- /dev/null +++ b/src/sfntly/src/sfntly/port/memory_input_stream.cc @@ -0,0 +1,147 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if defined (WIN32) +#include +#endif + +#include + +#include "sfntly/port/memory_input_stream.h" +#include "sfntly/port/exception_type.h" + +namespace sfntly { + +MemoryInputStream::MemoryInputStream() + : buffer_(NULL), + position_(0), + length_(0) { +} + +MemoryInputStream::~MemoryInputStream() { + Close(); +} + +int32_t MemoryInputStream::Available() { + return length_ - position_; +} + +void MemoryInputStream::Close() { +} + +void MemoryInputStream::Mark(int32_t readlimit) { + // NOP + UNREFERENCED_PARAMETER(readlimit); +} + +bool MemoryInputStream::MarkSupported() { + return false; +} + +int32_t MemoryInputStream::Read() { + if (!buffer_) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("no memory attached"); +#endif + return 0; + } + if (position_ >= length_) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("eof reached"); +#endif + return 0; + } + byte_t value = buffer_[position_++]; + return value; +} + +int32_t MemoryInputStream::Read(ByteVector* b) { + return Read(b, 0, b->size()); +} + +int32_t MemoryInputStream::Read(ByteVector* b, int32_t offset, int32_t length) { + assert(b); + if (!buffer_) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("no memory attached"); +#endif + return 0; + } + if (position_ >= length_) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("eof reached"); +#endif + return 0; + } + size_t read_count = std::min(length_ - position_, length); + if (b->size() < (size_t)(offset + read_count)) { + b->resize((size_t)(offset + read_count)); + } + memcpy(&((*b)[offset]), buffer_ + position_, read_count); + position_ += read_count; + return read_count; +} + +void MemoryInputStream::Reset() { + // NOP +} + +int64_t MemoryInputStream::Skip(int64_t n) { + if (!buffer_) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("no memory attached"); +#endif + return 0; + } + int64_t skip_count = 0; + if (n < 0) { // move backwards + skip_count = std::max(0 - (int64_t)position_, n); + position_ -= (size_t)(0 - skip_count); + } else { + skip_count = std::min(length_ - position_, (size_t)n); + position_ += (size_t)skip_count; + } + return skip_count; +} + +void MemoryInputStream::Unread(ByteVector* b) { + Unread(b, 0, b->size()); +} + +void MemoryInputStream::Unread(ByteVector* b, int32_t offset, int32_t length) { + assert(b); + assert(b->size() >= size_t(offset + length)); + if (!buffer_) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("no memory attached"); +#endif + return; + } + size_t unread_count = std::min(position_, length); + position_ -= unread_count; + Read(b, offset, length); + position_ -= unread_count; +} + +bool MemoryInputStream::Attach(const byte_t* buffer, size_t length) { + assert(buffer); + assert(length); + buffer_ = buffer; + length_ = length; + return true; +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/port/memory_input_stream.h b/src/sfntly/src/sfntly/port/memory_input_stream.h new file mode 100755 index 0000000000..bc861c3f13 --- /dev/null +++ b/src/sfntly/src/sfntly/port/memory_input_stream.h @@ -0,0 +1,57 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_INPUT_STREAM_H_ +#define SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_INPUT_STREAM_H_ + +#include + +#include "sfntly/port/input_stream.h" + +namespace sfntly { + +class MemoryInputStream : public PushbackInputStream { + public: + MemoryInputStream(); + virtual ~MemoryInputStream(); + + // InputStream methods + virtual int32_t Available(); + virtual void Close(); + virtual void Mark(int32_t readlimit); + virtual bool MarkSupported(); + virtual int32_t Read(); + virtual int32_t Read(ByteVector* b); + virtual int32_t Read(ByteVector* b, int32_t offset, int32_t length); + virtual void Reset(); + virtual int64_t Skip(int64_t n); + + // PushbackInputStream methods + virtual void Unread(ByteVector* b); + virtual void Unread(ByteVector* b, int32_t offset, int32_t length); + + // Own methods + virtual bool Attach(const byte_t* buffer, size_t length); + + private: + const byte_t* buffer_; + size_t position_; + size_t length_; +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_INPUT_STREAM_H_ diff --git a/src/sfntly/src/sfntly/port/memory_output_stream.cc b/src/sfntly/src/sfntly/port/memory_output_stream.cc new file mode 100644 index 0000000000..f2ff2e302e --- /dev/null +++ b/src/sfntly/src/sfntly/port/memory_output_stream.cc @@ -0,0 +1,72 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/port/memory_output_stream.h" + +namespace sfntly { + +MemoryOutputStream::MemoryOutputStream() { +} + +MemoryOutputStream::~MemoryOutputStream() { +} + +void MemoryOutputStream::Write(ByteVector* buffer) { + store_.insert(store_.end(), buffer->begin(), buffer->end()); +} + +void MemoryOutputStream::Write(ByteVector* buffer, + int32_t offset, + int32_t length) { + assert(buffer); + if (offset >= 0 && length > 0) { + store_.insert(store_.end(), + buffer->begin() + offset, + buffer->begin() + offset + length); + } else { +#if !defined(SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundException(); +#endif + } +} + +void MemoryOutputStream::Write(byte_t* buffer, int32_t offset, int32_t length) { + assert(buffer); + if (offset >= 0 && length > 0) { + store_.insert(store_.end(), buffer + offset, buffer + offset + length); + } else { +#if !defined(SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundException(); +#endif + } +} + +void MemoryOutputStream::Write(byte_t b) { + store_.push_back(b); +} + +byte_t* MemoryOutputStream::Get() { + if (store_.empty()) { + return NULL; + } + return &(store_[0]); +} + +size_t MemoryOutputStream::Size() { + return store_.size(); +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/port/memory_output_stream.h b/src/sfntly/src/sfntly/port/memory_output_stream.h new file mode 100644 index 0000000000..d1eda7faf8 --- /dev/null +++ b/src/sfntly/src/sfntly/port/memory_output_stream.h @@ -0,0 +1,51 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_OUTPUT_STREAM_H_ +#define SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_OUTPUT_STREAM_H_ + +#include +#include + +#include "sfntly/port/type.h" +#include "sfntly/port/output_stream.h" + +namespace sfntly { + +// OutputStream backed by STL vector + +class MemoryOutputStream : public OutputStream { + public: + MemoryOutputStream(); + virtual ~MemoryOutputStream(); + + virtual void Close() {} // no-op + virtual void Flush() {} // no-op + virtual void Write(ByteVector* buffer); + virtual void Write(ByteVector* buffer, int32_t offset, int32_t length); + virtual void Write(byte_t* buffer, int32_t offset, int32_t length); + virtual void Write(byte_t b); + + byte_t* Get(); + size_t Size(); + + private: + std::vector store_; +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_OUTPUT_STREAM_H_ diff --git a/src/sfntly/src/sfntly/port/output_stream.h b/src/sfntly/src/sfntly/port/output_stream.h new file mode 100644 index 0000000000..64a602471d --- /dev/null +++ b/src/sfntly/src/sfntly/port/output_stream.h @@ -0,0 +1,46 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_OUTPUT_STREAM_H_ +#define SFNTLY_CPP_SRC_SFNTLY_PORT_OUTPUT_STREAM_H_ + +#include "sfntly/port/type.h" + +namespace sfntly { + +// C++ equivalent to Java's OutputStream class +class OutputStream { + public: + // Make gcc -Wnon-virtual-dtor happy. + virtual ~OutputStream() {} + + virtual void Close() = 0; + virtual void Flush() = 0; + virtual void Write(ByteVector* buffer) = 0; + virtual void Write(byte_t b) = 0; + + // Note: C++ port offered both versions of Write() here. The first one is + // better because it does check bounds. The second one is there for + // performance concerns. + virtual void Write(ByteVector* buffer, int32_t offset, int32_t length) = 0; + + // Note: Caller is responsible for the boundary of buffer. + virtual void Write(byte_t* buffer, int32_t offset, int32_t length) = 0; +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_OUTPUT_STREAM_H_ diff --git a/src/sfntly/src/sfntly/port/refcount.h b/src/sfntly/src/sfntly/port/refcount.h new file mode 100644 index 0000000000..eed51622d7 --- /dev/null +++ b/src/sfntly/src/sfntly/port/refcount.h @@ -0,0 +1,277 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Object reference count and smart pointer implementation. + +// Smart pointer usage in sfntly: +// +// sfntly carries a smart pointer implementation like COM. Ref-countable object +// type inherits from RefCounted<>, which have AddRef and Release just like +// IUnknown (but no QueryInterface). Use a Ptr<> based smart pointer to hold +// the object so that the object ref count is handled correctly. +// +// class Foo : public RefCounted { +// public: +// static Foo* CreateInstance() { +// Ptr obj = new Foo(); // ref count = 1 +// return obj.Detach(); +// } +// }; +// typedef Ptr FooPtr; // common short-hand notation +// FooPtr obj; +// obj.Attach(Foo::CreatedInstance()); // ref count = 1 +// { +// FooPtr obj2 = obj; // ref count = 2 +// } // ref count = 1, obj2 out of scope +// obj.Release(); // ref count = 0, object destroyed + +// Notes on usage: +// 1. Virtual inherit from RefCount interface in base class if smart pointers +// are going to be defined. +// 2. All RefCounted objects must be instantiated on the heap. Allocating the +// object on stack will cause crash. +// 3. Be careful when you have complex inheritance. For example, +// class A : public RefCounted; +// class B : public A, public RefCounted; +// In this case the smart pointer is pretty dumb and don't count on it to +// nicely destroy your objects as designed. Try refactor your code like +// class I; // the common interface and implementations +// class A : public I, public RefCounted; // A specific implementation +// class B : public I, public RefCounted; // B specific implementation +// 4. Smart pointers here are very bad candidates for function parameters. Use +// dumb pointers in function parameter list. +// 5. When down_cast is performed on a dangling pointer due to bugs in code, +// VC++ will generate SEH which is not handled well in VC++ debugger. One +// can use WinDBG to run it and get the faulting stack. +// 6. Idioms for heap object as return value +// Foo* createFoo() { FooPtr obj = new Foo(); return obj.Detach(); } +// Foo* passthru() { FooPtr obj = createFoo(), return obj; } +// FooPtr end_scope_pointer; +// end_scope_pointer.Attach(passThrough); +// If you are not passing that object back, you are the end of scope. + +#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_REFCOUNT_H_ +#define SFNTLY_CPP_SRC_SFNTLY_PORT_REFCOUNT_H_ + +#if !defined (NDEBUG) + #define ENABLE_OBJECT_COUNTER +// #define REF_COUNT_DEBUGGING +#endif + +#if defined (REF_COUNT_DEBUGGING) + #include + #include +#endif + +#include "sfntly/port/atomic.h" +#include "sfntly/port/type.h" + +// Special tag for functions that requires caller to attach instead of using +// assignment operators. +#define CALLER_ATTACH + +#if defined (REF_COUNT_DEBUGGING) + #define DEBUG_OUTPUT(a) \ + fprintf(stderr, "%s%s:oc=%d,oid=%d,rc=%d\n", a, \ + typeid(this).name(), object_counter_, object_id_, ref_count_) +#else + #define DEBUG_OUTPUT(a) +#endif + +#if defined (_MSC_VER) + // VC 2008/2010 incorrectly gives this warning for pure virtual functions + // in virtual inheritance. The only way to get around it is to disable it. + #pragma warning(disable:4250) +#endif + +namespace sfntly { + +class RefCount { + public: + // Make gcc -Wnon-virtual-dtor happy. + virtual ~RefCount() {} + + virtual size_t AddRef() const = 0; + virtual size_t Release() const = 0; +}; + +template +class NoAddRefRelease : public T { + public: + NoAddRefRelease(); + ~NoAddRefRelease(); + + private: + virtual size_t AddRef() const = 0; + virtual size_t Release() const = 0; +}; + +template +class RefCounted : virtual public RefCount { + public: + RefCounted() : ref_count_(0) { +#if defined (ENABLE_OBJECT_COUNTER) + object_id_ = AtomicIncrement(&next_id_); + AtomicIncrement(&object_counter_); + DEBUG_OUTPUT("C "); +#endif + } + RefCounted(const RefCounted&) : ref_count_(0) {} + virtual ~RefCounted() { +#if defined (ENABLE_OBJECT_COUNTER) + AtomicDecrement(&object_counter_); + DEBUG_OUTPUT("D "); +#endif + } + + RefCounted& operator=(const RefCounted&) { + // Each object maintains own ref count, don't propagate. + return *this; + } + + virtual size_t AddRef() const { + size_t new_count = AtomicIncrement(&ref_count_); + DEBUG_OUTPUT("A "); + return new_count; + } + + virtual size_t Release() const { + size_t new_ref_count = AtomicDecrement(&ref_count_); + DEBUG_OUTPUT("R "); + if (new_ref_count == 0) { + // A C-style is used to cast away const-ness and to derived. + // lint does not like this but this is how it works. + delete (TDerived*)(this); + } + return new_ref_count; + } + + mutable size_t ref_count_; // reference count of current object +#if defined (ENABLE_OBJECT_COUNTER) + static size_t object_counter_; + static size_t next_id_; + mutable size_t object_id_; +#endif +}; + +#if defined (ENABLE_OBJECT_COUNTER) +template size_t RefCounted::object_counter_ = 0; +template size_t RefCounted::next_id_ = 0; +#endif + +// semi-smart pointer for RefCount derived objects, similar to CComPtr +template +class Ptr { + public: + Ptr() : p_(NULL) { + } + + // This constructor shall not be explicit. + // lint does not like this but this is how it works. + Ptr(T* pT) : p_(NULL) { + *this = pT; + } + + Ptr(const Ptr& p) : p_(NULL) { + *this = p; + } + + ~Ptr() { + Release(); + } + + T* operator=(T* pT) { + if (p_ == pT) { + return p_; + } + if (pT) { + RefCount* p = static_cast(pT); + if (p == NULL) { + return NULL; + } + p->AddRef(); // always AddRef() before Release() + } + Release(); + p_ = pT; + return p_; + } + + T* operator=(const Ptr& p) { + if (p_ == p.p_) { + return p_; + } + return operator=(p.p_); + } + + operator T*&() { + return p_; + } + + T& operator*() const { + return *p_; // It can throw! + } + + NoAddRefRelease* operator->() const { + return (NoAddRefRelease*)p_; // It can throw! + } + + bool operator!() const { + return (p_ == NULL); + } + + bool operator<(const Ptr& p) const { + return (p_ < p.p_); + } + + bool operator!=(T* pT) const { + return !operator==(pT); + } + + bool operator==(T* pT) const { + return (p_ == pT); + } + + size_t Release() const { + size_t ref_count = 0; + if (p_) { + RefCount* p = static_cast(p_); + if (p) { + ref_count = p->Release(); + } + p_ = NULL; + } + return ref_count; + } + + void Attach(T* pT) { + if (p_ != pT) { + Release(); + p_ = pT; + } + } + + T* Detach() { + T* pT = p_; + p_ = NULL; + return pT; + } + + mutable T* p_; +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_REFCOUNT_H_ diff --git a/src/sfntly/src/sfntly/port/type.h b/src/sfntly/src/sfntly/port/type.h new file mode 100644 index 0000000000..20a5ba8a89 --- /dev/null +++ b/src/sfntly/src/sfntly/port/type.h @@ -0,0 +1,102 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_TYPE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_PORT_TYPE_H_ + +#include + +#if defined (_MSC_VER) && (_MSC_VER < 1600) + typedef unsigned char uint8_t; + typedef signed char int8_t; + typedef unsigned __int16 uint16_t; + typedef signed __int16 int16_t; + typedef unsigned __int32 uint32_t; + typedef signed __int32 int32_t; + typedef unsigned __int64 uint64_t; + typedef signed __int64 int64_t; + // Definitions to avoid ICU redefinition issue + #define U_HAVE_INT8_T 1 + #define U_HAVE_UINT8_T 1 + #define U_HAVE_INT16_T 1 + #define U_HAVE_UINT16_T 1 + #define U_HAVE_INT32_T 1 + #define U_HAVE_UINT32_T 1 + #define U_HAVE_INT64_T 1 + #define U_HAVE_UINT64_T 1 +#else + #include +#endif + +#include +#include +#include + +namespace sfntly { + +typedef uint8_t byte_t; +typedef uint16_t word_t; +typedef uint32_t dword_t; +typedef uint64_t qword_t; + +typedef std::vector ByteVector; +typedef std::vector IntegerList; +typedef std::set IntegerSet; + +// A macro to disallow the copy constructor and operator= functions. +// This should be used in the private: declarations for a class. +#define NO_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) + +} // namespace sfntly + +// Make google3 happy since it prohibits RTTI. +template +inline To implicit_cast(From const &f) { + return f; +} + +template // use like this: down_cast(foo); +inline To down_cast(From* f) { // so we only accept pointers + // Ensures that To is a sub-type of From *. This test is here only + // for compile-time type checking, and has no overhead in an + // optimized build at run-time, as it will be optimized away + // completely. +#if defined (_MSC_VER) + #pragma warning(push) + #pragma warning(disable:4127) // disable "conditional expression is constant" +#endif + if (false) { + implicit_cast(0); + } +#if defined (_MSC_VER) + #pragma warning(pop) +#endif + +// The following code is the only place for RTTI. It is done so to allow +// additional type checking when SFNTLY_TYPE_VERIFICATION is defined. +#if defined (SFNTLY_TYPE_VERIFICATION) + assert(f == NULL || dynamic_cast(f) != NULL); +#endif + return static_cast(f); +} + +#if !defined(WIN32) + #define UNREFERENCED_PARAMETER(p) do { (void)p; } while (0) +#endif + +#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_TYPE_H_ diff --git a/src/sfntly/src/sfntly/table/bitmap/big_glyph_metrics.cc b/src/sfntly/src/sfntly/table/bitmap/big_glyph_metrics.cc new file mode 100644 index 0000000000..d853212bbe --- /dev/null +++ b/src/sfntly/src/sfntly/table/bitmap/big_glyph_metrics.cc @@ -0,0 +1,171 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/bitmap/big_glyph_metrics.h" + +namespace sfntly { +/****************************************************************************** + * BigGlyphMetrics class + ******************************************************************************/ +BigGlyphMetrics::BigGlyphMetrics(ReadableFontData* data) + : GlyphMetrics(data) { +} + +BigGlyphMetrics::~BigGlyphMetrics() { +} + +int32_t BigGlyphMetrics::Height() { + return data_->ReadByte(Offset::kHeight); +} + +int32_t BigGlyphMetrics::Width() { + return data_->ReadByte(Offset::kWidth); +} + +int32_t BigGlyphMetrics::HoriBearingX() { + return data_->ReadByte(Offset::kHoriBearingX); +} + +int32_t BigGlyphMetrics::HoriBearingY() { + return data_->ReadByte(Offset::kHoriBearingY); +} + +int32_t BigGlyphMetrics::HoriAdvance() { + return data_->ReadByte(Offset::kHoriAdvance); +} + +int32_t BigGlyphMetrics::VertBearingX() { + return data_->ReadByte(Offset::kVertBearingX); +} + +int32_t BigGlyphMetrics::VertBearingY() { + return data_->ReadByte(Offset::kVertBearingY); +} + +int32_t BigGlyphMetrics::VertAdvance() { + return data_->ReadByte(Offset::kVertAdvance); +} + +/****************************************************************************** + * BigGlyphMetrics::Builder class + ******************************************************************************/ +BigGlyphMetrics::Builder::Builder(WritableFontData* data) + : GlyphMetrics::Builder(data) { +} + +BigGlyphMetrics::Builder::Builder(ReadableFontData* data) + : GlyphMetrics::Builder(data) { +} + +BigGlyphMetrics::Builder::~Builder() { +} + +int32_t BigGlyphMetrics::Builder::Height() { + return InternalReadData()->ReadByte(Offset::kHeight); +} + +void BigGlyphMetrics::Builder::SetHeight(byte_t height) { + InternalWriteData()->WriteByte(Offset::kHeight, height); +} + +int32_t BigGlyphMetrics::Builder::Width() { + return InternalReadData()->ReadByte(Offset::kWidth); +} + +void BigGlyphMetrics::Builder::SetWidth(byte_t width) { + InternalWriteData()->WriteByte(Offset::kWidth, width); +} + +int32_t BigGlyphMetrics::Builder::HoriBearingX() { + return InternalReadData()->ReadByte(Offset::kHoriBearingX); +} + +void BigGlyphMetrics::Builder::SetHoriBearingX(byte_t bearing) { + InternalWriteData()->WriteByte(Offset::kHoriBearingX, bearing); +} + +int32_t BigGlyphMetrics::Builder::HoriBearingY() { + return InternalReadData()->ReadByte(Offset::kHoriBearingY); +} + +void BigGlyphMetrics::Builder::SetHoriBearingY(byte_t bearing) { + InternalWriteData()->WriteByte(Offset::kHoriBearingY, bearing); +} + +int32_t BigGlyphMetrics::Builder::HoriAdvance() { + return InternalReadData()->ReadByte(Offset::kHoriAdvance); +} + +void BigGlyphMetrics::Builder::SetHoriAdvance(byte_t advance) { + InternalWriteData()->WriteByte(Offset::kHoriAdvance, advance); +} + +int32_t BigGlyphMetrics::Builder::VertBearingX() { + return InternalReadData()->ReadByte(Offset::kVertBearingX); +} + +void BigGlyphMetrics::Builder::SetVertBearingX(byte_t bearing) { + InternalWriteData()->WriteByte(Offset::kVertBearingX, bearing); +} + +int32_t BigGlyphMetrics::Builder::VertBearingY() { + return InternalReadData()->ReadByte(Offset::kVertBearingY); +} + +void BigGlyphMetrics::Builder::SetVertBearingY(byte_t bearing) { + InternalWriteData()->WriteByte(Offset::kVertBearingY, bearing); +} + +int32_t BigGlyphMetrics::Builder::VertAdvance() { + return InternalReadData()->ReadByte(Offset::kVertAdvance); +} + +void BigGlyphMetrics::Builder::SetVertAdvance(byte_t advance) { + InternalWriteData()->WriteByte(Offset::kVertAdvance, advance); +} + +CALLER_ATTACH FontDataTable* + BigGlyphMetrics::Builder::SubBuildTable(ReadableFontData* data) { + BigGlyphMetricsPtr output = new BigGlyphMetrics(data); + return output.Detach(); +} + +void BigGlyphMetrics::Builder::SubDataSet() { + // NOP. +} + +int32_t BigGlyphMetrics::Builder::SubDataSizeToSerialize() { + return 0; +} + +bool BigGlyphMetrics::Builder::SubReadyToSerialize() { + return false; +} + +int32_t BigGlyphMetrics::Builder::SubSerialize(WritableFontData* new_data) { + return Data()->CopyTo(new_data); +} + +// static +CALLER_ATTACH +BigGlyphMetrics::Builder* BigGlyphMetrics::Builder::CreateBuilder() { + WritableFontDataPtr data; + data.Attach(WritableFontData::CreateWritableFontData(Offset::kMetricsLength)); + BigGlyphMetricsBuilderPtr output = new BigGlyphMetrics::Builder(data); + return output.Detach(); +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/bitmap/big_glyph_metrics.h b/src/sfntly/src/sfntly/table/bitmap/big_glyph_metrics.h new file mode 100644 index 0000000000..a91601c211 --- /dev/null +++ b/src/sfntly/src/sfntly/table/bitmap/big_glyph_metrics.h @@ -0,0 +1,96 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BIG_GLYPH_METRICS_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BIG_GLYPH_METRICS_H_ + +#include "sfntly/table/bitmap/glyph_metrics.h" + +namespace sfntly { + +class BigGlyphMetrics : public GlyphMetrics, + public RefCounted { + public: + struct Offset { + enum { + kMetricsLength = 8, + + kHeight = 0, + kWidth = 1, + kHoriBearingX = 2, + kHoriBearingY = 3, + kHoriAdvance = 4, + kVertBearingX = 5, + kVertBearingY = 6, + kVertAdvance = 7, + }; + }; + + class Builder : public GlyphMetrics::Builder, + public RefCounted { + public: + // Constructor scope altered to public because C++ does not allow base + // class to instantiate derived class with protected constructors. + explicit Builder(WritableFontData* data); + explicit Builder(ReadableFontData* data); + + virtual ~Builder(); + + int32_t Height(); + void SetHeight(byte_t height); + int32_t Width(); + void SetWidth(byte_t width); + int32_t HoriBearingX(); + void SetHoriBearingX(byte_t bearing); + int32_t HoriBearingY(); + void SetHoriBearingY(byte_t bearing); + int32_t HoriAdvance(); + void SetHoriAdvance(byte_t advance); + int32_t VertBearingX(); + void SetVertBearingX(byte_t bearing); + int32_t VertBearingY(); + void SetVertBearingY(byte_t bearing); + int32_t VertAdvance(); + void SetVertAdvance(byte_t advance); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + + // Static instantiation function. + static CALLER_ATTACH Builder* CreateBuilder(); + }; + + explicit BigGlyphMetrics(ReadableFontData* data); + virtual ~BigGlyphMetrics(); + + int32_t Height(); + int32_t Width(); + int32_t HoriBearingX(); + int32_t HoriBearingY(); + int32_t HoriAdvance(); + int32_t VertBearingX(); + int32_t VertBearingY(); + int32_t VertAdvance(); +}; +typedef Ptr BigGlyphMetricsPtr; +typedef Ptr BigGlyphMetricsBuilderPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BIG_GLYPH_METRICS_H_ diff --git a/src/sfntly/src/sfntly/table/bitmap/bitmap_glyph.cc b/src/sfntly/src/sfntly/table/bitmap/bitmap_glyph.cc new file mode 100644 index 0000000000..334a0c07fb --- /dev/null +++ b/src/sfntly/src/sfntly/table/bitmap/bitmap_glyph.cc @@ -0,0 +1,101 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 = the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/bitmap/bitmap_glyph.h" +#include "sfntly/table/bitmap/simple_bitmap_glyph.h" +#include "sfntly/table/bitmap/composite_bitmap_glyph.h" + +namespace sfntly { +/****************************************************************************** + * BitmapGlyph class + ******************************************************************************/ +BitmapGlyph::~BitmapGlyph() { +} + +CALLER_ATTACH BitmapGlyph* BitmapGlyph::CreateGlyph(ReadableFontData* data, + int32_t format) { + BitmapGlyphPtr glyph; + BitmapGlyphBuilderPtr builder; + builder.Attach(Builder::CreateGlyphBuilder(data, format)); + if (builder) { + glyph.Attach(down_cast(builder->Build())); + } + return glyph; +} + +BitmapGlyph::BitmapGlyph(ReadableFontData* data, int32_t format) + : SubTable(data), format_(format) { +} + +/****************************************************************************** + * BitmapGlyph::Builder class + ******************************************************************************/ +BitmapGlyph::Builder::~Builder() { +} + +CALLER_ATTACH BitmapGlyph::Builder* +BitmapGlyph::Builder::CreateGlyphBuilder(ReadableFontData* data, + int32_t format) { + BitmapGlyphBuilderPtr builder; + switch (format) { + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + builder = new SimpleBitmapGlyph::Builder(data, format); + break; + case 8: + case 9: + builder = new CompositeBitmapGlyph::Builder(data, format); + break; + } + return builder.Detach(); +} + +BitmapGlyph::Builder::Builder(WritableFontData* data, int32_t format) + : SubTable::Builder(data), format_(format) { +} + +BitmapGlyph::Builder::Builder(ReadableFontData* data, int32_t format) + : SubTable::Builder(data), format_(format) { +} + +CALLER_ATTACH +FontDataTable* BitmapGlyph::Builder::SubBuildTable(ReadableFontData* data) { + UNREFERENCED_PARAMETER(data); + return NULL; +} + +void BitmapGlyph::Builder::SubDataSet() { + // NOP +} + +int32_t BitmapGlyph::Builder::SubDataSizeToSerialize() { + return InternalReadData()->Length(); +} + +bool BitmapGlyph::Builder::SubReadyToSerialize() { + return true; +} + +int32_t BitmapGlyph::Builder::SubSerialize(WritableFontData* new_data) { + return InternalReadData()->CopyTo(new_data); +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/bitmap/bitmap_glyph.h b/src/sfntly/src/sfntly/table/bitmap/bitmap_glyph.h new file mode 100644 index 0000000000..2dd4c3a130 --- /dev/null +++ b/src/sfntly/src/sfntly/table/bitmap/bitmap_glyph.h @@ -0,0 +1,119 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 = the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_GLYPH_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_GLYPH_H_ + +#include +#include + +#include "sfntly/table/subtable.h" + +namespace sfntly { + +class BitmapGlyph : public SubTable { + public: + struct Offset { + enum { + // header + kVersion = 0, + + kSmallGlyphMetricsLength = 5, + kBigGlyphMetricsLength = 8, + // format 1 + kGlyphFormat1_imageData = kSmallGlyphMetricsLength, + + // format 2 + kGlyphFormat2_imageData = kSmallGlyphMetricsLength, + + // format 3 + + // format 4 + + // format 5 + kGlyphFormat5_imageData = 0, + + // format 6 + kGlyphFormat6_imageData = kBigGlyphMetricsLength, + + // format 7 + kGlyphFormat7_imageData = kBigGlyphMetricsLength, + + // format 8 + kGlyphFormat8_numComponents = kSmallGlyphMetricsLength + 1, + kGlyphFormat8_componentArray = kGlyphFormat8_numComponents + + DataSize::kUSHORT, + + // format 9 + kGlyphFormat9_numComponents = kBigGlyphMetricsLength, + kGlyphFormat9_componentArray = kGlyphFormat9_numComponents + + DataSize::kUSHORT, + + // ebdtComponent + kEbdtComponentLength = DataSize::kUSHORT + 2 * DataSize::kCHAR, + kEbdtComponent_glyphCode = 0, + kEbdtComponent_xOffset = 2, + kEbdtComponent_yOffset = 3, + }; + }; + + // TODO(stuartg): builder is not functional at all + // - need to add subclasses for each type of bitmap glyph + class Builder : public SubTable::Builder { + public: + virtual ~Builder(); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + + int32_t format() { return format_; } + + static CALLER_ATTACH Builder* CreateGlyphBuilder(ReadableFontData* data, + int32_t format); + + protected: + Builder(WritableFontData* data, int32_t format); + Builder(ReadableFontData* data, int32_t format); + + private: + int32_t format_; + }; + + virtual ~BitmapGlyph(); + + static CALLER_ATTACH BitmapGlyph* CreateGlyph(ReadableFontData* data, + int32_t format); + int32_t format() { return format_; } + + // UNIMPLEMENTED: toString() + + protected: + BitmapGlyph(ReadableFontData* data, int32_t format); + + private: + int32_t format_; +}; +typedef Ptr BitmapGlyphPtr; +typedef Ptr BitmapGlyphBuilderPtr; +typedef std::map BitmapGlyphBuilderMap; +typedef std::vector BitmapGlyphBuilderList; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_GLYPH_H_ diff --git a/src/sfntly/src/sfntly/table/bitmap/bitmap_glyph_info.cc b/src/sfntly/src/sfntly/table/bitmap/bitmap_glyph_info.cc new file mode 100644 index 0000000000..ab9953bc77 --- /dev/null +++ b/src/sfntly/src/sfntly/table/bitmap/bitmap_glyph_info.cc @@ -0,0 +1,68 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/bitmap/bitmap_glyph_info.h" + +namespace sfntly { + +BitmapGlyphInfo::BitmapGlyphInfo(int32_t glyph_id, + int32_t block_offset, + int32_t start_offset, + int32_t length, + int32_t format) + : glyph_id_(glyph_id), + relative_(true), + block_offset_(block_offset), + start_offset_(start_offset), + length_(length), + format_(format) { +} + +BitmapGlyphInfo::BitmapGlyphInfo(int32_t glyph_id, + int32_t start_offset, + int32_t length, + int32_t format) + : glyph_id_(glyph_id), + relative_(false), + block_offset_(0), + start_offset_(start_offset), + length_(length), + format_(format) { +} + +bool BitmapGlyphInfo::operator==(const BitmapGlyphInfo& rhs) const { + return (format_ == rhs.format_ && + glyph_id_ == rhs.glyph_id_ && + length_ == rhs.length_ && + offset() == rhs.offset()); +} + +bool BitmapGlyphInfo::operator==(BitmapGlyphInfo* rhs) { + if (rhs == NULL) { + return this == NULL; + } + return (format_ == rhs->format() && + glyph_id_ == rhs->glyph_id() && + length_ == rhs->length() && + offset() == rhs->offset()); +} + +bool StartOffsetComparator::operator()(BitmapGlyphInfo* lhs, + BitmapGlyphInfo* rhs) { + return lhs->start_offset() > rhs->start_offset(); +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/bitmap/bitmap_glyph_info.h b/src/sfntly/src/sfntly/table/bitmap/bitmap_glyph_info.h new file mode 100644 index 0000000000..9921d0d526 --- /dev/null +++ b/src/sfntly/src/sfntly/table/bitmap/bitmap_glyph_info.h @@ -0,0 +1,85 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_INFO_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_INFO_H_ + +#include +#include + +#include "sfntly/table/subtable.h" + +namespace sfntly { + +// An immutable class holding bitmap glyph information. +class BitmapGlyphInfo : public RefCounted { + public: + // Constructor for a relative located glyph. The glyph's position in the EBDT + // table is a combination of it's block offset and it's own start offset. + // @param glyphId the glyph id + // @param blockOffset the offset of the block to which the glyph belongs + // @param startOffset the offset of the glyph within the block + // @param length the byte length + // @param format the glyph image format + BitmapGlyphInfo(int32_t glyph_id, + int32_t block_offset, + int32_t start_offset, + int32_t length, + int32_t format); + + // Constructor for an absolute located glyph. The glyph's position in the EBDT + // table is only given by it's own start offset. + // @param glyphId the glyph id + // @param startOffset the offset of the glyph within the block + // @param length the byte length + // @param format the glyph image format + BitmapGlyphInfo(int32_t glyph_id, + int32_t start_offset, + int32_t length, + int32_t format); + + int32_t glyph_id() const { return glyph_id_; } + bool relative() const { return relative_; } + int32_t block_offset() const { return block_offset_; } + int32_t offset() const { return block_offset() + start_offset(); } + int32_t start_offset() const { return start_offset_; } + int32_t length() const { return length_; } + int32_t format() const { return format_; } + + // UNIMPLEMENTED: hashCode() + bool operator==(const BitmapGlyphInfo& rhs) const; + bool operator==(BitmapGlyphInfo* rhs); + + private: + int32_t glyph_id_; + bool relative_; + int32_t block_offset_; + int32_t start_offset_; + int32_t length_; + int32_t format_; +}; +typedef Ptr BitmapGlyphInfoPtr; +typedef std::map BitmapGlyphInfoMap; +typedef std::vector BitmapLocaList; + +class StartOffsetComparator { + public: + bool operator()(BitmapGlyphInfo* lhs, BitmapGlyphInfo* rhs); +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_INFO_H_ diff --git a/src/sfntly/src/sfntly/table/bitmap/bitmap_size_table.cc b/src/sfntly/src/sfntly/table/bitmap/bitmap_size_table.cc new file mode 100644 index 0000000000..6c7d7315a4 --- /dev/null +++ b/src/sfntly/src/sfntly/table/bitmap/bitmap_size_table.cc @@ -0,0 +1,604 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 = the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/bitmap/bitmap_size_table.h" + +#include +#include + +#include "sfntly/math/font_math.h" +#include "sfntly/table/bitmap/eblc_table.h" +#include "sfntly/table/bitmap/index_sub_table_format1.h" +#include "sfntly/table/bitmap/index_sub_table_format2.h" +#include "sfntly/table/bitmap/index_sub_table_format3.h" +#include "sfntly/table/bitmap/index_sub_table_format4.h" +#include "sfntly/table/bitmap/index_sub_table_format5.h" + +namespace sfntly { +/****************************************************************************** + * BitmapSizeTable class + ******************************************************************************/ +BitmapSizeTable::~BitmapSizeTable() { +} + +int32_t BitmapSizeTable::IndexSubTableArrayOffset() { + return data_->ReadULongAsInt( + EblcTable::Offset::kBitmapSizeTable_indexSubTableArrayOffset); +} + +int32_t BitmapSizeTable::IndexTableSize() { + return data_->ReadULongAsInt( + EblcTable::Offset::kBitmapSizeTable_indexTableSize); +} + +int32_t BitmapSizeTable::NumberOfIndexSubTables() { + return NumberOfIndexSubTables(data_, 0); +} + +int32_t BitmapSizeTable::ColorRef() { + return data_->ReadULongAsInt(EblcTable::Offset::kBitmapSizeTable_colorRef); +} + +int32_t BitmapSizeTable::StartGlyphIndex() { + return data_->ReadUShort(EblcTable::Offset::kBitmapSizeTable_startGlyphIndex); +} + +int32_t BitmapSizeTable::EndGlyphIndex() { + return data_->ReadUShort(EblcTable::Offset::kBitmapSizeTable_endGlyphIndex); +} + +int32_t BitmapSizeTable::PpemX() { + return data_->ReadByte(EblcTable::Offset::kBitmapSizeTable_ppemX); +} + +int32_t BitmapSizeTable::PpemY() { + return data_->ReadByte(EblcTable::Offset::kBitmapSizeTable_ppemY); +} + +int32_t BitmapSizeTable::BitDepth() { + return data_->ReadByte(EblcTable::Offset::kBitmapSizeTable_bitDepth); +} + +int32_t BitmapSizeTable::FlagsAsInt() { + return data_->ReadChar(EblcTable::Offset::kBitmapSizeTable_flags); +} + +IndexSubTable* BitmapSizeTable::GetIndexSubTable(int32_t index) { + IndexSubTableList* subtable_list = GetIndexSubTableList(); + if (index >= 0 && (size_t)index < subtable_list->size()) { + return (*subtable_list)[index]; + } + return NULL; +} + +int32_t BitmapSizeTable::GlyphOffset(int32_t glyph_id) { + IndexSubTable* subtable = SearchIndexSubTables(glyph_id); + if (subtable == NULL) { + return -1; + } + return subtable->GlyphOffset(glyph_id); +} + +int32_t BitmapSizeTable::GlyphLength(int32_t glyph_id) { + IndexSubTable* subtable = SearchIndexSubTables(glyph_id); + if (subtable == NULL) { + return -1; + } + return subtable->GlyphLength(glyph_id); +} + +CALLER_ATTACH BitmapGlyphInfo* BitmapSizeTable::GlyphInfo(int32_t glyph_id) { + IndexSubTable* sub_table = SearchIndexSubTables(glyph_id); + if (sub_table == NULL) { + return NULL; + } + return sub_table->GlyphInfo(glyph_id); +} + +int32_t BitmapSizeTable::GlyphFormat(int32_t glyph_id) { + IndexSubTable* subtable = SearchIndexSubTables(glyph_id); + if (subtable == NULL) { + return -1; + } + return subtable->image_format(); +} + +BitmapSizeTable::BitmapSizeTable(ReadableFontData* data, + ReadableFontData* master_data) + : SubTable(data, master_data) { +} + +// static +int32_t BitmapSizeTable::NumberOfIndexSubTables(ReadableFontData* data, + int32_t table_offset) { + return data->ReadULongAsInt(table_offset + + EblcTable::Offset::kBitmapSizeTable_numberOfIndexSubTables); +} + +IndexSubTable* BitmapSizeTable::SearchIndexSubTables(int32_t glyph_id) { + // would be faster to binary search but too many size tables don't have + // sorted subtables +#if (SFNTLY_BITMAPSIZE_USE_BINARY_SEARCH) + return BinarySearchIndexSubTables(glyph_id); +#else + return LinearSearchIndexSubTables(glyph_id); +#endif +} + +IndexSubTable* BitmapSizeTable::LinearSearchIndexSubTables(int32_t glyph_id) { + IndexSubTableList* subtable_list = GetIndexSubTableList(); + for (IndexSubTableList::iterator b = subtable_list->begin(), + e = subtable_list->end(); b != e; b++) { + if ((*b)->first_glyph_index() <= glyph_id && + (*b)->last_glyph_index() >= glyph_id) { + return *b; + } + } + return NULL; +} + +IndexSubTable* BitmapSizeTable::BinarySearchIndexSubTables(int32_t glyph_id) { + IndexSubTableList* subtable_list = GetIndexSubTableList(); + int32_t index = 0; + int32_t bottom = 0; + int32_t top = subtable_list->size(); + while (top != bottom) { + index = (top + bottom) / 2; + IndexSubTable* subtable = (*subtable_list)[index]; + if (glyph_id < subtable->first_glyph_index()) { + // Location beow current location + top = index; + } else { + if (glyph_id <= subtable->last_glyph_index()) { + return subtable; + } else { + bottom = index + 1; + } + } + } + return NULL; +} + +CALLER_ATTACH +IndexSubTable* BitmapSizeTable::CreateIndexSubTable(int32_t index) { + return IndexSubTable::CreateIndexSubTable(master_read_data(), + IndexSubTableArrayOffset(), + index); +} + +IndexSubTableList* BitmapSizeTable::GetIndexSubTableList() { + AutoLock lock(index_subtables_lock_); + if (index_subtables_.empty()) { + for (int32_t i = 0; i < NumberOfIndexSubTables(); ++i) { + IndexSubTablePtr table; + table.Attach(CreateIndexSubTable(i)); + index_subtables_.push_back(table); + } + } + return &index_subtables_; +} + +/****************************************************************************** + * BitmapSizeTable::Builder class + ******************************************************************************/ +BitmapSizeTable::Builder::~Builder() { +} + +CALLER_ATTACH +FontDataTable* BitmapSizeTable::Builder::SubBuildTable(ReadableFontData* data) { + BitmapSizeTablePtr output = new BitmapSizeTable(data, master_read_data()); + return output.Detach(); +} + +void BitmapSizeTable::Builder::SubDataSet() { + Revert(); +} + +int32_t BitmapSizeTable::Builder::SubDataSizeToSerialize() { + IndexSubTableBuilderList* builders = IndexSubTableBuilders(); + if (builders->empty()) { + return 0; + } + int32_t size = EblcTable::Offset::kBitmapSizeTableLength; + bool variable = false; + for (IndexSubTableBuilderList::iterator b = builders->begin(), + e = builders->end(); b != e; b++) { + size += EblcTable::Offset::kIndexSubTableEntryLength; + int32_t sub_table_size = (*b)->SubDataSizeToSerialize(); + int32_t padding = FontMath::PaddingRequired(abs(sub_table_size), + DataSize::kULONG); +#if defined (SFNTLY_DEBUG_BITMAP) + fprintf(stderr, "subtable size=%d\n", sub_table_size); +#endif + variable = (sub_table_size > 0) ? variable : true; + size += abs(sub_table_size) + padding; + } +#if defined (SFNTLY_DEBUG_BITMAP) + fprintf(stderr, "bitmap table size=%d\n", variable ? -size : size); +#endif + return variable ? -size : size; +} + +bool BitmapSizeTable::Builder::SubReadyToSerialize() { + if (IndexSubTableBuilders()->empty()) { + return false; + } + return true; +} + +int32_t BitmapSizeTable::Builder::SubSerialize(WritableFontData* new_data) { + SetNumberOfIndexSubTables(IndexSubTableBuilders()->size()); + int32_t size = InternalReadData()->CopyTo(new_data); + return size; +} + +CALLER_ATTACH BitmapSizeTable::Builder* +BitmapSizeTable::Builder::CreateBuilder(WritableFontData* data, + ReadableFontData* master_data) { + BitmapSizeTableBuilderPtr output = + new BitmapSizeTable::Builder(data, master_data); + return output.Detach(); +} + +CALLER_ATTACH BitmapSizeTable::Builder* +BitmapSizeTable::Builder::CreateBuilder(ReadableFontData* data, + ReadableFontData* master_data) { + BitmapSizeTableBuilderPtr output = + new BitmapSizeTable::Builder(data, master_data); + return output.Detach(); +} + +int32_t BitmapSizeTable::Builder::IndexSubTableArrayOffset() { + return InternalReadData()->ReadULongAsInt( + EblcTable::Offset::kBitmapSizeTable_indexSubTableArrayOffset); +} + +void BitmapSizeTable::Builder::SetIndexSubTableArrayOffset(int32_t offset) { + InternalWriteData()->WriteULong( + EblcTable::Offset::kBitmapSizeTable_indexSubTableArrayOffset, offset); +} + +int32_t BitmapSizeTable::Builder::IndexTableSize() { + return InternalReadData()->ReadULongAsInt( + EblcTable::Offset::kBitmapSizeTable_indexTableSize); +} + +void BitmapSizeTable::Builder::SetIndexTableSize(int32_t size) { + InternalWriteData()->WriteULong( + EblcTable::Offset::kBitmapSizeTable_indexTableSize, size); +} + +int32_t BitmapSizeTable::Builder::NumberOfIndexSubTables() { + return GetIndexSubTableBuilders()->size(); +} + +int32_t BitmapSizeTable::Builder::ColorRef() { + return InternalReadData()->ReadULongAsInt( + EblcTable::Offset::kBitmapSizeTable_colorRef); +} + +int32_t BitmapSizeTable::Builder::StartGlyphIndex() { + return InternalReadData()->ReadUShort( + EblcTable::Offset::kBitmapSizeTable_startGlyphIndex); +} + +int32_t BitmapSizeTable::Builder::EndGlyphIndex() { + return InternalReadData()->ReadUShort( + EblcTable::Offset::kBitmapSizeTable_endGlyphIndex); +} + +int32_t BitmapSizeTable::Builder::PpemX() { + return InternalReadData()->ReadByte( + EblcTable::Offset::kBitmapSizeTable_ppemX); +} + +int32_t BitmapSizeTable::Builder::PpemY() { + return InternalReadData()->ReadByte( + EblcTable::Offset::kBitmapSizeTable_ppemY); +} + +int32_t BitmapSizeTable::Builder::BitDepth() { + return InternalReadData()->ReadByte( + EblcTable::Offset::kBitmapSizeTable_bitDepth); +} + +int32_t BitmapSizeTable::Builder::FlagsAsInt() { + return InternalReadData()->ReadChar( + EblcTable::Offset::kBitmapSizeTable_flags); +} + +IndexSubTable::Builder* BitmapSizeTable::Builder::IndexSubTableBuilder( + int32_t index) { + IndexSubTableBuilderList* sub_table_list = GetIndexSubTableBuilders(); + return sub_table_list->at(index); +} + +CALLER_ATTACH BitmapGlyphInfo* BitmapSizeTable::Builder::GlyphInfo( + int32_t glyph_id) { + IndexSubTable::Builder* sub_table = SearchIndexSubTables(glyph_id); + if (sub_table == NULL) { + return NULL; + } + return sub_table->GlyphInfo(glyph_id); +} + +int32_t BitmapSizeTable::Builder::GlyphOffset(int32_t glyph_id) { + IndexSubTable::Builder* subtable = SearchIndexSubTables(glyph_id); + if (subtable == NULL) { + return -1; + } + return subtable->GlyphOffset(glyph_id); +} + +int32_t BitmapSizeTable::Builder::GlyphLength(int32_t glyph_id) { + IndexSubTable::Builder* subtable = SearchIndexSubTables(glyph_id); + if (subtable == NULL) { + return -1; + } + return subtable->GlyphLength(glyph_id); +} + +int32_t BitmapSizeTable::Builder::GlyphFormat(int32_t glyph_id) { + IndexSubTable::Builder* subtable = SearchIndexSubTables(glyph_id); + if (subtable == NULL) { + return -1; + } + return subtable->image_format(); +} + +IndexSubTableBuilderList* BitmapSizeTable::Builder::IndexSubTableBuilders() { + return GetIndexSubTableBuilders(); +} + +CALLER_ATTACH BitmapSizeTable::Builder::BitmapGlyphInfoIterator* +BitmapSizeTable::Builder::GetIterator() { + Ptr output = + new BitmapSizeTable::Builder::BitmapGlyphInfoIterator(this); + return output.Detach(); +} + +void BitmapSizeTable::Builder::GenerateLocaMap(BitmapGlyphInfoMap* output) { + assert(output); + Ptr it; + it.Attach(GetIterator()); + while (it->HasNext()) { + BitmapGlyphInfoPtr info; + info.Attach(it->Next()); + (*output)[info->glyph_id()] = info; + } +} + +void BitmapSizeTable::Builder::Revert() { + index_sub_tables_.clear(); + set_model_changed(false); +} + +BitmapSizeTable::Builder::Builder(WritableFontData* data, + ReadableFontData* master_data) + : SubTable::Builder(data, master_data) { +} + +BitmapSizeTable::Builder::Builder(ReadableFontData* data, + ReadableFontData* master_data) + : SubTable::Builder(data, master_data) { +} + +void BitmapSizeTable::Builder::SetNumberOfIndexSubTables(int32_t count) { + InternalWriteData()->WriteULong( + EblcTable::Offset::kBitmapSizeTable_numberOfIndexSubTables, count); +} + +IndexSubTable::Builder* BitmapSizeTable::Builder::SearchIndexSubTables( + int32_t glyph_id) { + // would be faster to binary search but too many size tables don't have + // sorted subtables +#if (SFNTLY_BITMAPSIZE_USE_BINARY_SEARCH) + return BinarySearchIndexSubTables(glyph_id); +#else + return LinearSearchIndexSubTables(glyph_id); +#endif +} + +IndexSubTable::Builder* BitmapSizeTable::Builder::LinearSearchIndexSubTables( + int32_t glyph_id) { + IndexSubTableBuilderList* subtable_list = GetIndexSubTableBuilders(); + for (IndexSubTableBuilderList::iterator b = subtable_list->begin(), + e = subtable_list->end(); + b != e; b++) { + if ((*b)->first_glyph_index() <= glyph_id && + (*b)->last_glyph_index() >= glyph_id) { + return *b; + } + } + return NULL; +} + +IndexSubTable::Builder* BitmapSizeTable::Builder::BinarySearchIndexSubTables( + int32_t glyph_id) { + IndexSubTableBuilderList* subtable_list = GetIndexSubTableBuilders(); + int32_t index = 0; + int32_t bottom = 0; + int32_t top = subtable_list->size(); + while (top != bottom) { + index = (top + bottom) / 2; + IndexSubTable::Builder* subtable = subtable_list->at(index); + if (glyph_id < subtable->first_glyph_index()) { + // Location beow current location + top = index; + } else { + if (glyph_id <= subtable->last_glyph_index()) { + return subtable; + } else { + bottom = index + 1; + } + } + } + return NULL; +} + +IndexSubTableBuilderList* BitmapSizeTable::Builder::GetIndexSubTableBuilders() { + if (index_sub_tables_.empty()) { + Initialize(InternalReadData()); + set_model_changed(); + } + return &index_sub_tables_; +} + +void BitmapSizeTable::Builder::Initialize(ReadableFontData* data) { + index_sub_tables_.clear(); + if (data) { + int32_t number_of_index_subtables = + BitmapSizeTable::NumberOfIndexSubTables(data, 0); + index_sub_tables_.resize(number_of_index_subtables); + for (int32_t i = 0; i < number_of_index_subtables; ++i) { + index_sub_tables_[i].Attach(CreateIndexSubTableBuilder(i)); + } + } +} + +CALLER_ATTACH IndexSubTable::Builder* +BitmapSizeTable::Builder::CreateIndexSubTableBuilder(int32_t index) { + return IndexSubTable::Builder::CreateBuilder(master_read_data(), + IndexSubTableArrayOffset(), + index); +} + +/****************************************************************************** + * BitmapSizeTable::Builder::BitmapGlyphInfoIterator class + ******************************************************************************/ +BitmapSizeTable::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator( + BitmapSizeTable::Builder* container) + : RefIterator(container) { + sub_table_iter_ = container->IndexSubTableBuilders()->begin(); + sub_table_glyph_info_iter_.Attach((*sub_table_iter_)->GetIterator()); +} + +bool BitmapSizeTable::Builder::BitmapGlyphInfoIterator::HasNext() { + if (sub_table_glyph_info_iter_ && HasNext(sub_table_glyph_info_iter_)) { + return true; + } + while (++sub_table_iter_ != container()->IndexSubTableBuilders()->end()) { + sub_table_glyph_info_iter_.Attach((*sub_table_iter_)->GetIterator()); + if (HasNext(sub_table_glyph_info_iter_)) { + return true; + } + } + return false; +} + +CALLER_ATTACH +BitmapGlyphInfo* BitmapSizeTable::Builder::BitmapGlyphInfoIterator::Next() { + if (!HasNext()) { + // Note: In C++, we do not throw exception when there's no element. + return NULL; + } + return Next(sub_table_glyph_info_iter_); +} + +bool BitmapSizeTable::Builder::BitmapGlyphInfoIterator::HasNext( + BitmapGlyphInfoIter* iterator_base) { + if (iterator_base) { + switch (iterator_base->container_base()->index_format()) { + case 1: { + IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator* it = + down_cast( + iterator_base); + return it->HasNext(); + } + + case 2: { + IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator* it = + down_cast( + iterator_base); + return it->HasNext(); + } + + case 3: { + IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator* it = + down_cast( + iterator_base); + return it->HasNext(); + } + + case 4: { + IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator* it = + down_cast( + iterator_base); + return it->HasNext(); + } + + case 5: { + IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator* it = + down_cast( + iterator_base); + return it->HasNext(); + } + + default: + break; + } + } + return false; +} + +CALLER_ATTACH +BitmapGlyphInfo* BitmapSizeTable::Builder::BitmapGlyphInfoIterator::Next( + BitmapGlyphInfoIter* iterator_base) { + if (iterator_base) { + switch (iterator_base->container_base()->index_format()) { + case 1: { + IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator* it = + down_cast( + iterator_base); + return it->Next(); + } + + case 2: { + IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator* it = + down_cast( + iterator_base); + return it->Next(); + } + + case 3: { + IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator* it = + down_cast( + iterator_base); + return it->Next(); + } + + case 4: { + IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator* it = + down_cast( + iterator_base); + return it->Next(); + } + + case 5: { + IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator* it = + down_cast( + iterator_base); + return it->Next(); + } + + default: + break; + } + } + return NULL; +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/bitmap/bitmap_size_table.h b/src/sfntly/src/sfntly/table/bitmap/bitmap_size_table.h new file mode 100644 index 0000000000..6733e20304 --- /dev/null +++ b/src/sfntly/src/sfntly/table/bitmap/bitmap_size_table.h @@ -0,0 +1,173 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 = the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_SIZE_TABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_SIZE_TABLE_H_ + +#include "sfntly/port/lock.h" +#include "sfntly/table/bitmap/bitmap_glyph_info.h" +#include "sfntly/table/bitmap/index_sub_table.h" + +namespace sfntly { +// Binary search would be faster but many fonts have index subtables that +// aren't sorted. +// Note: preprocessor define is used to avoid const expression warnings in C++ +// code. +#define SFNTLY_BITMAPSIZE_USE_BINARY_SEARCH 0 + +class BitmapSizeTable : public SubTable, + public RefCounted { + public: + class Builder : public SubTable::Builder, + public RefCounted { + public: + class BitmapGlyphInfoIterator : + public RefIterator { + public: + explicit BitmapGlyphInfoIterator(Builder* container); + virtual ~BitmapGlyphInfoIterator() {} + + virtual bool HasNext(); + CALLER_ATTACH virtual BitmapGlyphInfo* Next(); + + private: + bool HasNext(BitmapGlyphInfoIter* iterator_base); + CALLER_ATTACH BitmapGlyphInfo* Next(BitmapGlyphInfoIter* iterator_base); + + IndexSubTableBuilderList::iterator sub_table_iter_; + BitmapGlyphInfoIterPtr sub_table_glyph_info_iter_; + }; + + virtual ~Builder(); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + + static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data, + ReadableFontData* master_data); + static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data, + ReadableFontData* master_data); + // Gets the subtable array offset as set in the original table as read from + // the font file. This value cannot be explicitly set and will be generated + // during table building. + // @return the subtable array offset + int32_t IndexSubTableArrayOffset(); + + // Sets the subtable array offset. This is used only during the building + // process when the objects are being serialized. + // @param offset the offset to the index subtable array + void SetIndexSubTableArrayOffset(int32_t offset); + + // Gets the subtable array size as set in the original table as read from + // the font file. This value cannot be explicitly set and will be generated + // during table building. + // @return the subtable array size + int32_t IndexTableSize(); + + // Sets the subtable size. This is used only during the building process + // when the objects are being serialized. + // @param size the offset to the index subtable array + void SetIndexTableSize(int32_t size); + + int32_t NumberOfIndexSubTables(); + int32_t ColorRef(); + // TODO(stuartg): SBitLineMetrics hori(); + // TODO(stuartg): SBitLineMetrics vert(); + int32_t StartGlyphIndex(); + int32_t EndGlyphIndex(); + int32_t PpemX(); + int32_t PpemY(); + int32_t BitDepth(); + int32_t FlagsAsInt(); + + IndexSubTable::Builder* IndexSubTableBuilder(int32_t index); + CALLER_ATTACH BitmapGlyphInfo* GlyphInfo(int32_t glyph_id); + int32_t GlyphOffset(int32_t glyph_id); + int32_t GlyphLength(int32_t glyph_id); + int32_t GlyphFormat(int32_t glyph_id); + IndexSubTableBuilderList* IndexSubTableBuilders(); + // Note: renamed from iterator(), type is the derived type. + CALLER_ATTACH BitmapGlyphInfoIterator* GetIterator(); + void GenerateLocaMap(BitmapGlyphInfoMap* output); + + protected: + void Revert(); + + private: + Builder(WritableFontData* data, ReadableFontData* master_data); + Builder(ReadableFontData* data, ReadableFontData* master_data); + + void SetNumberOfIndexSubTables(int32_t count); + IndexSubTable::Builder* SearchIndexSubTables(int32_t glyph_id); + IndexSubTable::Builder* LinearSearchIndexSubTables(int32_t glyph_id); + IndexSubTable::Builder* BinarySearchIndexSubTables(int32_t glyph_id); + IndexSubTableBuilderList* GetIndexSubTableBuilders(); + void Initialize(ReadableFontData* data); + CALLER_ATTACH IndexSubTable::Builder* CreateIndexSubTableBuilder( + int32_t index); + + IndexSubTableBuilderList index_sub_tables_; + }; + + virtual ~BitmapSizeTable(); + + int32_t IndexSubTableArrayOffset(); + int32_t IndexTableSize(); + int32_t NumberOfIndexSubTables(); + int32_t ColorRef(); + // TODO(stuartg): SBitLineMetrics hori(); + // TODO(stuartg): SBitLineMetrics vert(); + int32_t StartGlyphIndex(); + int32_t EndGlyphIndex(); + int32_t PpemX(); + int32_t PpemY(); + int32_t BitDepth(); + int32_t FlagsAsInt(); + + // Note: renamed from indexSubTable() + IndexSubTable* GetIndexSubTable(int32_t index); + int32_t GlyphOffset(int32_t glyph_id); + int32_t GlyphLength(int32_t glyph_id); + CALLER_ATTACH BitmapGlyphInfo* GlyphInfo(int32_t glyph_id); + int32_t GlyphFormat(int32_t glyph_id); + + protected: + BitmapSizeTable(ReadableFontData* data, + ReadableFontData* master_data); + + private: + static int32_t NumberOfIndexSubTables(ReadableFontData* data, + int32_t table_offset); + IndexSubTable* SearchIndexSubTables(int32_t glyph_id); + IndexSubTable* LinearSearchIndexSubTables(int32_t glyph_id); + IndexSubTable* BinarySearchIndexSubTables(int32_t glyph_id); + CALLER_ATTACH IndexSubTable* CreateIndexSubTable(int32_t index); + IndexSubTableList* GetIndexSubTableList(); + + Lock index_subtables_lock_; + IndexSubTableList index_subtables_; +}; +typedef Ptr BitmapSizeTablePtr; +typedef std::vector BitmapSizeTableList; +typedef Ptr BitmapSizeTableBuilderPtr; +typedef std::vector BitmapSizeTableBuilderList; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_SIZE_TABLE_H_ diff --git a/src/sfntly/src/sfntly/table/bitmap/composite_bitmap_glyph.cc b/src/sfntly/src/sfntly/table/bitmap/composite_bitmap_glyph.cc new file mode 100644 index 0000000000..ae7dc5a731 --- /dev/null +++ b/src/sfntly/src/sfntly/table/bitmap/composite_bitmap_glyph.cc @@ -0,0 +1,109 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 = the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/bitmap/composite_bitmap_glyph.h" + +namespace sfntly { +/****************************************************************************** + * CompositeBitmapGlyph class + ******************************************************************************/ +CompositeBitmapGlyph::CompositeBitmapGlyph(ReadableFontData* data, + int32_t format) + : BitmapGlyph(data, format) { + Initialize(format); +} + +CompositeBitmapGlyph::~CompositeBitmapGlyph() { +} + +int32_t CompositeBitmapGlyph::NumComponents() { + return data_->ReadUShort(num_components_offset_); +} + +CompositeBitmapGlyph::Component CompositeBitmapGlyph::GetComponent( + int32_t component_num) const { + int32_t component_offset = component_array_offset_ + + component_num * Offset::kEbdtComponentLength; + return CompositeBitmapGlyph::Component( + data_->ReadUShort(component_offset + Offset::kEbdtComponent_glyphCode), + data_->ReadChar(component_offset + Offset::kEbdtComponent_xOffset), + data_->ReadChar(component_offset + Offset::kEbdtComponent_yOffset)); +} + +void CompositeBitmapGlyph::Initialize(int32_t format) { + if (format == 8) { + num_components_offset_ = Offset::kGlyphFormat8_numComponents; + component_array_offset_ = Offset::kGlyphFormat8_componentArray; + } else if (format == 9) { + num_components_offset_ = Offset::kGlyphFormat9_numComponents; + component_array_offset_ = Offset::kGlyphFormat9_componentArray; + } else { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IllegalStateException("Attempt to create a Composite Bitmap Glyph " + "with a non-composite format."); +#endif + } +} + +/****************************************************************************** + * CompositeBitmapGlyph::Component class + ******************************************************************************/ +CompositeBitmapGlyph::Component::Component(const Component& rhs) + : glyph_code_(rhs.glyph_code_), + x_offset_(rhs.x_offset_), + y_offset_(rhs.y_offset_) { +} + +bool CompositeBitmapGlyph::Component::operator==( + const CompositeBitmapGlyph::Component& rhs) { + return glyph_code_ == rhs.glyph_code_; +} + +CompositeBitmapGlyph::Component& CompositeBitmapGlyph::Component::operator=( + const CompositeBitmapGlyph::Component& rhs) { + glyph_code_ = rhs.glyph_code_; + x_offset_ = rhs.x_offset_; + y_offset_ = rhs.y_offset_; + return *this; +} + +CompositeBitmapGlyph::Component::Component(int32_t glyph_code, + int32_t x_offset, + int32_t y_offset) + : glyph_code_(glyph_code), x_offset_(x_offset), y_offset_(y_offset) { +} + +/****************************************************************************** + * CompositeBitmapGlyph::Builder class + ******************************************************************************/ +CompositeBitmapGlyph::Builder::Builder(ReadableFontData* data, int32_t format) + : BitmapGlyph::Builder(data, format) { +} + +CompositeBitmapGlyph::Builder::Builder(WritableFontData* data, int32_t format) + : BitmapGlyph::Builder(data, format) { +} + +CompositeBitmapGlyph::Builder::~Builder() { +} + +CALLER_ATTACH FontDataTable* +CompositeBitmapGlyph::Builder::SubBuildTable(ReadableFontData* data) { + Ptr glyph = new CompositeBitmapGlyph(data, format()); + return glyph.Detach(); +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/bitmap/composite_bitmap_glyph.h b/src/sfntly/src/sfntly/table/bitmap/composite_bitmap_glyph.h new file mode 100644 index 0000000000..897db7e22a --- /dev/null +++ b/src/sfntly/src/sfntly/table/bitmap/composite_bitmap_glyph.h @@ -0,0 +1,75 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 = the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_COMPOSITE_BITMAP_GLYPH_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_COMPOSITE_BITMAP_GLYPH_H_ + +#include "sfntly/table/bitmap/bitmap_glyph.h" + +namespace sfntly { + +class CompositeBitmapGlyph : public BitmapGlyph, + public RefCounted { + public: + class Component { + public: + Component(const Component& rhs); + + int32_t glyph_code() { return glyph_code_; } + int32_t x_offset() { return x_offset_; } + int32_t y_offset() { return y_offset_; } + + // UNIMPLEMENTED: int hashCode() + bool operator==(const Component& rhs); + Component& operator=(const Component& rhs); + + protected: + Component(int32_t glyph_code, int32_t x_offset, int32_t y_offset); + + private: + int32_t glyph_code_; + int32_t x_offset_; + int32_t y_offset_; + + friend class CompositeBitmapGlyph; + }; + + class Builder : public BitmapGlyph::Builder, + public RefCounted { + public: + Builder(WritableFontData* data, int32_t format); + Builder(ReadableFontData* data, int32_t format); + virtual ~Builder(); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + }; + + CompositeBitmapGlyph(ReadableFontData* data, int32_t format); + virtual ~CompositeBitmapGlyph(); + int32_t NumComponents(); + // Note: returned immutable object over stack. + Component GetComponent(int32_t component_num) const; + + private: + void Initialize(int32_t format); + + int32_t num_components_offset_; + int32_t component_array_offset_; +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_COMPOSITE_BITMAP_GLYPH_H_ diff --git a/src/sfntly/src/sfntly/table/bitmap/ebdt_table.cc b/src/sfntly/src/sfntly/table/bitmap/ebdt_table.cc new file mode 100644 index 0000000000..eeb1fa06b3 --- /dev/null +++ b/src/sfntly/src/sfntly/table/bitmap/ebdt_table.cc @@ -0,0 +1,236 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/bitmap/ebdt_table.h" + +#include + +#include "sfntly/table/bitmap/composite_bitmap_glyph.h" +#include "sfntly/table/bitmap/simple_bitmap_glyph.h" + +namespace sfntly { +/****************************************************************************** + * EbdtTable class + ******************************************************************************/ +EbdtTable::~EbdtTable() { +} + +int32_t EbdtTable::Version() { + return data_->ReadFixed(Offset::kVersion); +} + +CALLER_ATTACH +BitmapGlyph* EbdtTable::Glyph(int32_t offset, int32_t length, int32_t format) { + ReadableFontDataPtr glyph_data; + glyph_data.Attach(down_cast(data_->Slice(offset, length))); + return BitmapGlyph::CreateGlyph(glyph_data, format); +} + +EbdtTable::EbdtTable(Header* header, ReadableFontData* data) + : SubTableContainerTable(header, data) { +} + +/****************************************************************************** + * EbdtTable::Builder class + ******************************************************************************/ +EbdtTable::Builder::Builder(Header* header, WritableFontData* data) + : SubTableContainerTable::Builder(header, data) { +} + +EbdtTable::Builder::Builder(Header* header, ReadableFontData* data) + : SubTableContainerTable::Builder(header, data) { +} + +EbdtTable::Builder::~Builder() { +} + +CALLER_ATTACH FontDataTable* + EbdtTable::Builder::SubBuildTable(ReadableFontData* data) { + FontDataTablePtr table = new EbdtTable(header(), data); + return table.Detach(); +} + +void EbdtTable::Builder::SubDataSet() { + Revert(); +} + +int32_t EbdtTable::Builder::SubDataSizeToSerialize() { + if (glyph_builders_.empty()) { + return 0; + } + bool fixed = true; + int32_t size = Offset::kHeaderLength; + for (BitmapGlyphBuilderList::iterator builder_map = glyph_builders_.begin(), + builder_end = glyph_builders_.end(); + builder_map != builder_end; + builder_map++) { + for (BitmapGlyphBuilderMap::iterator glyph_entry = builder_map->begin(), + glyph_entry_end = builder_map->end(); + glyph_entry != glyph_entry_end; + glyph_entry++) { + int32_t glyph_size = glyph_entry->second->SubDataSizeToSerialize(); + size += abs(glyph_size); + fixed = (glyph_size <= 0) ? false : fixed; + } + } + return (fixed ? 1 : -1) * size; +} + +bool EbdtTable::Builder::SubReadyToSerialize() { + if (glyph_builders_.empty()) { + return false; + } + return true; +} + +int32_t EbdtTable::Builder::SubSerialize(WritableFontData* new_data) { + int32_t size = 0; + size += new_data->WriteFixed(Offset::kVersion, kVersion); + for (BitmapGlyphBuilderList::iterator builder_map = glyph_builders_.begin(), + builder_end = glyph_builders_.end(); + builder_map != builder_end; + builder_map++) { + for (BitmapGlyphBuilderMap::iterator glyph_entry = builder_map->begin(), + glyph_entry_end = builder_map->end(); + glyph_entry != glyph_entry_end; + glyph_entry++) { + WritableFontDataPtr slice; + slice.Attach(down_cast(new_data->Slice(size))); + size += glyph_entry->second->SubSerialize(slice); + } + } + return size; +} + +void EbdtTable::Builder::SetLoca(BitmapLocaList* loca_list) { + assert(loca_list); + Revert(); + glyph_loca_.resize(loca_list->size()); + std::copy(loca_list->begin(), loca_list->end(), glyph_loca_.begin()); +} + +void EbdtTable::Builder::GenerateLocaList(BitmapLocaList* output) { + assert(output); + output->clear(); + + if (glyph_builders_.empty()) { + if (glyph_loca_.empty()) { + return; + } + } + + int start_offset = Offset::kHeaderLength; + for (BitmapGlyphBuilderList::iterator builder_map = glyph_builders_.begin(), + builder_end = glyph_builders_.end(); + builder_map != builder_end; + builder_map++) { + BitmapGlyphInfoMap new_loca_map; + int32_t glyph_offset = 0; + for (BitmapGlyphBuilderMap::iterator glyph_entry = builder_map->begin(), + glyph_end = builder_map->end(); + glyph_entry != glyph_end; + glyph_entry++) { + BitmapGlyphBuilderPtr builder = glyph_entry->second; + int32_t size = builder->SubDataSizeToSerialize(); + BitmapGlyphInfoPtr info = new BitmapGlyphInfo(glyph_entry->first, + start_offset + glyph_offset, size, builder->format()); + new_loca_map[glyph_entry->first] = info; + glyph_offset += size; + } + start_offset += glyph_offset; + output->push_back(new_loca_map); + } +} + +BitmapGlyphBuilderList* EbdtTable::Builder::GlyphBuilders() { + return GetGlyphBuilders(); +} + +void EbdtTable::Builder::SetGlyphBuilders( + BitmapGlyphBuilderList* glyph_builders) { + glyph_builders_.clear(); + std::copy(glyph_builders->begin(), glyph_builders->end(), + glyph_builders_.begin()); + set_model_changed(); +} + +void EbdtTable::Builder::Revert() { + glyph_loca_.clear(); + glyph_builders_.clear(); + set_model_changed(false); +} + +CALLER_ATTACH +EbdtTable::Builder* EbdtTable::Builder::CreateBuilder(Header* header, + WritableFontData* data) { + Ptr builder; + builder = new Builder(header, data); + return builder.Detach(); +} + +CALLER_ATTACH +EbdtTable::Builder* EbdtTable::Builder::CreateBuilder(Header* header, + ReadableFontData* data) { + Ptr builder; + builder = new Builder(header, data); + return builder.Detach(); +} + +BitmapGlyphBuilderList* EbdtTable::Builder::GetGlyphBuilders() { + if (glyph_builders_.empty()) { + if (glyph_loca_.empty()) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IllegalStateException( + "Loca values not set - unable to parse glyph data."); +#endif + return NULL; + } + Initialize(InternalReadData(), &glyph_loca_, &glyph_builders_); + set_model_changed(); + } + return &glyph_builders_; +} + +void EbdtTable::Builder::Initialize(ReadableFontData* data, + BitmapLocaList* loca_list, + BitmapGlyphBuilderList* output) { + assert(loca_list); + assert(output); + + output->clear(); + if (data) { + for (BitmapLocaList::iterator loca_map = loca_list->begin(), + loca_end = loca_list->end(); + loca_map != loca_end; loca_map++) { + BitmapGlyphBuilderMap glyph_builder_map; + for (BitmapGlyphInfoMap::iterator entry = loca_map->begin(), + entry_end = loca_map->end(); + entry != entry_end; entry++) { + BitmapGlyphInfoPtr info = entry->second; + ReadableFontDataPtr slice; + slice.Attach(down_cast(data->Slice( + info->offset(), info->length()))); + BitmapGlyphBuilderPtr glyph_builder; + glyph_builder.Attach(BitmapGlyph::Builder::CreateGlyphBuilder( + slice, info->format())); + glyph_builder_map[entry->first] = glyph_builder; + } + output->push_back(glyph_builder_map); + } + } +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/bitmap/ebdt_table.h b/src/sfntly/src/sfntly/table/bitmap/ebdt_table.h new file mode 100644 index 0000000000..d138c14ca5 --- /dev/null +++ b/src/sfntly/src/sfntly/table/bitmap/ebdt_table.h @@ -0,0 +1,108 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBDT_TABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBDT_TABLE_H_ + +#include "sfntly/table/bitmap/bitmap_glyph.h" +#include "sfntly/table/bitmap/bitmap_glyph_info.h" +#include "sfntly/table/subtable_container_table.h" + +namespace sfntly { + +class EbdtTable : public SubTableContainerTable, + public RefCounted { + public: + struct Offset { + enum { + kVersion = 0, + kHeaderLength = DataSize::kFixed, + }; + }; + + class Builder : public SubTableContainerTable::Builder, + public RefCounted { + public: + // Constructor scope altered to public because C++ does not allow base + // class to instantiate derived class with protected constructors. + Builder(Header* header, WritableFontData* data); + Builder(Header* header, ReadableFontData* data); + virtual ~Builder(); + + virtual int32_t SubSerialize(WritableFontData* new_data); + virtual bool SubReadyToSerialize(); + virtual int32_t SubDataSizeToSerialize(); + virtual void SubDataSet(); + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + + void SetLoca(BitmapLocaList* loca_list); + void GenerateLocaList(BitmapLocaList* output); + + // Gets the List of glyph builders for the glyph table builder. These may be + // manipulated in any way by the caller and the changes will be reflected in + // the final glyph table produced. + // If there is no current data for the glyph builder or the glyph builders + // have not been previously set then this will return an empty glyph builder + // List. If there is current data (i.e. data read from an existing font) and + // the loca list has not been set or is null, empty, or invalid, then an + // empty glyph builder List will be returned. + // @return the list of glyph builders + BitmapGlyphBuilderList* GlyphBuilders(); + + // Replace the internal glyph builders with the one provided. The provided + // list and all contained objects belong to this builder. + // This call is only required if the entire set of glyphs in the glyph + // table builder are being replaced. If the glyph builder list provided from + // the {@link EbdtTable.Builder#glyphBuilders()} is being used and modified + // then those changes will already be reflected in the glyph table builder. + // @param glyphBuilders the new glyph builders + void SetGlyphBuilders(BitmapGlyphBuilderList* glyph_builders); + + void Revert(); + + // Create a new builder using the header information and data provided. + // @param header the header information + // @param data the data holding the table + static CALLER_ATTACH Builder* CreateBuilder(Header* header, + WritableFontData* data); + static CALLER_ATTACH Builder* CreateBuilder(Header* header, + ReadableFontData* data); + + private: + BitmapGlyphBuilderList* GetGlyphBuilders(); + static void Initialize(ReadableFontData* data, + BitmapLocaList* loca_list, + BitmapGlyphBuilderList* output); + + static const int32_t kVersion = 0x00020000; // TODO(stuartg): const/enum + BitmapLocaList glyph_loca_; + BitmapGlyphBuilderList glyph_builders_; + }; + + virtual ~EbdtTable(); + int32_t Version(); + CALLER_ATTACH BitmapGlyph* Glyph(int32_t offset, + int32_t length, + int32_t format); + protected: + EbdtTable(Header* header, ReadableFontData* data); +}; +typedef Ptr EbdtTablePtr; +typedef Ptr EbdtTableBuilderPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBDT_TABLE_H_ diff --git a/src/sfntly/src/sfntly/table/bitmap/eblc_table.cc b/src/sfntly/src/sfntly/table/bitmap/eblc_table.cc new file mode 100644 index 0000000000..0ad2764bf6 --- /dev/null +++ b/src/sfntly/src/sfntly/table/bitmap/eblc_table.cc @@ -0,0 +1,313 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/bitmap/eblc_table.h" + +#include +#include + +#include "sfntly/math/font_math.h" + +namespace sfntly { +/****************************************************************************** + * EblcTable class + ******************************************************************************/ +int32_t EblcTable::Version() { + return data_->ReadFixed(Offset::kVersion); +} + +int32_t EblcTable::NumSizes() { + return data_->ReadULongAsInt(Offset::kNumSizes); +} + +BitmapSizeTable* EblcTable::GetBitmapSizeTable(int32_t index) { + if (index < 0 || index > NumSizes()) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundException( + "Size table index is outside the range of tables."); +#endif + return NULL; + } + BitmapSizeTableList* bitmap_size_table_list = GetBitmapSizeTableList(); + if (bitmap_size_table_list) { + return (*bitmap_size_table_list)[index]; + } + return NULL; +} + +EblcTable::EblcTable(Header* header, ReadableFontData* data) + : SubTableContainerTable(header, data) { +} + +BitmapSizeTableList* EblcTable::GetBitmapSizeTableList() { + AutoLock lock(bitmap_size_table_lock_); + if (bitmap_size_table_.empty()) { + CreateBitmapSizeTable(data_, NumSizes(), &bitmap_size_table_); + } + return &bitmap_size_table_; +} + +// static +void EblcTable::CreateBitmapSizeTable(ReadableFontData* data, + int32_t num_sizes, + BitmapSizeTableList* output) { + assert(data); + assert(output); + for (int32_t i = 0; i < num_sizes; ++i) { + ReadableFontDataPtr new_data; + new_data.Attach(down_cast( + data->Slice(Offset::kBitmapSizeTableArrayStart + + i * Offset::kBitmapSizeTableLength, + Offset::kBitmapSizeTableLength))); + BitmapSizeTableBuilderPtr size_builder; + size_builder.Attach( + BitmapSizeTable::Builder::CreateBuilder(new_data, data)); + BitmapSizeTablePtr size; + size.Attach(down_cast(size_builder->Build())); + output->push_back(size); + } +} + +/****************************************************************************** + * EblcTable::Builder class + ******************************************************************************/ +EblcTable::Builder::Builder(Header* header, WritableFontData* data) + : SubTableContainerTable::Builder(header, data) { +} + +EblcTable::Builder::Builder(Header* header, ReadableFontData* data) + : SubTableContainerTable::Builder(header, data) { +} + +EblcTable::Builder::~Builder() { +} + +int32_t EblcTable::Builder::SubSerialize(WritableFontData* new_data) { + // header + int32_t size = new_data->WriteFixed(0, kVersion); + size += new_data->WriteULong(size, size_table_builders_.size()); + + // calculate the offsets + // offset to the start of the size table array + int32_t size_table_start_offset = size; + // walking offset in the size table array + int32_t size_table_offset = size_table_start_offset; + // offset to the start of the whole index subtable block + int32_t sub_table_block_start_offset = size_table_offset + + size_table_builders_.size() * Offset::kBitmapSizeTableLength; + // walking offset in the index subtable + // points to the start of the current subtable block + int32_t current_sub_table_block_start_offset = sub_table_block_start_offset; + +#if defined (SFNTLY_DEBUG_BITMAP) + int32_t size_index = 0; +#endif + for (BitmapSizeTableBuilderList::iterator + size_builder = size_table_builders_.begin(), + size_builder_end = size_table_builders_.end(); + size_builder != size_builder_end; size_builder++) { + (*size_builder)->SetIndexSubTableArrayOffset( + current_sub_table_block_start_offset); + IndexSubTableBuilderList* index_sub_table_builder_list = + (*size_builder)->IndexSubTableBuilders(); + + // walking offset within the current subTable array + int32_t index_sub_table_array_offset = current_sub_table_block_start_offset; + // walking offset within the subTable entries + int32_t index_sub_table_offset = index_sub_table_array_offset + + index_sub_table_builder_list->size() * Offset::kIndexSubHeaderLength; + +#if defined (SFNTLY_DEBUG_BITMAP) + fprintf(stderr, "size %d: sizeTable=%x, current subTable Block=%x, ", + size_index, size_table_offset, + current_sub_table_block_start_offset); + fprintf(stderr, "index subTableStart=%x\n", index_sub_table_offset); + size_index++; + int32_t sub_table_index = 0; +#endif + for (IndexSubTableBuilderList::iterator + index_sub_table_builder = index_sub_table_builder_list->begin(), + index_sub_table_builder_end = index_sub_table_builder_list->end(); + index_sub_table_builder != index_sub_table_builder_end; + index_sub_table_builder++) { +#if defined (SFNTLY_DEBUG_BITMAP) + fprintf(stderr, "\tsubTableIndex %d: format=%x, ", sub_table_index, + (*index_sub_table_builder)->index_format()); + fprintf(stderr, "indexSubTableArrayOffset=%x, indexSubTableOffset=%x\n", + index_sub_table_array_offset, index_sub_table_offset); + sub_table_index++; +#endif + // array entry + index_sub_table_array_offset += new_data->WriteUShort( + index_sub_table_array_offset, + (*index_sub_table_builder)->first_glyph_index()); + index_sub_table_array_offset += new_data->WriteUShort( + index_sub_table_array_offset, + (*index_sub_table_builder)->last_glyph_index()); + index_sub_table_array_offset += new_data->WriteULong( + index_sub_table_array_offset, + index_sub_table_offset - current_sub_table_block_start_offset); + + // index sub table + WritableFontDataPtr slice_index_sub_table; + slice_index_sub_table.Attach(down_cast( + new_data->Slice(index_sub_table_offset))); + int32_t current_sub_table_size = + (*index_sub_table_builder)->SubSerialize(slice_index_sub_table); + int32_t padding = FontMath::PaddingRequired(current_sub_table_size, + DataSize::kULONG); +#if defined (SFNTLY_DEBUG_BITMAP) + fprintf(stderr, "\t\tsubTableSize = %x, padding = %x\n", + current_sub_table_size, padding); +#endif + index_sub_table_offset += current_sub_table_size; + index_sub_table_offset += + new_data->WritePadding(index_sub_table_offset, padding); + } + + // serialize size table + (*size_builder)->SetIndexTableSize( + index_sub_table_offset - current_sub_table_block_start_offset); + WritableFontDataPtr slice_size_table; + slice_size_table.Attach(down_cast( + new_data->Slice(size_table_offset))); + size_table_offset += (*size_builder)->SubSerialize(slice_size_table); + + current_sub_table_block_start_offset = index_sub_table_offset; + } + return size + current_sub_table_block_start_offset; +} + +bool EblcTable::Builder::SubReadyToSerialize() { + if (size_table_builders_.empty()) { + return false; + } + for (BitmapSizeTableBuilderList::iterator b = size_table_builders_.begin(), + e = size_table_builders_.end(); + b != e; b++) { + if (!(*b)->SubReadyToSerialize()) { + return false; + } + } + return true; +} + +int32_t EblcTable::Builder::SubDataSizeToSerialize() { + if (size_table_builders_.empty()) { + return 0; + } + int32_t size = Offset::kHeaderLength; + bool variable = false; +#if defined (SFNTLY_DEBUG_BITMAP) + size_t size_index = 0; +#endif + for (BitmapSizeTableBuilderList::iterator b = size_table_builders_.begin(), + e = size_table_builders_.end(); + b != e; b++) { + int32_t size_builder_size = (*b)->SubDataSizeToSerialize(); +#if defined (SFNTLY_DEBUG_BITMAP) + fprintf(stderr, "sizeIndex = %d, sizeBuilderSize=0x%x (%d)\n", + size_index++, size_builder_size, size_builder_size); +#endif + variable = size_builder_size > 0 ? variable : true; + size += abs(size_builder_size); + } +#if defined (SFNTLY_DEBUG_BITMAP) + fprintf(stderr, "eblc size=%d\n", size); +#endif + return variable ? -size : size; +} + +void EblcTable::Builder::SubDataSet() { + Revert(); +} + +BitmapSizeTableBuilderList* EblcTable::Builder::BitmapSizeBuilders() { + return GetSizeList(); +} + +void EblcTable::Builder::Revert() { + size_table_builders_.clear(); + set_model_changed(false); +} + +void EblcTable::Builder::GenerateLocaList(BitmapLocaList* output) { + assert(output); + BitmapSizeTableBuilderList* size_builder_list = GetSizeList(); + output->clear(); +#if defined (SFNTLY_DEBUG_BITMAP) + int32_t size_index = 0; +#endif + for (BitmapSizeTableBuilderList::iterator b = size_builder_list->begin(), + e = size_builder_list->end(); + b != e; b++) { +#if defined (SFNTLY_DEBUG_BITMAP) + fprintf(stderr, "size table = %d\n", size_index++); +#endif + BitmapGlyphInfoMap loca_map; + (*b)->GenerateLocaMap(&loca_map); + output->push_back(loca_map); + } +} + +CALLER_ATTACH +FontDataTable* EblcTable::Builder::SubBuildTable(ReadableFontData* data) { + Ptr new_table = new EblcTable(header(), data); + return new_table.Detach(); +} + +// static +CALLER_ATTACH EblcTable::Builder* + EblcTable::Builder::CreateBuilder(Header* header, WritableFontData* data) { + Ptr new_builder = new EblcTable::Builder(header, data); + return new_builder.Detach(); +} + +// static +CALLER_ATTACH EblcTable::Builder* + EblcTable::Builder::CreateBuilder(Header* header, ReadableFontData* data) { + Ptr new_builder = new EblcTable::Builder(header, data); + return new_builder.Detach(); +} + +BitmapSizeTableBuilderList* EblcTable::Builder::GetSizeList() { + if (size_table_builders_.empty()) { + Initialize(InternalReadData(), &size_table_builders_); + set_model_changed(); + } + return &size_table_builders_; +} + +void EblcTable::Builder::Initialize(ReadableFontData* data, + BitmapSizeTableBuilderList* output) { + assert(output); + if (data) { + int32_t num_sizes = data->ReadULongAsInt(Offset::kNumSizes); + for (int32_t i = 0; i < num_sizes; ++i) { + ReadableFontDataPtr new_data; + new_data.Attach(down_cast( + data->Slice(Offset::kBitmapSizeTableArrayStart + + i * Offset::kBitmapSizeTableLength, + Offset::kBitmapSizeTableLength))); + BitmapSizeTableBuilderPtr size_builder; + size_builder.Attach(BitmapSizeTable::Builder::CreateBuilder( + new_data, data)); + output->push_back(size_builder); + } + } +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/bitmap/eblc_table.h b/src/sfntly/src/sfntly/table/bitmap/eblc_table.h new file mode 100644 index 0000000000..b04338a93b --- /dev/null +++ b/src/sfntly/src/sfntly/table/bitmap/eblc_table.h @@ -0,0 +1,194 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBLC_TABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBLC_TABLE_H_ + +#include "sfntly/port/lock.h" +#include "sfntly/table/bitmap/big_glyph_metrics.h" +#include "sfntly/table/bitmap/bitmap_glyph.h" +#include "sfntly/table/bitmap/bitmap_size_table.h" +#include "sfntly/table/subtable_container_table.h" + +namespace sfntly { + +class EblcTable : public SubTableContainerTable, + public RefCounted { + public: + struct Offset { + enum { + // header + kVersion = 0, + kNumSizes = 4, + kHeaderLength = kNumSizes + DataSize::kULONG, + + // bitmapSizeTable + kBitmapSizeTableArrayStart = kHeaderLength, + kBitmapSizeTableLength = 48, + kBitmapSizeTable_indexSubTableArrayOffset = 0, + kBitmapSizeTable_indexTableSize = 4, + kBitmapSizeTable_numberOfIndexSubTables = 8, + kBitmapSizeTable_colorRef = 12, + kBitmapSizeTable_hori = 16, + kBitmapSizeTable_vert = 28, + kBitmapSizeTable_startGlyphIndex = 40, + kBitmapSizeTable_endGlyphIndex = 42, + kBitmapSizeTable_ppemX = 44, + kBitmapSizeTable_ppemY = 45, + kBitmapSizeTable_bitDepth = 46, + kBitmapSizeTable_flags = 47, + + // sbitLineMetrics + kSbitLineMetricsLength = 12, + kSbitLineMetrics_ascender = 0, + kSbitLineMetrics_descender = 1, + kSbitLineMetrics_widthMax = 2, + kSbitLineMetrics_caretSlopeNumerator = 3, + kSbitLineMetrics_caretSlopeDenominator = 4, + kSbitLineMetrics_caretOffset = 5, + kSbitLineMetrics_minOriginSB = 6, + kSbitLineMetrics_minAdvanceSB = 7, + kSbitLineMetrics_maxBeforeBL = 8, + kSbitLineMetrics_minAfterBL = 9, + kSbitLineMetrics_pad1 = 10, + kSbitLineMetrics_pad2 = 11, + + // indexSubTable + kIndexSubTableEntryLength = 8, + kIndexSubTableEntry_firstGlyphIndex = 0, + kIndexSubTableEntry_lastGlyphIndex = 2, + kIndexSubTableEntry_additionalOffsetToIndexSubTable = 4, + + // indexSubHeader + kIndexSubHeaderLength = 8, + kIndexSubHeader_indexFormat = 0, + kIndexSubHeader_imageFormat = 2, + kIndexSubHeader_imageDataOffset = 4, + + // indexSubTable - all offset relative to the subtable start + + // indexSubTable1 + kIndexSubTable1_offsetArray = kIndexSubHeaderLength, + kIndexSubTable1_builderDataSize = kIndexSubHeaderLength, + + // kIndexSubTable2 + kIndexSubTable2Length = kIndexSubHeaderLength + + DataSize::kULONG + + BitmapGlyph::Offset::kBigGlyphMetricsLength, + kIndexSubTable2_imageSize = kIndexSubHeaderLength, + kIndexSubTable2_bigGlyphMetrics = kIndexSubTable2_imageSize + + DataSize::kULONG, + kIndexSubTable2_builderDataSize = kIndexSubTable2_bigGlyphMetrics + + BigGlyphMetrics::Offset::kMetricsLength, + + // kIndexSubTable3 + kIndexSubTable3_offsetArray = kIndexSubHeaderLength, + kIndexSubTable3_builderDataSize = kIndexSubTable3_offsetArray, + + // kIndexSubTable4 + kIndexSubTable4_numGlyphs = kIndexSubHeaderLength, + kIndexSubTable4_glyphArray = kIndexSubTable4_numGlyphs + + DataSize::kULONG, + kIndexSubTable4_codeOffsetPairLength = 2 * DataSize::kUSHORT, + kIndexSubTable4_codeOffsetPair_glyphCode = 0, + kIndexSubTable4_codeOffsetPair_offset = DataSize::kUSHORT, + kIndexSubTable4_builderDataSize = kIndexSubTable4_glyphArray, + + // kIndexSubTable5 + kIndexSubTable5_imageSize = kIndexSubHeaderLength, + kIndexSubTable5_bigGlyphMetrics = kIndexSubTable5_imageSize + + DataSize::kULONG, + kIndexSubTable5_numGlyphs = kIndexSubTable5_bigGlyphMetrics + + BitmapGlyph::Offset::kBigGlyphMetricsLength, + kIndexSubTable5_glyphArray = kIndexSubTable5_numGlyphs + + DataSize::kULONG, + kIndexSubTable5_builderDataSize = kIndexSubTable5_glyphArray, + + // codeOffsetPair + kCodeOffsetPairLength = 2 * DataSize::kUSHORT, + kCodeOffsetPair_glyphCode = 0, + kCodeOffsetPair_offset = DataSize::kUSHORT, + }; + }; + + class Builder : public SubTableContainerTable::Builder, + public RefCounted { + public: + // Constructor scope altered to public because C++ does not allow base + // class to instantiate derived class with protected constructors. + Builder(Header* header, WritableFontData* data); + Builder(Header* header, ReadableFontData* data); + virtual ~Builder(); + + virtual int32_t SubSerialize(WritableFontData* new_data); + virtual bool SubReadyToSerialize(); + virtual int32_t SubDataSizeToSerialize(); + virtual void SubDataSet(); + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + + BitmapSizeTableBuilderList* BitmapSizeBuilders(); + void Revert(); + + // Generates the loca list for the EBDT table. The list is intended to be + // used by the EBDT to allow it to parse the glyph data and generate glyph + // objects. After returning from this method the list belongs to the caller. + // The list entries are in the same order as the size table builders are at + // the time of this call. + // @return the list of loca maps with one for each size table builder + void GenerateLocaList(BitmapLocaList* output); + + // Create a new builder using the header information and data provided. + // @param header the header information + // @param data the data holding the table + static CALLER_ATTACH Builder* CreateBuilder(Header* header, + WritableFontData* data); + static CALLER_ATTACH Builder* CreateBuilder(Header* header, + ReadableFontData* data); + + private: + BitmapSizeTableBuilderList* GetSizeList(); + void Initialize(ReadableFontData* data, BitmapSizeTableBuilderList* output); + + static const int32_t kVersion = 0x00020000; + BitmapSizeTableBuilderList size_table_builders_; + }; + + int32_t Version(); + int32_t NumSizes(); + // UNIMPLEMENTED: toString() + + BitmapSizeTable* GetBitmapSizeTable(int32_t index); + + static const int32_t NOTDEF = -1; + + protected: + EblcTable(Header* header, ReadableFontData* data); + + private: + BitmapSizeTableList* GetBitmapSizeTableList(); + + static void CreateBitmapSizeTable(ReadableFontData* data, + int32_t num_sizes, + BitmapSizeTableList* output); + + Lock bitmap_size_table_lock_; + BitmapSizeTableList bitmap_size_table_; +}; +typedef Ptr EblcTablePtr; +typedef Ptr EblcTableBuilderPtr; +} + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBLC_TABLE_H_ diff --git a/src/sfntly/src/sfntly/table/bitmap/ebsc_table.cc b/src/sfntly/src/sfntly/table/bitmap/ebsc_table.cc new file mode 100644 index 0000000000..458c2d49e8 --- /dev/null +++ b/src/sfntly/src/sfntly/table/bitmap/ebsc_table.cc @@ -0,0 +1,107 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/bitmap/ebsc_table.h" + +namespace sfntly { +/****************************************************************************** + * EbscTable class + ******************************************************************************/ +EbscTable::~EbscTable() { +} + +int32_t EbscTable::Version() { + return data_->ReadFixed(Offset::kVersion); +} + +int32_t EbscTable::NumSizes() { + return data_->ReadULongAsInt(Offset::kNumSizes); +} + +EbscTable::EbscTable(Header* header, ReadableFontData* data) + : Table(header, data) { +} + +/****************************************************************************** + * EbscTable::BitmapScaleTable class + ******************************************************************************/ +EbscTable::BitmapScaleTable::~BitmapScaleTable() { +} + +EbscTable::BitmapScaleTable::BitmapScaleTable(ReadableFontData* data) + : SubTable(data) { +} + +int32_t EbscTable::BitmapScaleTable::PpemX() { + return data_->ReadByte(Offset::kBitmapScaleTable_ppemX); +} + +int32_t EbscTable::BitmapScaleTable::PpemY() { + return data_->ReadByte(Offset::kBitmapScaleTable_ppemY); +} + +int32_t EbscTable::BitmapScaleTable::SubstitutePpemX() { + return data_->ReadByte(Offset::kBitmapScaleTable_substitutePpemX); +} + +int32_t EbscTable::BitmapScaleTable::SubstitutePpemY() { + return data_->ReadByte(Offset::kBitmapScaleTable_substitutePpemY); +} + +/****************************************************************************** + * EbscTable::Builder class + ******************************************************************************/ +EbscTable::Builder::~Builder() { +} + +CALLER_ATTACH EbscTable::Builder* EbscTable::Builder::CreateBuilder( + Header* header, WritableFontData* data) { + EbscTableBuilderPtr builder = new EbscTable::Builder(header, data); + return builder.Detach(); +} + +EbscTable::Builder::Builder(Header* header, WritableFontData* data) + : Table::Builder(header, data) { +} + +EbscTable::Builder::Builder(Header* header, ReadableFontData* data) + : Table::Builder(header, data) { +} + +CALLER_ATTACH +FontDataTable* EbscTable::Builder::SubBuildTable(ReadableFontData* data) { + EbscTablePtr output = new EbscTable(header(), data); + return output.Detach(); +} + +void EbscTable::Builder::SubDataSet() { + // NOP +} + +int32_t EbscTable::Builder::SubDataSizeToSerialize() { + return 0; +} + +bool EbscTable::Builder::SubReadyToSerialize() { + return false; +} + +int32_t EbscTable::Builder::SubSerialize(WritableFontData* new_data) { + UNREFERENCED_PARAMETER(new_data); + return 0; +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/bitmap/ebsc_table.h b/src/sfntly/src/sfntly/table/bitmap/ebsc_table.h new file mode 100644 index 0000000000..b79df380df --- /dev/null +++ b/src/sfntly/src/sfntly/table/bitmap/ebsc_table.h @@ -0,0 +1,101 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBSC_TABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBSC_TABLE_H_ + +#include "sfntly/table/bitmap/eblc_table.h" + +namespace sfntly { + +class EbscTable : public Table, + public RefCounted { + public: + struct Offset { + enum { + // header + kVersion = 0, + kNumSizes = DataSize::kFixed, + kHeaderLength = kNumSizes + DataSize::kULONG, + kBitmapScaleTableStart = kHeaderLength, + + // bitmapScaleTable + kBitmapScaleTable_hori = 0, + kBitmapScaleTable_vert = EblcTable::Offset::kSbitLineMetricsLength, + kBitmapScaleTable_ppemX = kBitmapScaleTable_vert + + EblcTable::Offset::kSbitLineMetricsLength, + kBitmapScaleTable_ppemY = kBitmapScaleTable_ppemX + DataSize::kBYTE, + kBitmapScaleTable_substitutePpemX = kBitmapScaleTable_ppemY + + DataSize::kBYTE, + kBitmapScaleTable_substitutePpemY = kBitmapScaleTable_substitutePpemX + + DataSize::kBYTE, + kBitmapScaleTableLength = kBitmapScaleTable_substitutePpemY + + DataSize::kBYTE, + }; + }; + + class BitmapScaleTable : public SubTable, + public RefCounted { + public: + virtual ~BitmapScaleTable(); + int32_t PpemX(); + int32_t PpemY(); + int32_t SubstitutePpemX(); + int32_t SubstitutePpemY(); + + protected: + // Note: caller to do data->Slice(offset, Offset::kBitmapScaleTableLength) + explicit BitmapScaleTable(ReadableFontData* data); + }; + + // TODO(stuartg): currently the builder just builds from initial data + // - need to make fully working but few if any examples to test with + class Builder : public Table::Builder, + public RefCounted { + public: + virtual ~Builder(); + + static CALLER_ATTACH Builder* CreateBuilder(Header* header, + WritableFontData* data); + + protected: + Builder(Header* header, WritableFontData* data); + Builder(Header* header, ReadableFontData* data); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + }; + + virtual ~EbscTable(); + + int32_t Version(); + int32_t NumSizes(); + // Note: renamed from bitmapScaleTable + CALLER_ATTACH BitmapScaleTable* GetBitmapScaleTable(int32_t index); + + private: + EbscTable(Header* header, ReadableFontData* data); + friend class Builder; +}; +typedef Ptr EbscTablePtr; +typedef Ptr EbscTableBuilderPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBSC_TABLE_H_ diff --git a/src/sfntly/src/sfntly/table/bitmap/glyph_metrics.cc b/src/sfntly/src/sfntly/table/bitmap/glyph_metrics.cc new file mode 100644 index 0000000000..e91eb9921e --- /dev/null +++ b/src/sfntly/src/sfntly/table/bitmap/glyph_metrics.cc @@ -0,0 +1,39 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/bitmap/glyph_metrics.h" + +namespace sfntly { + +GlyphMetrics::~GlyphMetrics() { +} + +GlyphMetrics::GlyphMetrics(ReadableFontData* data) + : SubTable(data) { +} + +GlyphMetrics::Builder::~Builder() { +} + +GlyphMetrics::Builder::Builder(WritableFontData* data) + : SubTable::Builder(data) { +} + +GlyphMetrics::Builder::Builder(ReadableFontData* data) + : SubTable::Builder(data) { +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/bitmap/glyph_metrics.h b/src/sfntly/src/sfntly/table/bitmap/glyph_metrics.h new file mode 100644 index 0000000000..5f16aaa661 --- /dev/null +++ b/src/sfntly/src/sfntly/table/bitmap/glyph_metrics.h @@ -0,0 +1,43 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_METRICS_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_METRICS_H_ + +#include "sfntly/table/subtable.h" + +namespace sfntly { + +class GlyphMetrics : public SubTable { + public: + virtual ~GlyphMetrics(); + + protected: + class Builder : public SubTable::Builder { + public: + virtual ~Builder(); + + protected: + explicit Builder(WritableFontData* data); + explicit Builder(ReadableFontData* data); + }; + + explicit GlyphMetrics(ReadableFontData* data); +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_METRICS_H_ diff --git a/src/sfntly/src/sfntly/table/bitmap/index_sub_table.cc b/src/sfntly/src/sfntly/table/bitmap/index_sub_table.cc new file mode 100644 index 0000000000..5e29784504 --- /dev/null +++ b/src/sfntly/src/sfntly/table/bitmap/index_sub_table.cc @@ -0,0 +1,278 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/bitmap/index_sub_table.h" + +#include "sfntly/table/bitmap/eblc_table.h" +#include "sfntly/table/bitmap/index_sub_table_format1.h" +#include "sfntly/table/bitmap/index_sub_table_format2.h" +#include "sfntly/table/bitmap/index_sub_table_format3.h" +#include "sfntly/table/bitmap/index_sub_table_format4.h" +#include "sfntly/table/bitmap/index_sub_table_format5.h" + +namespace sfntly { +/****************************************************************************** + * IndexSubTable class + ******************************************************************************/ +CALLER_ATTACH BitmapGlyphInfo* IndexSubTable::GlyphInfo(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return NULL; + } + if (GlyphStartOffset(glyph_id) == -1) { + return NULL; + } + BitmapGlyphInfoPtr output = new BitmapGlyphInfo(glyph_id, + image_data_offset(), + GlyphStartOffset(glyph_id), + GlyphLength(glyph_id), + image_format()); + return output.Detach(); +} + +int32_t IndexSubTable::GlyphOffset(int32_t glyph_id) { + int32_t glyph_start_offset = GlyphStartOffset(glyph_id); + if (glyph_start_offset == -1) { + return -1; + } + return image_data_offset() + glyph_start_offset; +} + +// static +CALLER_ATTACH IndexSubTable* + IndexSubTable::CreateIndexSubTable(ReadableFontData* data, + int32_t offset_to_index_sub_table_array, + int32_t array_index) { + IndexSubTableBuilderPtr builder; + builder.Attach(IndexSubTable::Builder::CreateBuilder( + data, offset_to_index_sub_table_array, array_index)); + return down_cast(builder->Build()); +} + +IndexSubTable::IndexSubTable(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : SubTable(data), + first_glyph_index_(first_glyph_index), + last_glyph_index_(last_glyph_index) { + index_format_ = + data_->ReadUShort(EblcTable::Offset::kIndexSubHeader_indexFormat); + image_format_ = + data_->ReadUShort(EblcTable::Offset::kIndexSubHeader_imageFormat); + image_data_offset_ = + data_->ReadULongAsInt(EblcTable::Offset::kIndexSubHeader_imageDataOffset); +} + +int32_t IndexSubTable::CheckGlyphRange(int32_t glyph_id) { + return CheckGlyphRange(glyph_id, first_glyph_index(), last_glyph_index()); +} + +// static +int32_t IndexSubTable::CheckGlyphRange(int32_t glyph_id, + int32_t first_glyph_id, + int32_t last_glyph_id) { + if (glyph_id < first_glyph_id || glyph_id > last_glyph_id) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundException("Glyph ID is outside of the allowed range."); +#endif + return -1; + } + return glyph_id - first_glyph_id; +} + +/****************************************************************************** + * IndexSubTable::Builder class + ******************************************************************************/ +IndexSubTable::Builder::~Builder() { +} + +void IndexSubTable::Builder::Revert() { + set_model_changed(false); + Initialize(InternalReadData()); +} + +CALLER_ATTACH BitmapGlyphInfo* IndexSubTable::Builder::GlyphInfo( + int32_t glyph_id) { + BitmapGlyphInfoPtr glyph_info = + new BitmapGlyphInfo(glyph_id, + image_data_offset(), + GlyphStartOffset(glyph_id), + GlyphLength(glyph_id), + image_format()); + return glyph_info.Detach(); +} + +int32_t IndexSubTable::Builder::GlyphOffset(int32_t glyph_id) { + return image_data_offset() + GlyphStartOffset(glyph_id); +} + +// static +CALLER_ATTACH IndexSubTable::Builder* +IndexSubTable::Builder::CreateBuilder(int32_t index_format) { + switch (index_format) { + case Format::FORMAT_1: + return IndexSubTableFormat1::Builder::CreateBuilder(); + case Format::FORMAT_2: + return IndexSubTableFormat2::Builder::CreateBuilder(); + case Format::FORMAT_3: + return IndexSubTableFormat3::Builder::CreateBuilder(); + case Format::FORMAT_4: + return IndexSubTableFormat4::Builder::CreateBuilder(); + case Format::FORMAT_5: + return IndexSubTableFormat5::Builder::CreateBuilder(); + default: +#if !defined (SFNTLY_NO_EXCEPTION) + throw IllegalArgumentException("Invalid index subtable format"); +#endif + return NULL; + } +} + +// static +CALLER_ATTACH IndexSubTable::Builder* +IndexSubTable::Builder::CreateBuilder(ReadableFontData* data, + int32_t offset_to_index_sub_table_array, int32_t array_index) { + int32_t index_sub_table_entry_offset = + offset_to_index_sub_table_array + + array_index * EblcTable::Offset::kIndexSubTableEntryLength; + int32_t first_glyph_index = + data->ReadUShort(index_sub_table_entry_offset + + EblcTable::Offset::kIndexSubTableEntry_firstGlyphIndex); + int32_t last_glyph_index = + data->ReadUShort(index_sub_table_entry_offset + + EblcTable::Offset::kIndexSubTableEntry_lastGlyphIndex); + int32_t additional_offset_to_index_subtable = data->ReadULongAsInt( + index_sub_table_entry_offset + + EblcTable::Offset::kIndexSubTableEntry_additionalOffsetToIndexSubTable); + int32_t index_sub_table_offset = offset_to_index_sub_table_array + + additional_offset_to_index_subtable; + int32_t index_format = data->ReadUShort(index_sub_table_offset); + switch (index_format) { + case 1: + return IndexSubTableFormat1::Builder::CreateBuilder( + data, index_sub_table_offset, first_glyph_index, last_glyph_index); + case 2: + return IndexSubTableFormat2::Builder::CreateBuilder( + data, index_sub_table_offset, first_glyph_index, last_glyph_index); + case 3: + return IndexSubTableFormat3::Builder::CreateBuilder( + data, index_sub_table_offset, first_glyph_index, last_glyph_index); + case 4: + return IndexSubTableFormat4::Builder::CreateBuilder( + data, index_sub_table_offset, first_glyph_index, last_glyph_index); + case 5: + return IndexSubTableFormat5::Builder::CreateBuilder( + data, index_sub_table_offset, first_glyph_index, last_glyph_index); + default: + // Unknown format and unable to process. +#if !defined (SFNTLY_NO_EXCEPTION) + throw IllegalArgumentException("Invalid Index Subtable Format"); +#endif + break; + } + return NULL; +} + +CALLER_ATTACH +FontDataTable* IndexSubTable::Builder::SubBuildTable(ReadableFontData* data) { + UNREFERENCED_PARAMETER(data); + return NULL; +} + +void IndexSubTable::Builder::SubDataSet() { + // NOP +} + +int32_t IndexSubTable::Builder::SubDataSizeToSerialize() { + return 0; +} + +bool IndexSubTable::Builder::SubReadyToSerialize() { + return false; +} + +int32_t IndexSubTable::Builder::SubSerialize(WritableFontData* new_data) { + UNREFERENCED_PARAMETER(new_data); + return 0; +} + +IndexSubTable::Builder::Builder(int32_t data_size, int32_t index_format) + : SubTable::Builder(data_size), + first_glyph_index_(0), + last_glyph_index_(0), + index_format_(index_format), + image_format_(0), + image_data_offset_(0) { +} + +IndexSubTable::Builder::Builder(int32_t index_format, + int32_t image_format, + int32_t image_data_offset, + int32_t data_size) + : SubTable::Builder(data_size), + first_glyph_index_(0), + last_glyph_index_(0), + index_format_(index_format), + image_format_(image_format), + image_data_offset_(image_data_offset) { +} + +IndexSubTable::Builder::Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : SubTable::Builder(data), + first_glyph_index_(first_glyph_index), + last_glyph_index_(last_glyph_index) { + Initialize(data); +} + +IndexSubTable::Builder::Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : SubTable::Builder(data), + first_glyph_index_(first_glyph_index), + last_glyph_index_(last_glyph_index) { + Initialize(data); +} + +int32_t IndexSubTable::Builder::CheckGlyphRange(int32_t glyph_id) { + return IndexSubTable::CheckGlyphRange(glyph_id, + first_glyph_index(), + last_glyph_index()); +} + +int32_t IndexSubTable::Builder::SerializeIndexSubHeader( + WritableFontData* data) { + int32_t size = + data->WriteUShort(EblcTable::Offset::kIndexSubHeader_indexFormat, + index_format()); + size += data->WriteUShort(EblcTable::Offset::kIndexSubHeader_imageFormat, + image_format()); + size += data->WriteULong(EblcTable::Offset::kIndexSubHeader_imageDataOffset, + image_data_offset()); + return size; +} + +void IndexSubTable::Builder::Initialize(ReadableFontData* data) { + index_format_ = + data->ReadUShort(EblcTable::Offset::kIndexSubHeader_indexFormat); + image_format_ = + data->ReadUShort(EblcTable::Offset::kIndexSubHeader_imageFormat); + image_data_offset_ = + data->ReadULongAsInt(EblcTable::Offset::kIndexSubHeader_imageDataOffset); +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/bitmap/index_sub_table.h b/src/sfntly/src/sfntly/table/bitmap/index_sub_table.h new file mode 100644 index 0000000000..6d27129ccd --- /dev/null +++ b/src/sfntly/src/sfntly/table/bitmap/index_sub_table.h @@ -0,0 +1,178 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_H_ + +#include + +#include "sfntly/port/java_iterator.h" +#include "sfntly/table/subtable.h" +#include "sfntly/table/bitmap/bitmap_glyph_info.h" + +namespace sfntly { + +class IndexSubTable : public SubTable { + public: + struct Format { + enum { + FORMAT_1 = 1, + FORMAT_2 = 2, + FORMAT_3 = 3, + FORMAT_4 = 4, + FORMAT_5 = 5, + }; + }; + + class Builder : public SubTable::Builder { + public: + virtual ~Builder(); + + void Revert(); + + int32_t index_format() { return index_format_; } + int32_t first_glyph_index() { return first_glyph_index_; } + void set_first_glyph_index(int32_t v) { first_glyph_index_ = v; } + int32_t last_glyph_index() { return last_glyph_index_; } + void set_last_glyph_index(int32_t v) { last_glyph_index_ = v; } + int32_t image_format() { return image_format_; } + void set_image_format(int32_t v) { image_format_ = v; } + int32_t image_data_offset() { return image_data_offset_; } + void set_image_data_offset(int32_t v) { image_data_offset_ = v; } + + virtual int32_t NumGlyphs() = 0; + + // Gets the glyph info for the specified glyph id. + // @param glyphId the glyph id to look up + // @return the glyph info + CALLER_ATTACH virtual BitmapGlyphInfo* GlyphInfo(int32_t glyph_id); + + // Gets the full offset of the glyph within the EBDT table. + // @param glyphId the glyph id + // @return the glyph offset + virtual int32_t GlyphOffset(int32_t glyph_id); + + // Gets the offset of the glyph relative to the block for this index + // subtable. + // @param glyphId the glyph id + // @return the glyph offset + virtual int32_t GlyphStartOffset(int32_t glyph_id) = 0; + + // Gets the length of the glyph within the EBDT table. + // @param glyphId the glyph id + // @return the glyph offset + virtual int32_t GlyphLength(int32_t glyph_id) = 0; + + // Note: renamed from java iterator() + CALLER_ATTACH virtual Iterator* + GetIterator() = 0; + + // Static instantiation function. + static CALLER_ATTACH Builder* CreateBuilder(int32_t index_format); + static CALLER_ATTACH Builder* + CreateBuilder(ReadableFontData* data, + int32_t offset_to_index_sub_table_array, + int32_t array_index); + + // The following methods will never be called but they need to be here to + // allow the BitmapSizeTable to see these methods through an abstract + // reference. + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + + protected: + Builder(int32_t data_size, int32_t index_format); + Builder(int32_t index_format, + int32_t image_format, + int32_t image_data_offset, + int32_t data_size); + Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + + // Checks that the glyph id is within the correct range. If it returns the + // offset of the glyph id from the start of the range. + // @param glyphId + // @return the offset of the glyphId from the start of the glyph range + // @throws IndexOutOfBoundsException if the glyph id is not within the + // correct range + int32_t CheckGlyphRange(int32_t glyph_id); + int32_t SerializeIndexSubHeader(WritableFontData* data); + + private: + void Initialize(ReadableFontData* data); + + int32_t first_glyph_index_; + int32_t last_glyph_index_; + int32_t index_format_; + int32_t image_format_; + int32_t image_data_offset_; + }; + + int32_t index_format() { return index_format_; } + int32_t first_glyph_index() { return first_glyph_index_; } + int32_t last_glyph_index() { return last_glyph_index_; } + int32_t image_format() { return image_format_; } + int32_t image_data_offset() { return image_data_offset_; } + + CALLER_ATTACH BitmapGlyphInfo* GlyphInfo(int32_t glyph_id); + virtual int32_t GlyphOffset(int32_t glyph_id); + virtual int32_t GlyphStartOffset(int32_t glyph_id) = 0; + virtual int32_t GlyphLength(int32_t glyph_id) = 0; + virtual int32_t NumGlyphs() = 0; + + static CALLER_ATTACH IndexSubTable* + CreateIndexSubTable(ReadableFontData* data, + int32_t offset_to_index_sub_table_array, + int32_t array_index); + + protected: + // Note: the constructor does not implement offset/length form provided in + // Java to avoid heavy lifting in constructors. Callers to call + // GetDataLength() static method of the derived class to get proper + // length and slice ahead. + IndexSubTable(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + + int32_t CheckGlyphRange(int32_t glyph_id); + static int32_t CheckGlyphRange(int32_t glyph_id, + int32_t first_glyph_id, + int32_t last_glyph_id); + + private: + int32_t first_glyph_index_; + int32_t last_glyph_index_; + int32_t index_format_; + int32_t image_format_; + int32_t image_data_offset_; +}; +typedef Ptr IndexSubTablePtr; +typedef std::vector IndexSubTableList; +typedef Ptr IndexSubTableBuilderPtr; +typedef std::vector IndexSubTableBuilderList; +typedef Iterator BitmapGlyphInfoIter; +typedef Ptr BitmapGlyphInfoIterPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_H_ diff --git a/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format1.cc b/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format1.cc new file mode 100644 index 0000000000..db73723916 --- /dev/null +++ b/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format1.cc @@ -0,0 +1,299 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/bitmap/index_sub_table_format1.h" + +#include "sfntly/table/bitmap/eblc_table.h" + +namespace sfntly { +/****************************************************************************** + * IndexSubTableFormat1 class + ******************************************************************************/ +// static +int32_t IndexSubTableFormat1::GetDataLength(ReadableFontData* data, + int32_t offset, + int32_t first, + int32_t last) { + UNREFERENCED_PARAMETER(data); + UNREFERENCED_PARAMETER(offset); + return (last - first + 1 + 1) * DataSize::kULONG; +} + +IndexSubTableFormat1::~IndexSubTableFormat1() { +} + +int32_t IndexSubTableFormat1::NumGlyphs() { + return last_glyph_index() - first_glyph_index() + 1; +} + +int32_t IndexSubTableFormat1::GlyphStartOffset(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return -1; + } + return Loca(loca); +} + +int32_t IndexSubTableFormat1::GlyphLength(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return -1; + } + return Loca(loca + 1) - Loca(loca); +} + +IndexSubTableFormat1::IndexSubTableFormat1(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable(data, first_glyph_index, last_glyph_index) { +} + +int32_t IndexSubTableFormat1::Loca(int32_t loca) { + return image_data_offset() + + data_->ReadULongAsInt(EblcTable::Offset::kIndexSubTable1_offsetArray + + loca * DataSize::kULONG); +} + +/****************************************************************************** + * IndexSubTableFormat1::Builder class + ******************************************************************************/ +IndexSubTableFormat1::Builder::~Builder() { +} + +int32_t IndexSubTableFormat1::Builder::NumGlyphs() { + return GetOffsetArray()->size() - 1; +} + +int32_t IndexSubTableFormat1::Builder::GlyphLength(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return 0; + } + IntegerList* offset_array = GetOffsetArray(); + return offset_array->at(loca + 1) - offset_array->at(loca); +} + +int32_t IndexSubTableFormat1::Builder::GlyphStartOffset(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return -1; + } + return GetOffsetArray()->at(loca); +} + +CALLER_ATTACH IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator* + IndexSubTableFormat1::Builder::GetIterator() { + Ptr it = + new IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator(this); + return it.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat1::Builder* +IndexSubTableFormat1::Builder::CreateBuilder() { + IndexSubTableFormat1BuilderPtr output = new IndexSubTableFormat1::Builder(); + return output.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat1::Builder* +IndexSubTableFormat1::Builder::CreateBuilder(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t length = Builder::DataLength(data, + index_sub_table_offset, + first_glyph_index, + last_glyph_index); + ReadableFontDataPtr new_data; + new_data.Attach(down_cast( + data->Slice(index_sub_table_offset, length))); + IndexSubTableFormat1BuilderPtr output = + new IndexSubTableFormat1::Builder(new_data, + first_glyph_index, + last_glyph_index); + return output.Detach(); +} + + +// static +CALLER_ATTACH IndexSubTableFormat1::Builder* +IndexSubTableFormat1::Builder::CreateBuilder(WritableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t length = Builder::DataLength(data, + index_sub_table_offset, + first_glyph_index, + last_glyph_index); + WritableFontDataPtr new_data; + new_data.Attach(down_cast( + data->Slice(index_sub_table_offset, length))); + IndexSubTableFormat1BuilderPtr output = + new IndexSubTableFormat1::Builder(new_data, + first_glyph_index, + last_glyph_index); + return output.Detach(); +} + +CALLER_ATTACH FontDataTable* IndexSubTableFormat1::Builder::SubBuildTable( + ReadableFontData* data) { + IndexSubTableFormat1Ptr output = new IndexSubTableFormat1( + data, first_glyph_index(), last_glyph_index()); + return output.Detach(); +} + +void IndexSubTableFormat1::Builder::SubDataSet() { + Revert(); +} + +int32_t IndexSubTableFormat1::Builder::SubDataSizeToSerialize() { + if (offset_array_.empty()) { + return InternalReadData()->Length(); + } + return EblcTable::Offset::kIndexSubHeaderLength + + offset_array_.size() * DataSize::kULONG; +} + +bool IndexSubTableFormat1::Builder::SubReadyToSerialize() { + if (!offset_array_.empty()) { + return true; + } + return false; +} + +int32_t IndexSubTableFormat1::Builder::SubSerialize( + WritableFontData* new_data) { + int32_t size = SerializeIndexSubHeader(new_data); + if (!model_changed()) { + if (InternalReadData() == NULL) { + return size; + } + ReadableFontDataPtr source; + WritableFontDataPtr target; + source.Attach(down_cast(InternalReadData()->Slice( + EblcTable::Offset::kIndexSubTable1_offsetArray))); + target.Attach(down_cast(new_data->Slice( + EblcTable::Offset::kIndexSubTable1_offsetArray))); + size += source->CopyTo(target); + } else { + for (IntegerList::iterator b = GetOffsetArray()->begin(), + e = GetOffsetArray()->end(); b != e; b++) { + size += new_data->WriteLong(size, *b); + } + } + return size; +} + +IntegerList* IndexSubTableFormat1::Builder::OffsetArray() { + return GetOffsetArray(); +} + +void IndexSubTableFormat1::Builder::SetOffsetArray( + const IntegerList& offset_array) { + offset_array_.clear(); + offset_array_ = offset_array; + set_model_changed(); +} + +void IndexSubTableFormat1::Builder::Revert() { + offset_array_.clear(); + IndexSubTable::Builder::Revert(); +} + +IndexSubTableFormat1::Builder::Builder() + : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable1_builderDataSize, + IndexSubTable::Format::FORMAT_1) { +} + +IndexSubTableFormat1::Builder::Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { +} + +IndexSubTableFormat1::Builder::Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { +} + +IntegerList* IndexSubTableFormat1::Builder::GetOffsetArray() { + if (offset_array_.empty()) { + Initialize(InternalReadData()); + set_model_changed(); + } + return &offset_array_; +} + +void IndexSubTableFormat1::Builder::Initialize(ReadableFontData* data) { + offset_array_.clear(); + if (data) { + int32_t num_offsets = (last_glyph_index() - first_glyph_index() + 1) + 1; + for (int32_t i = 0; i < num_offsets; ++i) { + offset_array_.push_back(data->ReadULongAsInt( + EblcTable::Offset::kIndexSubTable1_offsetArray + + i * DataSize::kULONG)); + } + } +} + +// static +int32_t IndexSubTableFormat1::Builder::DataLength( + ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + UNREFERENCED_PARAMETER(data); + UNREFERENCED_PARAMETER(index_sub_table_offset); + return EblcTable::Offset::kIndexSubHeaderLength + + (last_glyph_index - first_glyph_index + 1 + 1) * DataSize::kULONG; +} + +/****************************************************************************** + * IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator class + ******************************************************************************/ +IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator( + IndexSubTableFormat1::Builder* container) + : RefIterator(container) { + glyph_id_ = container->first_glyph_index(); +} + +bool IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator::HasNext() { + if (glyph_id_ <= container()->last_glyph_index()) { + return true; + } + return false; +} + +CALLER_ATTACH BitmapGlyphInfo* +IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator::Next() { + BitmapGlyphInfoPtr output; + if (!HasNext()) { + // Note: In C++, we do not throw exception when there's no element. + return NULL; + } + output = new BitmapGlyphInfo(glyph_id_, + container()->image_data_offset(), + container()->GlyphStartOffset(glyph_id_), + container()->GlyphLength(glyph_id_), + container()->image_format()); + glyph_id_++; + return output.Detach(); +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format1.h b/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format1.h new file mode 100644 index 0000000000..33171c1561 --- /dev/null +++ b/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format1.h @@ -0,0 +1,116 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT1_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT1_H_ + +#include "sfntly/port/java_iterator.h" +#include "sfntly/table/bitmap/index_sub_table.h" + +namespace sfntly { +// Format 1 Index Subtable Entry. +class IndexSubTableFormat1 : public IndexSubTable, + public RefCounted { + public: + class Builder : public IndexSubTable::Builder, + public RefCounted { + public: + class BitmapGlyphInfoIterator + : public RefIterator { + public: + explicit BitmapGlyphInfoIterator(Builder* container); + virtual ~BitmapGlyphInfoIterator() {} + + virtual bool HasNext(); + CALLER_ATTACH virtual BitmapGlyphInfo* Next(); + + private: + int32_t glyph_id_; + }; + + virtual ~Builder(); + virtual int32_t NumGlyphs(); + virtual int32_t GlyphLength(int32_t glyph_id); + virtual int32_t GlyphStartOffset(int32_t glyph_id); + CALLER_ATTACH virtual BitmapGlyphInfoIterator* GetIterator(); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + + IntegerList* OffsetArray(); + void SetOffsetArray(const IntegerList& offset_array); + CALLER_ATTACH BitmapGlyphInfoIter* Iterator(); + + static CALLER_ATTACH Builder* CreateBuilder(); + static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + + protected: + void Revert(); + + private: + Builder(); + Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + IntegerList* GetOffsetArray(); + void Initialize(ReadableFontData* data); + + static int32_t DataLength(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + + IntegerList offset_array_; + }; + + virtual ~IndexSubTableFormat1(); + + virtual int32_t NumGlyphs(); + virtual int32_t GlyphStartOffset(int32_t glyph_id); + virtual int32_t GlyphLength(int32_t glyph_id); + + static int32_t GetDataLength(ReadableFontData* data, + int32_t offset, + int32_t first, + int32_t last); + + private: + IndexSubTableFormat1(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + int32_t Loca(int32_t loca_index); + + friend class Builder; +}; +typedef Ptr IndexSubTableFormat1Ptr; +typedef Ptr IndexSubTableFormat1BuilderPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT1_H_ diff --git a/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format2.cc b/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format2.cc new file mode 100644 index 0000000000..b3bffdad91 --- /dev/null +++ b/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format2.cc @@ -0,0 +1,272 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/bitmap/index_sub_table_format2.h" + +#include "sfntly/table/bitmap/eblc_table.h" + +namespace sfntly { +/****************************************************************************** + * IndexSubTableFormat2 class + ******************************************************************************/ +IndexSubTableFormat2::~IndexSubTableFormat2() { +} + +int32_t IndexSubTableFormat2::ImageSize() { + return data_->ReadULongAsInt(EblcTable::Offset::kIndexSubTable2_imageSize); +} + +CALLER_ATTACH BigGlyphMetrics* IndexSubTableFormat2::BigMetrics() { + ReadableFontDataPtr slice; + slice.Attach(down_cast( + data_->Slice(EblcTable::Offset::kIndexSubTable2_bigGlyphMetrics, + BigGlyphMetrics::Offset::kMetricsLength))); + BigGlyphMetricsPtr output = new BigGlyphMetrics(slice); + return output.Detach(); +} + +int32_t IndexSubTableFormat2::NumGlyphs() { + return last_glyph_index() - first_glyph_index() + 1; +} + +int32_t IndexSubTableFormat2::GlyphStartOffset(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return -1; + } + return loca * image_size_; +} + +int32_t IndexSubTableFormat2::GlyphLength(int32_t glyph_id) { + if (CheckGlyphRange(glyph_id) == -1) { + return 0; + } + return image_size_; +} + +IndexSubTableFormat2::IndexSubTableFormat2(ReadableFontData* data, + int32_t first, + int32_t last) + : IndexSubTable(data, first, last) { + image_size_ = + data_->ReadULongAsInt(EblcTable::Offset::kIndexSubTable2_imageSize); +} + +/****************************************************************************** + * IndexSubTableFormat2::Builder class + ******************************************************************************/ +IndexSubTableFormat2::Builder::~Builder() { +} + +int32_t IndexSubTableFormat2::Builder::NumGlyphs() { + return last_glyph_index() - first_glyph_index() + 1; +} + +int32_t IndexSubTableFormat2::Builder::GlyphStartOffset(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return -1; + } + return loca * ImageSize(); +} + +int32_t IndexSubTableFormat2::Builder::GlyphLength(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return 0; + } + return ImageSize(); +} + +CALLER_ATTACH IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator* + IndexSubTableFormat2::Builder::GetIterator() { + Ptr it = + new IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator(this); + return it.Detach(); +} + +int32_t IndexSubTableFormat2::Builder::ImageSize() { + return InternalReadData()->ReadULongAsInt( + EblcTable::Offset::kIndexSubTable2_imageSize); +} + +void IndexSubTableFormat2::Builder::SetImageSize(int32_t image_size) { + InternalWriteData()->WriteULong(EblcTable::Offset::kIndexSubTable2_imageSize, + image_size); +} + +BigGlyphMetrics::Builder* IndexSubTableFormat2::Builder::BigMetrics() { + if (metrics_ == NULL) { + WritableFontDataPtr data; + data.Attach(down_cast(InternalWriteData()->Slice( + EblcTable::Offset::kIndexSubTable2_bigGlyphMetrics, + BigGlyphMetrics::Offset::kMetricsLength))); + metrics_ = new BigGlyphMetrics::Builder(data); + } + return metrics_; +} + +// static +CALLER_ATTACH IndexSubTableFormat2::Builder* +IndexSubTableFormat2::Builder::CreateBuilder() { + IndexSubTableFormat2BuilderPtr output = new IndexSubTableFormat2::Builder(); + return output.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat2::Builder* +IndexSubTableFormat2::Builder::CreateBuilder(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t length = Builder::DataLength(data, + index_sub_table_offset, + first_glyph_index, + last_glyph_index); + ReadableFontDataPtr new_data; + new_data.Attach(down_cast( + data->Slice(index_sub_table_offset, length))); + IndexSubTableFormat2BuilderPtr output = + new IndexSubTableFormat2::Builder(new_data, + first_glyph_index, + last_glyph_index); + return output.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat2::Builder* +IndexSubTableFormat2::Builder::CreateBuilder(WritableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t length = Builder::DataLength(data, + index_sub_table_offset, + first_glyph_index, + last_glyph_index); + WritableFontDataPtr new_data; + new_data.Attach(down_cast( + data->Slice(index_sub_table_offset, length))); + IndexSubTableFormat2BuilderPtr output = + new IndexSubTableFormat2::Builder(new_data, + first_glyph_index, + last_glyph_index); + return output.Detach(); +} + +CALLER_ATTACH FontDataTable* IndexSubTableFormat2::Builder::SubBuildTable( + ReadableFontData* data) { + IndexSubTableFormat2Ptr output = new IndexSubTableFormat2( + data, first_glyph_index(), last_glyph_index()); + return output.Detach(); +} + +void IndexSubTableFormat2::Builder::SubDataSet() { + Revert(); +} + +int32_t IndexSubTableFormat2::Builder::SubDataSizeToSerialize() { + return EblcTable::Offset::kIndexSubTable2Length; +} + +bool IndexSubTableFormat2::Builder::SubReadyToSerialize() { + return true; +} + +int32_t IndexSubTableFormat2::Builder::SubSerialize( + WritableFontData* new_data) { + int32_t size = SerializeIndexSubHeader(new_data); + if (metrics_ == NULL) { + ReadableFontDataPtr source; + WritableFontDataPtr target; + source.Attach(down_cast( + InternalReadData()->Slice(size))); + target.Attach(down_cast(new_data->Slice(size))); + size += source->CopyTo(target); + } else { + WritableFontDataPtr slice; + size += new_data->WriteLong(EblcTable::Offset::kIndexSubTable2_imageSize, + ImageSize()); + slice.Attach(down_cast(new_data->Slice(size))); + size += metrics_->SubSerialize(slice); + } + return size; +} + +IndexSubTableFormat2::Builder::Builder() + : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable3_builderDataSize, + IndexSubTable::Format::FORMAT_2) { + metrics_.Attach(BigGlyphMetrics::Builder::CreateBuilder()); +} + +IndexSubTableFormat2::Builder::Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { +} + +IndexSubTableFormat2::Builder::Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { +} + +// static +int32_t IndexSubTableFormat2::Builder::DataLength( + ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + UNREFERENCED_PARAMETER(data); + UNREFERENCED_PARAMETER(index_sub_table_offset); + UNREFERENCED_PARAMETER(first_glyph_index); + UNREFERENCED_PARAMETER(last_glyph_index); + return EblcTable::Offset::kIndexSubTable2Length; +} + +/****************************************************************************** + * IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator class + ******************************************************************************/ +IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator( + IndexSubTableFormat2::Builder* container) + : RefIterator(container) { + glyph_id_ = container->first_glyph_index(); +} + +bool IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator::HasNext() { + if (glyph_id_ <= container()->last_glyph_index()) { + return true; + } + return false; +} + +CALLER_ATTACH BitmapGlyphInfo* +IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator::Next() { + BitmapGlyphInfoPtr output; + if (!HasNext()) { + // Note: In C++, we do not throw exception when there's no element. + return NULL; + } + output = new BitmapGlyphInfo(glyph_id_, + container()->image_data_offset(), + container()->GlyphStartOffset(glyph_id_), + container()->GlyphLength(glyph_id_), + container()->image_format()); + glyph_id_++; + return output.Detach(); +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format2.h b/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format2.h new file mode 100644 index 0000000000..784e8a39fe --- /dev/null +++ b/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format2.h @@ -0,0 +1,106 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT2_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT2_H_ + +#include "sfntly/table/bitmap/index_sub_table.h" +#include "sfntly/table/bitmap/big_glyph_metrics.h" + +namespace sfntly { +// Format 2 Index Subtable Entry. +class IndexSubTableFormat2 : public IndexSubTable, + public RefCounted { + public: + class Builder : public IndexSubTable::Builder, + public RefCounted { + public: + class BitmapGlyphInfoIterator + : public RefIterator { + public: + explicit BitmapGlyphInfoIterator(Builder* container); + virtual ~BitmapGlyphInfoIterator() {} + + virtual bool HasNext(); + CALLER_ATTACH virtual BitmapGlyphInfo* Next(); + + private: + int32_t glyph_id_; + }; + + virtual ~Builder(); + virtual int32_t NumGlyphs(); + virtual int32_t GlyphStartOffset(int32_t glyph_id); + virtual int32_t GlyphLength(int32_t glyph_id); + CALLER_ATTACH virtual BitmapGlyphInfoIterator* GetIterator(); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + + int32_t ImageSize(); + void SetImageSize(int32_t image_size); + BigGlyphMetrics::Builder* BigMetrics(); + + static CALLER_ATTACH Builder* CreateBuilder(); + static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + private: + Builder(); + Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + + static int32_t DataLength(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + + BigGlyphMetricsBuilderPtr metrics_; + }; + + virtual ~IndexSubTableFormat2(); + + int32_t ImageSize(); + CALLER_ATTACH BigGlyphMetrics* BigMetrics(); + + virtual int32_t NumGlyphs(); + virtual int32_t GlyphStartOffset(int32_t glyph_id); + virtual int32_t GlyphLength(int32_t glyph_id); + + private: + IndexSubTableFormat2(ReadableFontData* data, int32_t first, int32_t last); + + int32_t image_size_; + friend class Builder; +}; +typedef Ptr IndexSubTableFormat2Ptr; +typedef Ptr IndexSubTableFormat2BuilderPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT1_H_ diff --git a/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format3.cc b/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format3.cc new file mode 100644 index 0000000000..b3e418ff54 --- /dev/null +++ b/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format3.cc @@ -0,0 +1,295 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/bitmap/index_sub_table_format3.h" + +#include "sfntly/table/bitmap/eblc_table.h" + +namespace sfntly { +/****************************************************************************** + * IndexSubTableFormat3 class + ******************************************************************************/ +IndexSubTableFormat3::~IndexSubTableFormat3() { +} + +int32_t IndexSubTableFormat3::NumGlyphs() { + return last_glyph_index() - first_glyph_index() + 1; +} + +int32_t IndexSubTableFormat3::GlyphStartOffset(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca != -1) { + return Loca(loca); + } + return -1; +} + +int32_t IndexSubTableFormat3::GlyphLength(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca != -1) { + return Loca(glyph_id + 1) - Loca(glyph_id); + } + return 0; +} + +// static +int32_t IndexSubTableFormat3::GetDataLength(ReadableFontData* data, + int32_t offset, + int32_t first, + int32_t last) { + UNREFERENCED_PARAMETER(data); + UNREFERENCED_PARAMETER(offset); + return (last - first + 1 + 1) * DataSize::kUSHORT; +} + +IndexSubTableFormat3::IndexSubTableFormat3(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable(data, first_glyph_index, last_glyph_index) { +} + +int32_t IndexSubTableFormat3::Loca(int32_t loca) { + int32_t read_offset = + data_->ReadUShort(EblcTable::Offset::kIndexSubTable3_offsetArray + + loca * DataSize::kUSHORT); + return read_offset; +} + +/****************************************************************************** + * IndexSubTableFormat3::Builder class + ******************************************************************************/ +IndexSubTableFormat3::Builder::~Builder() { +} + +int32_t IndexSubTableFormat3::Builder::NumGlyphs() { + return GetOffsetArray()->size() - 1; +} + +int32_t IndexSubTableFormat3::Builder::GlyphStartOffset(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return -1; + } + return GetOffsetArray()->at(loca); +} + +int32_t IndexSubTableFormat3::Builder::GlyphLength(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return 0; + } + IntegerList* offset_array = GetOffsetArray(); + return offset_array->at(loca + 1) - offset_array->at(loca); +} + +CALLER_ATTACH IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator* + IndexSubTableFormat3::Builder::GetIterator() { + Ptr it = + new IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator(this); + return it.Detach(); +} + +void IndexSubTableFormat3::Builder::Revert() { + offset_array_.clear(); + IndexSubTable::Builder::Revert(); +} + +void IndexSubTableFormat3::Builder::SetOffsetArray( + const IntegerList& offset_array) { + offset_array_.clear(); + offset_array_ = offset_array; + set_model_changed(); +} + +// static +CALLER_ATTACH IndexSubTableFormat3::Builder* +IndexSubTableFormat3::Builder::CreateBuilder() { + IndexSubTableFormat3BuilderPtr output = new IndexSubTableFormat3::Builder(); + return output.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat3::Builder* +IndexSubTableFormat3::Builder::CreateBuilder(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t length = Builder::DataLength(data, + index_sub_table_offset, + first_glyph_index, + last_glyph_index); + ReadableFontDataPtr new_data; + new_data.Attach(down_cast( + data->Slice(index_sub_table_offset, length))); + IndexSubTableFormat3BuilderPtr output = + new IndexSubTableFormat3::Builder(new_data, + first_glyph_index, + last_glyph_index); + return output.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat3::Builder* +IndexSubTableFormat3::Builder::CreateBuilder(WritableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t length = Builder::DataLength(data, + index_sub_table_offset, + first_glyph_index, + last_glyph_index); + WritableFontDataPtr new_data; + new_data.Attach(down_cast( + data->Slice(index_sub_table_offset, length))); + IndexSubTableFormat3BuilderPtr output = + new IndexSubTableFormat3::Builder(new_data, + first_glyph_index, + last_glyph_index); + return output.Detach(); +} + +CALLER_ATTACH FontDataTable* IndexSubTableFormat3::Builder::SubBuildTable( + ReadableFontData* data) { + IndexSubTableFormat3Ptr output = new IndexSubTableFormat3( + data, first_glyph_index(), last_glyph_index()); + return output.Detach(); +} + +void IndexSubTableFormat3::Builder::SubDataSet() { + Revert(); +} + +int32_t IndexSubTableFormat3::Builder::SubDataSizeToSerialize() { + if (offset_array_.empty()) { + return InternalReadData()->Length(); + } + return EblcTable::Offset::kIndexSubHeaderLength + + offset_array_.size() * DataSize::kULONG; +} + +bool IndexSubTableFormat3::Builder::SubReadyToSerialize() { + if (!offset_array_.empty()) { + return true; + } + return false; +} + +int32_t IndexSubTableFormat3::Builder::SubSerialize( + WritableFontData* new_data) { + int32_t size = SerializeIndexSubHeader(new_data); + if (!model_changed()) { + if (InternalReadData() == NULL) { + return size; + } + ReadableFontDataPtr source; + WritableFontDataPtr target; + source.Attach(down_cast(InternalReadData()->Slice( + EblcTable::Offset::kIndexSubTable3_offsetArray))); + target.Attach(down_cast(new_data->Slice( + EblcTable::Offset::kIndexSubTable3_offsetArray))); + size += source->CopyTo(target); + } else { + for (IntegerList::iterator b = GetOffsetArray()->begin(), + e = GetOffsetArray()->end(); b != e; b++) { + size += new_data->WriteUShort(size, *b); + } + } + return size; +} + +IndexSubTableFormat3::Builder::Builder() + : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable3_builderDataSize, + IndexSubTable::Format::FORMAT_3) { +} + +IndexSubTableFormat3::Builder::Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { +} + +IndexSubTableFormat3::Builder::Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { +} + +IntegerList* IndexSubTableFormat3::Builder::GetOffsetArray() { + if (offset_array_.empty()) { + Initialize(InternalReadData()); + set_model_changed(); + } + return &offset_array_; +} + +void IndexSubTableFormat3::Builder::Initialize(ReadableFontData* data) { + offset_array_.clear(); + if (data) { + int32_t num_offsets = (last_glyph_index() - first_glyph_index() + 1) + 1; + for (int32_t i = 0; i < num_offsets; ++i) { + offset_array_.push_back(data->ReadUShort( + EblcTable::Offset::kIndexSubTable3_offsetArray + + i * DataSize::kUSHORT)); + } + } +} + +// static +int32_t IndexSubTableFormat3::Builder::DataLength( + ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + UNREFERENCED_PARAMETER(data); + UNREFERENCED_PARAMETER(index_sub_table_offset); + return EblcTable::Offset::kIndexSubHeaderLength + + (last_glyph_index - first_glyph_index + 1 + 1) * DataSize::kUSHORT; +} + +/****************************************************************************** + * IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator class + ******************************************************************************/ +IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator( + IndexSubTableFormat3::Builder* container) + : RefIterator(container) { + glyph_id_ = container->first_glyph_index(); +} + +bool IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator::HasNext() { + if (glyph_id_ <= container()->last_glyph_index()) { + return true; + } + return false; +} + +CALLER_ATTACH BitmapGlyphInfo* +IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator::Next() { + BitmapGlyphInfoPtr output; + if (!HasNext()) { + // Note: In C++, we do not throw exception when there's no element. + return NULL; + } + output = new BitmapGlyphInfo(glyph_id_, + container()->image_data_offset(), + container()->GlyphStartOffset(glyph_id_), + container()->GlyphLength(glyph_id_), + container()->image_format()); + glyph_id_++; + return output.Detach(); +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format3.h b/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format3.h new file mode 100644 index 0000000000..d71f8573cc --- /dev/null +++ b/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format3.h @@ -0,0 +1,113 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT3_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT3_H_ + +#include "sfntly/table/bitmap/index_sub_table.h" + +namespace sfntly { +// Format 3 Index Subtable Entry. +class IndexSubTableFormat3 : public IndexSubTable, + public RefCounted { + public: + class Builder : public IndexSubTable::Builder, + public RefCounted { + public: + class BitmapGlyphInfoIterator + : public RefIterator { + public: + explicit BitmapGlyphInfoIterator(Builder* container); + virtual ~BitmapGlyphInfoIterator() {} + + virtual bool HasNext(); + CALLER_ATTACH virtual BitmapGlyphInfo* Next(); + + private: + int32_t glyph_id_; + }; + + virtual ~Builder(); + virtual int32_t NumGlyphs(); + virtual int32_t GlyphStartOffset(int32_t glyph_id); + virtual int32_t GlyphLength(int32_t glyph_id); + CALLER_ATTACH virtual BitmapGlyphInfoIterator* GetIterator(); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + + void SetOffsetArray(const IntegerList& offset_array); + + static CALLER_ATTACH Builder* CreateBuilder(); + static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + + protected: + void Revert(); + + private: + Builder(); + Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + IntegerList* GetOffsetArray(); + void Initialize(ReadableFontData* data); + + static int32_t DataLength(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + + IntegerList offset_array_; + }; + + virtual ~IndexSubTableFormat3(); + + virtual int32_t NumGlyphs(); + virtual int32_t GlyphStartOffset(int32_t glyph_id); + virtual int32_t GlyphLength(int32_t glyph_id); + + static int32_t GetDataLength(ReadableFontData* data, + int32_t offset, + int32_t first, + int32_t last); + + private: + IndexSubTableFormat3(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + int32_t Loca(int32_t loca_index); + + friend class Builder; +}; +typedef Ptr IndexSubTableFormat3Ptr; +typedef Ptr IndexSubTableFormat3BuilderPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT3_H_ diff --git a/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format4.cc b/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format4.cc new file mode 100644 index 0000000000..23f3e47406 --- /dev/null +++ b/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format4.cc @@ -0,0 +1,381 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/bitmap/index_sub_table_format4.h" + +#include "sfntly/table/bitmap/eblc_table.h" + +namespace sfntly { +/****************************************************************************** + * IndexSubTableFormat4 class + ******************************************************************************/ +IndexSubTableFormat4::~IndexSubTableFormat4() { +} + +int32_t IndexSubTableFormat4::NumGlyphs() { + return IndexSubTableFormat4::NumGlyphs(data_, 0); +} + +int32_t IndexSubTableFormat4::GlyphStartOffset(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return -1; + } + int32_t pair_index = FindCodeOffsetPair(glyph_id); + if (pair_index < 0) { + return -1; + } + return data_->ReadUShort(EblcTable::Offset::kIndexSubTable4_glyphArray + + pair_index * + EblcTable::Offset::kCodeOffsetPairLength + + EblcTable::Offset::kCodeOffsetPair_offset); +} + +int32_t IndexSubTableFormat4::GlyphLength(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return -1; + } + + int32_t pair_index = FindCodeOffsetPair(glyph_id); + if (pair_index < 0) { + return -1; + } + return data_->ReadUShort( + EblcTable::Offset::kIndexSubTable4_glyphArray + + (pair_index + 1) * EblcTable::Offset::kCodeOffsetPairLength + + EblcTable::Offset::kCodeOffsetPair_offset) - + data_->ReadUShort( + EblcTable::Offset::kIndexSubTable4_glyphArray + + (pair_index) * EblcTable::Offset::kCodeOffsetPairLength + + EblcTable::Offset::kCodeOffsetPair_offset); +} + +IndexSubTableFormat4::IndexSubTableFormat4(ReadableFontData* data, + int32_t first, + int32_t last) + : IndexSubTable(data, first, last) { +} + +int32_t IndexSubTableFormat4::FindCodeOffsetPair(int32_t glyph_id) { + return data_->SearchUShort(EblcTable::Offset::kIndexSubTable4_glyphArray, + EblcTable::Offset::kCodeOffsetPairLength, + NumGlyphs(), + glyph_id); +} + +int32_t IndexSubTableFormat4::NumGlyphs(ReadableFontData* data, + int32_t table_offset) { + int32_t num_glyphs = data->ReadULongAsInt(table_offset + + EblcTable::Offset::kIndexSubTable4_numGlyphs); + return num_glyphs; +} + +/****************************************************************************** + * IndexSubTableFormat4::CodeOffsetPair related class + ******************************************************************************/ +IndexSubTableFormat4::CodeOffsetPair::CodeOffsetPair(int32_t glyph_code, + int32_t offset) + : glyph_code_(glyph_code), offset_(offset) { +} + +IndexSubTableFormat4::CodeOffsetPairBuilder::CodeOffsetPairBuilder() + : CodeOffsetPair(0, 0) { +} + +IndexSubTableFormat4::CodeOffsetPairBuilder::CodeOffsetPairBuilder( + int32_t glyph_code, int32_t offset) + : CodeOffsetPair(glyph_code, offset) { +} + +bool IndexSubTableFormat4::CodeOffsetPairGlyphCodeComparator::operator()( + const CodeOffsetPair& lhs, const CodeOffsetPair& rhs) { + return lhs.glyph_code() < rhs.glyph_code(); +} + +/****************************************************************************** + * IndexSubTableFormat4::Builder class + ******************************************************************************/ +IndexSubTableFormat4::Builder::~Builder() { +} + +int32_t IndexSubTableFormat4::Builder::NumGlyphs() { + return GetOffsetArray()->size() - 1; +} + +int32_t IndexSubTableFormat4::Builder::GlyphLength(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return 0; + } + int32_t pair_index = FindCodeOffsetPair(glyph_id); + if (pair_index == -1) { + return 0; + } + return GetOffsetArray()->at(pair_index + 1).offset() - + GetOffsetArray()->at(pair_index).offset(); +} + +int32_t IndexSubTableFormat4::Builder::GlyphStartOffset(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return -1; + } + int32_t pair_index = FindCodeOffsetPair(glyph_id); + if (pair_index == -1) { + return -1; + } + return GetOffsetArray()->at(pair_index).offset(); +} + +CALLER_ATTACH IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator* + IndexSubTableFormat4::Builder::GetIterator() { + Ptr it = + new IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator(this); + return it.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat4::Builder* +IndexSubTableFormat4::Builder::CreateBuilder() { + IndexSubTableFormat4BuilderPtr output = new IndexSubTableFormat4::Builder(); + return output.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat4::Builder* +IndexSubTableFormat4::Builder::CreateBuilder(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t length = Builder::DataLength(data, + index_sub_table_offset, + first_glyph_index, + last_glyph_index); + ReadableFontDataPtr new_data; + new_data.Attach(down_cast( + data->Slice(index_sub_table_offset, length))); + IndexSubTableFormat4BuilderPtr output = + new IndexSubTableFormat4::Builder(new_data, + first_glyph_index, + last_glyph_index); + return output.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat4::Builder* +IndexSubTableFormat4::Builder::CreateBuilder(WritableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t length = Builder::DataLength(data, + index_sub_table_offset, + first_glyph_index, + last_glyph_index); + WritableFontDataPtr new_data; + new_data.Attach(down_cast( + data->Slice(index_sub_table_offset, length))); + IndexSubTableFormat4BuilderPtr output = + new IndexSubTableFormat4::Builder(new_data, + first_glyph_index, + last_glyph_index); + return output.Detach(); +} + +CALLER_ATTACH FontDataTable* IndexSubTableFormat4::Builder::SubBuildTable( + ReadableFontData* data) { + IndexSubTableFormat4Ptr output = new IndexSubTableFormat4( + data, first_glyph_index(), last_glyph_index()); + return output.Detach(); +} + +void IndexSubTableFormat4::Builder::SubDataSet() { + Revert(); +} + +int32_t IndexSubTableFormat4::Builder::SubDataSizeToSerialize() { + if (offset_pair_array_.empty()) { + return InternalReadData()->Length(); + } + return EblcTable::Offset::kIndexSubHeaderLength + DataSize::kULONG + + GetOffsetArray()->size() * + EblcTable::Offset::kIndexSubTable4_codeOffsetPairLength; +} + +bool IndexSubTableFormat4::Builder::SubReadyToSerialize() { + if (!offset_pair_array_.empty()) { + return true; + } + return false; +} + +int32_t IndexSubTableFormat4::Builder::SubSerialize( + WritableFontData* new_data) { + int32_t size = SerializeIndexSubHeader(new_data); + if (!model_changed()) { + if (InternalReadData() == NULL) { + return size; + } + ReadableFontDataPtr source; + WritableFontDataPtr target; + source.Attach(down_cast(InternalReadData()->Slice( + EblcTable::Offset::kIndexSubTable4_glyphArray))); + target.Attach(down_cast(new_data->Slice( + EblcTable::Offset::kIndexSubTable4_glyphArray))); + size += source->CopyTo(target); + } else { + size += new_data->WriteLong(size, offset_pair_array_.size() - 1); + for (std::vector::iterator + b = GetOffsetArray()->begin(), e = GetOffsetArray()->end(); + b != e; b++) { + size += new_data->WriteUShort(size, b->glyph_code()); + size += new_data->WriteUShort(size, b->offset()); + } + } + return size; +} + +void IndexSubTableFormat4::Builder::Revert() { + offset_pair_array_.clear(); + IndexSubTable::Builder::Revert(); +} + +void IndexSubTableFormat4::Builder::SetOffsetArray( + const std::vector& pair_array) { + offset_pair_array_.clear(); + offset_pair_array_ = pair_array; + set_model_changed(); +} + +IndexSubTableFormat4::Builder::Builder() + : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable4_builderDataSize, + Format::FORMAT_4) { +} + +IndexSubTableFormat4::Builder::Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { +} + +IndexSubTableFormat4::Builder::Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { +} + +std::vector* +IndexSubTableFormat4::Builder::GetOffsetArray() { + if (offset_pair_array_.empty()) { + Initialize(InternalReadData()); + set_model_changed(); + } + return &offset_pair_array_; +} + +void IndexSubTableFormat4::Builder::Initialize(ReadableFontData* data) { + offset_pair_array_.clear(); + if (data) { + int32_t num_pairs = IndexSubTableFormat4::NumGlyphs(data, 0) + 1; + int32_t offset = EblcTable::Offset::kIndexSubTable4_glyphArray; + for (int32_t i = 0; i < num_pairs; ++i) { + int32_t glyph_code = data->ReadUShort(offset + + EblcTable::Offset::kIndexSubTable4_codeOffsetPair_glyphCode); + int32_t glyph_offset = data->ReadUShort(offset + + EblcTable::Offset::kIndexSubTable4_codeOffsetPair_offset); + offset += EblcTable::Offset::kIndexSubTable4_codeOffsetPairLength; + CodeOffsetPairBuilder pair_builder(glyph_code, glyph_offset); + offset_pair_array_.push_back(pair_builder); + } + } +} + +int32_t IndexSubTableFormat4::Builder::FindCodeOffsetPair(int32_t glyph_id) { + std::vector* pair_list = GetOffsetArray(); + int32_t location = 0; + int32_t bottom = 0; + int32_t top = pair_list->size(); + while (top != bottom) { + location = (top + bottom) / 2; + CodeOffsetPairBuilder* pair = &(pair_list->at(location)); + if (glyph_id < pair->glyph_code()) { + // location is below current location + top = location; + } else if (glyph_id > pair->glyph_code()) { + // location is above current location + bottom = location + 1; + } else { + return location; + } + } + return -1; +} + +// static +int32_t IndexSubTableFormat4::Builder::DataLength( + ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t num_glyphs = IndexSubTableFormat4::NumGlyphs(data, + index_sub_table_offset); + UNREFERENCED_PARAMETER(first_glyph_index); + UNREFERENCED_PARAMETER(last_glyph_index); + return EblcTable::Offset::kIndexSubTable4_glyphArray + + num_glyphs * EblcTable::Offset::kIndexSubTable4_codeOffsetPair_offset; +} + + +/****************************************************************************** + * IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator class + ******************************************************************************/ +IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator( + IndexSubTableFormat4::Builder* container) + : RefIterator(container), + code_offset_pair_index_(0) { +} + +bool IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator::HasNext() { + if (code_offset_pair_index_ < + (int32_t)(container()->GetOffsetArray()->size() - 1)) { + return true; + } + return false; +} + +CALLER_ATTACH BitmapGlyphInfo* +IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator::Next() { + BitmapGlyphInfoPtr output; + if (!HasNext()) { + // Note: In C++, we do not throw exception when there's no element. + return NULL; + } + std::vector* offset_array = + container()->GetOffsetArray(); + int32_t offset = offset_array->at(code_offset_pair_index_).offset(); + int32_t next_offset = offset_array->at(code_offset_pair_index_ + 1).offset(); + int32_t glyph_code = offset_array->at(code_offset_pair_index_).glyph_code(); + output = new BitmapGlyphInfo(glyph_code, + container()->image_data_offset(), + offset, + next_offset - offset, + container()->image_format()); + code_offset_pair_index_++; + return output.Detach(); +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format4.h b/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format4.h new file mode 100644 index 0000000000..efd540f178 --- /dev/null +++ b/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format4.h @@ -0,0 +1,135 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT4_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT4_H_ + +#include "sfntly/table/bitmap/index_sub_table.h" + +namespace sfntly { + +class IndexSubTableFormat4 : public IndexSubTable, + public RefCounted { + public: + class CodeOffsetPair { + public: + int32_t glyph_code() const { return glyph_code_; } + int32_t offset() const { return offset_; } + + protected: + CodeOffsetPair(int32_t glyph_code, int32_t offset); + + // TODO(arthurhsu): C++ style guide prohibits protected members. + int32_t glyph_code_; + int32_t offset_; + }; + + class CodeOffsetPairBuilder : public CodeOffsetPair { + public: + CodeOffsetPairBuilder(); + CodeOffsetPairBuilder(int32_t glyph_code, int32_t offset); + void set_glyph_code(int32_t v) { glyph_code_ = v; } + void set_offset(int32_t v) { offset_ = v; } + }; + + class CodeOffsetPairGlyphCodeComparator { + public: + bool operator()(const CodeOffsetPair& lhs, const CodeOffsetPair& rhs); + }; + + class Builder : public IndexSubTable::Builder, + public RefCounted { + public: + class BitmapGlyphInfoIterator + : public RefIterator { + public: + explicit BitmapGlyphInfoIterator(Builder* container); + virtual ~BitmapGlyphInfoIterator() {} + + virtual bool HasNext(); + CALLER_ATTACH virtual BitmapGlyphInfo* Next(); + + private: + int32_t code_offset_pair_index_; + }; + + virtual ~Builder(); + virtual int32_t NumGlyphs(); + virtual int32_t GlyphLength(int32_t glyph_id); + virtual int32_t GlyphStartOffset(int32_t glyph_id); + CALLER_ATTACH virtual BitmapGlyphInfoIterator* GetIterator(); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + + void Revert(); + void SetOffsetArray(const std::vector& pair_array); + + static CALLER_ATTACH Builder* CreateBuilder(); + static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + private: + Builder(); + Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + std::vector* GetOffsetArray(); + void Initialize(ReadableFontData* data); + int32_t FindCodeOffsetPair(int32_t glyph_id); + + static int32_t DataLength(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + + std::vector offset_pair_array_; + }; + + virtual ~IndexSubTableFormat4(); + + virtual int32_t NumGlyphs(); + virtual int32_t GlyphStartOffset(int32_t glyph_id); + virtual int32_t GlyphLength(int32_t glyph_id); + + private: + IndexSubTableFormat4(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + + int32_t FindCodeOffsetPair(int32_t glyph_id); + static int32_t NumGlyphs(ReadableFontData* data, int32_t table_offset); + + friend class Builder; +}; +typedef Ptr IndexSubTableFormat4Ptr; +typedef Ptr IndexSubTableFormat4BuilderPtr; +typedef std::vector + CodeOffsetPairBuilderList; +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT4_H_ diff --git a/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format5.cc b/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format5.cc new file mode 100644 index 0000000000..b4ab1b8e9e --- /dev/null +++ b/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format5.cc @@ -0,0 +1,344 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/bitmap/index_sub_table_format5.h" + +#include + +#include "sfntly/table/bitmap/eblc_table.h" + +namespace sfntly { +/****************************************************************************** + * IndexSubTableFormat5 class + ******************************************************************************/ +IndexSubTableFormat5::~IndexSubTableFormat5() { +} + +int32_t IndexSubTableFormat5::NumGlyphs() { + return NumGlyphs(data_, 0); +} + +int32_t IndexSubTableFormat5::GlyphStartOffset(int32_t glyph_id) { + int32_t check = CheckGlyphRange(glyph_id); + if (check == -1) { + return -1; + } + int32_t loca = ReadFontData()->SearchUShort( + EblcTable::Offset::kIndexSubTable5_glyphArray, + DataSize::kUSHORT, + NumGlyphs(), + glyph_id); + if (loca == -1) { + return loca; + } + return loca * ImageSize(); +} + +int32_t IndexSubTableFormat5::GlyphLength(int32_t glyph_id) { + int32_t check = CheckGlyphRange(glyph_id); + if (check == -1) { + return 0; + } + return image_size_; +} + +int32_t IndexSubTableFormat5::ImageSize() { + return data_->ReadULongAsInt(EblcTable::Offset::kIndexSubTable5_imageSize); +} + +CALLER_ATTACH BigGlyphMetrics* IndexSubTableFormat5::BigMetrics() { + ReadableFontDataPtr data; + data.Attach(down_cast(data_->Slice( + EblcTable::Offset::kIndexSubTable5_bigGlyphMetrics, + BigGlyphMetrics::Offset::kMetricsLength))); + BigGlyphMetricsPtr output = new BigGlyphMetrics(data); + return output.Detach(); +} + +IndexSubTableFormat5::IndexSubTableFormat5(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable(data, first_glyph_index, last_glyph_index) { + image_size_ = data_->ReadULongAsInt( + EblcTable::Offset::kIndexSubTable5_imageSize); +} + +// static +int32_t IndexSubTableFormat5::NumGlyphs(ReadableFontData* data, + int32_t table_offset) { + int32_t num_glyphs = data->ReadULongAsInt(table_offset + + EblcTable::Offset::kIndexSubTable5_numGlyphs); + return num_glyphs; +} + +/****************************************************************************** + * IndexSubTableFormat5::Builder class + ******************************************************************************/ +IndexSubTableFormat5::Builder::~Builder() { +} + +int32_t IndexSubTableFormat5::Builder::NumGlyphs() { + return GetGlyphArray()->size(); +} + +int32_t IndexSubTableFormat5::Builder::GlyphLength(int32_t glyph_id) { + UNREFERENCED_PARAMETER(glyph_id); + return ImageSize(); +} + +int32_t IndexSubTableFormat5::Builder::GlyphStartOffset(int32_t glyph_id) { + int32_t check = CheckGlyphRange(glyph_id); + if (check == -1) { + return -1; + } + IntegerList* glyph_array = GetGlyphArray(); + IntegerList::iterator it = std::find(glyph_array->begin(), + glyph_array->end(), + glyph_id); + if (it == glyph_array->end()) { + return -1; + } + return (it - glyph_array->begin()) * ImageSize(); +} + +CALLER_ATTACH IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator* + IndexSubTableFormat5::Builder::GetIterator() { + Ptr it = + new IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator(this); + return it.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat5::Builder* +IndexSubTableFormat5::Builder::CreateBuilder() { + IndexSubTableFormat5BuilderPtr output = new IndexSubTableFormat5::Builder(); + return output.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat5::Builder* +IndexSubTableFormat5::Builder::CreateBuilder(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t length = Builder::DataLength(data, + index_sub_table_offset, + first_glyph_index, + last_glyph_index); + ReadableFontDataPtr new_data; + new_data.Attach(down_cast( + data->Slice(index_sub_table_offset, length))); + IndexSubTableFormat5BuilderPtr output = + new IndexSubTableFormat5::Builder(new_data, + first_glyph_index, + last_glyph_index); + return output.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat5::Builder* +IndexSubTableFormat5::Builder::CreateBuilder(WritableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t length = Builder::DataLength(data, + index_sub_table_offset, + first_glyph_index, + last_glyph_index); + WritableFontDataPtr new_data; + new_data.Attach(down_cast( + data->Slice(index_sub_table_offset, length))); + IndexSubTableFormat5BuilderPtr output = + new IndexSubTableFormat5::Builder(new_data, + first_glyph_index, + last_glyph_index); + return output.Detach(); +} + +CALLER_ATTACH FontDataTable* IndexSubTableFormat5::Builder::SubBuildTable( + ReadableFontData* data) { + IndexSubTableFormat5Ptr output = new IndexSubTableFormat5( + data, first_glyph_index(), last_glyph_index()); + return output.Detach(); +} + +void IndexSubTableFormat5::Builder::SubDataSet() { + Revert(); +} + +int32_t IndexSubTableFormat5::Builder::SubDataSizeToSerialize() { + if (glyph_array_.empty()) { + return InternalReadData()->Length(); + } + return EblcTable::Offset::kIndexSubTable5_builderDataSize + + glyph_array_.size() * DataSize::kUSHORT; +} + +bool IndexSubTableFormat5::Builder::SubReadyToSerialize() { + if (!glyph_array_.empty()) { + return true; + } + return false; +} + +int32_t IndexSubTableFormat5::Builder::SubSerialize( + WritableFontData* new_data) { + int32_t size = SerializeIndexSubHeader(new_data); + if (!model_changed()) { + ReadableFontDataPtr source; + WritableFontDataPtr target; + source.Attach(down_cast(InternalReadData()->Slice( + EblcTable::Offset::kIndexSubTable5_imageSize))); + target.Attach(down_cast(new_data->Slice( + EblcTable::Offset::kIndexSubTable5_imageSize))); + size += source->CopyTo(target); + } else { + size += new_data->WriteULong(EblcTable::Offset::kIndexSubTable5_imageSize, + ImageSize()); + WritableFontDataPtr slice; + slice.Attach(down_cast(new_data->Slice(size))); + size += BigMetrics()->SubSerialize(slice); + size += new_data->WriteULong(size, glyph_array_.size()); + for (IntegerList::iterator b = glyph_array_.begin(), e = glyph_array_.end(); + b != e; b++) { + size += new_data->WriteUShort(size, *b); + } + } + return size; +} + +int32_t IndexSubTableFormat5::Builder::ImageSize() { + return InternalReadData()->ReadULongAsInt( + EblcTable::Offset::kIndexSubTable5_imageSize); +} + +void IndexSubTableFormat5::Builder::SetImageSize(int32_t image_size) { + InternalWriteData()->WriteULong( + EblcTable::Offset::kIndexSubTable5_imageSize, image_size); +} + +BigGlyphMetrics::Builder* IndexSubTableFormat5::Builder::BigMetrics() { + if (metrics_ == NULL) { + WritableFontDataPtr data; + data.Attach(down_cast(InternalWriteData()->Slice( + EblcTable::Offset::kIndexSubTable5_bigGlyphMetrics, + BigGlyphMetrics::Offset::kMetricsLength))); + metrics_ = new BigGlyphMetrics::Builder(data); + set_model_changed(); + } + return metrics_; +} + +IntegerList* IndexSubTableFormat5::Builder::GlyphArray() { + return GetGlyphArray(); +} + +void IndexSubTableFormat5::Builder::SetGlyphArray(const IntegerList& v) { + glyph_array_.clear(); + glyph_array_ = v; + set_model_changed(); +} + +void IndexSubTableFormat5::Builder::Revert() { + glyph_array_.clear(); + IndexSubTable::Builder::Revert(); +} + +IndexSubTableFormat5::Builder::Builder() + : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable5_builderDataSize, + IndexSubTable::Format::FORMAT_5) { +} + +IndexSubTableFormat5::Builder::Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { +} + +IndexSubTableFormat5::Builder::Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { +} + +IntegerList* IndexSubTableFormat5::Builder::GetGlyphArray() { + if (glyph_array_.empty()) { + Initialize(InternalReadData()); + set_model_changed(); + } + return &glyph_array_; +} + +void IndexSubTableFormat5::Builder::Initialize(ReadableFontData* data) { + glyph_array_.clear(); + if (data) { + int32_t num_glyphs = IndexSubTableFormat5::NumGlyphs(data, 0); + for (int32_t i = 0; i < num_glyphs; ++i) { + glyph_array_.push_back(data->ReadUShort( + EblcTable::Offset::kIndexSubTable5_glyphArray + + i * DataSize::kUSHORT)); + } + } +} + +// static +int32_t IndexSubTableFormat5::Builder::DataLength( + ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t num_glyphs = IndexSubTableFormat5::NumGlyphs(data, + index_sub_table_offset); + UNREFERENCED_PARAMETER(first_glyph_index); + UNREFERENCED_PARAMETER(last_glyph_index); + return EblcTable::Offset::kIndexSubTable5_glyphArray + + num_glyphs * DataSize::kUSHORT; +} + +/****************************************************************************** + * IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator class + ******************************************************************************/ +IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator( + IndexSubTableFormat5::Builder* container) + : RefIterator(container), + offset_index_(0) { +} + +bool IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator::HasNext() { + if (offset_index_ < (int32_t)(container()->GetGlyphArray()->size())) { + return true; + } + return false; +} + +CALLER_ATTACH BitmapGlyphInfo* +IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator::Next() { + BitmapGlyphInfoPtr output; + if (!HasNext()) { + // Note: In C++, we do not throw exception when there's no element. + return NULL; + } + output = new BitmapGlyphInfo(container()->GetGlyphArray()->at(offset_index_), + container()->image_data_offset(), + offset_index_ * container()->ImageSize(), + container()->ImageSize(), + container()->image_format()); + offset_index_++; + return output.Detach(); +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format5.h b/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format5.h new file mode 100644 index 0000000000..a39e88caca --- /dev/null +++ b/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format5.h @@ -0,0 +1,118 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT5_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT5_H_ + +#include "sfntly/table/bitmap/big_glyph_metrics.h" +#include "sfntly/table/bitmap/index_sub_table.h" + +namespace sfntly { + +class IndexSubTableFormat5 : public IndexSubTable, + public RefCounted { + public: + class Builder : public IndexSubTable::Builder, + public RefCounted { + public: + class BitmapGlyphInfoIterator + : public RefIterator { + public: + explicit BitmapGlyphInfoIterator(Builder* container); + virtual ~BitmapGlyphInfoIterator() {} + + virtual bool HasNext(); + CALLER_ATTACH virtual BitmapGlyphInfo* Next(); + + private: + int32_t offset_index_; + }; + virtual ~Builder(); + virtual int32_t NumGlyphs(); + virtual int32_t GlyphLength(int32_t glyph_id); + virtual int32_t GlyphStartOffset(int32_t glyph_id); + CALLER_ATTACH virtual BitmapGlyphInfoIterator* GetIterator(); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + + int32_t ImageSize(); + void SetImageSize(int32_t image_size); + BigGlyphMetrics::Builder* BigMetrics(); + IntegerList* GlyphArray(); + void SetGlyphArray(const IntegerList& v); + + static CALLER_ATTACH Builder* CreateBuilder(); + static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + protected: + void Revert(); + + private: + Builder(); + Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + + IntegerList* GetGlyphArray(); + void Initialize(ReadableFontData* data); + + static int32_t DataLength(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + + IntegerList glyph_array_; + BigGlyphMetricsBuilderPtr metrics_; + }; + virtual ~IndexSubTableFormat5(); + + virtual int32_t NumGlyphs(); + virtual int32_t GlyphStartOffset(int32_t glyph_id); + virtual int32_t GlyphLength(int32_t glyph_id); + + int32_t ImageSize(); + CALLER_ATTACH BigGlyphMetrics* BigMetrics(); + + private: + IndexSubTableFormat5(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + + static int32_t NumGlyphs(ReadableFontData* dta, int32_t table_offset); + + int32_t image_size_; + + friend class Builder; +}; +typedef Ptr IndexSubTableFormat5Ptr; +typedef Ptr IndexSubTableFormat5BuilderPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT5_H_ diff --git a/src/sfntly/src/sfntly/table/bitmap/simple_bitmap_glyph.cc b/src/sfntly/src/sfntly/table/bitmap/simple_bitmap_glyph.cc new file mode 100644 index 0000000000..87031a142b --- /dev/null +++ b/src/sfntly/src/sfntly/table/bitmap/simple_bitmap_glyph.cc @@ -0,0 +1,45 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 = the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/bitmap/simple_bitmap_glyph.h" + +namespace sfntly { + +SimpleBitmapGlyph::SimpleBitmapGlyph(ReadableFontData* data, int32_t format) + : BitmapGlyph(data, format) { +} + +SimpleBitmapGlyph::~SimpleBitmapGlyph() { +} + +SimpleBitmapGlyph::Builder::Builder(ReadableFontData* data, int32_t format) + : BitmapGlyph::Builder(data, format) { +} + +SimpleBitmapGlyph::Builder::Builder(WritableFontData* data, int32_t format) + : BitmapGlyph::Builder(data, format) { +} + +SimpleBitmapGlyph::Builder::~Builder() { +} + +CALLER_ATTACH FontDataTable* +SimpleBitmapGlyph::Builder::SubBuildTable(ReadableFontData* data) { + Ptr glyph = new SimpleBitmapGlyph(data, format()); + return glyph.Detach(); +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/bitmap/simple_bitmap_glyph.h b/src/sfntly/src/sfntly/table/bitmap/simple_bitmap_glyph.h new file mode 100644 index 0000000000..56ede10538 --- /dev/null +++ b/src/sfntly/src/sfntly/table/bitmap/simple_bitmap_glyph.h @@ -0,0 +1,44 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 = the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_SIMPLE_BITMAP_GLYPH_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_SIMPLE_BITMAP_GLYPH_H_ + +#include "sfntly/table/bitmap/bitmap_glyph.h" + +namespace sfntly { + +class SimpleBitmapGlyph : public BitmapGlyph, + public RefCounted { + public: + class Builder : public BitmapGlyph::Builder, + public RefCounted { + public: + Builder(WritableFontData* data, int32_t format); + Builder(ReadableFontData* data, int32_t format); + virtual ~Builder(); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + }; + + SimpleBitmapGlyph(ReadableFontData* data, int32_t format); + virtual ~SimpleBitmapGlyph(); +}; +typedef Ptr SimpleBitmapGlyphPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_SIMPLE_BITMAP_GLYPH_H_ diff --git a/src/sfntly/src/sfntly/table/bitmap/small_glyph_metrics.cc b/src/sfntly/src/sfntly/table/bitmap/small_glyph_metrics.cc new file mode 100644 index 0000000000..0f3c1e91d6 --- /dev/null +++ b/src/sfntly/src/sfntly/table/bitmap/small_glyph_metrics.cc @@ -0,0 +1,126 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/bitmap/small_glyph_metrics.h" + +namespace sfntly { +/****************************************************************************** + * SmallGlyphMetrics class + ******************************************************************************/ +SmallGlyphMetrics::SmallGlyphMetrics(ReadableFontData* data) + : GlyphMetrics(data) { +} + +SmallGlyphMetrics::~SmallGlyphMetrics() { +} + +int32_t SmallGlyphMetrics::Height() { + return data_->ReadByte(Offset::kHeight); +} + +int32_t SmallGlyphMetrics::Width() { + return data_->ReadByte(Offset::kWidth); +} + +int32_t SmallGlyphMetrics::BearingX() { + return data_->ReadByte(Offset::kBearingX); +} + +int32_t SmallGlyphMetrics::BearingY() { + return data_->ReadByte(Offset::kBearingY); +} + +int32_t SmallGlyphMetrics::Advance() { + return data_->ReadByte(Offset::kAdvance); +} + +/****************************************************************************** + * SmallGlyphMetrics::Builder class + ******************************************************************************/ +SmallGlyphMetrics::Builder::Builder(WritableFontData* data) + : GlyphMetrics::Builder(data) { +} + +SmallGlyphMetrics::Builder::Builder(ReadableFontData* data) + : GlyphMetrics::Builder(data) { +} + +SmallGlyphMetrics::Builder::~Builder() { +} + +int32_t SmallGlyphMetrics::Builder::Height() { + return InternalReadData()->ReadByte(Offset::kHeight); +} + +void SmallGlyphMetrics::Builder::SetHeight(byte_t height) { + InternalWriteData()->WriteByte(Offset::kHeight, height); +} + +int32_t SmallGlyphMetrics::Builder::Width() { + return InternalReadData()->ReadByte(Offset::kWidth); +} + +void SmallGlyphMetrics::Builder::SetWidth(byte_t width) { + InternalWriteData()->WriteByte(Offset::kWidth, width); +} + +int32_t SmallGlyphMetrics::Builder::BearingX() { + return InternalReadData()->ReadByte(Offset::kBearingX); +} + +void SmallGlyphMetrics::Builder::SetBearingX(byte_t bearing) { + InternalWriteData()->WriteByte(Offset::kBearingX, bearing); +} + +int32_t SmallGlyphMetrics::Builder::BearingY() { + return InternalReadData()->ReadByte(Offset::kBearingY); +} + +void SmallGlyphMetrics::Builder::SetBearingY(byte_t bearing) { + InternalWriteData()->WriteByte(Offset::kBearingY, bearing); +} + +int32_t SmallGlyphMetrics::Builder::Advance() { + return InternalReadData()->ReadByte(Offset::kAdvance); +} + +void SmallGlyphMetrics::Builder::SetAdvance(byte_t advance) { + InternalWriteData()->WriteByte(Offset::kAdvance, advance); +} + +CALLER_ATTACH FontDataTable* + SmallGlyphMetrics::Builder::SubBuildTable(ReadableFontData* data) { + SmallGlyphMetricsPtr output = new SmallGlyphMetrics(data); + return output.Detach(); +} + +void SmallGlyphMetrics::Builder::SubDataSet() { + // NOP. +} + +int32_t SmallGlyphMetrics::Builder::SubDataSizeToSerialize() { + return 0; +} + +bool SmallGlyphMetrics::Builder::SubReadyToSerialize() { + return false; +} + +int32_t SmallGlyphMetrics::Builder::SubSerialize(WritableFontData* new_data) { + return Data()->CopyTo(new_data); +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/bitmap/small_glyph_metrics.h b/src/sfntly/src/sfntly/table/bitmap/small_glyph_metrics.h new file mode 100644 index 0000000000..ea13720d8f --- /dev/null +++ b/src/sfntly/src/sfntly/table/bitmap/small_glyph_metrics.h @@ -0,0 +1,79 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_SMALL_GLYPH_METRICS_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_SMALL_GLYPH_METRICS_H_ + +#include "sfntly/port/refcount.h" +#include "sfntly/table/bitmap/glyph_metrics.h" + +namespace sfntly { + +class SmallGlyphMetrics : public GlyphMetrics, + public RefCounted { + public: + struct Offset { + enum { + kMetricsLength = 5, + kHeight = 0, + kWidth = 1, + kBearingX = 2, + kBearingY = 3, + kAdvance = 4, + }; + }; + + class Builder : public GlyphMetrics::Builder, + public RefCounted { + public: + // Constructor scope altered to public because C++ does not allow base + // class to instantiate derived class with protected constructors. + explicit Builder(WritableFontData* data); + explicit Builder(ReadableFontData* data); + virtual ~Builder(); + + int32_t Height(); + void SetHeight(byte_t height); + int32_t Width(); + void SetWidth(byte_t width); + int32_t BearingX(); + void SetBearingX(byte_t bearing); + int32_t BearingY(); + void SetBearingY(byte_t bearing); + int32_t Advance(); + void SetAdvance(byte_t advance); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + }; + + explicit SmallGlyphMetrics(ReadableFontData* data); + virtual ~SmallGlyphMetrics(); + + int32_t Height(); + int32_t Width(); + int32_t BearingX(); + int32_t BearingY(); + int32_t Advance(); +}; +typedef Ptr SmallGlyphMetricsPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_SMALL_GLYPH_METRICS_H_ diff --git a/src/sfntly/src/sfntly/table/byte_array_table_builder.cc b/src/sfntly/src/sfntly/table/byte_array_table_builder.cc new file mode 100644 index 0000000000..631a05fdd6 --- /dev/null +++ b/src/sfntly/src/sfntly/table/byte_array_table_builder.cc @@ -0,0 +1,70 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/byte_array_table_builder.h" + +namespace sfntly { + +ByteArrayTableBuilder::~ByteArrayTableBuilder() {} + +int32_t ByteArrayTableBuilder::ByteValue(int32_t index) { + ReadableFontDataPtr data = InternalReadData(); + if (data == NULL) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("No font data for the table"); +#endif + return -1; + } + return data->ReadByte(index); +} + +void ByteArrayTableBuilder::SetByteValue(int32_t index, byte_t b) { + WritableFontDataPtr data = InternalWriteData(); + if (data == NULL) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("No font data for the table"); +#endif + return; + } + data->WriteByte(index, b); +} + +int32_t ByteArrayTableBuilder::ByteCount() { + ReadableFontDataPtr data = InternalReadData(); + if (data == NULL) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("No font data for the table"); +#endif + return 0; + } + return data->Length(); +} + +ByteArrayTableBuilder::ByteArrayTableBuilder(Header* header, + WritableFontData* data) + : TableBasedTableBuilder(header, data) { +} + +ByteArrayTableBuilder::ByteArrayTableBuilder(Header* header, + ReadableFontData* data) + : TableBasedTableBuilder(header, data) { +} + +ByteArrayTableBuilder::ByteArrayTableBuilder(Header* header) + : TableBasedTableBuilder(header) { +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/byte_array_table_builder.h b/src/sfntly/src/sfntly/table/byte_array_table_builder.h new file mode 100644 index 0000000000..42d27a8df0 --- /dev/null +++ b/src/sfntly/src/sfntly/table/byte_array_table_builder.h @@ -0,0 +1,53 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BYTE_ARRAY_TABLE_BUILDER_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BYTE_ARRAY_TABLE_BUILDER_H_ + +#include "sfntly/table/table_based_table_builder.h" + +namespace sfntly { + +// An abstract builder base for byte array based tables. +class ByteArrayTableBuilder : public TableBasedTableBuilder { + public: + virtual ~ByteArrayTableBuilder(); + + // Get the byte value at the specified index. The index is relative to the + // start of the table. + // @param index index relative to the start of the table + // @return byte value at the given index + virtual int32_t ByteValue(int32_t index); + + // Set the byte value at the specified index. The index is relative to the + // start of the table. + // @param index index relative to the start of the table + // @param b byte value to set + virtual void SetByteValue(int32_t index, byte_t b); + + // Get the number of bytes set for this table. It may include padding bytes at + // the end. + virtual int32_t ByteCount(); + + protected: + ByteArrayTableBuilder(Header* header, WritableFontData* data); + ByteArrayTableBuilder(Header* header, ReadableFontData* data); + explicit ByteArrayTableBuilder(Header* header); +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BYTE_ARRAY_TABLE_BUILDER_H_ diff --git a/src/sfntly/src/sfntly/table/core/cmap_table.cc b/src/sfntly/src/sfntly/table/core/cmap_table.cc new file mode 100644 index 0000000000..0b4f89a2bd --- /dev/null +++ b/src/sfntly/src/sfntly/table/core/cmap_table.cc @@ -0,0 +1,1288 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// type.h needs to be included first because of building issues on Windows +// Type aliases we delcare are defined in other headers and make the build +// fail otherwise. +#include "sfntly/port/type.h" +#include "sfntly/table/core/cmap_table.h" + +#include +#include + +#include + +#include "sfntly/font.h" +#include "sfntly/math/font_math.h" +#include "sfntly/port/endian.h" +#include "sfntly/port/exception_type.h" +#include "sfntly/table/core/name_table.h" + +namespace sfntly { + +const int32_t CMapTable::NOTDEF = 0; + +CMapTable::CMapId CMapTable::WINDOWS_BMP = { + PlatformId::kWindows, + WindowsEncodingId::kUnicodeUCS2 +}; +CMapTable::CMapId CMapTable::WINDOWS_UCS4 = { + PlatformId::kWindows, + WindowsEncodingId::kUnicodeUCS4 +}; +CMapTable::CMapId CMapTable::MAC_ROMAN = { + PlatformId::kWindows, + MacintoshEncodingId::kRoman +}; + +/****************************************************************************** + * CMapTable class + ******************************************************************************/ +CMapTable::CMapTable(Header* header, ReadableFontData* data) + : SubTableContainerTable(header, data) { +} + +CMapTable::~CMapTable() {} + +CALLER_ATTACH CMapTable::CMap* CMapTable::GetCMap(const int32_t index) { + if (index < 0 || index > NumCMaps()) { +#ifndef SFNTLY_NO_EXCEPTION + throw IndexOutOfBoundException("Requested CMap index is out of bounds."); +#else + return NULL; +#endif + } + int32_t platform_id = PlatformId(index); + int32_t encoding_id = EncodingId(index); + CMapId cmap_id = NewCMapId(platform_id, encoding_id); + int32_t offset_ = Offset(index); + Ptr cmap_builder = + (CMap::Builder::GetBuilder(data_, offset_, cmap_id)); + if (!cmap_builder) { +#ifndef SFNTLY_NO_EXCEPTION + throw NoSuchElementException("Cannot find builder for requested CMap."); +#else + return NULL; +#endif + } + return down_cast(cmap_builder->Build()); +} + +CALLER_ATTACH CMapTable::CMap* CMapTable::GetCMap(const int32_t platform_id, + const int32_t encoding_id) { + return GetCMap(NewCMapId(platform_id, encoding_id)); +} + +CALLER_ATTACH CMapTable::CMap* +CMapTable::GetCMap(const CMapTable::CMapId cmap_id) { + CMapIdFilter id_filter(cmap_id); + CMapIterator cmap_iterator(this, &id_filter); + // There can only be one cmap with a particular CMapId + if (cmap_iterator.HasNext()) { + Ptr cmap; + cmap.Attach(cmap_iterator.Next()); + return cmap.Detach(); + } +#ifndef SFNTLY_NO_EXCEPTION + throw NoSuchElementException(); +#else + return NULL; +#endif +} + +int32_t CMapTable::Version() { + return data_->ReadUShort(Offset::kVersion); +} + +int32_t CMapTable::NumCMaps() { + return data_->ReadUShort(Offset::kNumTables); +} + +CMapTable::CMapId CMapTable::GetCMapId(int32_t index) { + return NewCMapId(PlatformId(index), EncodingId(index)); +} + +int32_t CMapTable::PlatformId(int32_t index) { + return data_->ReadUShort(Offset::kEncodingRecordPlatformId + + OffsetForEncodingRecord(index)); +} + +int32_t CMapTable::EncodingId(int32_t index) { + return data_->ReadUShort(Offset::kEncodingRecordEncodingId + + OffsetForEncodingRecord(index)); +} + +int32_t CMapTable::Offset(int32_t index) { + return data_->ReadULongAsInt(Offset::kEncodingRecordOffset + + OffsetForEncodingRecord(index)); +} + +int32_t CMapTable::OffsetForEncodingRecord(int32_t index) { + return Offset::kEncodingRecordStart + index * Offset::kEncodingRecordSize; +} + +CMapTable::CMapId CMapTable::NewCMapId(int32_t platform_id, + int32_t encoding_id) { + CMapId result; + result.platform_id = platform_id; + result.encoding_id = encoding_id; + return result; +} + +CMapTable::CMapId CMapTable::NewCMapId(const CMapId& obj) { + CMapId result; + result.platform_id = obj.platform_id; + result.encoding_id = obj.encoding_id; + return result; +} + +/****************************************************************************** + * CMapTable::CMapIterator class + ******************************************************************************/ +CMapTable::CMapIterator::CMapIterator(CMapTable* table, + const CMapFilter* filter) + : table_index_(0), filter_(filter), table_(table) { +} + +bool CMapTable::CMapIterator::HasNext() { + if (!filter_) { + if (table_index_ < table_->NumCMaps()) { + return true; + } + return false; + } + + for (; table_index_ < table_->NumCMaps(); ++table_index_) { + if (filter_->accept(table_->GetCMapId(table_index_))) { + return true; + } + } + return false; +} + +CALLER_ATTACH CMapTable::CMap* CMapTable::CMapIterator::Next() { + if (!HasNext()) { +#ifndef SFNTLY_NO_EXCEPTION + throw NoSuchElementException(); +#else + return NULL; +#endif + } + CMapPtr next_cmap; + next_cmap.Attach(table_->GetCMap(table_index_++)); + if (next_cmap == NULL) { +#ifndef SFNTLY_NO_EXCEPTION + throw NoSuchElementException("Error during the creation of the CMap"); +#else + return NULL; +#endif + } + return next_cmap.Detach(); +} + +/****************************************************************************** + * CMapTable::CMapId class + ******************************************************************************/ + +/****************************************************************************** + * CMapTable::CMapIdComparator class + ******************************************************************************/ + +bool CMapTable::CMapIdComparator::operator()(const CMapId& lhs, + const CMapId& rhs) const { + return ((lhs.platform_id << 8 | lhs.encoding_id) > + (rhs.platform_id << 8 | rhs.encoding_id)); +} + +/****************************************************************************** + * CMapTable::CMapIdFilter class + ******************************************************************************/ +CMapTable::CMapIdFilter::CMapIdFilter(const CMapId wanted_id) + : wanted_id_(wanted_id), + comparator_(NULL) { +} + +CMapTable::CMapIdFilter::CMapIdFilter(const CMapId wanted_id, + const CMapIdComparator* comparator) + : wanted_id_(wanted_id), + comparator_(comparator) { +} + +bool CMapTable::CMapIdFilter::accept(const CMapId& cmap_id) const { + if (!comparator_) + return wanted_id_ == cmap_id; + return (*comparator_)(wanted_id_, cmap_id); +} + +/****************************************************************************** + * CMapTable::CMap class + ******************************************************************************/ +CMapTable::CMap::CMap(ReadableFontData* data, int32_t format, + const CMapId& cmap_id) + : SubTable(data), format_(format), cmap_id_(cmap_id) { +} + +CMapTable::CMap::~CMap() { +} + +/****************************************************************************** + * CMapTable::CMap::Builder class + ******************************************************************************/ +CMapTable::CMap::Builder::~Builder() { +} + +CALLER_ATTACH CMapTable::CMap::Builder* + CMapTable::CMap::Builder::GetBuilder(ReadableFontData* data, int32_t offset, + const CMapId& cmap_id) { + // NOT IMPLEMENTED: Java enum value validation + int32_t format = data->ReadUShort(offset); + CMapBuilderPtr builder; + switch (format) { + case CMapFormat::kFormat0: + builder.Attach(CMapFormat0::Builder::NewInstance(data, offset, cmap_id)); + break; + case CMapFormat::kFormat2: +#if defined (SFNTLY_DEBUG_CMAP) + fprintf(stderr, "Requesting Format2 builder, but it's unsupported; " + "returning NULL\n"); +#endif + break; + case CMapFormat::kFormat4: + builder.Attach(CMapFormat4::Builder::NewInstance(data, offset, cmap_id)); + break; + default: +#ifdef SFNTLY_DEBUG_CMAP + fprintf(stderr, "Unknown builder format requested\n"); +#endif + break; + } + return builder.Detach(); +} + +CALLER_ATTACH CMapTable::CMap::Builder* +CMapTable::CMap::Builder::GetBuilder(int32_t format, const CMapId& cmap_id) { + Ptr builder; + switch (format) { + case CMapFormat::kFormat0: + builder.Attach(CMapFormat0::Builder::NewInstance(cmap_id)); + break; + case CMapFormat::kFormat2: +#if defined (SFNTLY_DEBUG_CMAP) + fprintf(stderr, "Requesting Format2 builder, but it's unsupported; " + "returning NULL\n"); +#endif + break; + case CMapFormat::kFormat4: + builder.Attach(CMapFormat4::Builder::NewInstance(cmap_id)); + break; + default: +#ifdef SFNTLY_DEBUG_CMAP + fprintf(stderr, "Unknown builder format requested\n"); +#endif + break; + } + return builder.Detach(); +} + +CMapTable::CMap::Builder::Builder(ReadableFontData* data, + int32_t format, + const CMapId& cmap_id) + : SubTable::Builder(data), + format_(format), + cmap_id_(cmap_id), + language_(0) { +} + +CMapTable::CMap::Builder::Builder(WritableFontData* data, + int32_t format, + const CMapId& cmap_id) + : SubTable::Builder(data), + format_(format), + cmap_id_(cmap_id), + language_(0) { +} + +int32_t CMapTable::CMap::Builder::SubSerialize(WritableFontData* new_data) { + return InternalReadData()->CopyTo(new_data); +} + +bool CMapTable::CMap::Builder::SubReadyToSerialize() { + return true; +} + +int32_t CMapTable::CMap::Builder::SubDataSizeToSerialize() { + ReadableFontDataPtr read_data = InternalReadData(); + if (!read_data) + return 0; + return read_data->Length(); +} + +void CMapTable::CMap::Builder::SubDataSet() { + // NOP +} + +/****************************************************************************** + * CMapTable::CMapFormat0 + ******************************************************************************/ +CMapTable::CMapFormat0::~CMapFormat0() { +} + +int32_t CMapTable::CMapFormat0::Language() { + return 0; +} + +int32_t CMapTable::CMapFormat0::GlyphId(int32_t character) { + if (character < 0 || character > 255) { + return CMapTable::NOTDEF; + } + return data_->ReadUByte(character + Offset::kFormat0GlyphIdArray); +} + +CMapTable::CMapFormat0::CMapFormat0(ReadableFontData* data, + const CMapId& cmap_id) + : CMap(data, CMapFormat::kFormat0, cmap_id) { +} + +CMapTable::CMap::CharacterIterator* CMapTable::CMapFormat0::Iterator() { + return new CMapTable::CMapFormat0::CharacterIterator(0, 0xff); +} + + +/****************************************************************************** + * CMapTable::CMapFormat0::CharacterIterator + ******************************************************************************/ +CMapTable::CMapFormat0::CharacterIterator::CharacterIterator(int32_t start, + int32_t end) + : character_(start), + max_character_(end) { +} + +CMapTable::CMapFormat0::CharacterIterator::~CharacterIterator() {} + +bool CMapTable::CMapFormat0::CharacterIterator::HasNext() { + return character_ < max_character_; +} + +int32_t CMapTable::CMapFormat0::CharacterIterator::Next() { + if (HasNext()) + return character_++; +#ifndef SFNTLY_NO_EXCEPTION + throw NoSuchElementException("No more characters to iterate."); +#endif + return -1; +} + +/****************************************************************************** + * CMapTable::CMapFormat0::Builder + ******************************************************************************/ +// static +CALLER_ATTACH CMapTable::CMapFormat0::Builder* +CMapTable::CMapFormat0::Builder::NewInstance(WritableFontData* data, + int32_t offset, + const CMapId& cmap_id) { + WritableFontDataPtr wdata; + if (data) { + wdata.Attach(down_cast( + data->Slice(offset, + data->ReadUShort(offset + Offset::kFormat0Length)))); + } + return new Builder(wdata, CMapFormat::kFormat0, cmap_id); +} + +// static +CALLER_ATTACH CMapTable::CMapFormat0::Builder* +CMapTable::CMapFormat0::Builder::NewInstance(ReadableFontData* data, + int32_t offset, + const CMapId& cmap_id) { + ReadableFontDataPtr rdata; + if (data) { + rdata.Attach(down_cast( + data->Slice(offset, + data->ReadUShort(offset + Offset::kFormat0Length)))); + } + return new Builder(rdata, CMapFormat::kFormat0, cmap_id); +} + +// static +CALLER_ATTACH CMapTable::CMapFormat0::Builder* +CMapTable::CMapFormat0::Builder::NewInstance(const CMapId& cmap_id) { + return new Builder(cmap_id); +} + +// Always call NewInstance instead of the constructor for creating a new builder +// object! This refactoring avoids memory leaks when slicing the font data. +CMapTable::CMapFormat0::Builder::Builder(WritableFontData* data, int32_t offset, + const CMapId& cmap_id) + : CMapTable::CMap::Builder(data, CMapFormat::kFormat0, cmap_id) { + UNREFERENCED_PARAMETER(offset); +} + +CMapTable::CMapFormat0::Builder::Builder( + ReadableFontData* data, + int32_t offset, + const CMapId& cmap_id) + : CMapTable::CMap::Builder(data, CMapFormat::kFormat0, cmap_id) { + UNREFERENCED_PARAMETER(offset); +} + +CMapTable::CMapFormat0::Builder::Builder(const CMapId& cmap_id) + : CMap::Builder(reinterpret_cast(NULL), + CMapFormat::kFormat0, + cmap_id) { +} + +CMapTable::CMapFormat0::Builder::~Builder() { +} + +CALLER_ATTACH FontDataTable* + CMapTable::CMapFormat0::Builder::SubBuildTable(ReadableFontData* data) { + FontDataTablePtr table = new CMapFormat0(data, cmap_id()); + return table.Detach(); +} + +/****************************************************************************** + * CMapTable::CMapFormat2 + ******************************************************************************/ +CMapTable::CMapFormat2::~CMapFormat2() { +} + +int32_t CMapTable::CMapFormat2::Language() { + return 0; +} + +int32_t CMapTable::CMapFormat2::GlyphId(int32_t character) { + if (character > 0xffff) { + return CMapTable::NOTDEF; + } + + uint32_t c = ToBE32(character); + byte_t high_byte = (c >> 8) & 0xff; + byte_t low_byte = c & 0xff; + int32_t offset = SubHeaderOffset(high_byte); + + if (offset == 0) { + low_byte = high_byte; + high_byte = 0; + } + + int32_t first_code = FirstCode(high_byte); + int32_t entry_count = EntryCount(high_byte); + + if (low_byte < first_code || low_byte >= first_code + entry_count) { + return CMapTable::NOTDEF; + } + + int32_t id_range_offset = IdRangeOffset(high_byte); + + // position of idRangeOffset + value of idRangeOffset + index for low byte + // = firstcode + int32_t p_location = (offset + Offset::kFormat2SubHeader_idRangeOffset) + + id_range_offset + + (low_byte - first_code) * DataSize::kUSHORT; + int p = data_->ReadUShort(p_location); + if (p == 0) { + return CMapTable::NOTDEF; + } + + if (offset == 0) { + return p; + } + int id_delta = IdDelta(high_byte); + return (p + id_delta) % 65536; +} + +int32_t CMapTable::CMapFormat2::BytesConsumed(int32_t character) { + uint32_t c = ToBE32(character); + int32_t high_byte = (c >> 8) & 0xff; + int32_t offset = SubHeaderOffset(high_byte); + return (offset == 0) ? 1 : 2; +} + +CMapTable::CMapFormat2::CMapFormat2(ReadableFontData* data, + const CMapId& cmap_id) + : CMap(data, CMapFormat::kFormat2, cmap_id) { +} + +int32_t CMapTable::CMapFormat2::SubHeaderOffset(int32_t sub_header_index) { + return data_->ReadUShort(Offset::kFormat2SubHeaderKeys + + sub_header_index * DataSize::kUSHORT); +} + +int32_t CMapTable::CMapFormat2::FirstCode(int32_t sub_header_index) { + int32_t sub_header_offset = SubHeaderOffset(sub_header_index); + return data_->ReadUShort(sub_header_offset + + Offset::kFormat2SubHeaderKeys + + Offset::kFormat2SubHeader_firstCode); +} + +int32_t CMapTable::CMapFormat2::EntryCount(int32_t sub_header_index) { + int32_t sub_header_offset = SubHeaderOffset(sub_header_index); + return data_->ReadUShort(sub_header_offset + + Offset::kFormat2SubHeaderKeys + + Offset::kFormat2SubHeader_entryCount); +} + +int32_t CMapTable::CMapFormat2::IdRangeOffset(int32_t sub_header_index) { + int32_t sub_header_offset = SubHeaderOffset(sub_header_index); + return data_->ReadUShort(sub_header_offset + + Offset::kFormat2SubHeaderKeys + + Offset::kFormat2SubHeader_idRangeOffset); +} + +int32_t CMapTable::CMapFormat2::IdDelta(int32_t sub_header_index) { + int32_t sub_header_offset = SubHeaderOffset(sub_header_index); + return data_->ReadUShort(sub_header_offset + + Offset::kFormat2SubHeaderKeys + + Offset::kFormat2SubHeader_idDelta); +} + +CMapTable::CMap::CharacterIterator* CMapTable::CMapFormat2::Iterator() { + // UNIMPLEMENTED + return NULL; +} + +/****************************************************************************** + * CMapTable::CMapFormat2::Builder + ******************************************************************************/ +CMapTable::CMapFormat2::Builder::Builder(WritableFontData* data, + int32_t offset, + const CMapId& cmap_id) + : CMapTable::CMap::Builder(data ? down_cast( + data->Slice(offset, data->ReadUShort( + offset + Offset::kFormat0Length))) + : reinterpret_cast(NULL), + CMapFormat::kFormat2, cmap_id) { + // TODO(arthurhsu): FIXIT: heavy lifting and leak, need fix. +} + +CMapTable::CMapFormat2::Builder::Builder(ReadableFontData* data, + int32_t offset, + const CMapId& cmap_id) + : CMapTable::CMap::Builder(data ? down_cast( + data->Slice(offset, data->ReadUShort( + offset + Offset::kFormat0Length))) + : reinterpret_cast(NULL), + CMapFormat::kFormat2, cmap_id) { + // TODO(arthurhsu): FIXIT: heavy lifting and leak, need fix. +} + +CMapTable::CMapFormat2::Builder::~Builder() { +} + +CALLER_ATTACH FontDataTable* + CMapTable::CMapFormat2::Builder::SubBuildTable(ReadableFontData* data) { + FontDataTablePtr table = new CMapFormat2(data, cmap_id()); + return table.Detach(); +} + +/****************************************************************************** + * CMapTable::CMapFormat4 + ******************************************************************************/ +CMapTable::CMapFormat4::CMapFormat4(ReadableFontData* data, + const CMapId& cmap_id) + : CMap(data, CMapFormat::kFormat4, cmap_id), + seg_count_(SegCount(data)), + start_code_offset_(StartCodeOffset(seg_count_)), + end_code_offset_(Offset::kFormat4EndCount), + id_delta_offset_(IdDeltaOffset(seg_count_)), + glyph_id_array_offset_(GlyphIdArrayOffset(seg_count_)) { +} + +CMapTable::CMapFormat4::~CMapFormat4() { +} + +int32_t CMapTable::CMapFormat4::GlyphId(int32_t character) { + int32_t segment = data_->SearchUShort(StartCodeOffset(seg_count_), + DataSize::kUSHORT, + Offset::kFormat4EndCount, + DataSize::kUSHORT, + seg_count_, + character); + if (segment == -1) { + return CMapTable::NOTDEF; + } + int32_t start_code = StartCode(segment); + return RetrieveGlyphId(segment, start_code, character); +} + +int32_t CMapTable::CMapFormat4::RetrieveGlyphId(int32_t segment, + int32_t start_code, + int32_t character) { + if (character < start_code) { + return CMapTable::NOTDEF; + } + int32_t id_range_offset = IdRangeOffset(segment); + if (id_range_offset == 0) { + return (character + IdDelta(segment)) % 65536; + } + return data_->ReadUShort(id_range_offset + + IdRangeOffsetLocation(segment) + + 2 * (character - start_code)); +} + +int32_t CMapTable::CMapFormat4::seg_count() { + return seg_count_; +} + +int32_t CMapTable::CMapFormat4::Length() { + return Length(data_); +} + +int32_t CMapTable::CMapFormat4::StartCode(int32_t segment) { + if (!IsValidIndex(segment)) { + return -1; + } + return StartCode(data_.p_, seg_count_, segment); +} + +// static +int32_t CMapTable::CMapFormat4::Language(ReadableFontData* data) { + int32_t language = data->ReadUShort(Offset::kFormat4Language); + return language; +} + +// static +int32_t CMapTable::CMapFormat4::Length(ReadableFontData* data) { + int32_t length = data->ReadUShort(Offset::kFormat4Length); + return length; +} + +// static +int32_t CMapTable::CMapFormat4::SegCount(ReadableFontData* data) { + int32_t seg_count = data->ReadUShort(Offset::kFormat4SegCountX2) / 2; + return seg_count; +} + +// static +int32_t CMapTable::CMapFormat4::StartCode(ReadableFontData* data, + int32_t seg_count, + int32_t index) { + int32_t start_code = data->ReadUShort(StartCodeOffset(seg_count) + + index * DataSize::kUSHORT); + return start_code; +} + +// static +int32_t CMapTable::CMapFormat4::StartCodeOffset(int32_t seg_count) { + int32_t start_code_offset = Offset::kFormat4EndCount + + (seg_count + 1) * DataSize::kUSHORT; + return start_code_offset; +} + +// static +int32_t CMapTable::CMapFormat4::EndCode(ReadableFontData* data, + int32_t seg_count, + int32_t index) { + UNREFERENCED_PARAMETER(seg_count); + int32_t end_code = data->ReadUShort(Offset::kFormat4EndCount + + index * DataSize::kUSHORT); + return end_code; +} + +// static +int32_t CMapTable::CMapFormat4::IdDelta(ReadableFontData* data, + int32_t seg_count, + int32_t index) { + int32_t id_delta = data->ReadUShort(IdDeltaOffset(seg_count) + + index * DataSize::kUSHORT); + return id_delta; +} + +// static +int32_t CMapTable::CMapFormat4::IdDeltaOffset(int32_t seg_count) { + int32_t id_delta_offset = + Offset::kFormat4EndCount + (2 * seg_count + 1) * DataSize::kUSHORT; + return id_delta_offset; +} + +// static +int32_t CMapTable::CMapFormat4::IdRangeOffset(ReadableFontData* data, + int32_t seg_count, + int32_t index) { + int32_t id_range_offset = + data->ReadUShort(IdRangeOffsetOffset(seg_count) + + index * DataSize::kUSHORT); + return id_range_offset; +} + +// static +int32_t CMapTable::CMapFormat4::IdRangeOffsetOffset(int32_t seg_count) { + int32_t id_range_offset_offset = + Offset::kFormat4EndCount + (2 * seg_count + 1) * DataSize::kUSHORT + + seg_count * DataSize::kSHORT; + return id_range_offset_offset; +} + +// static +int32_t CMapTable::CMapFormat4::GlyphIdArrayOffset(int32_t seg_count) { + int32_t glyph_id_array_offset = + Offset::kFormat4EndCount + (3 * seg_count + 1) * DataSize::kUSHORT + + seg_count * DataSize::kSHORT; + return glyph_id_array_offset; +} + +int32_t CMapTable::CMapFormat4::EndCode(int32_t segment) { + if (IsValidIndex(segment)) { + return EndCode(data_, seg_count_, segment); + } +#if defined (SFNTLY_NO_EXCEPTION) + return -1; +#else + throw IllegalArgumentException(); +#endif +} + +bool CMapTable::CMapFormat4::IsValidIndex(int32_t segment) { + if (segment < 0 || segment >= seg_count_) { +#if defined (SFNTLY_NO_EXCEPTION) + return false; +#else + throw IllegalArgumentException(); +#endif + } + return true; +} + +int32_t CMapTable::CMapFormat4::IdDelta(int32_t segment) { + if (IsValidIndex(segment)) + return IdDelta(data_, seg_count_, segment); + return -1; +} + +int32_t CMapTable::CMapFormat4::IdRangeOffset(int32_t segment) { + if (IsValidIndex(segment)) + return data_->ReadUShort(IdRangeOffsetLocation(segment)); + return -1; +} + +int32_t CMapTable::CMapFormat4::IdRangeOffsetLocation(int32_t segment) { + if (IsValidIndex(segment)) + return IdRangeOffsetOffset(seg_count_) + segment * DataSize::kUSHORT; + return -1; +} + +int32_t CMapTable::CMapFormat4::GlyphIdArray(int32_t index) { + return data_->ReadUShort(glyph_id_array_offset_ + index * DataSize::kUSHORT); +} + +int32_t CMapTable::CMapFormat4::Language() { + return Language(data_); +} + + +CMapTable::CMap::CharacterIterator* CMapTable::CMapFormat4::Iterator() { + return new CharacterIterator(this); +} + +/****************************************************************************** + * CMapTable::CMapFormat4::CharacterIterator class + ******************************************************************************/ +CMapTable::CMapFormat4::CharacterIterator::CharacterIterator( + CMapFormat4* parent) + : parent_(parent), + segment_index_(0), + first_char_in_segment_(-1), + last_char_in_segment_(-1), + next_char_(-1), + next_char_set_(false) { +} + +bool CMapTable::CMapFormat4::CharacterIterator::HasNext() { + if (next_char_set_) + return true; + while (segment_index_ < parent_->seg_count_) { + if (first_char_in_segment_ < 0) { + first_char_in_segment_ = parent_->StartCode(segment_index_); + last_char_in_segment_ = parent_->EndCode(segment_index_); + next_char_ = first_char_in_segment_; + next_char_set_ = true; + return true; + } + if (next_char_ < last_char_in_segment_) { + next_char_++; + next_char_set_ = true; + return true; + } + segment_index_++; + first_char_in_segment_ = -1; + } + return false; +} + +int32_t CMapTable::CMapFormat4::CharacterIterator::Next() { + if (!next_char_set_) { + if (!HasNext()) { +#if defined (SFNTLY_NO_EXCEPTION) + return -1; +#else + throw NoSuchElementException("No more characters to iterate."); +#endif + } + } + next_char_set_ = false; + return next_char_; +} + +/****************************************************************************** + * CMapTable::CMapFormat4::Builder::Segment class + ******************************************************************************/ +CMapTable::CMapFormat4::Builder::Segment::Segment() {} + +CMapTable::CMapFormat4::Builder::Segment::Segment(Segment* other) + : start_count_(other->start_count_), + end_count_(other->end_count_), + id_delta_(other->id_delta_), + id_range_offset_(other->id_range_offset_) { +} + +CMapTable::CMapFormat4::Builder::Segment::Segment(int32_t start_count, + int32_t end_count, + int32_t id_delta, + int32_t id_range_offset) + : start_count_(start_count), + end_count_(end_count), + id_delta_(id_delta), + id_range_offset_(id_range_offset) { +} + +CMapTable::CMapFormat4::Builder::Segment::~Segment() {} + +int32_t CMapTable::CMapFormat4::Builder::Segment::start_count() { + return start_count_; +} + +void +CMapTable::CMapFormat4::Builder::Segment::set_start_count(int32_t start_count) { + start_count_ = start_count; +} + +int32_t CMapTable::CMapFormat4::Builder::Segment::end_count() { + return end_count_; +} + +void +CMapTable::CMapFormat4::Builder::Segment::set_end_count(int32_t end_count) { + end_count_ = end_count; +} + +int32_t CMapTable::CMapFormat4::Builder::Segment::id_delta() { + return id_delta_; +} + +void +CMapTable::CMapFormat4::Builder::Segment::set_id_delta(int32_t id_delta) { + id_delta_ = id_delta; +} + +int32_t CMapTable::CMapFormat4::Builder::Segment::id_range_offset() { + return id_range_offset_; +} + +void +CMapTable::CMapFormat4::Builder::Segment:: +set_id_range_offset(int32_t id_range_offset) { + id_range_offset_ = id_range_offset; +} + +// static +CALLER_ATTACH SegmentList* +CMapTable::CMapFormat4::Builder::Segment::DeepCopy(SegmentList* original) { + SegmentList* list = new SegmentList; + for (SegmentList::iterator it = original->begin(), + e = original->end(); it != e; ++it) { + list->push_back(*it); + } + return list; +} + +/****************************************************************************** + * CMapTable::CMapFormat4::Builder class + ******************************************************************************/ +CALLER_ATTACH CMapTable::CMapFormat4::Builder* +CMapTable::CMapFormat4::Builder::NewInstance(ReadableFontData* data, + int32_t offset, + const CMapId& cmap_id) { + ReadableFontDataPtr rdata; + if (data) { + rdata.Attach + (down_cast + (data->Slice(offset, + data->ReadUShort(offset + Offset::kFormat4Length)))); + } + return new Builder(rdata, CMapFormat::kFormat4, cmap_id); +} + +CALLER_ATTACH CMapTable::CMapFormat4::Builder* +CMapTable::CMapFormat4::Builder::NewInstance(WritableFontData* data, + int32_t offset, + const CMapId& cmap_id) { + WritableFontDataPtr wdata; + if (data) { + wdata.Attach + (down_cast + (data->Slice(offset, + data->ReadUShort(offset + Offset::kFormat4Length)))); + } + return new Builder(wdata, CMapFormat::kFormat4, cmap_id); +} + +CALLER_ATTACH CMapTable::CMapFormat4::Builder* +CMapTable::CMapFormat4::Builder::NewInstance(const CMapId& cmap_id) { + return new Builder(cmap_id); +} + +CMapTable::CMapFormat4::Builder::Builder(ReadableFontData* data, int32_t offset, + const CMapId& cmap_id) + : CMap::Builder(data, CMapFormat::kFormat4, cmap_id) { + UNREFERENCED_PARAMETER(offset); +} + +CMapTable::CMapFormat4::Builder::Builder(WritableFontData* data, int32_t offset, + const CMapId& cmap_id) + : CMap::Builder(data, CMapFormat::kFormat4, cmap_id) { + UNREFERENCED_PARAMETER(offset); +} + +CMapTable::CMapFormat4::Builder::Builder(SegmentList* segments, + IntegerList* glyph_id_array, + const CMapId& cmap_id) + : CMap::Builder(reinterpret_cast(NULL), + CMapFormat::kFormat4, cmap_id), + segments_(segments->begin(), segments->end()), + glyph_id_array_(glyph_id_array->begin(), glyph_id_array->end()) { + set_model_changed(); +} + +CMapTable::CMapFormat4::Builder::Builder(const CMapId& cmap_id) + : CMap::Builder(reinterpret_cast(NULL), + CMapFormat::kFormat4, cmap_id) { +} + +CMapTable::CMapFormat4::Builder::~Builder() {} + +void CMapTable::CMapFormat4::Builder::Initialize(ReadableFontData* data) { + if (data == NULL || data->Length() == 0) + return; + + // build segments + int32_t seg_count = CMapFormat4::SegCount(data); + for (int32_t index = 0; index < seg_count; ++index) { + Ptr segment = new Segment; + segment->set_start_count(CMapFormat4::StartCode(data, seg_count, index)); +#if defined SFNTLY_DEBUG_CMAP + fprintf(stderr, "Segment %d; start %d\n", index, segment->start_count()); +#endif + segment->set_end_count(CMapFormat4::EndCode(data, seg_count, index)); + segment->set_id_delta(CMapFormat4::IdDelta(data, seg_count, index)); + segment->set_id_range_offset(CMapFormat4::IdRangeOffset(data, + seg_count, + index)); + segments_.push_back(segment); + } + + // build glyph id array + int32_t glyph_id_array_offset = CMapFormat4::GlyphIdArrayOffset(seg_count); + int32_t glyph_id_array_length = + (CMapFormat4::Length(data) - glyph_id_array_offset) + / DataSize::kUSHORT; + fprintf(stderr, "id array size %d\n", glyph_id_array_length); + for (int32_t i = 0; i < glyph_id_array_length; i += DataSize::kUSHORT) { + glyph_id_array_.push_back(data->ReadUShort(glyph_id_array_offset + i)); + } +} + +SegmentList* CMapTable::CMapFormat4::Builder::segments() { + if (segments_.empty()) { + Initialize(InternalReadData()); + set_model_changed(); + } + return &segments_; +} + +void CMapTable::CMapFormat4::Builder::set_segments(SegmentList* segments) { + segments_.assign(segments->begin(), segments->end()); + set_model_changed(); +} + +IntegerList* CMapTable::CMapFormat4::Builder::glyph_id_array() { + if (glyph_id_array_.empty()) { + Initialize(InternalReadData()); + set_model_changed(); + } + return &glyph_id_array_; +} + +void CMapTable::CMapFormat4::Builder:: +set_glyph_id_array(IntegerList* glyph_id_array) { + glyph_id_array_.assign(glyph_id_array->begin(), glyph_id_array->end()); + set_model_changed(); +} + +CALLER_ATTACH FontDataTable* +CMapTable::CMapFormat4::Builder::SubBuildTable(ReadableFontData* data) { + FontDataTablePtr table = new CMapFormat4(data, cmap_id()); + return table.Detach(); +} + +void CMapTable::CMapFormat4::Builder::SubDataSet() { + segments_.clear(); + glyph_id_array_.clear(); + set_model_changed(); +} + +int32_t CMapTable::CMapFormat4::Builder::SubDataSizeToSerialize() { + if (!model_changed()) { + return CMap::Builder::SubDataSizeToSerialize(); + } + int32_t size = Offset::kFormat4FixedSize + segments_.size() + * (3 * DataSize::kUSHORT + DataSize::kSHORT) + + glyph_id_array_.size() * DataSize::kSHORT; + return size; +} + +bool CMapTable::CMapFormat4::Builder::SubReadyToSerialize() { + if (!model_changed()) { + return CMap::Builder::SubReadyToSerialize(); + } + if (!segments()->empty()) { + return true; + } + return false; +} + +int32_t +CMapTable::CMapFormat4::Builder::SubSerialize(WritableFontData* new_data) { + if (!model_changed()) { + return CMap::Builder::SubSerialize(new_data); + } + int32_t index = 0; + index += new_data->WriteUShort(index, CMapFormat::kFormat4); + index += DataSize::kUSHORT; // length - write this at the end + index += new_data->WriteUShort(index, language()); + + int32_t seg_count = segments_.size(); + index += new_data->WriteUShort(index, seg_count * 2); + int32_t log2_seg_count = FontMath::Log2(seg_count); + int32_t search_range = 1 << (log2_seg_count + 1); + index += new_data->WriteUShort(index, search_range); + int32_t entry_selector = log2_seg_count; + index += new_data->WriteUShort(index, entry_selector); + int32_t range_shift = 2 * seg_count - search_range; + index += new_data->WriteUShort(index, range_shift); + + for (int32_t i = 0; i < seg_count; ++i) { + index += new_data->WriteUShort(index, segments_[i]->end_count()); + } + index += new_data->WriteUShort(index, 0); // reserved ushort + for (int32_t i = 0; i < seg_count; ++i) { +#if defined SFNTLY_DEBUG_CMAP + fprintf(stderr, "Segment %d; start %d\n", i, segments_[i]->start_count()); +#endif + index += new_data->WriteUShort(index, segments_[i]->start_count()); + } + for (int32_t i = 0; i < seg_count; ++i) { + index += new_data->WriteShort(index, segments_[i]->id_delta()); + } + for (int32_t i = 0; i < seg_count; ++i) { + index += new_data->WriteUShort(index, segments_[i]->id_range_offset()); + } + +#if defined SFNTLY_DEBUG_CMAP + fprintf(stderr, "Glyph id array size %lu\n", glyph_id_array_.size()); +#endif + for (size_t i = 0; i < glyph_id_array_.size(); ++i) { + index += new_data->WriteUShort(index, glyph_id_array_[i]); + } + + new_data->WriteUShort(Offset::kFormat4Length, index); + return index; +} + +/****************************************************************************** + * CMapTable::Builder class + ******************************************************************************/ +CMapTable::Builder::Builder(Header* header, WritableFontData* data) + : SubTableContainerTable::Builder(header, data), version_(0) { +} + +CMapTable::Builder::Builder(Header* header, ReadableFontData* data) + : SubTableContainerTable::Builder(header, data), version_(0) { +} + +CMapTable::Builder::~Builder() { +} + +int32_t CMapTable::Builder::SubSerialize(WritableFontData* new_data) { + int32_t size = new_data->WriteUShort(CMapTable::Offset::kVersion, + version_); + size += new_data->WriteUShort(CMapTable::Offset::kNumTables, + GetCMapBuilders()->size()); + + int32_t index_offset = size; + size += GetCMapBuilders()->size() * CMapTable::Offset::kEncodingRecordSize; + for (CMapBuilderMap::iterator it = GetCMapBuilders()->begin(), + e = GetCMapBuilders()->end(); it != e; ++it) { + CMapBuilderPtr b = it->second; + // header entry + index_offset += new_data->WriteUShort(index_offset, b->platform_id()); + index_offset += new_data->WriteUShort(index_offset, b->encoding_id()); + index_offset += new_data->WriteULong(index_offset, size); + + // cmap + FontDataPtr slice; + slice.Attach(new_data->Slice(size)); + size += b->SubSerialize(down_cast(slice.p_)); + } + return size; +} + +bool CMapTable::Builder::SubReadyToSerialize() { + if (GetCMapBuilders()->empty()) + return false; + + // check each table + for (CMapBuilderMap::iterator it = GetCMapBuilders()->begin(), + e = GetCMapBuilders()->end(); it != e; ++it) { + if (!it->second->SubReadyToSerialize()) + return false; + } + return true; +} + +int32_t CMapTable::Builder::SubDataSizeToSerialize() { + if (GetCMapBuilders()->empty()) + return 0; + + bool variable = false; + int32_t size = CMapTable::Offset::kEncodingRecordStart + + GetCMapBuilders()->size() * CMapTable::Offset::kEncodingRecordSize; + + // calculate size of each table + for (CMapBuilderMap::iterator it = GetCMapBuilders()->begin(), + e = GetCMapBuilders()->end(); it != e; ++it) { + int32_t cmap_size = it->second->SubDataSizeToSerialize(); + size += abs(cmap_size); + variable |= cmap_size <= 0; + } + return variable ? -size : size; +} + +void CMapTable::Builder::SubDataSet() { + GetCMapBuilders()->clear(); + Table::Builder::set_model_changed(); +} + +CALLER_ATTACH FontDataTable* + CMapTable::Builder::SubBuildTable(ReadableFontData* data) { + FontDataTablePtr table = new CMapTable(header(), data); + return table.Detach(); +} + +CALLER_ATTACH CMapTable::Builder* + CMapTable::Builder::CreateBuilder(Header* header, + WritableFontData* data) { + Ptr builder; + builder = new CMapTable::Builder(header, data); + return builder.Detach(); +} + +// static +CALLER_ATTACH CMapTable::CMap::Builder* + CMapTable::Builder::CMapBuilder(ReadableFontData* data, int32_t index) { + if (index < 0 || index > NumCMaps(data)) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundException( + "CMap table is outside of the bounds of the known tables."); +#endif + return NULL; + } + + int32_t platform_id = data->ReadUShort(Offset::kEncodingRecordPlatformId + + OffsetForEncodingRecord(index)); + int32_t encoding_id = data->ReadUShort(Offset::kEncodingRecordEncodingId + + OffsetForEncodingRecord(index)); + int32_t offset = data->ReadULongAsInt(Offset::kEncodingRecordOffset + + OffsetForEncodingRecord(index)); + return CMap::Builder::GetBuilder(data, offset, + NewCMapId(platform_id, encoding_id)); +} + +// static +int32_t CMapTable::Builder::NumCMaps(ReadableFontData* data) { + if (data == NULL) { + return 0; + } + return data->ReadUShort(Offset::kNumTables); +} + +int32_t CMapTable::Builder::NumCMaps() { + return GetCMapBuilders()->size(); +} + +void CMapTable::Builder::Initialize(ReadableFontData* data) { + int32_t num_cmaps = NumCMaps(data); + for (int32_t i = 0; i < num_cmaps; ++i) { + CMapTable::CMap::Builder* cmap_builder = CMapBuilder(data, i); + if (!cmap_builder) + continue; + cmap_builders_[cmap_builder->cmap_id()] = cmap_builder; + } +} + +CMapTable::CMap::Builder* CMapTable::Builder::NewCMapBuilder( + const CMapId& cmap_id, + ReadableFontData* data) { + Ptr wfd; + wfd.Attach(WritableFontData::CreateWritableFontData(data->Size())); + data->CopyTo(wfd.p_); + CMapTable::CMapBuilderPtr builder; + builder.Attach(CMap::Builder::GetBuilder(wfd.p_, 0, cmap_id)); + CMapBuilderMap* cmap_builders = CMapTable::Builder::GetCMapBuilders(); + cmap_builders->insert(std::make_pair(cmap_id, builder.p_)); + return builder.Detach(); +} + +CMapTable::CMap::Builder* +CMapTable::Builder::NewCMapBuilder(int32_t format, const CMapId& cmap_id) { + Ptr cmap_builder; + cmap_builder.Attach(CMap::Builder::GetBuilder(format, cmap_id)); + CMapBuilderMap* cmap_builders = CMapTable::Builder::GetCMapBuilders(); + cmap_builders->insert(std::make_pair(cmap_id, cmap_builder.p_)); + return cmap_builder.Detach(); +} + +CMapTable::CMap::Builder* +CMapTable::Builder::CMapBuilder(const CMapId& cmap_id) { + CMapBuilderMap* cmap_builders = this->GetCMapBuilders(); + CMapBuilderMap::iterator builder = cmap_builders->find(cmap_id); + if (builder != cmap_builders->end()) + return builder->second; +#ifndef SFNTLY_NO_EXCEPTION + throw NoSuchElementException("No builder found for cmap_id"); +#else + return NULL; +#endif +} + +CMapTable::CMapBuilderMap* CMapTable::Builder::GetCMapBuilders() { + if (cmap_builders_.empty()) { + Initialize(InternalReadData()); + set_model_changed(); + } + return &cmap_builders_; +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/core/cmap_table.h b/src/sfntly/src/sfntly/table/core/cmap_table.h new file mode 100644 index 0000000000..29ce3e4189 --- /dev/null +++ b/src/sfntly/src/sfntly/table/core/cmap_table.h @@ -0,0 +1,711 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_CMAP_TABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_CMAP_TABLE_H_ + +// type.h needs to be included first because of building issues on Windows +// Type aliases we delcare are defined in other headers and make the build +// fail otherwise. +#include "sfntly/port/type.h" +#include +#include + +#include "sfntly/port/refcount.h" +#include "sfntly/table/subtable.h" +#include "sfntly/table/subtable_container_table.h" + +namespace sfntly { + +// CMap subtable formats +struct CMapFormat { + enum { + kFormat0 = 0, + kFormat2 = 2, + kFormat4 = 4, + kFormat6 = 6, + kFormat8 = 8, + kFormat10 = 10, + kFormat12 = 12, + kFormat13 = 13, + kFormat14 = 14 + }; +}; + +// A CMap table +class CMapTable : public SubTableContainerTable, public RefCounted { +public: + // CMapTable::CMapId + struct CMapId { + int32_t platform_id; + int32_t encoding_id; + bool operator==(const CMapId& obj) const { + return platform_id == obj.platform_id && encoding_id == obj.encoding_id; + } + }; + static CMapId WINDOWS_BMP; + static CMapId WINDOWS_UCS4; + static CMapId MAC_ROMAN; + + // CMapTable::CMapIdComparator + class CMapIdComparator { + public: + bool operator()(const CMapId& lhs, const CMapId& rhs) const; + }; + + // A filter on cmap + // CMapTable::CMapFilter + class CMapFilter { + public: + // Test on whether the cmap is acceptable or not + // @param cmap_id the id of the cmap + // @return true if the cmap is acceptable; false otherwise + virtual bool accept(const CMapId& cmap_id) const = 0; + // Make gcc -Wnon-virtual-dtor happy. + virtual ~CMapFilter() {} + }; + + // Filters CMaps by CMapId to implement CMapTable::get() + // wanted_id is the CMap we'd like to find. + // We compare the current CMap to it either by equality (==) or using a + // comparator. + // CMapTable::CMapIdFilter + class CMapIdFilter : public CMapFilter { + public: + explicit CMapIdFilter(const CMapId wanted_id); + CMapIdFilter(const CMapId wanted_id, + const CMapIdComparator* comparator); + ~CMapIdFilter() {} + virtual bool accept(const CMapId& cmap_id) const; + private: + CMapIdFilter& operator=(const CMapIdFilter& that); + const CMapId wanted_id_; + const CMapIdComparator *comparator_; + }; + + // The abstract base class for all cmaps. + // + // CMap equality is based on the equality of the (@link {@link CMapId} that + // defines the CMap. In the cmap table for a font there can only be one cmap + // with a given cmap id (pair of platform and encoding ids) no matter what the + // type of the cmap is. + // + // The cmap offers CharacterIterator to allow iteration over + // characters that are mapped by the cmap. This iteration mostly returns the + // characters mapped by the cmap. It will return all characters mapped by the + // cmap to anything but .notdef but it may return some that are not + // mapped or are mapped to .notdef. Various cmap tables provide ranges and + // such to describe characters for lookup but without going the full way to + // mapping to the glyph id it isn't always possible to tell if a character + // will end up with a valid glyph id. So, some of the characters returned from + // the Iterator may still end up pointing to the .notdef glyph. However, the + // number of such characters should be small in most cases with well designed + // cmaps. + class Builder; + class CMap : public SubTable { + public: + // CMapTable::CMap::Builder + class Builder : public SubTable::Builder { + public: + virtual ~Builder(); + + CALLER_ATTACH static Builder* + GetBuilder(ReadableFontData* data, + int32_t offset, + const CMapId& cmap_id); + CALLER_ATTACH static Builder* + GetBuilder(int32_t format, + const CMapId& cmap_id); + + // Note: yes, an object is returned on stack since it's small enough. + virtual CMapId cmap_id() { return cmap_id_; } + virtual int32_t platform_id() { return cmap_id_.platform_id; } + virtual int32_t encoding_id() { return cmap_id_.encoding_id; } + virtual int32_t format() { return format_; } + virtual int32_t language() { return language_; } + virtual void set_language(int32_t language) { language_ = language; } + + protected: + Builder(ReadableFontData* data, + int32_t format, + const CMapId& cmap_id); + Builder(WritableFontData* data, + int32_t format, + const CMapId& cmap_id); + + virtual int32_t SubSerialize(WritableFontData* new_data); + virtual bool SubReadyToSerialize(); + virtual int32_t SubDataSizeToSerialize(); + virtual void SubDataSet(); + + private: + int32_t format_; + CMapId cmap_id_; + int32_t language_; + + friend class CMapTable::Builder; + }; + // Abstract CMap character iterator + // The fully qualified name is CMapTable::CMap::CharacterIterator + class CharacterIterator { + public: + virtual ~CharacterIterator() {} + virtual bool HasNext() = 0; + // Returns -1 if there are no more characters to iterate through + // and exceptions are turned off + virtual int32_t Next() = 0; + + protected: + // Use the CMap::Iterator method below instead of directly requesting + // a CharacterIterator. + CharacterIterator() {} + }; + + CMap(ReadableFontData* data, int32_t format, const CMapId& cmap_id); + virtual ~CMap(); + + virtual CMap::CharacterIterator* Iterator() = 0; + + virtual int32_t format() { return format_; } + virtual CMapId cmap_id() { return cmap_id_; } + virtual int32_t platform_id() { return cmap_id_.platform_id; } + virtual int32_t encoding_id() { return cmap_id_.encoding_id; } + + // Get the language of the cmap. + // + // Note on the language field in 'cmap' subtables: The language field must + // be set to zero for all cmap subtables whose platform IDs are other than + // Macintosh (platform ID 1). For cmap subtables whose platform IDs are + // Macintosh, set this field to the Macintosh language ID of the cmap + // subtable plus one, or to zero if the cmap subtable is not + // language-specific. For example, a Mac OS Turkish cmap subtable must set + // this field to 18, since the Macintosh language ID for Turkish is 17. A + // Mac OS Roman cmap subtable must set this field to 0, since Mac OS Roman + // is not a language-specific encoding. + // + // @return the language id + virtual int32_t Language() = 0; + + // Gets the glyph id for the character code provided. + // The character code provided must be in the encoding used by the cmap + // table. + virtual int32_t GlyphId(int32_t character) = 0; + + private: + int32_t format_; + CMapId cmap_id_; + }; + typedef Ptr CMapPtr; + typedef Ptr CMapBuilderPtr; + typedef std::map CMapBuilderMap; + + // A cmap format 0 sub table + class CMapFormat0 : public CMap, public RefCounted { + public: + // The fully qualified name is CMapTable::CMapFormat0::Builder + class Builder : public CMap::Builder, + public RefCounted { + public: + CALLER_ATTACH static Builder* NewInstance(ReadableFontData* data, + int32_t offset, + const CMapId& cmap_id); + CALLER_ATTACH static Builder* NewInstance(WritableFontData* data, + int32_t offset, + const CMapId& cmap_id); + CALLER_ATTACH static Builder* NewInstance(const CMapId& cmap_id); + virtual ~Builder(); + + protected: + virtual CALLER_ATTACH FontDataTable* + SubBuildTable(ReadableFontData* data); + + private: + // When creating a new CMapFormat0 Builder, use NewInstance instead of + // the constructors! This avoids a memory leak when slicing the FontData. + Builder(ReadableFontData* data, int32_t offset, const CMapId& cmap_id); + Builder(WritableFontData* data, int32_t offset, const CMapId& cmap_id); + Builder(const CMapId& cmap_id); + }; + + // The fully qualified name is CMapTable::CMapFormat0::CharacterIterator + class CharacterIterator : public CMap::CharacterIterator { + public: + virtual ~CharacterIterator(); + virtual bool HasNext(); + virtual int32_t Next(); + + private: + CharacterIterator(int32_t start, int32_t end); + friend class CMapFormat0; + int32_t character_, max_character_; + }; + + virtual ~CMapFormat0(); + virtual int32_t Language(); + virtual int32_t GlyphId(int32_t character); + CMap::CharacterIterator* Iterator(); + + private: + CMapFormat0(ReadableFontData* data, const CMapId& cmap_id); + }; + + // A cmap format 2 sub table + // The format 2 cmap is used for multi-byte encodings such as SJIS, + // EUC-JP/KR/CN, Big5, etc. + class CMapFormat2 : public CMap, public RefCounted { + public: + // CMapTable::CMapFormat2::Builder + class Builder : public CMap::Builder, + public RefCounted { + public: + Builder(ReadableFontData* data, + int32_t offset, + const CMapId& cmap_id); + Builder(WritableFontData* data, + int32_t offset, + const CMapId& cmap_id); + virtual ~Builder(); + + protected: + virtual CALLER_ATTACH FontDataTable* + SubBuildTable(ReadableFontData* data); + }; + // CMapTable::CMapFormat2::CharacterIterator + class CharacterIterator : public CMap::CharacterIterator { + public: + virtual ~CharacterIterator(); + virtual bool hasNext(); + virtual int32_t next(); + + private: + CharacterIterator(); + }; + + virtual int32_t Language(); + virtual int32_t GlyphId(int32_t character); + + // Returns how many bytes would be consumed by a lookup of this character + // with this cmap. This comes about because the cmap format 2 table is + // designed around multi-byte encodings such as SJIS, EUC-JP, Big5, etc. + // return the number of bytes consumed from this "character" - either 1 or 2 + virtual int32_t BytesConsumed(int32_t character); + + virtual ~CMapFormat2(); + + private: + CMapFormat2(ReadableFontData* data, const CMapId& cmap_id); + + int32_t SubHeaderOffset(int32_t sub_header_index); + int32_t FirstCode(int32_t sub_header_index); + int32_t EntryCount(int32_t sub_header_index); + int32_t IdRangeOffset(int32_t sub_header_index); + int32_t IdDelta(int32_t sub_header_index); + CMap::CharacterIterator* Iterator(); + }; + + // CMapTable::CMapFormat4 + class CMapFormat4 : public CMap, + public RefCounted { + public: + // CMapTable::CMapFormat4::Builder + class Builder : public CMap::Builder, + public RefCounted { + public: + // CMapTable::CMapFormat4::Builder::Segment + class Segment : public RefCounted { + public: + Segment(); + explicit Segment(Segment* other); + Segment(int32_t start_count, + int32_t end_count, + int32_t id_delta, + int32_t id_range_offset); + ~Segment(); + + // @return the startCount + int32_t start_count(); + // @param startCount the startCount to set + void set_start_count(int32_t start_count); + // @return the endCount + int32_t end_count(); + // @param endcount the endCount to set + void set_end_count(int32_t end_count); + // @return the idDelta + int32_t id_delta(); + // @param idDelta the idDelta to set + void set_id_delta(int32_t id_delta); + // @return the idRangeOffset + int32_t id_range_offset(); + // @param idRangeOffset the idRangeOffset to set + void set_id_range_offset(int32_t id_range_offset); + + static CALLER_ATTACH + std::vector >* + DeepCopy(std::vector >* original); + + private: + int32_t start_count_; + int32_t end_count_; + int32_t id_delta_; + int32_t id_range_offset_; + }; + typedef std::vector > SegmentList; + + static CALLER_ATTACH Builder* NewInstance(WritableFontData* data, + int32_t offset, + const CMapId& cmap_id); + static CALLER_ATTACH Builder* NewInstance(ReadableFontData* data, + int32_t offset, + const CMapId& cmap_id); + static CALLER_ATTACH Builder* NewInstance(const CMapId& cmap_id); + virtual ~Builder(); + SegmentList* segments(); + void set_segments(SegmentList* segments); + IntegerList* glyph_id_array(); + void set_glyph_id_array(IntegerList* glyph_id_array); + + protected: + Builder(WritableFontData* data, int32_t offset, const CMapId& cmap_id); + Builder(ReadableFontData* data, int32_t offset, const CMapId& cmap_id); + Builder(SegmentList* segments, IntegerList* glyph_id_array, + const CMapId& cmap_id); + explicit Builder(const CMapId& cmap_id); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable( + ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + + private: + void Initialize(ReadableFontData* data); + + SegmentList segments_; + IntegerList glyph_id_array_; + }; + + CMap::CharacterIterator* Iterator(); + // CMapTable::CMapFormat4::CharacterIterator + class CharacterIterator : public CMap::CharacterIterator { + public: + bool HasNext(); + int32_t Next(); + virtual ~CharacterIterator() {} + + private: + explicit CharacterIterator(CMapFormat4 *parent); + friend CMap::CharacterIterator* CMapFormat4::Iterator(); + + CMapFormat4* parent_; + int32_t segment_index_; + int32_t first_char_in_segment_; + int32_t last_char_in_segment_; + int32_t next_char_; + bool next_char_set_; + }; + + virtual int32_t GlyphId(int32_t character); + + // Lower level glyph code retrieval that requires processing the Format 4 + // segments to use. + // @param segment the cmap segment + // @param startCode the start code for the segment + // @param character the character to be looked up + // @return the glyph id for the character; CMapTable.NOTDEF if not found + int32_t RetrieveGlyphId(int32_t segment, + int32_t start_count, + int32_t character); + virtual int32_t Language(); + + // Get the count of the number of segments in this cmap. + // @return the number of segments + int32_t seg_count(); + int32_t Length(); + // Get the start code for a segment. + // @param segment the segment in the lookup table + // @return the start code for a segment + int32_t StartCode(int32_t segment); + // Get the end code for a segment. + // @param segment the segment in the look up table + // @return the end code for the segment + int32_t EndCode(int32_t segment); + // Get the id delta for a segment + // @param segment the segment in the look up table + // @return the id delta for the segment + int32_t IdDelta(int32_t segment); + // Get the id range offset for a segment + // @param segment the segment in the look up table + // @return the id range offset for the segment + int32_t IdRangeOffset(int32_t segment); + // Get the location of the id range offset for a segment + // @param segment the segment in the look up table + // @return the location of the id range offset for the segment + int32_t IdRangeOffsetLocation(int32_t segment); + // Declared above to allow friending inside CharacterIterator class. + // CMap::CharacterIterator* Iterator(); + virtual ~CMapFormat4(); + + protected: + CMapFormat4(ReadableFontData* data, const CMapId& cmap_id); + + private: + static int32_t Language(ReadableFontData* data); + static int32_t Length(ReadableFontData* data); + static int32_t SegCount(ReadableFontData* data); + static int32_t StartCode(ReadableFontData* data, + int32_t seg_count, + int32_t index); + static int32_t StartCodeOffset(int32_t seg_count); + static int32_t EndCode(ReadableFontData* data, + int32_t seg_count, + int32_t index); + static int32_t IdDelta(ReadableFontData* data, + int32_t seg_count, + int32_t index); + static int32_t IdDeltaOffset(int32_t seg_count); + static int32_t IdRangeOffset(ReadableFontData* data, + int32_t seg_count, + int32_t index); + static int32_t IdRangeOffsetOffset(int32_t seg_count); + static int32_t GlyphIdArrayOffset(int32_t seg_count); + // Refactored void to bool to work without exceptions. + bool IsValidIndex(int32_t segment); + int32_t GlyphIdArray(int32_t index); + + int32_t seg_count_; + int32_t start_code_offset_; + int32_t end_code_offset_; + int32_t id_delta_offset_; + int32_t id_range_offset_offset_; + int32_t glyph_id_array_offset_; + }; + + // CMapTable::Builder + class Builder : public SubTableContainerTable::Builder, + public RefCounted { + public: + // Constructor scope is public because C++ does not allow base class to + // instantiate derived class with protected constructors. + Builder(Header* header, WritableFontData* data); + Builder(Header* header, ReadableFontData* data); + virtual ~Builder(); + + virtual int32_t SubSerialize(WritableFontData* new_data); + virtual bool SubReadyToSerialize(); + virtual int32_t SubDataSizeToSerialize(); + virtual void SubDataSet(); + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + + static CALLER_ATTACH Builder* CreateBuilder(Header* header, + WritableFontData* data); + + CMap::Builder* NewCMapBuilder(const CMapId& cmap_id, + ReadableFontData* data); + // Create a new empty CMapBuilder of the type specified in the id. + CMap::Builder* NewCMapBuilder(int32_t format, const CMapId& cmap_id); + CMap::Builder* CMapBuilder(const CMapId& cmap_id); + + int32_t NumCMaps(); + void SetVersion(int32_t version); + + CMapBuilderMap* GetCMapBuilders(); + + protected: + static CALLER_ATTACH CMap::Builder* CMapBuilder(ReadableFontData* data, + int32_t index); + + private: + void Initialize(ReadableFontData* data); + static int32_t NumCMaps(ReadableFontData* data); + + int32_t version_; + CMapBuilderMap cmap_builders_; + }; + typedef Ptr CMapTableBuilderPtr; + + class CMapIterator { + public: + // If filter is NULL, filter through all tables. + CMapIterator(CMapTable* table, const CMapFilter* filter); + bool HasNext(); + CMap* Next(); + + private: + int32_t table_index_; + const CMapFilter* filter_; + CMapTable* table_; + }; + + // Make a CMapId from a platform_id, encoding_id pair + static CMapId NewCMapId(int32_t platform_id, int32_t encoding_id); + // Make a CMapId from another CMapId + static CMapId NewCMapId(const CMapId& obj); + + // Get the CMap with the specified parameters if it exists. + // Returns NULL otherwise. + CALLER_ATTACH CMap* GetCMap(const int32_t index); + CALLER_ATTACH CMap* GetCMap(const int32_t platform_id, + const int32_t encoding_id); + CALLER_ATTACH CMap* GetCMap(const CMapId GetCMap_id); + + // Get the table version. + virtual int32_t Version(); + + // Get the number of cmaps within the CMap table. + virtual int32_t NumCMaps(); + + // Get the cmap id for the cmap with the given index. + // Note: yes, an object is returned on stack since it's small enough. + // This function is renamed from cmapId to GetCMapId(). + virtual CMapId GetCMapId(int32_t index); + + virtual int32_t PlatformId(int32_t index); + virtual int32_t EncodingId(int32_t index); + + // Get the offset in the table data for the cmap table with the given index. + // The offset is from the beginning of the table. + virtual int32_t Offset(int32_t index); + + virtual ~CMapTable(); + + static const int32_t NOTDEF; + + private: + // Offsets to specific elements in the underlying data. These offsets are + // relative to the start of the table or the start of sub-blocks within + // the table. + struct Offset { + enum { + kVersion = 0, + kNumTables = 2, + kEncodingRecordStart = 4, + + // offsets relative to the encoding record + kEncodingRecordPlatformId = 0, + kEncodingRecordEncodingId = 2, + kEncodingRecordOffset = 4, + kEncodingRecordSize = 8, + + kFormat = 0, + + // Format 0: Byte encoding table + kFormat0Format = 0, + kFormat0Length = 2, + kFormat0Language = 4, + kFormat0GlyphIdArray = 6, + + // Format 2: High-byte mapping through table + kFormat2Format = 0, + kFormat2Length = 2, + kFormat2Language = 4, + kFormat2SubHeaderKeys = 6, + kFormat2SubHeaders = 518, + // offset relative to the subHeader structure + kFormat2SubHeader_firstCode = 0, + kFormat2SubHeader_entryCount = 2, + kFormat2SubHeader_idDelta = 4, + kFormat2SubHeader_idRangeOffset = 6, + kFormat2SubHeader_structLength = 8, + + // Format 4: Segment mapping to delta values + kFormat4Format = 0, + kFormat4Length = 2, + kFormat4Language = 4, + kFormat4SegCountX2 = 6, + kFormat4SearchRange = 8, + kFormat4EntrySelector = 10, + kFormat4RangeShift = 12, + kFormat4EndCount = 14, + kFormat4FixedSize = 16, + + // format 6: Trimmed table mapping + kFormat6Format = 0, + kFormat6Length = 2, + kFormat6Language = 4, + kFormat6FirstCode = 6, + kFormat6EntryCount = 8, + kFormat6GlyphIdArray = 10, + + // Format 8: mixed 16-bit and 32-bit coverage + kFormat8Format = 0, + kFormat8Length = 4, + kFormat8Language = 8, + kFormat8Is32 = 12, + kFormat8nGroups204 = 8204, + kFormat8Groups208 = 8208, + // offset relative to the group structure + kFormat8Group_startCharCode = 0, + kFormat8Group_endCharCode = 4, + kFormat8Group_startGlyphId = 8, + kFormat8Group_structLength = 12, + + // Format 10: Trimmed array + kFormat10Format = 0, + kFormat10Length = 4, + kFormat10Language = 8, + kFormat10StartCharCode = 12, + kFormat10NumChars = 16, + kFormat10Glyphs0 = 20, + + // Format 12: Segmented coverage + kFormat12Format = 0, + kFormat12Length = 4, + kFormat12Language = 8, + kFormat12nGroups = 12, + kFormat12Groups = 16, + kFormat12Groups_structLength = 12, + // offsets within the group structure + kFormat12_startCharCode = 0, + kFormat12_endCharCode = 4, + kFormat12_startGlyphId = 8, + + // Format 13: Last Resort Font + kFormat13Format = 0, + kFormat13Length = 4, + kFormat13Language = 8, + kFormat13nGroups = 12, + kFormat13Groups = 16, + kFormat13Groups_structLength = 12, + // offsets within the group structure + kFormat13_startCharCode = 0, + kFormat13_endCharCode = 4, + kFormat13_glyphId = 8, + + // Format 14: Unicode Variation Sequences + kFormat14Format = 0, + kFormat14Length = 2, + + // TODO(stuartg): finish tables + // Default UVS Table + + // Non-default UVS Table + kLast = -1 + }; + }; + + CMapTable(Header* header, ReadableFontData* data); + + // Get the offset in the table data for the encoding record for the cmap with + // the given index. The offset is from the beginning of the table. + static int32_t OffsetForEncodingRecord(int32_t index); +}; +typedef std::vector CMapIdList; +typedef Ptr CMapTablePtr; +typedef std::vector > SegmentList; +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_CMAP_TABLE_H_ diff --git a/src/sfntly/src/sfntly/table/core/font_header_table.cc b/src/sfntly/src/sfntly/table/core/font_header_table.cc new file mode 100644 index 0000000000..60015ca954 --- /dev/null +++ b/src/sfntly/src/sfntly/table/core/font_header_table.cc @@ -0,0 +1,265 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/core/font_header_table.h" + +namespace sfntly { +/****************************************************************************** + * FontHeaderTable class + ******************************************************************************/ +FontHeaderTable::~FontHeaderTable() {} + +int32_t FontHeaderTable::TableVersion() { + return data_->ReadFixed(Offset::kTableVersion); +} + +int32_t FontHeaderTable::FontRevision() { + return data_->ReadFixed(Offset::kFontRevision); +} + +int64_t FontHeaderTable::ChecksumAdjustment() { + return data_->ReadULong(Offset::kCheckSumAdjustment); +} + +int64_t FontHeaderTable::MagicNumber() { + return data_->ReadULong(Offset::kMagicNumber); +} + +int32_t FontHeaderTable::FlagsAsInt() { + return data_->ReadUShort(Offset::kFlags); +} + +int32_t FontHeaderTable::UnitsPerEm() { + return data_->ReadUShort(Offset::kUnitsPerEm); +} + +int64_t FontHeaderTable::Created() { + return data_->ReadDateTimeAsLong(Offset::kCreated); +} + +int64_t FontHeaderTable::Modified() { + return data_->ReadDateTimeAsLong(Offset::kModified); +} + +int32_t FontHeaderTable::XMin() { + return data_->ReadUShort(Offset::kXMin); +} + +int32_t FontHeaderTable::YMin() { + return data_->ReadUShort(Offset::kYMin); +} + +int32_t FontHeaderTable::XMax() { + return data_->ReadUShort(Offset::kXMax); +} + +int32_t FontHeaderTable::YMax() { + return data_->ReadUShort(Offset::kYMax); +} + +int32_t FontHeaderTable::MacStyleAsInt() { + return data_->ReadUShort(Offset::kMacStyle); +} + +int32_t FontHeaderTable::LowestRecPPEM() { + return data_->ReadUShort(Offset::kLowestRecPPEM); +} + +int32_t FontHeaderTable::FontDirectionHint() { + return data_->ReadShort(Offset::kFontDirectionHint); +} + +int32_t FontHeaderTable::IndexToLocFormat() { + return data_->ReadShort(Offset::kIndexToLocFormat); +} + +int32_t FontHeaderTable::GlyphDataFormat() { + return data_->ReadShort(Offset::kGlyphDataFormat); +} + +FontHeaderTable::FontHeaderTable(Header* header, ReadableFontData* data) + : Table(header, data) { + IntegerList checksum_ranges; + checksum_ranges.push_back(0); + checksum_ranges.push_back(Offset::kCheckSumAdjustment); + checksum_ranges.push_back(Offset::kMagicNumber); + data_->SetCheckSumRanges(checksum_ranges); +} + +/****************************************************************************** + * FontHeaderTable::Builder class + ******************************************************************************/ +FontHeaderTable::Builder::Builder(Header* header, WritableFontData* data) + : TableBasedTableBuilder(header, data) { +} + +FontHeaderTable::Builder::Builder(Header* header, ReadableFontData* data) + : TableBasedTableBuilder(header, data) { +} + +FontHeaderTable::Builder::~Builder() {} + +CALLER_ATTACH FontDataTable* FontHeaderTable::Builder::SubBuildTable( + ReadableFontData* data) { + FontDataTablePtr table = new FontHeaderTable(header(), data); + return table.Detach(); +} + +int32_t FontHeaderTable::Builder::TableVersion() { + return down_cast(GetTable())->TableVersion(); +} + +void FontHeaderTable::Builder::SetTableVersion(int32_t version) { + InternalWriteData()->WriteFixed(Offset::kTableVersion, version); +} + +int32_t FontHeaderTable::Builder::FontRevision() { + return down_cast(GetTable())->FontRevision(); +} + +void FontHeaderTable::Builder::SetFontRevision(int32_t revision) { + InternalWriteData()->WriteFixed(Offset::kFontRevision, revision); +} + +int64_t FontHeaderTable::Builder::ChecksumAdjustment() { + return down_cast(GetTable())->ChecksumAdjustment(); +} + +void FontHeaderTable::Builder::SetChecksumAdjustment(int64_t adjustment) { + InternalWriteData()->WriteULong(Offset::kCheckSumAdjustment, adjustment); +} + +int64_t FontHeaderTable::Builder::MagicNumber() { + return down_cast(GetTable())->MagicNumber(); +} + +void FontHeaderTable::Builder::SetMagicNumber(int64_t magic_number) { + InternalWriteData()->WriteULong(Offset::kMagicNumber, magic_number); +} + +int32_t FontHeaderTable::Builder::FlagsAsInt() { + return down_cast(GetTable())->FlagsAsInt(); +} + +void FontHeaderTable::Builder::SetFlagsAsInt(int32_t flags) { + InternalWriteData()->WriteUShort(Offset::kFlags, flags); +} + +int32_t FontHeaderTable::Builder::UnitsPerEm() { + return down_cast(GetTable())->UnitsPerEm(); +} + +void FontHeaderTable::Builder::SetUnitsPerEm(int32_t units) { + InternalWriteData()->WriteUShort(Offset::kUnitsPerEm, units); +} + +int64_t FontHeaderTable::Builder::Created() { + return down_cast(GetTable())->Created(); +} + +void FontHeaderTable::Builder::SetCreated(int64_t date) { + InternalWriteData()->WriteDateTime(Offset::kCreated, date); +} + +int64_t FontHeaderTable::Builder::Modified() { + return down_cast(GetTable())->Modified(); +} + +void FontHeaderTable::Builder::SetModified(int64_t date) { + InternalWriteData()->WriteDateTime(Offset::kModified, date); +} + +int32_t FontHeaderTable::Builder::XMin() { + return down_cast(GetTable())->XMin(); +} + +void FontHeaderTable::Builder::SetXMin(int32_t xmin) { + InternalWriteData()->WriteShort(Offset::kXMin, xmin); +} + +int32_t FontHeaderTable::Builder::YMin() { + return down_cast(GetTable())->YMin(); +} + +void FontHeaderTable::Builder::SetYMin(int32_t ymin) { + InternalWriteData()->WriteShort(Offset::kYMin, ymin); +} + +int32_t FontHeaderTable::Builder::XMax() { + return down_cast(GetTable())->XMax(); +} + +void FontHeaderTable::Builder::SetXMax(int32_t xmax) { + InternalWriteData()->WriteShort(Offset::kXMax, xmax); +} + +int32_t FontHeaderTable::Builder::YMax() { + return down_cast(GetTable())->YMax(); +} + +void FontHeaderTable::Builder::SetYMax(int32_t ymax) { + InternalWriteData()->WriteShort(Offset::kYMax, ymax); +} + +int32_t FontHeaderTable::Builder::MacStyleAsInt() { + return down_cast(GetTable())->MacStyleAsInt(); +} + +void FontHeaderTable::Builder::SetMacStyleAsInt(int32_t style) { + InternalWriteData()->WriteUShort(Offset::kMacStyle, style); +} + +int32_t FontHeaderTable::Builder::LowestRecPPEM() { + return down_cast(GetTable())->LowestRecPPEM(); +} + +void FontHeaderTable::Builder::SetLowestRecPPEM(int32_t size) { + InternalWriteData()->WriteUShort(Offset::kLowestRecPPEM, size); +} + +int32_t FontHeaderTable::Builder::FontDirectionHint() { + return down_cast(GetTable())->FontDirectionHint(); +} + +void FontHeaderTable::Builder::SetFontDirectionHint(int32_t hint) { + InternalWriteData()->WriteShort(Offset::kFontDirectionHint, hint); +} + +int32_t FontHeaderTable::Builder::IndexToLocFormat() { + return down_cast(GetTable())->IndexToLocFormat(); +} + +void FontHeaderTable::Builder::SetIndexToLocFormat(int32_t format) { + InternalWriteData()->WriteShort(Offset::kIndexToLocFormat, format); +} + +int32_t FontHeaderTable::Builder::GlyphDataFormat() { + return down_cast(GetTable())->GlyphDataFormat(); +} + +void FontHeaderTable::Builder::SetGlyphDataFormat(int32_t format) { + InternalWriteData()->WriteShort(Offset::kGlyphDataFormat, format); +} + +CALLER_ATTACH FontHeaderTable::Builder* + FontHeaderTable::Builder::CreateBuilder(Header* header, + WritableFontData* data) { + Ptr builder; + builder = new FontHeaderTable::Builder(header, data); + return builder.Detach(); +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/core/font_header_table.h b/src/sfntly/src/sfntly/table/core/font_header_table.h new file mode 100644 index 0000000000..841955b423 --- /dev/null +++ b/src/sfntly/src/sfntly/table/core/font_header_table.h @@ -0,0 +1,168 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_FONT_HEADER_TABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_FONT_HEADER_TABLE_H_ + +#include "sfntly/table/table.h" +#include "sfntly/table/table_based_table_builder.h" + +namespace sfntly { + +struct IndexToLocFormat { + enum { + kShortOffset = 0, + kLongOffset = 1 + }; +}; + +struct FontDirectionHint { + enum { + kFullyMixed = 0, + kOnlyStrongLTR = 1, + kStrongLTRAndNeutral = 2, + kOnlyStrongRTL = -1, + kStrongRTLAndNeutral = -2 + }; +}; + +class FontHeaderTable : public Table, public RefCounted { + public: + class Builder : public TableBasedTableBuilder, public RefCounted { + public: + // Constructor scope altered to public because C++ does not allow base + // class to instantiate derived class with protected constructors. + Builder(Header* header, WritableFontData* data); + Builder(Header* header, ReadableFontData* data); + virtual ~Builder(); + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + + virtual int32_t TableVersion(); + virtual void SetTableVersion(int32_t version); + virtual int32_t FontRevision(); + virtual void SetFontRevision(int32_t revision); + virtual int64_t ChecksumAdjustment(); + virtual void SetChecksumAdjustment(int64_t adjustment); + virtual int64_t MagicNumber(); + virtual void SetMagicNumber(int64_t magic_number); + virtual int32_t FlagsAsInt(); + virtual void SetFlagsAsInt(int32_t flags); + // TODO(arthurhsu): IMPLEMENT EnumSet Flags() + // TODO(arthurhsu): IMPLEMENT setFlags(EnumSet flags) + virtual int32_t UnitsPerEm(); + virtual void SetUnitsPerEm(int32_t units); + virtual int64_t Created(); + virtual void SetCreated(int64_t date); + virtual int64_t Modified(); + virtual void SetModified(int64_t date); + virtual int32_t XMin(); + virtual void SetXMin(int32_t xmin); + virtual int32_t YMin(); + virtual void SetYMin(int32_t ymin); + virtual int32_t XMax(); + virtual void SetXMax(int32_t xmax); + virtual int32_t YMax(); + virtual void SetYMax(int32_t ymax); + virtual int32_t MacStyleAsInt(); + virtual void SetMacStyleAsInt(int32_t style); + // TODO(arthurhsu): IMPLEMENT EnumSet macStyle() + // TODO(arthurhsu): IMPLEMENT setMacStyle(EnumSet style) + virtual int32_t LowestRecPPEM(); + virtual void SetLowestRecPPEM(int32_t size); + virtual int32_t FontDirectionHint(); + virtual void SetFontDirectionHint(int32_t hint); + virtual int32_t IndexToLocFormat(); + virtual void SetIndexToLocFormat(int32_t format); + virtual int32_t GlyphDataFormat(); + virtual void SetGlyphDataFormat(int32_t format); + + static CALLER_ATTACH Builder* CreateBuilder(Header* header, + WritableFontData* data); + }; + + virtual ~FontHeaderTable(); + int32_t TableVersion(); + int32_t FontRevision(); + + // Get the checksum adjustment. To compute: set it to 0, sum the entire font + // as ULONG, then store 0xB1B0AFBA - sum. + int64_t ChecksumAdjustment(); + + // Get the magic number. Set to 0x5F0F3CF5. + int64_t MagicNumber(); + + // TODO(arthurhsu): IMPLEMENT: EnumSet + int32_t FlagsAsInt(); + // TODO(arthurhsu): IMPLEMENT: Flags() returning EnumSet + + int32_t UnitsPerEm(); + + // Get the created date. Number of seconds since 12:00 midnight, January 1, + // 1904. 64-bit integer. + int64_t Created(); + // Get the modified date. Number of seconds since 12:00 midnight, January 1, + // 1904. 64-bit integer. + int64_t Modified(); + + // Get the x min. For all glyph bounding boxes. + int32_t XMin(); + // Get the y min. For all glyph bounding boxes. + int32_t YMin(); + // Get the x max. For all glyph bounding boxes. + int32_t XMax(); + // Get the y max. For all glyph bounding boxes. + int32_t YMax(); + + // TODO(arthurhsu): IMPLEMENT: EnumSet + int32_t MacStyleAsInt(); + // TODO(arthurhsu): IMPLEMENT: macStyle() returning EnumSet + + int32_t LowestRecPPEM(); + int32_t FontDirectionHint(); // Note: no AsInt() form, already int + int32_t IndexToLocFormat(); // Note: no AsInt() form, already int + int32_t GlyphDataFormat(); + + private: + struct Offset { + enum { + kTableVersion = 0, + kFontRevision = 4, + kCheckSumAdjustment = 8, + kMagicNumber = 12, + kFlags = 16, + kUnitsPerEm = 18, + kCreated = 20, + kModified = 28, + kXMin = 36, + kYMin = 38, + kXMax = 40, + kYMax = 42, + kMacStyle = 44, + kLowestRecPPEM = 46, + kFontDirectionHint = 48, + kIndexToLocFormat = 50, + kGlyphDataFormat = 52 + }; + }; + + FontHeaderTable(Header* header, ReadableFontData* data); +}; +typedef Ptr FontHeaderTablePtr; +typedef Ptr FontHeaderTableBuilderPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_FONT_HEADER_TABLE_H_ diff --git a/src/sfntly/src/sfntly/table/core/horizontal_device_metrics_table.cc b/src/sfntly/src/sfntly/table/core/horizontal_device_metrics_table.cc new file mode 100644 index 0000000000..50b0cf579d --- /dev/null +++ b/src/sfntly/src/sfntly/table/core/horizontal_device_metrics_table.cc @@ -0,0 +1,124 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/core/horizontal_device_metrics_table.h" + +namespace sfntly { +/****************************************************************************** + * HorizontalDeviceMetricsTable class + ******************************************************************************/ +HorizontalDeviceMetricsTable:: ~HorizontalDeviceMetricsTable() {} + +int32_t HorizontalDeviceMetricsTable::Version() { + return data_->ReadUShort(Offset::kVersion); +} + +int32_t HorizontalDeviceMetricsTable::NumRecords() { + return data_->ReadShort(Offset::kNumRecords); +} + +int32_t HorizontalDeviceMetricsTable::RecordSize() { + return data_->ReadLong(Offset::kSizeDeviceRecord); +} + +int32_t HorizontalDeviceMetricsTable::PixelSize(int32_t record_index) { + if (record_index < 0 || record_index >= NumRecords()) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundsException(); +#endif + return -1; + } + return data_->ReadUByte(Offset::kRecords + record_index * RecordSize() + + Offset::kDeviceRecordPixelSize); +} + +int32_t HorizontalDeviceMetricsTable::MaxWidth(int32_t record_index) { + if (record_index < 0 || record_index >= NumRecords()) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundsException(); +#endif + return -1; + } + return data_->ReadUByte(Offset::kRecords + record_index * RecordSize() + + Offset::kDeviceRecordMaxWidth); +} + +int32_t HorizontalDeviceMetricsTable::Width(int32_t record_index, + int32_t glyph_num) { + if (record_index < 0 || record_index >= NumRecords() || + glyph_num < 0 || glyph_num >= num_glyphs_) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundsException(); +#endif + return -1; + } + return data_->ReadUByte(Offset::kRecords + record_index * RecordSize() + + Offset::kDeviceRecordWidths + glyph_num); +} + +HorizontalDeviceMetricsTable::HorizontalDeviceMetricsTable( + Header* header, + ReadableFontData* data, + int32_t num_glyphs) + : Table(header, data), num_glyphs_(num_glyphs) { +} + +/****************************************************************************** + * HorizontalDeviceMetricsTable::Builder class + ******************************************************************************/ +HorizontalDeviceMetricsTable::Builder::Builder(Header* header, + WritableFontData* data) + : TableBasedTableBuilder(header, data), num_glyphs_(-1) { +} + +HorizontalDeviceMetricsTable::Builder::Builder(Header* header, + ReadableFontData* data) + : TableBasedTableBuilder(header, data), num_glyphs_(-1) { +} + +HorizontalDeviceMetricsTable::Builder::~Builder() {} + +CALLER_ATTACH FontDataTable* +HorizontalDeviceMetricsTable::Builder::SubBuildTable(ReadableFontData* data) { + FontDataTablePtr table = new HorizontalDeviceMetricsTable(header(), data, + num_glyphs_); + return table.Detach(); +} + +void HorizontalDeviceMetricsTable::Builder::SetNumGlyphs(int32_t num_glyphs) { + if (num_glyphs < 0) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IllegalArgumentException("Number of glyphs can't be negative."); +#endif + return; + } + num_glyphs_ = num_glyphs; + HorizontalDeviceMetricsTable* table = + down_cast(GetTable()); + if (table) { + table->num_glyphs_ = num_glyphs; + } +} + +CALLER_ATTACH HorizontalDeviceMetricsTable::Builder* +HorizontalDeviceMetricsTable::Builder::CreateBuilder(Header* header, + WritableFontData* data) { + Ptr builder; + builder = new HorizontalDeviceMetricsTable::Builder(header, data); + return builder.Detach(); +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/core/horizontal_device_metrics_table.h b/src/sfntly/src/sfntly/table/core/horizontal_device_metrics_table.h new file mode 100644 index 0000000000..4a27ba0964 --- /dev/null +++ b/src/sfntly/src/sfntly/table/core/horizontal_device_metrics_table.h @@ -0,0 +1,82 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_DEVICE_METRICS_TABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_DEVICE_METRICS_TABLE_H_ + +#include "sfntly/table/table.h" +#include "sfntly/table/table_based_table_builder.h" + +namespace sfntly { + +// A Horizontal Device Metrics table - 'hdmx' +class HorizontalDeviceMetricsTable + : public Table, + public RefCounted { + public: + class Builder : public TableBasedTableBuilder, public RefCounted { + public: + // Constructor scope altered to public because C++ does not allow base + // class to instantiate derived class with protected constructors. + Builder(Header* header, WritableFontData* data); + Builder(Header* header, ReadableFontData* data); + virtual ~Builder(); + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + + static CALLER_ATTACH Builder* CreateBuilder(Header* header, + WritableFontData* data); + + void SetNumGlyphs(int32_t num_glyphs); + + private: + int32_t num_glyphs_; + }; + + virtual ~HorizontalDeviceMetricsTable(); + + int32_t Version(); + int32_t NumRecords(); + int32_t RecordSize(); + int32_t PixelSize(int32_t record_index); + int32_t MaxWidth(int32_t record_index); + int32_t Width(int32_t record_index, int32_t glyph_num); + + private: + struct Offset { + enum { + kVersion = 0, + kNumRecords = 2, + kSizeDeviceRecord = 4, + kRecords = 8, + + // Offsets within a device record + kDeviceRecordPixelSize = 0, + kDeviceRecordMaxWidth = 1, + kDeviceRecordWidths = 2, + }; + }; + HorizontalDeviceMetricsTable(Header* header, + ReadableFontData* data, + int32_t num_glyphs); + + int32_t num_glyphs_; +}; +typedef Ptr HorizontalDeviceMetricsTablePtr; +typedef Ptr + HorizontalDeviceMetricsTableBuilderPtr; +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_DEVICE_METRICS_TABLE_H_ diff --git a/src/sfntly/src/sfntly/table/core/horizontal_header_table.cc b/src/sfntly/src/sfntly/table/core/horizontal_header_table.cc new file mode 100644 index 0000000000..43c20585d3 --- /dev/null +++ b/src/sfntly/src/sfntly/table/core/horizontal_header_table.cc @@ -0,0 +1,213 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/core/horizontal_header_table.h" + +namespace sfntly { +/****************************************************************************** + * HorizontalHeaderTable class + ******************************************************************************/ +HorizontalHeaderTable:: ~HorizontalHeaderTable() {} + +int32_t HorizontalHeaderTable::TableVersion() { + return data_->ReadFixed(Offset::kVersion); +} + +int32_t HorizontalHeaderTable::Ascender() { + return data_->ReadShort(Offset::kAscender); +} + +int32_t HorizontalHeaderTable::Descender() { + return data_->ReadShort(Offset::kDescender); +} + +int32_t HorizontalHeaderTable::LineGap() { + return data_->ReadShort(Offset::kLineGap); +} + +int32_t HorizontalHeaderTable::AdvanceWidthMax() { + return data_->ReadUShort(Offset::kAdvanceWidthMax); +} + +int32_t HorizontalHeaderTable::MinLeftSideBearing() { + return data_->ReadShort(Offset::kMinLeftSideBearing); +} + +int32_t HorizontalHeaderTable::MinRightSideBearing() { + return data_->ReadShort(Offset::kMinRightSideBearing); +} + +int32_t HorizontalHeaderTable::XMaxExtent() { + return data_->ReadShort(Offset::kXMaxExtent); +} + +int32_t HorizontalHeaderTable::CaretSlopeRise() { + return data_->ReadShort(Offset::kCaretSlopeRise); +} + +int32_t HorizontalHeaderTable::CaretSlopeRun() { + return data_->ReadShort(Offset::kCaretSlopeRun); +} + +int32_t HorizontalHeaderTable::CaretOffset() { + return data_->ReadShort(Offset::kCaretOffset); +} + +int32_t HorizontalHeaderTable::MetricDataFormat() { + return data_->ReadShort(Offset::kMetricDataFormat); +} + +int32_t HorizontalHeaderTable::NumberOfHMetrics() { + return data_->ReadUShort(Offset::kNumberOfHMetrics); +} + +HorizontalHeaderTable:: HorizontalHeaderTable(Header* header, + ReadableFontData* data) + : Table(header, data) { +} + +/****************************************************************************** + * HorizontalHeaderTable::Builder class + ******************************************************************************/ +HorizontalHeaderTable::Builder::Builder(Header* header, WritableFontData* data) + : TableBasedTableBuilder(header, data) { +} + +HorizontalHeaderTable::Builder::Builder(Header* header, ReadableFontData* data) + : TableBasedTableBuilder(header, data) { +} + +HorizontalHeaderTable::Builder::~Builder() {} + +CALLER_ATTACH FontDataTable* + HorizontalHeaderTable::Builder::SubBuildTable(ReadableFontData* data) { + FontDataTablePtr table = new HorizontalHeaderTable(header(), data); + return table.Detach(); +} + +CALLER_ATTACH HorizontalHeaderTable::Builder* + HorizontalHeaderTable::Builder::CreateBuilder(Header* header, + WritableFontData* data) { + Ptr builder; + builder = new HorizontalHeaderTable::Builder(header, data); + return builder.Detach(); +} + +int32_t HorizontalHeaderTable::Builder::TableVersion() { + return InternalReadData()->ReadFixed(Offset::kVersion); +} + +void HorizontalHeaderTable::Builder::SetTableVersion(int32_t version) { + InternalWriteData()->WriteFixed(Offset::kVersion, version); +} + +int32_t HorizontalHeaderTable::Builder::Ascender() { + return InternalReadData()->ReadShort(Offset::kAscender); +} + +void HorizontalHeaderTable::Builder::SetAscender(int32_t ascender) { + InternalWriteData()->WriteShort(Offset::kVersion, ascender); +} + +int32_t HorizontalHeaderTable::Builder::Descender() { + return InternalReadData()->ReadShort(Offset::kDescender); +} + +void HorizontalHeaderTable::Builder::SetDescender(int32_t descender) { + InternalWriteData()->WriteShort(Offset::kDescender, descender); +} + +int32_t HorizontalHeaderTable::Builder::LineGap() { + return InternalReadData()->ReadShort(Offset::kLineGap); +} + +void HorizontalHeaderTable::Builder::SetLineGap(int32_t line_gap) { + InternalWriteData()->WriteShort(Offset::kLineGap, line_gap); +} + +int32_t HorizontalHeaderTable::Builder::AdvanceWidthMax() { + return InternalReadData()->ReadUShort(Offset::kAdvanceWidthMax); +} + +void HorizontalHeaderTable::Builder::SetAdvanceWidthMax(int32_t value) { + InternalWriteData()->WriteUShort(Offset::kAdvanceWidthMax, value); +} + +int32_t HorizontalHeaderTable::Builder::MinLeftSideBearing() { + return InternalReadData()->ReadShort(Offset::kMinLeftSideBearing); +} + +void HorizontalHeaderTable::Builder::SetMinLeftSideBearing(int32_t value) { + InternalWriteData()->WriteShort(Offset::kMinLeftSideBearing, value); +} + +int32_t HorizontalHeaderTable::Builder::MinRightSideBearing() { + return InternalReadData()->ReadShort(Offset::kMinRightSideBearing); +} + +void HorizontalHeaderTable::Builder::SetMinRightSideBearing(int32_t value) { + InternalWriteData()->WriteShort(Offset::kMinRightSideBearing, value); +} + +int32_t HorizontalHeaderTable::Builder::XMaxExtent() { + return InternalReadData()->ReadShort(Offset::kXMaxExtent); +} + +void HorizontalHeaderTable::Builder::SetXMaxExtent(int32_t value) { + InternalWriteData()->WriteShort(Offset::kXMaxExtent, value); +} + +int32_t HorizontalHeaderTable::Builder::CaretSlopeRise() { + return InternalReadData()->ReadUShort(Offset::kCaretSlopeRise); +} + +void HorizontalHeaderTable::Builder::SetCaretSlopeRise(int32_t value) { + InternalWriteData()->WriteUShort(Offset::kCaretSlopeRise, value); +} + +int32_t HorizontalHeaderTable::Builder::CaretSlopeRun() { + return InternalReadData()->ReadUShort(Offset::kCaretSlopeRun); +} + +void HorizontalHeaderTable::Builder::SetCaretSlopeRun(int32_t value) { + InternalWriteData()->WriteUShort(Offset::kCaretSlopeRun, value); +} + +int32_t HorizontalHeaderTable::Builder::CaretOffset() { + return InternalReadData()->ReadUShort(Offset::kCaretOffset); +} + +void HorizontalHeaderTable::Builder::SetCaretOffset(int32_t value) { + InternalWriteData()->WriteUShort(Offset::kCaretOffset, value); +} + +int32_t HorizontalHeaderTable::Builder::MetricDataFormat() { + return InternalReadData()->ReadUShort(Offset::kMetricDataFormat); +} + +void HorizontalHeaderTable::Builder::SetMetricDataFormat(int32_t value) { + InternalWriteData()->WriteUShort(Offset::kMetricDataFormat, value); +} + +int32_t HorizontalHeaderTable::Builder::NumberOfHMetrics() { + return InternalReadData()->ReadUShort(Offset::kNumberOfHMetrics); +} + +void HorizontalHeaderTable::Builder::SetNumberOfHMetrics(int32_t value) { + InternalWriteData()->WriteUShort(Offset::kNumberOfHMetrics, value); +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/core/horizontal_header_table.h b/src/sfntly/src/sfntly/table/core/horizontal_header_table.h new file mode 100644 index 0000000000..71f30b4475 --- /dev/null +++ b/src/sfntly/src/sfntly/table/core/horizontal_header_table.h @@ -0,0 +1,111 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_HEADER_TABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_HEADER_TABLE_H_ + +#include "sfntly/table/table.h" +#include "sfntly/table/table_based_table_builder.h" + +namespace sfntly { + +// A Horizontal Header table - 'hhea'. +class HorizontalHeaderTable : public Table, + public RefCounted { + public: + // Builder for a Horizontal Header table - 'hhea'. + class Builder : public TableBasedTableBuilder, public RefCounted { + public: + // Constructor scope altered to public because C++ does not allow base + // class to instantiate derived class with protected constructors. + Builder(Header* header, WritableFontData* data); + Builder(Header* header, ReadableFontData* data); + virtual ~Builder(); + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + + static CALLER_ATTACH Builder* CreateBuilder(Header* header, + WritableFontData* data); + + int32_t TableVersion(); + void SetTableVersion(int32_t version); + int32_t Ascender(); + void SetAscender(int32_t ascender); + int32_t Descender(); + void SetDescender(int32_t descender); + int32_t LineGap(); + void SetLineGap(int32_t line_gap); + int32_t AdvanceWidthMax(); + void SetAdvanceWidthMax(int32_t value); + int32_t MinLeftSideBearing(); + void SetMinLeftSideBearing(int32_t value); + int32_t MinRightSideBearing(); + void SetMinRightSideBearing(int32_t value); + int32_t XMaxExtent(); + void SetXMaxExtent(int32_t value); + int32_t CaretSlopeRise(); + void SetCaretSlopeRise(int32_t value); + int32_t CaretSlopeRun(); + void SetCaretSlopeRun(int32_t value); + int32_t CaretOffset(); + void SetCaretOffset(int32_t value); + int32_t MetricDataFormat(); + void SetMetricDataFormat(int32_t value); + int32_t NumberOfHMetrics(); + void SetNumberOfHMetrics(int32_t value); + }; + + virtual ~HorizontalHeaderTable(); + int32_t TableVersion(); + int32_t Ascender(); + int32_t Descender(); + int32_t LineGap(); + int32_t AdvanceWidthMax(); + int32_t MinLeftSideBearing(); + int32_t MinRightSideBearing(); + int32_t XMaxExtent(); + int32_t CaretSlopeRise(); + int32_t CaretSlopeRun(); + int32_t CaretOffset(); + int32_t MetricDataFormat(); + int32_t NumberOfHMetrics(); + + private: + struct Offset { + enum { + kVersion = 0, + kAscender = 4, + kDescender = 6, + kLineGap = 8, + kAdvanceWidthMax = 10, + kMinLeftSideBearing = 12, + kMinRightSideBearing = 14, + kXMaxExtent = 16, + kCaretSlopeRise = 18, + kCaretSlopeRun = 20, + kCaretOffset = 22, + kMetricDataFormat = 32, + kNumberOfHMetrics = 34, + }; + }; + + HorizontalHeaderTable(Header* header, ReadableFontData* data); +}; +typedef Ptr HorizontalHeaderTablePtr; +typedef Ptr HorizontalHeaderTableBuilderPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_HEADER_TABLE_H_ diff --git a/src/sfntly/src/sfntly/table/core/horizontal_metrics_table.cc b/src/sfntly/src/sfntly/table/core/horizontal_metrics_table.cc new file mode 100644 index 0000000000..156387daaf --- /dev/null +++ b/src/sfntly/src/sfntly/table/core/horizontal_metrics_table.cc @@ -0,0 +1,138 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/core/horizontal_metrics_table.h" +#include "sfntly/port/exception_type.h" + +namespace sfntly { +/****************************************************************************** + * HorizontalMetricsTable class + ******************************************************************************/ +HorizontalMetricsTable::~HorizontalMetricsTable() {} + +int32_t HorizontalMetricsTable::NumberOfHMetrics() { + return num_hmetrics_; +} + +int32_t HorizontalMetricsTable::NumberOfLSBs() { + return num_glyphs_ - num_hmetrics_; +} + +int32_t HorizontalMetricsTable::HMetricAdvanceWidth(int32_t entry) { + if (entry > num_hmetrics_) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundException(); +#endif + return 0; + } + int32_t offset = Offset::kHMetricsStart + (entry * Offset::kHMetricsSize) + + Offset::kHMetricsAdvanceWidth; + return data_->ReadUShort(offset); +} + +int32_t HorizontalMetricsTable::HMetricLSB(int32_t entry) { + if (entry > num_hmetrics_) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundException(); +#endif + return 0; + } + int32_t offset = Offset::kHMetricsStart + (entry * Offset::kHMetricsSize) + + Offset::kHMetricsLeftSideBearing; + return data_->ReadShort(offset); +} + +int32_t HorizontalMetricsTable::LsbTableEntry(int32_t entry) { + if (entry > num_hmetrics_) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundException(); +#endif + return 0; + } + int32_t offset = Offset::kHMetricsStart + (entry * Offset::kHMetricsSize) + + Offset::kLeftSideBearingSize; + return data_->ReadShort(offset); +} + +int32_t HorizontalMetricsTable::AdvanceWidth(int32_t glyph_id) { + if (glyph_id < num_hmetrics_) { + return HMetricAdvanceWidth(glyph_id); + } + return HMetricAdvanceWidth(glyph_id - num_hmetrics_); +} + +int32_t HorizontalMetricsTable::LeftSideBearing(int32_t glyph_id) { + if (glyph_id < num_hmetrics_) { + return HMetricLSB(glyph_id); + } + return LsbTableEntry(glyph_id - num_hmetrics_); +} + +HorizontalMetricsTable::HorizontalMetricsTable(Header* header, + ReadableFontData* data, + int32_t num_hmetrics, + int32_t num_glyphs) + : Table(header, data), + num_hmetrics_(num_hmetrics), + num_glyphs_(num_glyphs) { +} + +/****************************************************************************** + * HorizontalMetricsTable::Builder class + ******************************************************************************/ +HorizontalMetricsTable::Builder::Builder(Header* header, WritableFontData* data) + : TableBasedTableBuilder(header, data), num_hmetrics_(-1), num_glyphs_(-1) { +} + +HorizontalMetricsTable::Builder::Builder(Header* header, ReadableFontData* data) + : TableBasedTableBuilder(header, data), num_hmetrics_(-1), num_glyphs_(-1) { +} + +HorizontalMetricsTable::Builder::~Builder() {} + +CALLER_ATTACH FontDataTable* + HorizontalMetricsTable::Builder::SubBuildTable(ReadableFontData* data) { + FontDataTablePtr table = + new HorizontalMetricsTable(header(), data, num_hmetrics_, num_glyphs_); + return table.Detach(); +} + +CALLER_ATTACH HorizontalMetricsTable::Builder* + HorizontalMetricsTable::Builder::CreateBuilder(Header* header, + WritableFontData* data) { + Ptr builder; + builder = new HorizontalMetricsTable::Builder(header, data); + return builder.Detach(); +} + +void HorizontalMetricsTable::Builder::SetNumberOfHMetrics( + int32_t num_hmetrics) { + assert(num_hmetrics >= 0); + num_hmetrics_ = num_hmetrics; + HorizontalMetricsTable* table = + down_cast(this->GetTable()); + table->num_hmetrics_ = num_hmetrics; +} + +void HorizontalMetricsTable::Builder::SetNumGlyphs(int32_t num_glyphs) { + assert(num_glyphs >= 0); + num_glyphs_ = num_glyphs; + HorizontalMetricsTable* table = + down_cast(this->GetTable()); + table->num_glyphs_ = num_glyphs; +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/core/horizontal_metrics_table.h b/src/sfntly/src/sfntly/table/core/horizontal_metrics_table.h new file mode 100644 index 0000000000..44b51f2d79 --- /dev/null +++ b/src/sfntly/src/sfntly/table/core/horizontal_metrics_table.h @@ -0,0 +1,87 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_METRICS_TABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_METRICS_TABLE_H_ + +#include "sfntly/table/table.h" +#include "sfntly/table/table_based_table_builder.h" + +namespace sfntly { + +// A Horizontal Metrics table - 'hmtx'. +class HorizontalMetricsTable : public Table, + public RefCounted { + public: + // Builder for a Horizontal Metrics Table - 'hmtx'. + class Builder : public TableBasedTableBuilder, public RefCounted { + public: + // Constructor scope altered to public because C++ does not allow base + // class to instantiate derived class with protected constructors. + Builder(Header* header, WritableFontData* data); + Builder(Header* header, ReadableFontData* data); + virtual ~Builder(); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + static CALLER_ATTACH Builder* CreateBuilder(Header* header, + WritableFontData* data); + + void SetNumberOfHMetrics(int32_t num_hmetrics); + void SetNumGlyphs(int32_t num_glyphs); + + private: + int32_t num_hmetrics_; + int32_t num_glyphs_; + }; + + virtual ~HorizontalMetricsTable(); + int32_t NumberOfHMetrics(); + int32_t NumberOfLSBs(); + int32_t HMetricAdvanceWidth(int32_t entry); + int32_t HMetricLSB(int32_t entry); + int32_t LsbTableEntry(int32_t entry); + int32_t AdvanceWidth(int32_t glyph_id); + int32_t LeftSideBearing(int32_t glyph_id); + + private: + struct Offset { + enum { + // hMetrics + kHMetricsStart = 0, + kHMetricsSize = 4, + + // Offset within an hMetric + kHMetricsAdvanceWidth = 0, + kHMetricsLeftSideBearing = 2, + + kLeftSideBearingSize = 2 + }; + }; + + HorizontalMetricsTable(Header* header, + ReadableFontData* data, + int32_t num_hmetrics, + int32_t num_glyphs); + + int32_t num_hmetrics_; + int32_t num_glyphs_; +}; +typedef Ptr HorizontalMetricsTablePtr; +typedef Ptr HorizontalMetricsTableBuilderPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_METRICS_TABLE_H_ diff --git a/src/sfntly/src/sfntly/table/core/maximum_profile_table.cc b/src/sfntly/src/sfntly/table/core/maximum_profile_table.cc new file mode 100644 index 0000000000..a8ac3bc93a --- /dev/null +++ b/src/sfntly/src/sfntly/table/core/maximum_profile_table.cc @@ -0,0 +1,240 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/core/maximum_profile_table.h" + +namespace sfntly { +/****************************************************************************** + * MaximumProfileTable class + ******************************************************************************/ +MaximumProfileTable::~MaximumProfileTable() {} + +int32_t MaximumProfileTable::TableVersion() { + return data_->ReadFixed(Offset::kVersion); +} + +int32_t MaximumProfileTable::NumGlyphs() { + return data_->ReadUShort(Offset::kNumGlyphs); +} + +int32_t MaximumProfileTable::MaxPoints() { + return data_->ReadUShort(Offset::kMaxPoints); +} + +int32_t MaximumProfileTable::MaxContours() { + return data_->ReadUShort(Offset::kMaxContours); +} + +int32_t MaximumProfileTable::MaxCompositePoints() { + return data_->ReadUShort(Offset::kMaxCompositePoints); +} + +int32_t MaximumProfileTable::MaxCompositeContours() { + return data_->ReadUShort(Offset::kMaxCompositeContours); +} + +int32_t MaximumProfileTable::MaxZones() { + return data_->ReadUShort(Offset::kMaxZones); +} + +int32_t MaximumProfileTable::MaxTwilightPoints() { + return data_->ReadUShort(Offset::kMaxTwilightPoints); +} + +int32_t MaximumProfileTable::MaxStorage() { + return data_->ReadUShort(Offset::kMaxStorage); +} + +int32_t MaximumProfileTable::MaxFunctionDefs() { + return data_->ReadUShort(Offset::kMaxFunctionDefs); +} + +int32_t MaximumProfileTable::MaxStackElements() { + return data_->ReadUShort(Offset::kMaxStackElements); +} + +int32_t MaximumProfileTable::MaxSizeOfInstructions() { + return data_->ReadUShort(Offset::kMaxSizeOfInstructions); +} + +int32_t MaximumProfileTable::MaxComponentElements() { + return data_->ReadUShort(Offset::kMaxComponentElements); +} + +int32_t MaximumProfileTable::MaxComponentDepth() { + return data_->ReadUShort(Offset::kMaxComponentDepth); +} + +MaximumProfileTable::MaximumProfileTable(Header* header, + ReadableFontData* data) + : Table(header, data) { +} + +/****************************************************************************** + * MaximumProfileTable::Builder class + ******************************************************************************/ +MaximumProfileTable::Builder::Builder(Header* header, WritableFontData* data) + : TableBasedTableBuilder(header, data) { +} + +MaximumProfileTable::Builder::Builder(Header* header, ReadableFontData* data) + : TableBasedTableBuilder(header, data) { +} + +MaximumProfileTable::Builder::~Builder() {} + +CALLER_ATTACH FontDataTable* + MaximumProfileTable::Builder::SubBuildTable(ReadableFontData* data) { + FontDataTablePtr table = new MaximumProfileTable(header(), data); + return table.Detach(); +} + +CALLER_ATTACH MaximumProfileTable::Builder* + MaximumProfileTable::Builder::CreateBuilder(Header* header, + WritableFontData* data) { + Ptr builder; + builder = new MaximumProfileTable::Builder(header, data); + return builder.Detach(); +} + +int32_t MaximumProfileTable::Builder::TableVersion() { + return InternalReadData()->ReadUShort(Offset::kVersion); +} + +void MaximumProfileTable::Builder::SetTableVersion(int32_t version) { + InternalWriteData()->WriteUShort(Offset::kVersion, version); +} + +int32_t MaximumProfileTable::Builder::NumGlyphs() { + return InternalReadData()->ReadUShort(Offset::kNumGlyphs); +} + +void MaximumProfileTable::Builder::SetNumGlyphs(int32_t num_glyphs) { + InternalWriteData()->WriteUShort(Offset::kNumGlyphs, num_glyphs); +} + +int32_t MaximumProfileTable::Builder::MaxPoints() { + return InternalReadData()->ReadUShort(Offset::kMaxPoints); +} + +void MaximumProfileTable::Builder::SetMaxPoints(int32_t max_points) { + InternalWriteData()->WriteUShort(Offset::kMaxPoints, max_points); +} + +int32_t MaximumProfileTable::Builder::MaxContours() { + return InternalReadData()->ReadUShort(Offset::kMaxContours); +} + +void MaximumProfileTable::Builder::SetMaxContours(int32_t max_contours) { + InternalWriteData()->WriteUShort(Offset::kMaxContours, max_contours); +} + +int32_t MaximumProfileTable::Builder::MaxCompositePoints() { + return InternalReadData()->ReadUShort(Offset::kMaxCompositePoints); +} + +void MaximumProfileTable::Builder::SetMaxCompositePoints( + int32_t max_composite_points) { + InternalWriteData()->WriteUShort(Offset::kMaxCompositePoints, + max_composite_points); +} + +int32_t MaximumProfileTable::Builder::MaxCompositeContours() { + return InternalReadData()->ReadUShort(Offset::kMaxCompositeContours); +} + +void MaximumProfileTable::Builder::SetMaxCompositeContours( + int32_t max_composite_contours) { + InternalWriteData()->WriteUShort(Offset::kMaxCompositeContours, + max_composite_contours); +} + +int32_t MaximumProfileTable::Builder::MaxZones() { + return InternalReadData()->ReadUShort(Offset::kMaxZones); +} + +void MaximumProfileTable::Builder::SetMaxZones(int32_t max_zones) { + InternalWriteData()->WriteUShort(Offset::kMaxZones, max_zones); +} + +int32_t MaximumProfileTable::Builder::MaxTwilightPoints() { + return InternalReadData()->ReadUShort(Offset::kMaxTwilightPoints); +} + +void MaximumProfileTable::Builder::SetMaxTwilightPoints( + int32_t max_twilight_points) { + InternalWriteData()->WriteUShort(Offset::kMaxTwilightPoints, + max_twilight_points); +} + +int32_t MaximumProfileTable::Builder::MaxStorage() { + return InternalReadData()->ReadUShort(Offset::kMaxStorage); +} + +void MaximumProfileTable::Builder::SetMaxStorage(int32_t max_storage) { + InternalWriteData()->WriteUShort(Offset::kMaxStorage, max_storage); +} + +int32_t MaximumProfileTable::Builder::MaxFunctionDefs() { + return InternalReadData()->ReadUShort(Offset::kMaxFunctionDefs); +} + +void MaximumProfileTable::Builder::SetMaxFunctionDefs( + int32_t max_function_defs) { + InternalWriteData()->WriteUShort(Offset::kMaxFunctionDefs, max_function_defs); +} + +int32_t MaximumProfileTable::Builder::MaxStackElements() { + return InternalReadData()->ReadUShort(Offset::kMaxStackElements); +} + +void MaximumProfileTable::Builder::SetMaxStackElements( + int32_t max_stack_elements) { + InternalWriteData()->WriteUShort(Offset::kMaxStackElements, + max_stack_elements); +} + +int32_t MaximumProfileTable::Builder::MaxSizeOfInstructions() { + return InternalReadData()->ReadUShort(Offset::kMaxSizeOfInstructions); +} + +void MaximumProfileTable::Builder::SetMaxSizeOfInstructions( + int32_t max_size_of_instructions) { + InternalWriteData()->WriteUShort(Offset::kMaxSizeOfInstructions, + max_size_of_instructions); +} + +int32_t MaximumProfileTable::Builder::MaxComponentElements() { + return InternalReadData()->ReadUShort(Offset::kMaxComponentElements); +} + +void MaximumProfileTable::Builder::SetMaxComponentElements( + int32_t max_component_elements) { + InternalWriteData()->WriteUShort(Offset::kMaxComponentElements, + max_component_elements); +} + +int32_t MaximumProfileTable::Builder::MaxComponentDepth() { + return InternalReadData()->ReadUShort(Offset::kMaxComponentDepth); +} + +void MaximumProfileTable::Builder::SetMaxComponentDepth( + int32_t max_component_depth) { + InternalWriteData()->WriteUShort(Offset::kMaxComponentDepth, + max_component_depth); +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/core/maximum_profile_table.h b/src/sfntly/src/sfntly/table/core/maximum_profile_table.h new file mode 100644 index 0000000000..e7c5abb3ff --- /dev/null +++ b/src/sfntly/src/sfntly/table/core/maximum_profile_table.h @@ -0,0 +1,120 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_MAXIMUM_PROFILE_TABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_MAXIMUM_PROFILE_TABLE_H_ + +#include "sfntly/port/refcount.h" +#include "sfntly/table/table.h" +#include "sfntly/table/table_based_table_builder.h" + +namespace sfntly { + +// A Maximum Profile table - 'maxp'. +class MaximumProfileTable : public Table, + public RefCounted { + public: + // Builder for a Maximum Profile table - 'maxp'. + class Builder : public TableBasedTableBuilder, public RefCounted { + public: + // Constructor scope altered to public because C++ does not allow base + // class to instantiate derived class with protected constructors. + Builder(Header* header, WritableFontData* data); + Builder(Header* header, ReadableFontData* data); + virtual ~Builder(); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + static CALLER_ATTACH Builder* CreateBuilder(Header* header, + WritableFontData* data); + + int32_t TableVersion(); + void SetTableVersion(int32_t version); + int32_t NumGlyphs(); + void SetNumGlyphs(int32_t num_glyphs); + int32_t MaxPoints(); + void SetMaxPoints(int32_t max_points); + int32_t MaxContours(); + void SetMaxContours(int32_t max_contours); + int32_t MaxCompositePoints(); + void SetMaxCompositePoints(int32_t max_composite_points); + int32_t MaxCompositeContours(); + void SetMaxCompositeContours(int32_t max_composite_contours); + int32_t MaxZones(); + void SetMaxZones(int32_t max_zones); + int32_t MaxTwilightPoints(); + void SetMaxTwilightPoints(int32_t max_twilight_points); + int32_t MaxStorage(); + void SetMaxStorage(int32_t max_storage); + int32_t MaxFunctionDefs(); + void SetMaxFunctionDefs(int32_t max_function_defs); + int32_t MaxStackElements(); + void SetMaxStackElements(int32_t max_stack_elements); + int32_t MaxSizeOfInstructions(); + void SetMaxSizeOfInstructions(int32_t max_size_of_instructions); + int32_t MaxComponentElements(); + void SetMaxComponentElements(int32_t max_component_elements); + int32_t MaxComponentDepth(); + void SetMaxComponentDepth(int32_t max_component_depth); + }; + + virtual ~MaximumProfileTable(); + int32_t TableVersion(); + int32_t NumGlyphs(); + int32_t MaxPoints(); + int32_t MaxContours(); + int32_t MaxCompositePoints(); + int32_t MaxCompositeContours(); + int32_t MaxZones(); + int32_t MaxTwilightPoints(); + int32_t MaxStorage(); + int32_t MaxFunctionDefs(); + int32_t MaxStackElements(); + int32_t MaxSizeOfInstructions(); + int32_t MaxComponentElements(); + int32_t MaxComponentDepth(); + + private: + struct Offset { + enum { + // version 0.5 and 1.0 + kVersion = 0, + kNumGlyphs = 4, + + // version 1.0 + kMaxPoints = 6, + kMaxContours = 8, + kMaxCompositePoints = 10, + kMaxCompositeContours = 12, + kMaxZones = 14, + kMaxTwilightPoints = 16, + kMaxStorage = 18, + kMaxFunctionDefs = 20, + kMaxInstructionDefs = 22, + kMaxStackElements = 24, + kMaxSizeOfInstructions = 26, + kMaxComponentElements = 28, + kMaxComponentDepth = 30, + }; + }; + + MaximumProfileTable(Header* header, ReadableFontData* data); +}; +typedef Ptr MaximumProfileTablePtr; +typedef Ptr MaximumProfileTableBuilderPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_MAXIMUM_PROFILE_TABLE_H_ diff --git a/src/sfntly/src/sfntly/table/core/name_table.cc b/src/sfntly/src/sfntly/table/core/name_table.cc new file mode 100644 index 0000000000..5f6d5a5172 --- /dev/null +++ b/src/sfntly/src/sfntly/table/core/name_table.cc @@ -0,0 +1,721 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/core/name_table.h" + +#include +#include + +#include + +#include "sfntly/font.h" +#include "sfntly/port/exception_type.h" + +namespace sfntly { +/****************************************************************************** + * NameTable::NameEntryId class + ******************************************************************************/ +NameTable::NameEntryId::NameEntryId() + : platform_id_(0), + encoding_id_(0), + language_id_(0), + name_id_(0) { +} + +NameTable::NameEntryId::NameEntryId(int32_t platform_id, + int32_t encoding_id, + int32_t language_id, + int32_t name_id) + : platform_id_(platform_id), + encoding_id_(encoding_id), + language_id_(language_id), + name_id_(name_id) { +} + +NameTable::NameEntryId::NameEntryId(const NameTable::NameEntryId& rhs) { + *this = rhs; +} + +const NameTable::NameEntryId& + NameTable::NameEntryId::operator=(const NameTable::NameEntryId& rhs) const { + platform_id_ = rhs.platform_id_; + encoding_id_ = rhs.encoding_id_; + language_id_ = rhs.language_id_; + name_id_ = rhs.name_id_; + return *this; +} + +bool NameTable::NameEntryId::operator==(const NameEntryId& rhs) const { + return platform_id_ == rhs.platform_id_ && + encoding_id_ == rhs.encoding_id_ && + language_id_ == rhs.language_id_ && + name_id_ == rhs.name_id_; +} + +bool NameTable::NameEntryId::operator<(const NameEntryId& rhs) const { + if (platform_id_ != rhs.platform_id_) return platform_id_ < rhs.platform_id_; + if (encoding_id_ != rhs.encoding_id_) return encoding_id_ < rhs.encoding_id_; + if (language_id_ != rhs.language_id_) return language_id_ < rhs.language_id_; + return name_id_ < rhs.name_id_; +} + +/****************************************************************************** + * NameTable::NameEntry class + ******************************************************************************/ +NameTable::NameEntry::NameEntry() { + Init(0, 0, 0, 0, NULL); +} + +NameTable::NameEntry::NameEntry(const NameEntryId& name_entry_id, + const ByteVector& name_bytes) { + Init(name_entry_id.platform_id(), + name_entry_id.encoding_id(), + name_entry_id.language_id(), + name_entry_id.name_id(), + &name_bytes); +} + +NameTable::NameEntry::NameEntry(int32_t platform_id, + int32_t encoding_id, + int32_t language_id, + int32_t name_id, + const ByteVector& name_bytes) { + Init(platform_id, encoding_id, language_id, name_id, &name_bytes); +} + +NameTable::NameEntry::~NameEntry() {} + +ByteVector* NameTable::NameEntry::NameAsBytes() { + return &name_bytes_; +} + +int32_t NameTable::NameEntry::NameBytesLength() { + return name_bytes_.size(); +} + +UChar* NameTable::NameEntry::Name() { + return NameTable::ConvertFromNameBytes(&name_bytes_, + platform_id(), + encoding_id()); +} + +bool NameTable::NameEntry::operator==(const NameEntry& rhs) const { + return (name_entry_id_ == rhs.name_entry_id_ && + name_bytes_ == rhs.name_bytes_); +} + +void NameTable::NameEntry::Init(int32_t platform_id, + int32_t encoding_id, + int32_t language_id, + int32_t name_id, + const ByteVector* name_bytes) { + name_entry_id_ = NameEntryId(platform_id, encoding_id, language_id, name_id); + if (name_bytes) { + name_bytes_ = *name_bytes; + } else { + name_bytes_.clear(); + } +} + +/****************************************************************************** + * NameTable::NameEntryBuilder class + ******************************************************************************/ +NameTable::NameEntryBuilder::NameEntryBuilder() { + Init(0, 0, 0, 0, NULL); +} + +NameTable::NameEntryBuilder::NameEntryBuilder(const NameEntryId& name_entry_id, + const ByteVector& name_bytes) { + Init(name_entry_id.platform_id(), + name_entry_id.encoding_id(), + name_entry_id.language_id(), + name_entry_id.name_id(), + &name_bytes); +} + +NameTable::NameEntryBuilder::NameEntryBuilder( + const NameEntryId& name_entry_id) { + Init(name_entry_id.platform_id(), + name_entry_id.encoding_id(), + name_entry_id.language_id(), + name_entry_id.name_id(), + NULL); +} + +NameTable::NameEntryBuilder::NameEntryBuilder(NameEntry* b) { + Init(b->platform_id(), + b->encoding_id(), + b->language_id(), + b->name_id(), + b->NameAsBytes()); +} + +NameTable::NameEntryBuilder::~NameEntryBuilder() {} + +void NameTable::NameEntryBuilder::SetName(const UChar* name) { + if (name == NULL) { + name_entry_->name_bytes_.clear(); + return; + } + NameTable::ConvertToNameBytes(name, + name_entry_->platform_id(), + name_entry_->encoding_id(), + &name_entry_->name_bytes_); +} + +void NameTable::NameEntryBuilder::SetName(const ByteVector& name_bytes) { + name_entry_->name_bytes_.clear(); + std::copy(name_bytes.begin(), + name_bytes.end(), + name_entry_->name_bytes_.begin()); +} + +void NameTable::NameEntryBuilder::SetName(const ByteVector& name_bytes, + int32_t offset, + int32_t length) { + name_entry_->name_bytes_.clear(); + std::copy(name_bytes.begin() + offset, + name_bytes.begin() + offset + length, + name_entry_->name_bytes_.begin()); +} + +void NameTable::NameEntryBuilder::Init(int32_t platform_id, + int32_t encoding_id, + int32_t language_id, + int32_t name_id, + const ByteVector* name_bytes) { + name_entry_ = new NameEntry(); + name_entry_->Init(platform_id, encoding_id, language_id, name_id, name_bytes); +} + +/****************************************************************************** + * NameTable::NameEntryFilterInPlace class (C++ port only) + ******************************************************************************/ +NameTable::NameEntryFilterInPlace::NameEntryFilterInPlace(int32_t platform_id, + int32_t encoding_id, + int32_t language_id, + int32_t name_id) + : platform_id_(platform_id), + encoding_id_(encoding_id), + language_id_(language_id), + name_id_(name_id) { +} + +bool NameTable::NameEntryFilterInPlace::Accept(int32_t platform_id, + int32_t encoding_id, + int32_t language_id, + int32_t name_id) { + return (platform_id_ == platform_id && + encoding_id_ == encoding_id && + language_id_ == language_id && + name_id_ == name_id); +} + +/****************************************************************************** + * NameTable::NameEntryIterator class + ******************************************************************************/ +NameTable::NameEntryIterator::NameEntryIterator(NameTable* table) + : RefIterator(table), + name_index_(0), + filter_(NULL) { +} + +NameTable::NameEntryIterator::NameEntryIterator(NameTable* table, + NameEntryFilter* filter) + : RefIterator(table), + name_index_(0), + filter_(filter) { +} + +bool NameTable::NameEntryIterator::HasNext() { + if (!filter_) { + if (name_index_ < container()->NameCount()) { + return true; + } + return false; + } + for (; name_index_ < container()->NameCount(); ++name_index_) { + if (filter_->Accept(container()->PlatformId(name_index_), + container()->EncodingId(name_index_), + container()->LanguageId(name_index_), + container()->NameId(name_index_))) { + return true; + } + } + return false; +} + +CALLER_ATTACH NameTable::NameEntry* NameTable::NameEntryIterator::Next() { + if (!HasNext()) + return NULL; + return container()->GetNameEntry(name_index_++); +} + +/****************************************************************************** + * NameTable::Builder class + ******************************************************************************/ +NameTable::Builder::Builder(Header* header, WritableFontData* data) + : SubTableContainerTable::Builder(header, data) { +} + +NameTable::Builder::Builder(Header* header, ReadableFontData* data) + : SubTableContainerTable::Builder(header, data) { +} + +CALLER_ATTACH NameTable::Builder* + NameTable::Builder::CreateBuilder(Header* header, + WritableFontData* data) { + Ptr builder; + builder = new NameTable::Builder(header, data); + return builder.Detach(); +} + +void NameTable::Builder::RevertNames() { + name_entry_map_.clear(); + set_model_changed(false); +} + +int32_t NameTable::Builder::BuilderCount() { + GetNameBuilders(); // Ensure name_entry_map_ is built. + return (int32_t)name_entry_map_.size(); +} + +bool NameTable::Builder::Has(int32_t platform_id, + int32_t encoding_id, + int32_t language_id, + int32_t name_id) { + NameEntryId probe(platform_id, encoding_id, language_id, name_id); + GetNameBuilders(); // Ensure name_entry_map_ is built. + return (name_entry_map_.find(probe) != name_entry_map_.end()); +} + +CALLER_ATTACH NameTable::NameEntryBuilder* + NameTable::Builder::NameBuilder(int32_t platform_id, + int32_t encoding_id, + int32_t language_id, + int32_t name_id) { + NameEntryId probe(platform_id, encoding_id, language_id, name_id); + NameEntryBuilderMap builders; + GetNameBuilders(); // Ensure name_entry_map_ is built. + if (name_entry_map_.find(probe) != name_entry_map_.end()) { + return name_entry_map_[probe]; + } + NameEntryBuilderPtr builder = new NameEntryBuilder(probe); + name_entry_map_[probe] = builder; + return builder.Detach(); +} + +bool NameTable::Builder::Remove(int32_t platform_id, + int32_t encoding_id, + int32_t language_id, + int32_t name_id) { + NameEntryId probe(platform_id, encoding_id, language_id, name_id); + GetNameBuilders(); // Ensure name_entry_map_ is built. + NameEntryBuilderMap::iterator position = name_entry_map_.find(probe); + if (position != name_entry_map_.end()) { + name_entry_map_.erase(position); + return true; + } + return false; +} + +CALLER_ATTACH FontDataTable* + NameTable::Builder::SubBuildTable(ReadableFontData* data) { + FontDataTablePtr table = new NameTable(header(), data); + return table.Detach(); +} + +void NameTable::Builder::SubDataSet() { + name_entry_map_.clear(); + set_model_changed(false); +} + +int32_t NameTable::Builder::SubDataSizeToSerialize() { + if (name_entry_map_.empty()) { + return 0; + } + + int32_t size = NameTable::Offset::kNameRecordStart + + name_entry_map_.size() * NameTable::Offset::kNameRecordSize; + for (NameEntryBuilderMap::iterator b = name_entry_map_.begin(), + end = name_entry_map_.end(); + b != end; ++b) { + NameEntryBuilderPtr p = b->second; + NameEntry* entry = p->name_entry(); + size += entry->NameBytesLength(); + } + return size; +} + +bool NameTable::Builder::SubReadyToSerialize() { + return !name_entry_map_.empty(); +} + +int32_t NameTable::Builder::SubSerialize(WritableFontData* new_data) { + int32_t string_table_start_offset = + NameTable::Offset::kNameRecordStart + + name_entry_map_.size() * NameTable::Offset::kNameRecordSize; + + // Header + new_data->WriteUShort(NameTable::Offset::kFormat, 0); + new_data->WriteUShort(NameTable::Offset::kCount, name_entry_map_.size()); + new_data->WriteUShort(NameTable::Offset::kStringOffset, + string_table_start_offset); + int32_t name_record_offset = NameTable::Offset::kNameRecordStart; + int32_t string_offset = 0; + // Note: we offered operator< in NameEntryId, which will be used by std::less, + // and therefore our map will act like TreeMap in Java to provide + // sorted key set. + for (NameEntryBuilderMap::iterator b = name_entry_map_.begin(), + end = name_entry_map_.end(); + b != end; ++b) { + new_data->WriteUShort( + name_record_offset + NameTable::Offset::kNameRecordPlatformId, + b->first.platform_id()); + new_data->WriteUShort( + name_record_offset + NameTable::Offset::kNameRecordEncodingId, + b->first.encoding_id()); + new_data->WriteUShort( + name_record_offset + NameTable::Offset::kNameRecordLanguageId, + b->first.language_id()); + new_data->WriteUShort( + name_record_offset + NameTable::Offset::kNameRecordNameId, + b->first.name_id()); + NameEntry* builder_entry = b->second->name_entry(); + new_data->WriteUShort( + name_record_offset + NameTable::Offset::kNameRecordStringLength, + builder_entry->NameBytesLength()); + new_data->WriteUShort( + name_record_offset + NameTable::Offset::kNameRecordStringOffset, + string_offset); + name_record_offset += NameTable::Offset::kNameRecordSize; + string_offset += new_data->WriteBytes( + string_offset + string_table_start_offset, + builder_entry->NameAsBytes()); + } + + return string_offset + string_table_start_offset; +} + +void NameTable::Builder::Initialize(ReadableFontData* data) { + if (data) { + NameTablePtr table = new NameTable(header(), data); + Ptr name_iter; + name_iter.Attach(table->Iterator()); + while (name_iter->HasNext()) { + NameEntryPtr name_entry; + name_entry.Attach(name_iter->Next()); + NameEntryBuilderPtr name_entry_builder = new NameEntryBuilder(name_entry); + NameEntry* builder_entry = name_entry_builder->name_entry(); + NameEntryId probe = builder_entry->name_entry_id(); + name_entry_map_[probe] = name_entry_builder; + } + } +} + +NameTable::NameEntryBuilderMap* NameTable::Builder::GetNameBuilders() { + if (name_entry_map_.empty()) { + Initialize(InternalReadData()); + } + set_model_changed(); + return &name_entry_map_; +} + +/****************************************************************************** + * NameTable class + ******************************************************************************/ +NameTable::~NameTable() {} + +int32_t NameTable::Format() { + return data_->ReadUShort(Offset::kFormat); +} + +int32_t NameTable::NameCount() { + return data_->ReadUShort(Offset::kCount); +} + +int32_t NameTable::PlatformId(int32_t index) { + return data_->ReadUShort(Offset::kNameRecordPlatformId + + OffsetForNameRecord(index)); +} + +int32_t NameTable::EncodingId(int32_t index) { + return data_->ReadUShort(Offset::kNameRecordEncodingId + + OffsetForNameRecord(index)); +} + +int32_t NameTable::LanguageId(int32_t index) { + return data_->ReadUShort(Offset::kNameRecordLanguageId + + OffsetForNameRecord(index)); +} + +int32_t NameTable::NameId(int32_t index) { + return data_->ReadUShort(Offset::kNameRecordNameId + + OffsetForNameRecord(index)); +} + +void NameTable::NameAsBytes(int32_t index, ByteVector* b) { + assert(b); + int32_t length = NameLength(index); + b->clear(); + b->resize(length); + data_->ReadBytes(NameOffset(index), &((*b)[0]), 0, length); +} + +void NameTable::NameAsBytes(int32_t platform_id, + int32_t encoding_id, + int32_t language_id, + int32_t name_id, + ByteVector* b) { + assert(b); + NameEntryPtr entry; + entry.Attach(GetNameEntry(platform_id, encoding_id, language_id, name_id)); + if (entry) { + ByteVector* name = entry->NameAsBytes(); + std::copy(name->begin(), name->end(), b->begin()); + } +} + +UChar* NameTable::Name(int32_t index) { + ByteVector b; + NameAsBytes(index, &b); + return ConvertFromNameBytes(&b, PlatformId(index), EncodingId(index)); +} + +UChar* NameTable::Name(int32_t platform_id, + int32_t encoding_id, + int32_t language_id, + int32_t name_id) { + NameEntryPtr entry; + entry.Attach(GetNameEntry(platform_id, encoding_id, language_id, name_id)); + if (entry) { + return entry->Name(); + } + return NULL; +} + +CALLER_ATTACH NameTable::NameEntry* NameTable::GetNameEntry(int32_t index) { + ByteVector b; + NameAsBytes(index, &b); + NameEntryPtr instance = new NameEntry(PlatformId(index), + EncodingId(index), + LanguageId(index), + NameId(index), b); + return instance.Detach(); +} + +CALLER_ATTACH NameTable::NameEntry* NameTable::GetNameEntry(int32_t platform_id, + int32_t encoding_id, + int32_t language_id, + int32_t name_id) { + NameTable::NameEntryFilterInPlace + filter(platform_id, encoding_id, language_id, name_id); + Ptr name_entry_iter; + name_entry_iter.Attach(Iterator(&filter)); + NameEntryPtr result; + if (name_entry_iter->HasNext()) { + result = name_entry_iter->Next(); + } + return result; +} + +CALLER_ATTACH NameTable::NameEntryIterator* NameTable::Iterator() { + Ptr output = new NameTable::NameEntryIterator(this); + return output.Detach(); +} + +CALLER_ATTACH +NameTable::NameEntryIterator* NameTable::Iterator(NameEntryFilter* filter) { + Ptr output = + new NameTable::NameEntryIterator(this, filter); + return output.Detach(); +} + +NameTable::NameTable(Header* header, ReadableFontData* data) + : SubTableContainerTable(header, data) {} + +int32_t NameTable::StringOffset() { + return data_->ReadUShort(Offset::kStringOffset); +} + +int32_t NameTable::OffsetForNameRecord(int32_t index) { + return Offset::kNameRecordStart + index * Offset::kNameRecordSize; +} + +int32_t NameTable::NameLength(int32_t index) { + return data_->ReadUShort(Offset::kNameRecordStringLength + + OffsetForNameRecord(index)); +} + +int32_t NameTable::NameOffset(int32_t index) { + return data_->ReadUShort(Offset::kNameRecordStringOffset + + OffsetForNameRecord(index)) + StringOffset(); +} + +const char* NameTable::GetEncodingName(int32_t platform_id, + int32_t encoding_id) { + switch (platform_id) { + case PlatformId::kUnicode: + return "UTF-16BE"; + case PlatformId::kMacintosh: + switch (encoding_id) { + case MacintoshEncodingId::kRoman: + return "MacRoman"; + case MacintoshEncodingId::kJapanese: + return "Shift-JIS"; + case MacintoshEncodingId::kChineseTraditional: + return "Big5"; + case MacintoshEncodingId::kKorean: + return "EUC-KR"; + case MacintoshEncodingId::kArabic: + return "MacArabic"; + case MacintoshEncodingId::kHebrew: + return "MacHebrew"; + case MacintoshEncodingId::kGreek: + return "MacGreek"; + case MacintoshEncodingId::kRussian: + return "MacCyrillic"; + case MacintoshEncodingId::kRSymbol: + return "MacSymbol"; + case MacintoshEncodingId::kThai: + return "MacThai"; + case MacintoshEncodingId::kChineseSimplified: + return "EUC-CN"; + default: // Note: unknown/unconfirmed cases are not ported. + break; + } + break; + case PlatformId::kISO: + break; + case PlatformId::kWindows: + switch (encoding_id) { + case WindowsEncodingId::kSymbol: + case WindowsEncodingId::kUnicodeUCS2: + return "UTF-16BE"; + case WindowsEncodingId::kShiftJIS: + return "windows-933"; + case WindowsEncodingId::kPRC: + return "windows-936"; + case WindowsEncodingId::kBig5: + return "windows-950"; + case WindowsEncodingId::kWansung: + return "windows-949"; + case WindowsEncodingId::kJohab: + return "ms1361"; + case WindowsEncodingId::kUnicodeUCS4: + return "UCS-4"; + } + break; + case PlatformId::kCustom: + break; + default: + break; + } + return NULL; +} + +UConverter* NameTable::GetCharset(int32_t platform_id, int32_t encoding_id) { + UErrorCode error_code = U_ZERO_ERROR; + UConverter* conv = ucnv_open(GetEncodingName(platform_id, encoding_id), + &error_code); + if (U_SUCCESS(error_code)) { + return conv; + } + + if (conv) { + ucnv_close(conv); + } + return NULL; +} + +void NameTable::ConvertToNameBytes(const UChar* name, + int32_t platform_id, + int32_t encoding_id, + ByteVector* b) { + assert(b); + assert(name); + b->clear(); + UConverter* cs = GetCharset(platform_id, encoding_id); + if (cs == NULL) { + return; + } + + // Preflight to get buffer size. + UErrorCode error_code = U_ZERO_ERROR; + int32_t length = ucnv_fromUChars(cs, NULL, 0, name, -1, &error_code); + b->resize(length + 4); // The longest termination "\0" is 4 bytes. + memset(&((*b)[0]), 0, length + 4); + error_code = U_ZERO_ERROR; + ucnv_fromUChars(cs, + reinterpret_cast(&((*b)[0])), + length + 4, + name, + -1, + &error_code); + if (!U_SUCCESS(error_code)) { + b->clear(); + } + ucnv_close(cs); +} + +UChar* NameTable::ConvertFromNameBytes(ByteVector* name_bytes, + int32_t platform_id, + int32_t encoding_id) { + if (name_bytes == NULL) { + return NULL; + } + UConverter* cs = GetCharset(platform_id, encoding_id); + UErrorCode error_code = U_ZERO_ERROR; + if (cs == NULL) { + char buffer[11] = {0}; +#if defined (WIN32) + _itoa_s(platform_id, buffer, 16); +#else + snprintf(buffer, sizeof(buffer), "%x", platform_id); +#endif + UChar* result = new UChar[12]; + memset(result, 0, sizeof(UChar) * 12); + cs = ucnv_open("utf-8", &error_code); + if (U_SUCCESS(error_code)) { + ucnv_toUChars(cs, result, 12, buffer, 11, &error_code); + ucnv_close(cs); + if (U_SUCCESS(error_code)) { + return result; + } + } + delete[] result; + return NULL; + } + + // No preflight needed here, we will be bigger. + UChar* output_buffer = new UChar[name_bytes->size() + 1]; + memset(output_buffer, 0, sizeof(UChar) * (name_bytes->size() + 1)); + int32_t length = ucnv_toUChars(cs, + output_buffer, + name_bytes->size(), + reinterpret_cast(&((*name_bytes)[0])), + name_bytes->size(), + &error_code); + ucnv_close(cs); + if (length > 0) { + return output_buffer; + } + + delete[] output_buffer; + return NULL; +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/core/name_table.h b/src/sfntly/src/sfntly/table/core/name_table.h new file mode 100644 index 0000000000..01d3b29076 --- /dev/null +++ b/src/sfntly/src/sfntly/table/core/name_table.h @@ -0,0 +1,744 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_NAME_TABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_NAME_TABLE_H_ + +// Must include this before ICU to avoid stdint redefinition issue. +#include "sfntly/port/type.h" + +#include +#include + +#include +#include + +#include "sfntly/port/java_iterator.h" +#include "sfntly/table/subtable_container_table.h" + +namespace sfntly { + +// The following code implements the name table defined in TTF/OTF spec, which +// can be found at http://www.microsoft.com/typography/otspec/name.htm. + +// Name IDs defined in TTF/OTF spec. +struct NameId { + enum { + kUnknown = -1, + kCopyrightNotice = 0, + kFontFamilyName = 1, + kFontSubfamilyName = 2, + kUniqueFontIdentifier = 3, + kFullFontName = 4, + kVersionString = 5, + kPostscriptName = 6, + kTrademark = 7, + kManufacturerName = 8, + kDesigner = 9, + kDescription = 10, + kVendorURL = 11, + kDesignerURL = 12, + kLicenseDescription = 13, + kLicenseInfoURL = 14, + kReserved15 = 15, + kPreferredFamily = 16, + kPreferredSubfamily = 17, + kCompatibleFullName = 18, + kSampleText = 19, + kPostscriptCID = 20, + kWWSFamilyName = 21, + kWWSSubfamilyName = 22 + }; +}; + +// Unicode language IDs used in Name Records. +struct UnicodeLanguageId { + enum { + kUnknown = -1, + kAll = 0 + }; +}; + +// Macintosh Language IDs (platform ID = 1) +struct MacintoshLanguageId { + enum { + kUnknown = -1, + kEnglish = 0, + kFrench = 1, + kGerman = 2, + kItalian = 3, + kDutch = 4, + kSwedish = 5, + kSpanish = 6, + kDanish = 7, + kPortuguese = 8, + kNorwegian = 9, + kHebrew = 10, + kJapanese = 11, + kArabic = 12, + kFinnish = 13, + kGreek = 14, + kIcelandic = 15, + kMaltese = 16, + kTurkish = 17, + kCroatian = 18, + kChinese_Traditional = 19, + kUrdu = 20, + kHindi = 21, + kThai = 22, + kKorean = 23, + kLithuanian = 24, + kPolish = 25, + kHungarian = 26, + kEstonian = 27, + kLatvian = 28, + kSami = 29, + kFaroese = 30, + kFarsiPersian = 31, + kRussian = 32, + kChinese_Simplified = 33, + kFlemish = 34, + kIrishGaelic = 35, + kAlbanian = 36, + kRomanian = 37, + kCzech = 38, + kSlovak = 39, + kSlovenian = 40, + kYiddish = 41, + kSerbian = 42, + kMacedonian = 43, + kBulgarian = 44, + kUkrainian = 45, + kByelorussian = 46, + kUzbek = 47, + kKazakh = 48, + kAzerbaijani_Cyrillic = 49, + kAzerbaijani_Arabic = 50, + kArmenian = 51, + kGeorgian = 52, + kMoldavian = 53, + kKirghiz = 54, + kTajiki = 55, + kTurkmen = 56, + kMongolian_Mongolian = 57, + kMongolian_Cyrillic = 58, + kPashto = 59, + kKurdish = 60, + kKashmiri = 61, + kSindhi = 62, + kTibetan = 63, + kNepali = 64, + kSanskrit = 65, + kMarathi = 66, + kBengali = 67, + kAssamese = 68, + kGujarati = 69, + kPunjabi = 70, + kOriya = 71, + kMalayalam = 72, + kKannada = 73, + kTamil = 74, + kTelugu = 75, + kSinhalese = 76, + kBurmese = 77, + kKhmer = 78, + kLao = 79, + kVietnamese = 80, + kIndonesian = 81, + kTagalong = 82, + kMalay_Roman = 83, + kMalay_Arabic = 84, + kAmharic = 85, + kTigrinya = 86, + kGalla = 87, + kSomali = 88, + kSwahili = 89, + kKinyarwandaRuanda = 90, + kRundi = 91, + kNyanjaChewa = 92, + kMalagasy = 93, + kEsperanto = 94, + kWelsh = 128, + kBasque = 129, + kCatalan = 130, + kLatin = 131, + kQuenchua = 132, + kGuarani = 133, + kAymara = 134, + kTatar = 135, + kUighur = 136, + kDzongkha = 137, + kJavanese_Roman = 138, + kSundanese_Roman = 139, + kGalician = 140, + kAfrikaans = 141, + kBreton = 142, + kInuktitut = 143, + kScottishGaelic = 144, + kManxGaelic = 145, + kIrishGaelic_WithDotAbove = 146, + kTongan = 147, + kGreek_Polytonic = 148, + kGreenlandic = 149, + kAzerbaijani_Roman = 150 + }; +}; + +// Windows Language IDs (platformID = 3) +struct WindowsLanguageId { + enum { + kUnknown = -1, + kAfrikaans_SouthAfrica = 0x0436, + kAlbanian_Albania = 0x041C, + kAlsatian_France = 0x0484, + kAmharic_Ethiopia = 0x045E, + kArabic_Algeria = 0x1401, + kArabic_Bahrain = 0x3C01, + kArabic_Egypt = 0x0C01, + kArabic_Iraq = 0x0801, + kArabic_Jordan = 0x2C01, + kArabic_Kuwait = 0x3401, + kArabic_Lebanon = 0x3001, + kArabic_Libya = 0x1001, + kArabic_Morocco = 0x1801, + kArabic_Oman = 0x2001, + kArabic_Qatar = 0x4001, + kArabic_SaudiArabia = 0x0401, + kArabic_Syria = 0x2801, + kArabic_Tunisia = 0x1C01, + kArabic_UAE = 0x3801, + kArabic_Yemen = 0x2401, + kArmenian_Armenia = 0x042B, + kAssamese_India = 0x044D, + kAzeri_Cyrillic_Azerbaijan = 0x082C, + kAzeri_Latin_Azerbaijan = 0x042C, + kBashkir_Russia = 0x046D, + kBasque_Basque = 0x042D, + kBelarusian_Belarus = 0x0423, + kBengali_Bangladesh = 0x0845, + kBengali_India = 0x0445, + kBosnian_Cyrillic_BosniaAndHerzegovina = 0x201A, + kBosnian_Latin_BosniaAndHerzegovina = 0x141A, + kBreton_France = 0x047E, + kBulgarian_Bulgaria = 0x0402, + kCatalan_Catalan = 0x0403, + kChinese_HongKongSAR = 0x0C04, + kChinese_MacaoSAR = 0x1404, + kChinese_PeoplesRepublicOfChina = 0x0804, + kChinese_Singapore = 0x1004, + kChinese_Taiwan = 0x0404, + kCorsican_France = 0x0483, + kCroatian_Croatia = 0x041A, + kCroatian_Latin_BosniaAndHerzegovina = 0x101A, + kCzech_CzechRepublic = 0x0405, + kDanish_Denmark = 0x0406, + kDari_Afghanistan = 0x048C, + kDivehi_Maldives = 0x0465, + kDutch_Belgium = 0x0813, + kDutch_Netherlands = 0x0413, + kEnglish_Australia = 0x0C09, + kEnglish_Belize = 0x2809, + kEnglish_Canada = 0x1009, + kEnglish_Caribbean = 0x2409, + kEnglish_India = 0x4009, + kEnglish_Ireland = 0x1809, + kEnglish_Jamaica = 0x2009, + kEnglish_Malaysia = 0x4409, + kEnglish_NewZealand = 0x1409, + kEnglish_RepublicOfThePhilippines = 0x3409, + kEnglish_Singapore = 0x4809, + kEnglish_SouthAfrica = 0x1C09, + kEnglish_TrinidadAndTobago = 0x2C09, + kEnglish_UnitedKingdom = 0x0809, + kEnglish_UnitedStates = 0x0409, + kEnglish_Zimbabwe = 0x3009, + kEstonian_Estonia = 0x0425, + kFaroese_FaroeIslands = 0x0438, + kFilipino_Philippines = 0x0464, + kFinnish_Finland = 0x040B, + kFrench_Belgium = 0x080C, + kFrench_Canada = 0x0C0C, + kFrench_France = 0x040C, + kFrench_Luxembourg = 0x140c, + kFrench_PrincipalityOfMonoco = 0x180C, + kFrench_Switzerland = 0x100C, + kFrisian_Netherlands = 0x0462, + kGalician_Galician = 0x0456, + kGeorgian_Georgia = 0x0437, + kGerman_Austria = 0x0C07, + kGerman_Germany = 0x0407, + kGerman_Liechtenstein = 0x1407, + kGerman_Luxembourg = 0x1007, + kGerman_Switzerland = 0x0807, + kGreek_Greece = 0x0408, + kGreenlandic_Greenland = 0x046F, + kGujarati_India = 0x0447, + kHausa_Latin_Nigeria = 0x0468, + kHebrew_Israel = 0x040D, + kHindi_India = 0x0439, + kHungarian_Hungary = 0x040E, + kIcelandic_Iceland = 0x040F, + kIgbo_Nigeria = 0x0470, + kIndonesian_Indonesia = 0x0421, + kInuktitut_Canada = 0x045D, + kInuktitut_Latin_Canada = 0x085D, + kIrish_Ireland = 0x083C, + kisiXhosa_SouthAfrica = 0x0434, + kisiZulu_SouthAfrica = 0x0435, + kItalian_Italy = 0x0410, + kItalian_Switzerland = 0x0810, + kJapanese_Japan = 0x0411, + kKannada_India = 0x044B, + kKazakh_Kazakhstan = 0x043F, + kKhmer_Cambodia = 0x0453, + kKiche_Guatemala = 0x0486, + kKinyarwanda_Rwanda = 0x0487, + kKiswahili_Kenya = 0x0441, + kKonkani_India = 0x0457, + kKorean_Korea = 0x0412, + kKyrgyz_Kyrgyzstan = 0x0440, + kLao_LaoPDR = 0x0454, + kLatvian_Latvia = 0x0426, + kLithuanian_Lithuania = 0x0427, + kLowerSorbian_Germany = 0x082E, + kLuxembourgish_Luxembourg = 0x046E, + kMacedonian_FYROM_FormerYugoslavRepublicOfMacedonia = 0x042F, + kMalay_BruneiDarussalam = 0x083E, + kMalay_Malaysia = 0x043E, + kMalayalam_India = 0x044C, + kMaltese_Malta = 0x043A, + kMaori_NewZealand = 0x0481, + kMapudungun_Chile = 0x047A, + kMarathi_India = 0x044E, + kMohawk_Mohawk = 0x047C, + kMongolian_Cyrillic_Mongolia = 0x0450, + kMongolian_Traditional_PeoplesRepublicOfChina = 0x0850, + kNepali_Nepal = 0x0461, + kNorwegian_Bokmal_Norway = 0x0414, + kNorwegian_Nynorsk_Norway = 0x0814, + kOccitan_France = 0x0482, + kOriya_India = 0x0448, + kPashto_Afghanistan = 0x0463, + kPolish_Poland = 0x0415, + kPortuguese_Brazil = 0x0416, + kPortuguese_Portugal = 0x0816, + kPunjabi_India = 0x0446, + kQuechua_Bolivia = 0x046B, + kQuechua_Ecuador = 0x086B, + kQuechua_Peru = 0x0C6B, + kRomanian_Romania = 0x0418, + kRomansh_Switzerland = 0x0417, + kRussian_Russia = 0x0419, + kSami_Inari_Finland = 0x243B, + kSami_Lule_Norway = 0x103B, + kSami_Lule_Sweden = 0x143B, + kSami_Northern_Finland = 0x0C3B, + kSami_Northern_Norway = 0x043B, + kSami_Northern_Sweden = 0x083B, + kSami_Skolt_Finland = 0x203B, + kSami_Southern_Norway = 0x183B, + kSami_Southern_Sweden = 0x1C3B, + kSanskrit_India = 0x044F, + kSerbian_Cyrillic_BosniaAndHerzegovina = 0x1C1A, + kSerbian_Cyrillic_Serbia = 0x0C1A, + kSerbian_Latin_BosniaAndHerzegovina = 0x181A, + kSerbian_Latin_Serbia = 0x081A, + kSesothoSaLeboa_SouthAfrica = 0x046C, + kSetswana_SouthAfrica = 0x0432, + kSinhala_SriLanka = 0x045B, + kSlovak_Slovakia = 0x041B, + kSlovenian_Slovenia = 0x0424, + kSpanish_Argentina = 0x2C0A, + kSpanish_Bolivia = 0x400A, + kSpanish_Chile = 0x340A, + kSpanish_Colombia = 0x240A, + kSpanish_CostaRica = 0x140A, + kSpanish_DominicanRepublic = 0x1C0A, + kSpanish_Ecuador = 0x300A, + kSpanish_ElSalvador = 0x440A, + kSpanish_Guatemala = 0x100A, + kSpanish_Honduras = 0x480A, + kSpanish_Mexico = 0x080A, + kSpanish_Nicaragua = 0x4C0A, + kSpanish_Panama = 0x180A, + kSpanish_Paraguay = 0x3C0A, + kSpanish_Peru = 0x280A, + kSpanish_PuertoRico = 0x500A, + kSpanish_ModernSort_Spain = 0x0C0A, + kSpanish_TraditionalSort_Spain = 0x040A, + kSpanish_UnitedStates = 0x540A, + kSpanish_Uruguay = 0x380A, + kSpanish_Venezuela = 0x200A, + kSweden_Finland = 0x081D, + kSwedish_Sweden = 0x041D, + kSyriac_Syria = 0x045A, + kTajik_Cyrillic_Tajikistan = 0x0428, + kTamazight_Latin_Algeria = 0x085F, + kTamil_India = 0x0449, + kTatar_Russia = 0x0444, + kTelugu_India = 0x044A, + kThai_Thailand = 0x041E, + kTibetan_PRC = 0x0451, + kTurkish_Turkey = 0x041F, + kTurkmen_Turkmenistan = 0x0442, + kUighur_PRC = 0x0480, + kUkrainian_Ukraine = 0x0422, + kUpperSorbian_Germany = 0x042E, + kUrdu_IslamicRepublicOfPakistan = 0x0420, + kUzbek_Cyrillic_Uzbekistan = 0x0843, + kUzbek_Latin_Uzbekistan = 0x0443, + kVietnamese_Vietnam = 0x042A, + kWelsh_UnitedKingdom = 0x0452, + kWolof_Senegal = 0x0448, + kYakut_Russia = 0x0485, + kYi_PRC = 0x0478, + kYoruba_Nigeria = 0x046A + }; +}; + +class NameTable : public SubTableContainerTable, public RefCounted { + public: + // Unique identifier for a given name record. + class NameEntryId { + public: + NameEntryId(); // C++ port only, must provide default constructor. + NameEntryId(int32_t platform_id, int32_t encoding_id, int32_t language_id, + int32_t name_id); + NameEntryId(const NameEntryId&); + // Make gcc -Wnon-virtual-dtor happy. + virtual ~NameEntryId() {} + + int32_t platform_id() const { return platform_id_; } + int32_t encoding_id() const { return encoding_id_; } + int32_t language_id() const { return language_id_; } + int32_t name_id() const { return name_id_; } + + const NameEntryId& operator=(const NameEntryId& rhs) const; + bool operator==(const NameEntryId& rhs) const; + bool operator<(const NameEntryId& rhs) const; + + // UNIMPLEMENTED: int hashCode() + // String toString() + + private: + mutable int32_t platform_id_; + mutable int32_t encoding_id_; + mutable int32_t language_id_; + mutable int32_t name_id_; + }; + + class NameEntryBuilder; + + // Class to represent a name entry in the name table. + class NameEntry : public RefCounted { + public: + NameEntry(); + NameEntry(const NameEntryId& name_entry_id, const ByteVector& name_bytes); + NameEntry(int32_t platform_id, + int32_t encoding_id, + int32_t language_id, + int32_t name_id, + const ByteVector& name_bytes); + virtual ~NameEntry(); + + NameEntryId& name_entry_id() { return name_entry_id_; } + int32_t platform_id() const { return name_entry_id_.platform_id(); } + int32_t encoding_id() const { return name_entry_id_.encoding_id(); } + int32_t language_id() const { return name_entry_id_.language_id(); } + int32_t name_id() const { return name_entry_id_.name_id(); } + + // Get the bytes for name. Returned pointer is the address of private + // member of this class, do not attempt to delete. + ByteVector* NameAsBytes(); + + // C++ port only: get the length of NameAsBytes. + int32_t NameBytesLength(); + + // Returns the name in Unicode as UChar array. + // Note: ICU UChar* convention requires caller to delete[] it. + UChar* Name(); + bool operator==(const NameEntry& rhs) const; + + // UNIMPLEMENTED: String toString() + // int hashCode() + + private: + void Init(int32_t platform_id, int32_t encoding_id, int32_t language_id, + int32_t name_id, const ByteVector* name_bytes); + + NameEntryId name_entry_id_; + int32_t length_; + ByteVector name_bytes_; + + friend class NameEntryBuilder; + }; + + // Builder of a name entry. + // C++ port: original Java hierarchy inherits from NameEntry. In C++ port, we + // opted not doing so to avoid ref count issues and nasty protected members. + class NameEntryBuilder : public RefCounted { + public: + NameEntryBuilder(); + NameEntryBuilder(const NameEntryId& name_entry_id, + const ByteVector& name_bytes); + explicit NameEntryBuilder(const NameEntryId& name_entry_id); + explicit NameEntryBuilder(NameEntry* entry); + virtual ~NameEntryBuilder(); + + virtual void SetName(const UChar* name); + virtual void SetName(const ByteVector& name_bytes); + virtual void SetName(const ByteVector& name_bytes, + int32_t offset, + int32_t length); + + // C++ port only. CALLER_ATTACH is not added because the lifetime shall be + // controlled by this class, therefore the caller shall not increase the ref + // count. + NameEntry* name_entry() { return name_entry_; } + + private: + void Init(int32_t platform_id, int32_t encoding_id, int32_t language_id, + int32_t name_id, const ByteVector* name_bytes); + + Ptr name_entry_; + }; + typedef std::map > NameEntryBuilderMap; + + // An interface for a filter to use with the name entry iterator. This allows + // name entries to be iterated and only those acceptable to the filter will be + // returned. + class NameEntryFilter { + public: + virtual bool Accept(int32_t platform_id, + int32_t encoding_id, + int32_t language_id, + int32_t name_id) = 0; + // Make gcc -Wnon-virtual-dtor happy. + virtual ~NameEntryFilter() {} + }; + + // C++ port only: an in-place filter to mimic Java Iterator's filtering. + class NameEntryFilterInPlace : public NameEntryFilter { + public: + NameEntryFilterInPlace(int32_t platform_id, + int32_t encoding_id, + int32_t language_id, + int32_t name_id); + // Make gcc -Wnon-virtual-dtor happy. + virtual ~NameEntryFilterInPlace() {} + + virtual bool Accept(int32_t platform_id, + int32_t encoding_id, + int32_t language_id, + int32_t name_id); + + private: + int32_t platform_id_; + int32_t encoding_id_; + int32_t language_id_; + int32_t name_id_; + }; + + class NameEntryIterator : public RefIterator { + public: + // If filter is NULL, filter through all tables. + explicit NameEntryIterator(NameTable* table); + NameEntryIterator(NameTable* table, NameEntryFilter* filter); + virtual ~NameEntryIterator() {} + + virtual bool HasNext(); + virtual CALLER_ATTACH NameEntry* Next(); + + private: + int32_t name_index_; + NameEntryFilter* filter_; + }; + + // The builder to construct name table for outputting. + class Builder : public SubTableContainerTable::Builder, + public RefCounted { + public: + // Constructor scope altered to public because C++ does not allow base + // class to instantiate derived class with protected constructors. + Builder(Header* header, WritableFontData* data); + Builder(Header* header, ReadableFontData* data); + + static CALLER_ATTACH Builder* CreateBuilder(Header* header, + WritableFontData* data); + + // Revert the name builders for the name table to the last version that came + // from data. + void RevertNames(); + + // Number of name entry builders contained. + int32_t BuilderCount(); + + // Note: For C++ port, clear() is not implemented. The clear() function + // implies completely remove name entry builders, which is easy in + // Java but will take a lot of efforts in C++ to release the builders + // nicely and correctly. + // TODO(arthurhsu): IMPLEMENT + // Clear the name builders for the name table. + // void clear(); + + // Check the existance of a name entry builder by key. + bool Has(int32_t platform_id, int32_t encoding_id, int32_t language_id, + int32_t name_id); + + // Get name entry builder by key. + CALLER_ATTACH NameEntryBuilder* NameBuilder(int32_t platform_id, + int32_t encoding_id, int32_t language_id, int32_t name_id); + + // Remove name entry builder by key. + bool Remove(int32_t platform_id, int32_t encoding_id, int32_t language_id, + int32_t name_id); + + // FontDataTable::Builder API implementation + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + + private: + void Initialize(ReadableFontData* data); + NameEntryBuilderMap* GetNameBuilders(); + + // Note: callers should use the getter funtion provided above to ensure that + // this is lazily initialized instead of accessing directly. + NameEntryBuilderMap name_entry_map_; + }; + + /**************************************************************************** + * public methods of NameTable class + ****************************************************************************/ + virtual ~NameTable(); + + // Get the format used in the name table. + virtual int32_t Format(); + + // Get the number of names in the name table. + virtual int32_t NameCount(); + + // Get the platform id for the given name record. + virtual int32_t PlatformId(int32_t index); + + // Get the encoding id for the given name record. + // see MacintoshEncodingId, WindowsEncodingId, UnicodeEncodingId + virtual int32_t EncodingId(int32_t index); + + // Get the language id for the given name record. + virtual int32_t LanguageId(int32_t index); + + // Get the name id for given name record. + virtual int32_t NameId(int32_t index); + + // Get the name as bytes for the specified name. If there is no entry for the + // requested name, then empty vector is returned. + virtual void NameAsBytes(int32_t index, ByteVector* b); + virtual void NameAsBytes(int32_t platform_id, int32_t encoding_id, + int32_t language_id, int32_t name_id, + ByteVector* b); + + // Get the name as a UChar* for the given name record. If there is no + // encoding conversion available for the name record then a best attempt + // UChar* will be returned. + // Note: ICU UChar* convention requires caller to delete[] it. + virtual UChar* Name(int32_t index); + + // Get the name as a UChar* for the specified name. If there is no entry for + // the requested name then NULL is returned. If there is no encoding + // conversion available for the name then a best attempt UChar* will be + // returned. + // Note: ICU UChar* convention requires caller to delete[] it. + virtual UChar* Name(int32_t platform_id, int32_t encoding_id, + int32_t language_id, int32_t name_id); + + // Note: These functions are renamed in C++ port. Their original Java name is + // nameEntry(). + virtual CALLER_ATTACH NameEntry* GetNameEntry(int32_t index); + virtual CALLER_ATTACH NameEntry* GetNameEntry(int32_t platform_id, + int32_t encoding_id, int32_t language_id, int32_t name_id); + + // Note: Not implemented in C++ port due to complexity and low usage. + // virtual void names(std::set*); + + // Get the iterator to iterate through all name entries. + virtual CALLER_ATTACH NameEntryIterator* Iterator(); + virtual CALLER_ATTACH NameEntryIterator* Iterator(NameEntryFilter* filter); + + private: + struct Offset { + enum { + kFormat = 0, + kCount = 2, + kStringOffset = 4, + kNameRecordStart = 6, + + // Format 1 - offset from the end of the name records + kLangTagCount = 0, + kLangTagRecord = 2, + + kNameRecordSize = 12, + // Name Records + kNameRecordPlatformId = 0, + kNameRecordEncodingId = 2, + kNameRecordLanguageId = 4, + kNameRecordNameId = 6, + kNameRecordStringLength = 8, + kNameRecordStringOffset = 10 + }; + }; + + // The table shall be constructed using Builder, no direct instantiation. + NameTable(Header* header, ReadableFontData* data); + + // Get the offset to the string data in the name table. + int32_t StringOffset(); + + // Get the offset for the given name record. + int32_t OffsetForNameRecord(int32_t index); + + // Get the length of the string data for the given name record. + int32_t NameLength(int32_t index); + + // Get the offset of the string data for the given name record. + int32_t NameOffset(int32_t index); + + // Note: string literals are returned. Caller shall not attempt to manipulate + // the returned pointer. + static const char* GetEncodingName(int32_t platform_id, int32_t encoding_id); + + // Note: ICU UConverter* convention requires caller to ucnv_close() it. + static UConverter* GetCharset(int32_t platform_id, int32_t encoding_id); + + // Note: Output will be stored in ByteVector* b. Original data in b will be + // erased and replaced with converted name bytes. + static void ConvertToNameBytes(const UChar* name, int32_t platform_id, + int32_t encoding_id, ByteVector* b); + + // Note: ICU UChar* convention requires caller to delete[] it. + static UChar* ConvertFromNameBytes(ByteVector* name_bytes, + int32_t platform_id, int32_t encoding_id); +}; // class NameTable +typedef Ptr NameTablePtr; +typedef Ptr NameEntryPtr; +typedef Ptr NameTableBuilderPtr; +typedef Ptr NameEntryBuilderPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_NAME_TABLE_H_ diff --git a/src/sfntly/src/sfntly/table/core/os2_table.cc b/src/sfntly/src/sfntly/table/core/os2_table.cc new file mode 100644 index 0000000000..7ca9d9a4fd --- /dev/null +++ b/src/sfntly/src/sfntly/table/core/os2_table.cc @@ -0,0 +1,608 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/core/os2_table.h" + +namespace sfntly { +/****************************************************************************** + * Constants + ******************************************************************************/ +const int64_t CodePageRange::kLatin1_1252 = (int64_t)1 << 0; +const int64_t CodePageRange::kLatin2_1250 = (int64_t)1 << (int64_t)1; +const int64_t CodePageRange::kCyrillic_1251 = (int64_t)1 << 2; +const int64_t CodePageRange::kGreek_1253 = (int64_t)1 << 3; +const int64_t CodePageRange::kTurkish_1254 = (int64_t)1 << 4; +const int64_t CodePageRange::kHebrew_1255 = (int64_t)1 << 5; +const int64_t CodePageRange::kArabic_1256 = (int64_t)1 << 6; +const int64_t CodePageRange::kWindowsBaltic_1257 = (int64_t)1 << 7; +const int64_t CodePageRange::kVietnamese_1258 = (int64_t)1 << 8; +const int64_t CodePageRange::kAlternateANSI9 = (int64_t)1 << 9; +const int64_t CodePageRange::kAlternateANSI10 = (int64_t)1 << 10; +const int64_t CodePageRange::kAlternateANSI11 = (int64_t)1 << 11; +const int64_t CodePageRange::kAlternateANSI12 = (int64_t)1 << 12; +const int64_t CodePageRange::kAlternateANSI13 = (int64_t)1 << 13; +const int64_t CodePageRange::kAlternateANSI14 = (int64_t)1 << 14; +const int64_t CodePageRange::kAlternateANSI15 = (int64_t)1 << 15; +const int64_t CodePageRange::kThai_874 = (int64_t)1 << 16; +const int64_t CodePageRange::kJapanJIS_932 = (int64_t)1 << 17; +const int64_t CodePageRange::kChineseSimplified_936 = (int64_t)1 << 18; +const int64_t CodePageRange::kKoreanWansung_949 = (int64_t)1 << 19; +const int64_t CodePageRange::kChineseTraditional_950 = (int64_t)1 << 20; +const int64_t CodePageRange::kKoreanJohab_1361 = (int64_t)1 << 21; +const int64_t CodePageRange::kAlternateANSI22 = (int64_t)1 << 22; +const int64_t CodePageRange::kAlternateANSI23 = (int64_t)1 << 23; +const int64_t CodePageRange::kAlternateANSI24 = (int64_t)1 << 24; +const int64_t CodePageRange::kAlternateANSI25 = (int64_t)1 << 25; +const int64_t CodePageRange::kAlternateANSI26 = (int64_t)1 << 26; +const int64_t CodePageRange::kAlternateANSI27 = (int64_t)1 << 27; +const int64_t CodePageRange::kAlternateANSI28 = (int64_t)1 << 28; +const int64_t CodePageRange::kMacintoshCharacterSet = (int64_t)1 << 29; +const int64_t CodePageRange::kOEMCharacterSet = (int64_t)1 << 30; +const int64_t CodePageRange::kSymbolCharacterSet = (int64_t)1 << 31; +const int64_t CodePageRange::kReservedForOEM32 = (int64_t)1 << 32; +const int64_t CodePageRange::kReservedForOEM33 = (int64_t)1 << 33; +const int64_t CodePageRange::kReservedForOEM34 = (int64_t)1 << 34; +const int64_t CodePageRange::kReservedForOEM35 = (int64_t)1 << 35; +const int64_t CodePageRange::kReservedForOEM36 = (int64_t)1 << 36; +const int64_t CodePageRange::kReservedForOEM37 = (int64_t)1 << 37; +const int64_t CodePageRange::kReservedForOEM38 = (int64_t)1 << 38; +const int64_t CodePageRange::kReservedForOEM39 = (int64_t)1 << 39; +const int64_t CodePageRange::kReservedForOEM40 = (int64_t)1 << 40; +const int64_t CodePageRange::kReservedForOEM41 = (int64_t)1 << 41; +const int64_t CodePageRange::kReservedForOEM42 = (int64_t)1 << 42; +const int64_t CodePageRange::kReservedForOEM43 = (int64_t)1 << 43; +const int64_t CodePageRange::kReservedForOEM44 = (int64_t)1 << 44; +const int64_t CodePageRange::kReservedForOEM45 = (int64_t)1 << 45; +const int64_t CodePageRange::kReservedForOEM46 = (int64_t)1 << 46; +const int64_t CodePageRange::kReservedForOEM47 = (int64_t)1 << 47; +const int64_t CodePageRange::kIBMGreek_869 = (int64_t)1 << 48; +const int64_t CodePageRange::kMSDOSRussion_866 = (int64_t)1 << 49; +const int64_t CodePageRange::kMSDOSNordic_865 = (int64_t)1 << 50; +const int64_t CodePageRange::kArabic_864 = (int64_t)1 << 51; +const int64_t CodePageRange::kMSDOSCanadianFrench_863 = (int64_t)1 << 52; +const int64_t CodePageRange::kHebrew_862 = (int64_t)1 << 53; +const int64_t CodePageRange::kMSDOSIcelandic_861 = (int64_t)1 << 54; +const int64_t CodePageRange::kMSDOSPortugese_860 = (int64_t)1 << 55; +const int64_t CodePageRange::kIBMTurkish_857 = (int64_t)1 << 56; +const int64_t CodePageRange::kIBMCyrillic_855 = (int64_t)1 << 57; +const int64_t CodePageRange::kLatin2_852 = (int64_t)1 << 58; +const int64_t CodePageRange::kMSDOSBaltic_775 = (int64_t)1 << 59; +const int64_t CodePageRange::kGreek_737 = (int64_t)1 << 60; +const int64_t CodePageRange::kArabic_708 = (int64_t)1 << 61; +const int64_t CodePageRange::kLatin1_850 = (int64_t)1 << 62; +const int64_t CodePageRange::kUS_437 = (int64_t)1 << 63; + +/****************************************************************************** + * struct UnicodeRange + ******************************************************************************/ +int32_t UnicodeRange::range(int32_t bit) { + if (bit < 0 || bit > kLast) { + return -1; + } + return bit; +} + +/****************************************************************************** + * class OS2Table + ******************************************************************************/ +OS2Table::~OS2Table() {} + +int32_t OS2Table::TableVersion() { + return data_->ReadUShort(Offset::kVersion); +} + +int32_t OS2Table::XAvgCharWidth() { + return data_->ReadShort(Offset::kXAvgCharWidth); +} + +int32_t OS2Table::UsWeightClass() { + return data_->ReadUShort(Offset::kUsWeightClass); +} + +int32_t OS2Table::UsWidthClass() { + return data_->ReadUShort(Offset::kUsWidthClass); +} + +int32_t OS2Table::FsType() { + return data_->ReadUShort(Offset::kFsType); +} + +int32_t OS2Table::YSubscriptXSize() { + return data_->ReadShort(Offset::kYSubscriptXSize); +} + +int32_t OS2Table::YSubscriptYSize() { + return data_->ReadShort(Offset::kYSubscriptYSize); +} + +int32_t OS2Table::YSubscriptXOffset() { + return data_->ReadShort(Offset::kYSubscriptXOffset); +} + +int32_t OS2Table::YSubscriptYOffset() { + return data_->ReadShort(Offset::kYSubscriptYOffset); +} + +int32_t OS2Table::YSuperscriptXSize() { + return data_->ReadShort(Offset::kYSuperscriptXSize); +} + +int32_t OS2Table::YSuperscriptYSize() { + return data_->ReadShort(Offset::kYSuperscriptYSize); +} + +int32_t OS2Table::YSuperscriptXOffset() { + return data_->ReadShort(Offset::kYSuperscriptXOffset); +} + +int32_t OS2Table::YSuperscriptYOffset() { + return data_->ReadShort(Offset::kYSuperscriptYOffset); +} + +int32_t OS2Table::YStrikeoutSize() { + return data_->ReadShort(Offset::kYStrikeoutSize); +} + +int32_t OS2Table::YStrikeoutPosition() { + return data_->ReadShort(Offset::kYStrikeoutPosition); +} + +int32_t OS2Table::SFamilyClass() { + return data_->ReadShort(Offset::kSFamilyClass); +} + +void OS2Table::Panose(ByteVector* value) { + assert(value); + value->clear(); + value->resize(10); + data_->ReadBytes(Offset::kPanose, &((*value)[0]), 0, 10); +} + +int64_t OS2Table::UlUnicodeRange1() { + return data_->ReadULong(Offset::kUlUnicodeRange1); +} + +int64_t OS2Table::UlUnicodeRange2() { + return data_->ReadULong(Offset::kUlUnicodeRange2); +} + +int64_t OS2Table::UlUnicodeRange3() { + return data_->ReadULong(Offset::kUlUnicodeRange3); +} + +int64_t OS2Table::UlUnicodeRange4() { + return data_->ReadULong(Offset::kUlUnicodeRange4); +} + +void OS2Table::AchVendId(ByteVector* b) { + assert(b); + b->clear(); + b->resize(4); + data_->ReadBytes(Offset::kAchVendId, &((*b)[0]), 0, 4); +} + +int32_t OS2Table::FsSelection() { + return data_->ReadUShort(Offset::kFsSelection); +} + +int32_t OS2Table::UsFirstCharIndex() { + return data_->ReadUShort(Offset::kUsFirstCharIndex); +} + +int32_t OS2Table::UsLastCharIndex() { + return data_->ReadUShort(Offset::kUsLastCharIndex); +} + +int32_t OS2Table::STypoAscender() { + return data_->ReadShort(Offset::kSTypoAscender); +} + +int32_t OS2Table::STypoDescender() { + return data_->ReadShort(Offset::kSTypoDescender); +} + +int32_t OS2Table::STypoLineGap() { + return data_->ReadShort(Offset::kSTypoLineGap); +} + +int32_t OS2Table::UsWinAscent() { + return data_->ReadUShort(Offset::kUsWinAscent); +} + +int32_t OS2Table::UsWinDescent() { + return data_->ReadUShort(Offset::kUsWinDescent); +} + +int64_t OS2Table::UlCodePageRange1() { + return data_->ReadULong(Offset::kUlCodePageRange1); +} + +int64_t OS2Table::UlCodePageRange2() { + return data_->ReadULong(Offset::kUlCodePageRange2); +} + +int32_t OS2Table::SxHeight() { + return data_->ReadShort(Offset::kSxHeight); +} + +int32_t OS2Table::SCapHeight() { + return data_->ReadShort(Offset::kSCapHeight); +} + +int32_t OS2Table::UsDefaultChar() { + return data_->ReadUShort(Offset::kUsDefaultChar); +} + +int32_t OS2Table::UsBreakChar() { + return data_->ReadUShort(Offset::kUsBreakChar); +} + +int32_t OS2Table::UsMaxContext() { + return data_->ReadUShort(Offset::kUsMaxContext); +} + +OS2Table::OS2Table(Header* header, ReadableFontData* data) + : Table(header, data) { +} + +/****************************************************************************** + * class OS2Table::Builder + ******************************************************************************/ +OS2Table::Builder::Builder(Header* header, WritableFontData* data) + : TableBasedTableBuilder(header, data) { +} + +OS2Table::Builder::Builder(Header* header, ReadableFontData* data) + : TableBasedTableBuilder(header, data) { +} + +OS2Table::Builder::~Builder() {} + +CALLER_ATTACH FontDataTable* OS2Table::Builder::SubBuildTable( + ReadableFontData* data) { + FontDataTablePtr table = new OS2Table(header(), data); + return table.Detach(); +} + +CALLER_ATTACH OS2Table::Builder* + OS2Table::Builder::CreateBuilder(Header* header, + WritableFontData* data) { + Ptr builder; + builder = new OS2Table::Builder(header, data); + return builder.Detach(); +} + +int32_t OS2Table::Builder::TableVersion() { + return InternalReadData()->ReadUShort(Offset::kVersion); +} + +void OS2Table::Builder::SetTableVersion(int32_t version) { + InternalWriteData()->WriteUShort(Offset::kVersion, version); +} + +int32_t OS2Table::Builder::XAvgCharWidth() { + return InternalReadData()->ReadShort(Offset::kXAvgCharWidth); +} + +void OS2Table::Builder::SetXAvgCharWidth(int32_t width) { + InternalWriteData()->WriteShort(Offset::kXAvgCharWidth, width); +} + +int32_t OS2Table::Builder::UsWeightClass() { + return InternalReadData()->ReadUShort(Offset::kUsWeightClass); +} + +void OS2Table::Builder::SetUsWeightClass(int32_t weight) { + InternalWriteData()->WriteUShort(Offset::kUsWeightClass, weight); +} + +int32_t OS2Table::Builder::UsWidthClass() { + return InternalReadData()->ReadUShort(Offset::kUsWidthClass); +} + +void OS2Table::Builder::SetUsWidthClass(int32_t width) { + InternalWriteData()->WriteUShort(Offset::kUsWidthClass, width); +} + +int32_t OS2Table::Builder::FsType() { + return InternalReadData()->ReadUShort(Offset::kFsType); +} + +void OS2Table::Builder::SetFsType(int32_t fs_type) { + InternalWriteData()->WriteUShort(Offset::kFsType, fs_type); +} + +int32_t OS2Table::Builder::YSubscriptXSize() { + return InternalReadData()->ReadShort(Offset::kYSubscriptXSize); +} + +void OS2Table::Builder::SetYSubscriptXSize(int32_t size) { + InternalWriteData()->WriteShort(Offset::kYSubscriptXSize, size); +} + +int32_t OS2Table::Builder::YSubscriptYSize() { + return InternalReadData()->ReadShort(Offset::kYSubscriptYSize); +} + +void OS2Table::Builder::SetYSubscriptYSize(int32_t size) { + InternalWriteData()->WriteShort(Offset::kYSubscriptYSize, size); +} + +int32_t OS2Table::Builder::YSubscriptXOffset() { + return InternalReadData()->ReadShort(Offset::kYSubscriptXOffset); +} + +void OS2Table::Builder::SetYSubscriptXOffset(int32_t offset) { + InternalWriteData()->WriteShort(Offset::kYSubscriptXOffset, offset); +} + +int32_t OS2Table::Builder::YSubscriptYOffset() { + return InternalReadData()->ReadShort(Offset::kYSubscriptYOffset); +} + +void OS2Table::Builder::SetYSubscriptYOffset(int32_t offset) { + InternalWriteData()->WriteShort(Offset::kYSubscriptYOffset, offset); +} + +int32_t OS2Table::Builder::YSuperscriptXSize() { + return InternalReadData()->ReadShort(Offset::kYSuperscriptXSize); +} + +void OS2Table::Builder::SetYSuperscriptXSize(int32_t size) { + InternalWriteData()->WriteShort(Offset::kYSuperscriptXSize, size); +} + +int32_t OS2Table::Builder::YSuperscriptYSize() { + return InternalReadData()->ReadShort(Offset::kYSuperscriptYSize); +} + +void OS2Table::Builder::SetYSuperscriptYSize(int32_t size) { + InternalWriteData()->WriteShort(Offset::kYSuperscriptYSize, size); +} + +int32_t OS2Table::Builder::YSuperscriptXOffset() { + return InternalReadData()->ReadShort(Offset::kYSuperscriptXOffset); +} + +void OS2Table::Builder::SetYSuperscriptXOffset(int32_t offset) { + InternalWriteData()->WriteShort(Offset::kYSuperscriptXOffset, offset); +} + +int32_t OS2Table::Builder::YSuperscriptYOffset() { + return InternalReadData()->ReadShort(Offset::kYSuperscriptYOffset); +} + +void OS2Table::Builder::SetYSuperscriptYOffset(int32_t offset) { + InternalWriteData()->WriteShort(Offset::kYSuperscriptYOffset, offset); +} + +int32_t OS2Table::Builder::YStrikeoutSize() { + return InternalReadData()->ReadShort(Offset::kYStrikeoutSize); +} + +void OS2Table::Builder::SetYStrikeoutSize(int32_t size) { + InternalWriteData()->WriteShort(Offset::kYStrikeoutSize, size); +} + +int32_t OS2Table::Builder::YStrikeoutPosition() { + return InternalReadData()->ReadShort(Offset::kYStrikeoutPosition); +} + +void OS2Table::Builder::SetYStrikeoutPosition(int32_t position) { + InternalWriteData()->WriteShort(Offset::kYStrikeoutPosition, position); +} + +int32_t OS2Table::Builder::SFamilyClass() { + return InternalReadData()->ReadShort(Offset::kSFamilyClass); +} + +void OS2Table::Builder::SetSFamilyClass(int32_t family) { + InternalWriteData()->WriteShort(Offset::kSFamilyClass, family); +} + +void OS2Table::Builder::Panose(ByteVector* value) { + assert(value); + value->clear(); + value->resize(Offset::kPanoseLength); + InternalReadData()->ReadBytes(Offset::kPanose, + &((*value)[0]), + 0, + Offset::kPanoseLength); +} + +void OS2Table::Builder::SetPanose(ByteVector* panose) { + assert(panose); + if (panose->size() != Offset::kPanoseLength) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IllegalArgumentException("Panose bytes must be exactly 10 in length"); +#endif + return; + } + InternalWriteData()->WriteBytes(Offset::kPanose, panose); +} + +int64_t OS2Table::Builder::UlUnicodeRange1() { + return InternalReadData()->ReadULong(Offset::kUlUnicodeRange1); +} + +void OS2Table::Builder::SetUlUnicodeRange1(int64_t range) { + InternalWriteData()->WriteULong(Offset::kUlUnicodeRange1, range); +} + +int64_t OS2Table::Builder::UlUnicodeRange2() { + return InternalReadData()->ReadULong(Offset::kUlUnicodeRange2); +} + +void OS2Table::Builder::SetUlUnicodeRange2(int64_t range) { + InternalWriteData()->WriteULong(Offset::kUlUnicodeRange2, range); +} + +int64_t OS2Table::Builder::UlUnicodeRange3() { + return InternalReadData()->ReadULong(Offset::kUlUnicodeRange3); +} + +void OS2Table::Builder::SetUlUnicodeRange3(int64_t range) { + InternalWriteData()->WriteULong(Offset::kUlUnicodeRange3, range); +} + +int64_t OS2Table::Builder::UlUnicodeRange4() { + return InternalReadData()->ReadULong(Offset::kUlUnicodeRange4); +} + +void OS2Table::Builder::SetUlUnicodeRange4(int64_t range) { + InternalWriteData()->WriteULong(Offset::kUlUnicodeRange4, range); +} + +void OS2Table::Builder::AchVendId(ByteVector* b) { + assert(b); + b->clear(); + b->resize(4); + InternalReadData()->ReadBytes(Offset::kAchVendId, &((*b)[0]), 0, 4); +} + +void OS2Table::Builder::SetAchVendId(ByteVector* b) { + assert(b); + assert(b->size()); + InternalWriteData()->WriteBytesPad(Offset::kAchVendId, + b, + 0, + std::min( + (size_t)Offset::kAchVendIdLength, + b->size()), + static_cast(' ')); +} + +int32_t OS2Table::Builder::FsSelection() { + return InternalReadData()->ReadUShort(Offset::kFsSelection); +} + +void OS2Table::Builder::SetFsSelection(int32_t fs_selection) { + InternalWriteData()->WriteUShort(Offset::kFsSelection, fs_selection); +} + +int32_t OS2Table::Builder::UsFirstCharIndex() { + return InternalReadData()->ReadUShort(Offset::kUsFirstCharIndex); +} + +void OS2Table::Builder::SetUsFirstCharIndex(int32_t first_index) { + InternalWriteData()->WriteUShort(Offset::kUsFirstCharIndex, first_index); +} + +int32_t OS2Table::Builder::UsLastCharIndex() { + return InternalReadData()->ReadUShort(Offset::kUsLastCharIndex); +} + +void OS2Table::Builder::SetUsLastCharIndex(int32_t last_index) { + InternalWriteData()->WriteUShort(Offset::kUsLastCharIndex, last_index); +} + +int32_t OS2Table::Builder::STypoAscender() { + return InternalReadData()->ReadShort(Offset::kSTypoAscender); +} + +void OS2Table::Builder::SetSTypoAscender(int32_t ascender) { + InternalWriteData()->WriteShort(Offset::kSTypoAscender, ascender); +} + +int32_t OS2Table::Builder::STypoDescender() { + return InternalReadData()->ReadShort(Offset::kSTypoDescender); +} + +void OS2Table::Builder::SetSTypoDescender(int32_t descender) { + InternalWriteData()->WriteShort(Offset::kSTypoDescender, descender); +} + +int32_t OS2Table::Builder::STypoLineGap() { + return InternalReadData()->ReadShort(Offset::kSTypoLineGap); +} + +void OS2Table::Builder::SetSTypoLineGap(int32_t line_gap) { + InternalWriteData()->WriteShort(Offset::kSTypoLineGap, line_gap); +} + +int32_t OS2Table::Builder::UsWinAscent() { + return InternalReadData()->ReadUShort(Offset::kUsWinAscent); +} + +void OS2Table::Builder::SetUsWinAscent(int32_t ascent) { + InternalWriteData()->WriteUShort(Offset::kUsWinAscent, ascent); +} + +int32_t OS2Table::Builder::UsWinDescent() { + return InternalReadData()->ReadUShort(Offset::kUsWinDescent); +} + +void OS2Table::Builder::SetUsWinDescent(int32_t descent) { + InternalWriteData()->WriteUShort(Offset::kUsWinDescent, descent); +} + +int64_t OS2Table::Builder::UlCodePageRange1() { + return InternalReadData()->ReadULong(Offset::kUlCodePageRange1); +} + +void OS2Table::Builder::SetUlCodePageRange1(int64_t range) { + InternalWriteData()->WriteULong(Offset::kUlCodePageRange1, range); +} + +int64_t OS2Table::Builder::UlCodePageRange2() { + return InternalReadData()->ReadULong(Offset::kUlCodePageRange2); +} + +void OS2Table::Builder::SetUlCodePageRange2(int64_t range) { + InternalWriteData()->WriteULong(Offset::kUlCodePageRange2, range); +} + +int32_t OS2Table::Builder::SxHeight() { + return InternalReadData()->ReadShort(Offset::kSxHeight); +} + +void OS2Table::Builder::SetSxHeight(int32_t height) { + InternalWriteData()->WriteShort(Offset::kSxHeight, height); +} + +int32_t OS2Table::Builder::SCapHeight() { + return InternalReadData()->ReadShort(Offset::kSCapHeight); +} + +void OS2Table::Builder::SetSCapHeight(int32_t height) { + InternalWriteData()->WriteShort(Offset::kSCapHeight, height); +} + +int32_t OS2Table::Builder::UsDefaultChar() { + return InternalReadData()->ReadUShort(Offset::kUsDefaultChar); +} + +void OS2Table::Builder::SetUsDefaultChar(int32_t default_char) { + InternalWriteData()->WriteUShort(Offset::kUsDefaultChar, default_char); +} + +int32_t OS2Table::Builder::UsBreakChar() { + return InternalReadData()->ReadUShort(Offset::kUsBreakChar); +} + +void OS2Table::Builder::SetUsBreakChar(int32_t break_char) { + InternalWriteData()->WriteUShort(Offset::kUsBreakChar, break_char); +} + +int32_t OS2Table::Builder::UsMaxContext() { + return InternalReadData()->ReadUShort(Offset::kUsMaxContext); +} + +void OS2Table::Builder::SetUsMaxContext(int32_t max_context) { + InternalWriteData()->WriteUShort(Offset::kUsMaxContext, max_context); +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/core/os2_table.h b/src/sfntly/src/sfntly/table/core/os2_table.h new file mode 100644 index 0000000000..00d26d2a3b --- /dev/null +++ b/src/sfntly/src/sfntly/table/core/os2_table.h @@ -0,0 +1,508 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_OS2_TABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_OS2_TABLE_H_ + +#include "sfntly/port/refcount.h" +#include "sfntly/table/table.h" +#include "sfntly/table/table_based_table_builder.h" + +namespace sfntly { + +struct WeightClass { + enum { + kThin = 100, + kExtraLight = 200, + kUltraLight = 200, + kLight = 300, + kNormal = 400, + kRegular = 400, + kMedium = 500, + kSemiBold = 600, + kDemiBold = 600, + kBold = 700, + kExtraBold = 800, + kUltraBold = 800, + kBlack = 900, + kHeavy = 900 + }; +}; + +struct WidthClass { + enum { + kUltraCondensed = 1, + kExtraCondensed = 2, + kCondensed = 3, + kSemiCondensed = 4, + kMedium = 5, + kNormal = 5, + kSemiExpanded = 6, + kExpanded = 7, + kExtraExpanded = 8, + kUltraExpanded = 9 + }; +}; + +// Flags to indicate the embedding licensing rights for a font. +struct EmbeddingFlags { + enum { + kReserved0 = 1 << 0, + kRestrictedLicenseEmbedding = 1 << 1, + kPreviewAndPrintEmbedding = 1 << 2, + kEditableEmbedding = 1 << 3, + kReserved4 = 1 << 4, + kReserved5 = 1 << 5, + kReserved6 = 1 << 6, + kReserved7 = 1 << 7, + kNoSubsetting = 1 << 8, + kBitmapEmbeddingOnly = 1 << 9, + kReserved10 = 1 << 10, + kReserved11 = 1 << 11, + kReserved12 = 1 << 12, + kReserved13 = 1 << 13, + kReserved14 = 1 << 14, + kReserved15 = 1 << 15 + }; +}; + +struct UnicodeRange { + enum { + // Do NOT reorder. This enum relies on the ordering of the data matching the + // ordinal numbers of the properties. + kBasicLatin, + kLatin1Supplement, + kLatinExtendedA, + kLatinExtendedB, + kIPAExtensions, + kSpacingModifierLetters, + kCombiningDiacriticalMarks, + kGreekAndCoptic, + kCoptic, + kCyrillic, + kArmenian, + kHebrew, + kVai, + kArabic, + kNKo, + kDevanagari, + kBengali, + kGurmukhi, + kGujarati, + kOriya, + kTamil, + kTelugu, + kKannada, + kMalayalam, + kThai, + kLao, + kGeorgian, + kBalinese, + kHangulJamo, + kLatinExtendedAdditional, + kGreekExtended, + kGeneralPunctuation, + kSuperscriptsAndSubscripts, + kCurrencySymbols, + kNumberForms, + kArrows, + kMathematicalOperators, + kMiscTechnical, + kControlPictures, + kOCR, + kEnclosedAlphanumerics, + kBoxDrawing, + kBlockElements, + kGeometricShapes, + kMiscSymbols, + kDingbats, + kCJKSymbolsAndPunctuation, + kHiragana, + kKatakana, + kBopomofo, + kHangulCompatibilityJamo, + kPhagspa, + kEnclosedCJKLettersAndMonths, + kCJKCompatibility, + kHangulSyllables, + kNonPlane0, + kPhoenician, + kCJKUnifiedIdeographs, + kPrivateUseAreaPlane0, + kCJKStrokes, + kAlphabeticPresentationForms, + kArabicPresentationFormsA, + kCombiningHalfMarks, + kVerticalForms, + kSmallFormVariants, + kArabicPresentationFormsB, + kHalfwidthAndFullwidthForms, + kSpecials, + kTibetan, + kSyriac, + kThaana, + kSinhala, + kMyanmar, + kEthiopic, + kCherokee, + kUnifiedCanadianAboriginalSyllabics, + kOgham, + kRunic, + kKhmer, + kMongolian, + kBraillePatterns, + kYiSyllables, + kTagalog, + kOldItalic, + kGothic, + kDeseret, + kMusicalSymbols, + kMathematicalAlphanumericSymbols, + kPrivateUsePlane15And16, + kVariationSelectors, + kTags, + kLimbu, + kTaiLe, + kNewTaiLue, + kBuginese, + kGlagolitic, + kTifnagh, + kYijingHexagramSymbols, + kSylotiNagari, + kLinearB, + kAncientGreekNumbers, + kUgaritic, + kOldPersian, + kShavian, + kOsmanya, + kCypriotSyllabary, + kKharoshthi, + kTaiXuanJingSymbols, + kCuneiform, + kCountingRodNumerals, + kSudanese, + kLepcha, + kOlChiki, + kSaurashtra, + kKayahLi, + kRejang, + kCharm, + kAncientSymbols, + kPhaistosDisc, + kCarian, + kDominoTiles, + kReserved123, + kReserved124, + kReserved125, + kReserved126, + kReserved127, + kLast = kReserved127 + }; + + int32_t range(int32_t bit); + // UNIMPLEMENTED: EnumSet asSet(long range1, long range2, + // long range3, long range4) + // long[] asArray(EnumSet rangeSet) +}; + +struct FsSelection { + enum { + kITALIC = 1 << 0, + kUNDERSCORE = 1 << 1, + kNEGATIVE = 1 << 2, + kOUTLINED = 1 << 3, + kSTRIKEOUT = 1 << 4, + kBOLD = 1 << 5, + kREGULAR = 1 << 6, + kUSE_TYPO_METRICS = 1 << 7, + kWWS = 1 << 8, + kOBLIQUE = 1 << 9 + }; + // UNIMPLEMENTED: EnumSet asSet(long range1, long range2, + // long range3, long range4) + // long[] asArray(EnumSet rangeSet) +}; + +// C++ port only: C++ does not support 64-bit enums until C++0x. For better +// portability, we need to use static const int64_t instead. +struct CodePageRange { + static const int64_t kLatin1_1252; + static const int64_t kLatin2_1250; + static const int64_t kCyrillic_1251; + static const int64_t kGreek_1253; + static const int64_t kTurkish_1254; + static const int64_t kHebrew_1255; + static const int64_t kArabic_1256; + static const int64_t kWindowsBaltic_1257; + static const int64_t kVietnamese_1258; + static const int64_t kAlternateANSI9; + static const int64_t kAlternateANSI10; + static const int64_t kAlternateANSI11; + static const int64_t kAlternateANSI12; + static const int64_t kAlternateANSI13; + static const int64_t kAlternateANSI14; + static const int64_t kAlternateANSI15; + static const int64_t kThai_874; + static const int64_t kJapanJIS_932; + static const int64_t kChineseSimplified_936; + static const int64_t kKoreanWansung_949; + static const int64_t kChineseTraditional_950; + static const int64_t kKoreanJohab_1361; + static const int64_t kAlternateANSI22; + static const int64_t kAlternateANSI23; + static const int64_t kAlternateANSI24; + static const int64_t kAlternateANSI25; + static const int64_t kAlternateANSI26; + static const int64_t kAlternateANSI27; + static const int64_t kAlternateANSI28; + static const int64_t kMacintoshCharacterSet; + static const int64_t kOEMCharacterSet; + static const int64_t kSymbolCharacterSet; + static const int64_t kReservedForOEM32; + static const int64_t kReservedForOEM33; + static const int64_t kReservedForOEM34; + static const int64_t kReservedForOEM35; + static const int64_t kReservedForOEM36; + static const int64_t kReservedForOEM37; + static const int64_t kReservedForOEM38; + static const int64_t kReservedForOEM39; + static const int64_t kReservedForOEM40; + static const int64_t kReservedForOEM41; + static const int64_t kReservedForOEM42; + static const int64_t kReservedForOEM43; + static const int64_t kReservedForOEM44; + static const int64_t kReservedForOEM45; + static const int64_t kReservedForOEM46; + static const int64_t kReservedForOEM47; + static const int64_t kIBMGreek_869; + static const int64_t kMSDOSRussion_866; + static const int64_t kMSDOSNordic_865; + static const int64_t kArabic_864; + static const int64_t kMSDOSCanadianFrench_863; + static const int64_t kHebrew_862; + static const int64_t kMSDOSIcelandic_861; + static const int64_t kMSDOSPortugese_860; + static const int64_t kIBMTurkish_857; + static const int64_t kIBMCyrillic_855; + static const int64_t kLatin2_852; + static const int64_t kMSDOSBaltic_775; + static const int64_t kGreek_737; + static const int64_t kArabic_708; + static const int64_t kLatin1_850; + static const int64_t kUS_437; + + // UNIMPLEMENTED: EnumSet asSet(long range1, long range2, + // long range3, long range4) + // long[] asArray(EnumSet rangeSet) +}; + +// An OS/2 table - 'OS/2'. +class OS2Table : public Table, public RefCounted { + public: + // A builder for the OS/2 table = 'OS/2'. + class Builder : public TableBasedTableBuilder, public RefCounted { + public: + Builder(Header* header, WritableFontData* data); + Builder(Header* header, ReadableFontData* data); + virtual ~Builder(); + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + + static CALLER_ATTACH Builder* CreateBuilder(Header* header, + WritableFontData* data); + + int32_t TableVersion(); + void SetTableVersion(int32_t version); + int32_t XAvgCharWidth(); + void SetXAvgCharWidth(int32_t width); + int32_t UsWeightClass(); + void SetUsWeightClass(int32_t weight); + int32_t UsWidthClass(); + void SetUsWidthClass(int32_t width); + // UNIMPLEMENTED: EnumSet fsType() + // void setFsType(EnumSeT flagSet) + int32_t FsType(); + void SetFsType(int32_t fs_type); + int32_t YSubscriptXSize(); + void SetYSubscriptXSize(int32_t size); + int32_t YSubscriptYSize(); + void SetYSubscriptYSize(int32_t size); + int32_t YSubscriptXOffset(); + void SetYSubscriptXOffset(int32_t offset); + int32_t YSubscriptYOffset(); + void SetYSubscriptYOffset(int32_t offset); + int32_t YSuperscriptXSize(); + void SetYSuperscriptXSize(int32_t size); + int32_t YSuperscriptYSize(); + void SetYSuperscriptYSize(int32_t size); + int32_t YSuperscriptXOffset(); + void SetYSuperscriptXOffset(int32_t offset); + int32_t YSuperscriptYOffset(); + void SetYSuperscriptYOffset(int32_t offset); + int32_t YStrikeoutSize(); + void SetYStrikeoutSize(int32_t size); + int32_t YStrikeoutPosition(); + void SetYStrikeoutPosition(int32_t position); + int32_t SFamilyClass(); + void SetSFamilyClass(int32_t family); + void Panose(ByteVector* value); + void SetPanose(ByteVector* panose); + int64_t UlUnicodeRange1(); + void SetUlUnicodeRange1(int64_t range); + int64_t UlUnicodeRange2(); + void SetUlUnicodeRange2(int64_t range); + int64_t UlUnicodeRange3(); + void SetUlUnicodeRange3(int64_t range); + int64_t UlUnicodeRange4(); + void SetUlUnicodeRange4(int64_t range); + // UNIMPLEMENTED: EnumSet UlUnicodeRange() + // setUlUnicodeRange(EnumSet rangeSet) + void AchVendId(ByteVector* b); + // This field is 4 bytes in length and only the first 4 bytes of the byte + // array will be written. If the byte array is less than 4 bytes it will be + // padded out with space characters (0x20). + // @param b ach Vendor Id + void SetAchVendId(ByteVector* b); + // UNIMPLEMENTED: public EnumSet fsSelection() + int32_t FsSelection(); + void SetFsSelection(int32_t fs_selection); + int32_t UsFirstCharIndex(); + void SetUsFirstCharIndex(int32_t first_index); + int32_t UsLastCharIndex(); + void SetUsLastCharIndex(int32_t last_index); + int32_t STypoAscender(); + void SetSTypoAscender(int32_t ascender); + int32_t STypoDescender(); + void SetSTypoDescender(int32_t descender); + int32_t STypoLineGap(); + void SetSTypoLineGap(int32_t line_gap); + int32_t UsWinAscent(); + void SetUsWinAscent(int32_t ascent); + int32_t UsWinDescent(); + void SetUsWinDescent(int32_t descent); + int64_t UlCodePageRange1(); + void SetUlCodePageRange1(int64_t range); + int64_t UlCodePageRange2(); + void SetUlCodePageRange2(int64_t range); + // UNIMPLEMENTED: EnumSet ulCodePageRange() + // void setUlCodePageRange(EnumSet rangeSet) + int32_t SxHeight(); + void SetSxHeight(int32_t height); + int32_t SCapHeight(); + void SetSCapHeight(int32_t height); + int32_t UsDefaultChar(); + void SetUsDefaultChar(int32_t default_char); + int32_t UsBreakChar(); + void SetUsBreakChar(int32_t break_char); + int32_t UsMaxContext(); + void SetUsMaxContext(int32_t max_context); + }; + + ~OS2Table(); + + int32_t TableVersion(); + int32_t XAvgCharWidth(); + int32_t UsWeightClass(); + int32_t UsWidthClass(); + // UNIMPLEMENTED: public EnumSet fsType() + int32_t FsType(); + int32_t YSubscriptXSize(); + int32_t YSubscriptYSize(); + int32_t YSubscriptXOffset(); + int32_t YSubscriptYOffset(); + int32_t YSuperscriptXSize(); + int32_t YSuperscriptYSize(); + int32_t YSuperscriptXOffset(); + int32_t YSuperscriptYOffset(); + int32_t YStrikeoutSize(); + int32_t YStrikeoutPosition(); + int32_t SFamilyClass(); + void Panose(ByteVector* value); + int64_t UlUnicodeRange1(); + int64_t UlUnicodeRange2(); + int64_t UlUnicodeRange3(); + int64_t UlUnicodeRange4(); + // UNIMPLEMENTED: public EnumSet UlUnicodeRange() + void AchVendId(ByteVector* b); + // UNIMPLEMENTED: public EnumSet fsSelection() + int32_t FsSelection(); + int32_t UsFirstCharIndex(); + int32_t UsLastCharIndex(); + int32_t STypoAscender(); + int32_t STypoDescender(); + int32_t STypoLineGap(); + int32_t UsWinAscent(); + int32_t UsWinDescent(); + int64_t UlCodePageRange1(); + int64_t UlCodePageRange2(); + // UNIMPLEMENTED: public EnumSet ulCodePageRange() + int32_t SxHeight(); + int32_t SCapHeight(); + int32_t UsDefaultChar(); + int32_t UsBreakChar(); + int32_t UsMaxContext(); + + private: + struct Offset { + enum { + kVersion = 0, + kXAvgCharWidth = 2, + kUsWeightClass = 4, + kUsWidthClass = 6, + kFsType = 8, + kYSubscriptXSize = 10, + kYSubscriptYSize = 12, + kYSubscriptXOffset = 14, + kYSubscriptYOffset = 16, + kYSuperscriptXSize = 18, + kYSuperscriptYSize = 20, + kYSuperscriptXOffset = 22, + kYSuperscriptYOffset = 24, + kYStrikeoutSize = 26, + kYStrikeoutPosition = 28, + kSFamilyClass = 30, + kPanose = 32, + kPanoseLength = 10, // Length of panose bytes. + kUlUnicodeRange1 = 42, + kUlUnicodeRange2 = 46, + kUlUnicodeRange3 = 50, + kUlUnicodeRange4 = 54, + kAchVendId = 58, + kAchVendIdLength = 4, // Length of ach vend id bytes. + kFsSelection = 62, + kUsFirstCharIndex = 64, + kUsLastCharIndex = 66, + kSTypoAscender = 68, + kSTypoDescender = 70, + kSTypoLineGap = 72, + kUsWinAscent = 74, + kUsWinDescent = 76, + kUlCodePageRange1 = 78, + kUlCodePageRange2 = 82, + kSxHeight = 86, + kSCapHeight = 88, + kUsDefaultChar = 90, + kUsBreakChar = 92, + kUsMaxContext = 94 + }; + }; + + OS2Table(Header* header, ReadableFontData* data); +}; +typedef Ptr OS2TablePtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_OS2_TABLE_H_ diff --git a/src/sfntly/src/sfntly/table/font_data_table.cc b/src/sfntly/src/sfntly/table/font_data_table.cc new file mode 100644 index 0000000000..0e27f7a771 --- /dev/null +++ b/src/sfntly/src/sfntly/table/font_data_table.cc @@ -0,0 +1,193 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/font_data_table.h" + +#include "sfntly/data/font_output_stream.h" + +namespace sfntly { + +/****************************************************************************** + * FontDataTable class + ******************************************************************************/ + +FontDataTable::FontDataTable(ReadableFontData* data) { + data_ = data; +} + +FontDataTable::~FontDataTable() {} + +ReadableFontData* FontDataTable::ReadFontData() { + return data_; +} + +int32_t FontDataTable::DataLength() { + return data_->Length(); +} + +int32_t FontDataTable::Serialize(OutputStream* os) { + return data_->CopyTo(os); +} + +int32_t FontDataTable::Serialize(WritableFontData* data) { + return data_->CopyTo(data); +} + +/****************************************************************************** + * FontDataTable::Builder class + ******************************************************************************/ +CALLER_ATTACH WritableFontData* FontDataTable::Builder::Data() { + WritableFontDataPtr new_data; + if (model_changed_) { + if (!SubReadyToSerialize()) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("Table not ready to build."); +#endif + return NULL; + } + int32_t size = SubDataSizeToSerialize(); + new_data.Attach(WritableFontData::CreateWritableFontData(size)); + SubSerialize(new_data); + } else { + ReadableFontDataPtr data = InternalReadData(); + new_data.Attach(WritableFontData::CreateWritableFontData( + data != NULL ? data->Length() : 0)); + if (data != NULL) { + data->CopyTo(new_data); + } + } + return new_data.Detach(); +} + +void FontDataTable::Builder::SetData(ReadableFontData* data) { + InternalSetData(data, true); +} + + +CALLER_ATTACH FontDataTable* FontDataTable::Builder::Build() { + FontDataTablePtr table; // NULL default table + ReadableFontDataPtr data = InternalReadData(); + if (model_changed_) { + // Let subclass serialize from model. + if (!SubReadyToSerialize()) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("Table not ready to build."); +#endif + return NULL; + } + int32_t size = SubDataSizeToSerialize(); + WritableFontDataPtr new_data; + new_data.Attach(WritableFontData::CreateWritableFontData(size)); + SubSerialize(new_data); + data = new_data; + } + + if (data != NULL) { + table = SubBuildTable(data); + NotifyPostTableBuild(table); + } + + r_data_.Release(); + w_data_.Release(); + return table; +} + +bool FontDataTable::Builder::ReadyToBuild() { + return true; +} + +ReadableFontData* FontDataTable::Builder::InternalReadData() { + return (r_data_ != NULL) ? r_data_.p_ : + static_cast(w_data_.p_); +} + +WritableFontData* FontDataTable::Builder::InternalWriteData() { + if (w_data_ == NULL) { + WritableFontDataPtr new_data; + new_data.Attach(WritableFontData::CreateWritableFontData( + r_data_ == NULL ? 0 : r_data_->Length())); +#if !defined (SFNTLY_NO_EXCEPTION) + try { +#endif + if (r_data_) { + r_data_->CopyTo(new_data); + } +#if !defined (SFNTLY_NO_EXCEPTION) + } catch (IOException& e) { + // TODO(stuartg): fix when IOExceptions are cleaned up + } +#endif + InternalSetData(new_data, false); + } + return w_data_.p_; +} + +FontDataTable::Builder::Builder() + : model_changed_(false), + contained_model_changed_(false), + data_changed_(false) { +} + +FontDataTable::Builder::Builder(int32_t data_size) + : model_changed_(false), + contained_model_changed_(false), + data_changed_(false) { + w_data_.Attach(WritableFontData::CreateWritableFontData(data_size)); +} + +FontDataTable::Builder::Builder(WritableFontData* data) + : model_changed_(false), + contained_model_changed_(false), + data_changed_(false) { + w_data_ = data; +} + +FontDataTable::Builder::Builder(ReadableFontData* data) + : model_changed_(false), + contained_model_changed_(false), + data_changed_(false) { + r_data_ = data; +} + +FontDataTable::Builder::~Builder() { +} + +void FontDataTable::Builder::NotifyPostTableBuild(FontDataTable* table) { + // Default: NOP. + UNREFERENCED_PARAMETER(table); +} + +void FontDataTable::Builder::InternalSetData(WritableFontData* data, + bool data_changed) { + w_data_ = data; + r_data_ = NULL; + if (data_changed) { + data_changed_ = true; + SubDataSet(); + } +} + +void FontDataTable::Builder::InternalSetData(ReadableFontData* data, + bool data_changed) { + w_data_ = NULL; + r_data_ = data; + if (data_changed) { + data_changed_ = true; + SubDataSet(); + } +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/font_data_table.h b/src/sfntly/src/sfntly/table/font_data_table.h new file mode 100644 index 0000000000..5e437e2f34 --- /dev/null +++ b/src/sfntly/src/sfntly/table/font_data_table.h @@ -0,0 +1,123 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_FONT_DATA_TABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_FONT_DATA_TABLE_H_ + +#include "sfntly/data/readable_font_data.h" +#include "sfntly/data/writable_font_data.h" +#include "sfntly/port/refcount.h" + +namespace sfntly { + +// An abstract base for any table that contains a FontData. This is the root of +// the table class hierarchy. +class FontDataTable : virtual public RefCount { + public: + // Note: original version is abstract Builder + // C++ template is not designed that way so plain class is chosen. + class Builder : virtual public RefCount { + public: + // Get a snapshot copy of the internal data of the builder. + // This causes any internal data structures to be serialized to a new data + // object. This data object belongs to the caller and must be properly + // disposed of. No changes are made to the builder and any changes to the + // data directly do not affect the internal state. To do that a subsequent + // call must be made to {@link #SetData(WritableFontData)}. + // @return a copy of the internal data of the builder + CALLER_ATTACH WritableFontData* Data(); + virtual void SetData(ReadableFontData* data); + + // Note: changed from protected to avoid accessibility error in C++ + virtual CALLER_ATTACH FontDataTable* Build(); + virtual bool ReadyToBuild(); + + ReadableFontData* InternalReadData(); + WritableFontData* InternalWriteData(); + + bool data_changed() { return data_changed_; } + bool model_changed() { + return current_model_changed() || contained_model_changed(); + } + bool current_model_changed() { return model_changed_; } + bool contained_model_changed() { return contained_model_changed_; } + + bool set_model_changed() { return set_model_changed(true); } + bool set_model_changed(bool changed) { + bool old = model_changed_; + model_changed_ = changed; + return old; + } + + protected: + explicit Builder(); + + // Construct a FontDataTable.Builder with a WritableFontData backing store + // of size given. A positive size will create a fixed size backing store and + // a 0 or less size is an estimate for a growable backing store with the + // estimate being the absolute of the size. + // @param dataSize if positive then a fixed size; if 0 or less then an + // estimate for a growable size + Builder(int32_t data_size); + Builder(WritableFontData* data); + Builder(ReadableFontData* data); + virtual ~Builder(); + + // subclass API + virtual void NotifyPostTableBuild(FontDataTable* table); + virtual int32_t SubSerialize(WritableFontData* new_data) = 0; + virtual bool SubReadyToSerialize() = 0; + virtual int32_t SubDataSizeToSerialize() = 0; + virtual void SubDataSet() = 0; + virtual CALLER_ATTACH FontDataTable* + SubBuildTable(ReadableFontData* data) = 0; + + private: + void InternalSetData(WritableFontData* data, bool data_changed); + void InternalSetData(ReadableFontData* data, bool data_changed); + + WritableFontDataPtr w_data_; + ReadableFontDataPtr r_data_; + bool model_changed_; + bool contained_model_changed_; // may expand to list of submodel states + bool data_changed_; + }; + + explicit FontDataTable(ReadableFontData* data); + virtual ~FontDataTable(); + + // Get the readable font data for this table. + ReadableFontData* ReadFontData(); + + // Get the length of the data for this table in bytes. This is the full + // allocated length of the data underlying the table and may or may not + // include any padding. + virtual int32_t DataLength(); + + virtual int32_t Serialize(OutputStream* os); + + protected: + virtual int32_t Serialize(WritableFontData* data); + + // TODO(arthurhsu): style guide violation: protected member, need refactoring + ReadableFontDataPtr data_; +}; +typedef Ptr FontDataTablePtr; +typedef Ptr FontDataTableBuilderPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_FONT_DATA_TABLE_H_ diff --git a/src/sfntly/src/sfntly/table/generic_table_builder.cc b/src/sfntly/src/sfntly/table/generic_table_builder.cc new file mode 100644 index 0000000000..78e679772c --- /dev/null +++ b/src/sfntly/src/sfntly/table/generic_table_builder.cc @@ -0,0 +1,49 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/generic_table_builder.h" + +namespace sfntly { + +GenericTableBuilder::~GenericTableBuilder() {} + +CALLER_ATTACH +FontDataTable* GenericTableBuilder::SubBuildTable(ReadableFontData* data) { + // Note: In C++ port, we use GenericTable, the ref-counted version of Table + UNREFERENCED_PARAMETER(data); + Ptr table = new GenericTable(header(), InternalReadData()); + return table.Detach(); +} + +// static +CALLER_ATTACH GenericTableBuilder* + GenericTableBuilder::CreateBuilder(Header* header, WritableFontData* data) { + Ptr builder = + new GenericTableBuilder(header, data); + return builder.Detach(); +} + +GenericTableBuilder::GenericTableBuilder(Header* header, + WritableFontData* data) + : TableBasedTableBuilder(header, data) { +} + +GenericTableBuilder::GenericTableBuilder(Header* header, + ReadableFontData* data) + : TableBasedTableBuilder(header, data) { +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/generic_table_builder.h b/src/sfntly/src/sfntly/table/generic_table_builder.h new file mode 100644 index 0000000000..a100ea072c --- /dev/null +++ b/src/sfntly/src/sfntly/table/generic_table_builder.h @@ -0,0 +1,42 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_GENERIC_TABLE_BUILDER_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_GENERIC_TABLE_BUILDER_H_ + +#include "sfntly/table/table_based_table_builder.h" + +namespace sfntly { + +// A table builder to do the minimal table building for an unknown table type. +class GenericTableBuilder : public TableBasedTableBuilder, + public RefCounted { + public: + virtual ~GenericTableBuilder(); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + + static CALLER_ATTACH GenericTableBuilder* + CreateBuilder(Header* header, WritableFontData* data); + + private: + GenericTableBuilder(Header* header, WritableFontData* data); + GenericTableBuilder(Header* header, ReadableFontData* data); +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BYTE_ARRAY_TABLE_BUILDER_H_ diff --git a/src/sfntly/src/sfntly/table/header.cc b/src/sfntly/src/sfntly/table/header.cc new file mode 100644 index 0000000000..672ace5749 --- /dev/null +++ b/src/sfntly/src/sfntly/table/header.cc @@ -0,0 +1,66 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/header.h" + +namespace sfntly { + +/****************************************************************************** + * Header class + ******************************************************************************/ +Header::Header(int32_t tag) + : tag_(tag), + offset_(0), + offset_valid_(false), + length_(0), + length_valid_(false), + checksum_(0), + checksum_valid_(false) { +} + +Header::Header(int32_t tag, int32_t length) + : tag_(tag), + offset_(0), + offset_valid_(false), + length_(length), + length_valid_(true), + checksum_(0), + checksum_valid_(false) { +} + +Header::Header(int32_t tag, int64_t checksum, int32_t offset, int32_t length) + : tag_(tag), + offset_(offset), + offset_valid_(true), + length_(length), + length_valid_(true), + checksum_(checksum), + checksum_valid_(true) { +} + +Header::~Header() {} + +bool HeaderComparatorByOffset::operator() (const HeaderPtr lhs, + const HeaderPtr rhs) { + return lhs->offset_ > rhs->offset_; +} + +bool HeaderComparatorByTag::operator() (const HeaderPtr lhs, + const HeaderPtr rhs) { + return lhs->tag_ > rhs->tag_; +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/header.h b/src/sfntly/src/sfntly/table/header.h new file mode 100644 index 0000000000..280e556c47 --- /dev/null +++ b/src/sfntly/src/sfntly/table/header.h @@ -0,0 +1,114 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_HEADER_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_HEADER_H_ + +#include "sfntly/port/refcount.h" + +namespace sfntly { + +class Header : public RefCounted
{ + public: + // Make a partial header with only the basic info for an empty new table. + explicit Header(int32_t tag); + + // Make a partial header with only the basic info for a new table. + Header(int32_t tag, int32_t length); + + // Make a full header as read from an existing font. + Header(int32_t tag, int64_t checksum, int32_t offset, int32_t length); + virtual ~Header(); + + // Get the table tag. + int32_t tag() { return tag_; } + + // Get the table offset. The offset is from the start of the font file. This + // offset value is what was read from the font file during construction of the + // font. It may not be meaningful if the font was maninpulated through the + // builders. + int32_t offset() { return offset_; } + + // Is the offset in the header valid. The offset will not be valid if the + // table was constructed during building and has no physical location in a + // font file. + bool offset_valid() { return offset_valid_; } + + // Get the length of the table as recorded in the table record header. During + // building the header length will reflect the length that was initially read + // from the font file. This may not be consistent with the current state of + // the data. + int32_t length() { return length_; } + + // Is the length in the header valid. The length will not be valid if the + // table was constructed during building and has no physical location in a + // font file until the table is built from the builder. + bool length_valid() { return length_valid_; } + + // Get the checksum for the table as recorded in the table record header. + int64_t checksum() { return checksum_; } + + // Is the checksum valid. The checksum will not be valid if the table was + // constructed during building and has no physical location in a font file. + // Note that this does *NOT* check the validity of the checksum against + // the calculated checksum for the table data. + bool checksum_valid() { return checksum_valid_; } + + // UNIMPLEMENTED: boolean equals(Object obj) + // int hashCode() + // string toString() + + private: + int32_t tag_; + int32_t offset_; + bool offset_valid_; + int32_t length_; + bool length_valid_; + int64_t checksum_; + bool checksum_valid_; + + friend class HeaderComparatorByOffset; + friend class HeaderComparatorByTag; +}; +typedef Ptr
HeaderPtr; + +class HeaderComparator { + public: + virtual ~HeaderComparator() {} + virtual bool operator()(const HeaderPtr h1, + const HeaderPtr h2) = 0; +}; + +class HeaderComparatorByOffset : public HeaderComparator { + public: + virtual ~HeaderComparatorByOffset() {} + virtual bool operator()(const HeaderPtr h1, + const HeaderPtr h2); +}; + +class HeaderComparatorByTag : public HeaderComparator { + public: + virtual ~HeaderComparatorByTag() {} + virtual bool operator()(const HeaderPtr h1, + const HeaderPtr h2); +}; + +typedef std::set HeaderOffsetSortedSet; +typedef std::set HeaderTagSortedSet; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_HEADER_H_ diff --git a/src/sfntly/src/sfntly/table/subtable.cc b/src/sfntly/src/sfntly/table/subtable.cc new file mode 100644 index 0000000000..e5b906fd37 --- /dev/null +++ b/src/sfntly/src/sfntly/table/subtable.cc @@ -0,0 +1,64 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/subtable.h" + +namespace sfntly { +/****************************************************************************** + * SubTable class + ******************************************************************************/ +SubTable::~SubTable() {} + +SubTable::SubTable(ReadableFontData* data, ReadableFontData* master_data) + : FontDataTable(data), padding_(0) { + master_data_ = master_data; +} + +SubTable::SubTable(ReadableFontData* data) + : FontDataTable(data), padding_(0) { +} + +/****************************************************************************** + * SubTable::Builder class + ******************************************************************************/ +SubTable::Builder::~Builder() { +} + +SubTable::Builder::Builder(int32_t data_size) + : FontDataTable::Builder(data_size) { +} + +SubTable::Builder::Builder(WritableFontData* data, + ReadableFontData* master_data) + : FontDataTable::Builder(data) { + master_data_ = master_data; +} + +SubTable::Builder::Builder(ReadableFontData* data, + ReadableFontData* master_data) + : FontDataTable::Builder(data) { + master_data_ = master_data; +} + +SubTable::Builder::Builder(WritableFontData* data) + : FontDataTable::Builder(data) { +} + +SubTable::Builder::Builder(ReadableFontData* data) + : FontDataTable::Builder(data) { +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/subtable.h b/src/sfntly/src/sfntly/table/subtable.h new file mode 100644 index 0000000000..fa6f4c6bcd --- /dev/null +++ b/src/sfntly/src/sfntly/table/subtable.h @@ -0,0 +1,73 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_SUBTABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_SUBTABLE_H_ + +#include "sfntly/table/font_data_table.h" + +namespace sfntly { + +// An abstract base class for subtables. Subtables are smaller tables nested +// within other tables and don't have an entry in the main font index. Examples +// of these are the CMap subtables within CMap table (cmap) or a glyph within +// the glyph table (glyf). +class SubTable : public FontDataTable { + public: + class Builder : public FontDataTable::Builder { + public: + virtual ~Builder(); + + protected: + // @param data the data for the subtable being built + // @param master_data the data for the full table + Builder(int32_t data_size); + Builder(WritableFontData* data, ReadableFontData* master_data); + Builder(ReadableFontData* data, ReadableFontData* master_data); + explicit Builder(WritableFontData* data); + explicit Builder(ReadableFontData* data); + + ReadableFontData* master_read_data() { return master_data_; } + + private: + ReadableFontDataPtr master_data_; + }; + + virtual ~SubTable(); + virtual int32_t Padding() { return padding_; } + + // Sets the amount of padding that is part of the data being used by this + // subtable. + void set_padding(int32_t padding) { padding_ = padding; } + + protected: + SubTable(ReadableFontData* data, ReadableFontData* master_data); + + // Note: constructor refactored in C++ to avoid heavy lifting. + // caller need to do data->Slice(offset, length) beforehand. + explicit SubTable(ReadableFontData* data); + + ReadableFontData* master_read_data() { return master_data_; } + + private: + // The data for the whole table in which this subtable is contained. + ReadableFontDataPtr master_data_; + int32_t padding_; +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_SUBTABLE_H_ diff --git a/src/sfntly/src/sfntly/table/subtable_container_table.h b/src/sfntly/src/sfntly/table/subtable_container_table.h new file mode 100644 index 0000000000..0f099debb4 --- /dev/null +++ b/src/sfntly/src/sfntly/table/subtable_container_table.h @@ -0,0 +1,48 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TYPOGRAPHY_FONT_SFNTLY_SRC_SFNTLY_TABLE_SUBTABLE_CONTAINER_TABLE_H_ +#define TYPOGRAPHY_FONT_SFNTLY_SRC_SFNTLY_TABLE_SUBTABLE_CONTAINER_TABLE_H_ + +#include "sfntly/table/table.h" + +namespace sfntly { + +class SubTableContainerTable : public Table { + public: + class Builder : public Table::Builder { + public: + Builder(Header* header, WritableFontData* data) + : Table::Builder(header, data) { + } + + Builder(Header* header, ReadableFontData* data) + : Table::Builder(header, data) { + } + + virtual ~Builder() {} + }; + + SubTableContainerTable(Header* header, ReadableFontData* data) + : Table(header, data) { + } + + virtual ~SubTableContainerTable() {} +}; + +} // namespace sfntly + +#endif // TYPOGRAPHY_FONT_SFNTLY_SRC_SFNTLY_TABLE_SUBTABLE_CONTAINER_TABLE_H_ diff --git a/src/sfntly/src/sfntly/table/table.cc b/src/sfntly/src/sfntly/table/table.cc new file mode 100644 index 0000000000..cf574b838b --- /dev/null +++ b/src/sfntly/src/sfntly/table/table.cc @@ -0,0 +1,162 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// type.h needs to be included first because of building issues on Windows +// Type aliases we delcare are defined in other headers and make the build +// fail otherwise. +#include "sfntly/port/type.h" +#include "sfntly/table/table.h" + +#include "sfntly/font.h" +#include "sfntly/tag.h" +#include "sfntly/table/bitmap/ebdt_table.h" +#include "sfntly/table/bitmap/eblc_table.h" +#include "sfntly/table/bitmap/ebsc_table.h" +#include "sfntly/table/core/cmap_table.h" +#include "sfntly/table/core/font_header_table.h" +#include "sfntly/table/core/horizontal_device_metrics_table.h" +#include "sfntly/table/core/horizontal_header_table.h" +#include "sfntly/table/core/horizontal_metrics_table.h" +#include "sfntly/table/core/maximum_profile_table.h" +#include "sfntly/table/core/name_table.h" +#include "sfntly/table/core/os2_table.h" +#include "sfntly/table/generic_table_builder.h" +#include "sfntly/table/table_based_table_builder.h" +#include "sfntly/table/truetype/glyph_table.h" +#include "sfntly/table/truetype/loca_table.h" + +namespace sfntly { + +/****************************************************************************** + * Table class + ******************************************************************************/ +Table::~Table() {} + +int64_t Table::CalculatedChecksum() { + return data_->Checksum(); +} + +void Table::SetFont(Font* font) { + font_ = font; +} + +Table::Table(Header* header, ReadableFontData* data) + : FontDataTable(data) { + header_ = header; +} + +/****************************************************************************** + * Table::Builder class + ******************************************************************************/ +Table::Builder::~Builder() { + header_.Release(); +} + +void Table::Builder::NotifyPostTableBuild(FontDataTable* table) { + if (model_changed() || data_changed()) { + Table* derived_table = down_cast(table); + derived_table->header_ = new Header(header()->tag(), + derived_table->DataLength()); + } +} + +CALLER_ATTACH +Table::Builder* Table::Builder::GetBuilder(Header* header, + WritableFontData* table_data) { + int32_t tag = header->tag(); + Table::Builder* builder_raw = NULL; + + // Note: Tables are commented out when they are not used/ported. + // TODO(arthurhsu): IMPLEMENT: finish tables that are not ported. + if (tag == Tag::head) { + builder_raw = static_cast( + FontHeaderTable::Builder::CreateBuilder(header, table_data)); +#if defined (SFNTLY_EXPERIMENTAL) + } else if (tag == Tag::cmap) { + builder_raw = static_cast( + CMapTable::Builder::CreateBuilder(header, table_data)); +#endif // SFNTLY_EXPERIMENTAL + } else if (tag == Tag::hhea) { + builder_raw = static_cast( + HorizontalHeaderTable::Builder::CreateBuilder(header, table_data)); + } else if (tag == Tag::hmtx) { + builder_raw = static_cast( + HorizontalMetricsTable::Builder::CreateBuilder(header, table_data)); + } else if (tag == Tag::maxp) { + builder_raw = static_cast( + MaximumProfileTable::Builder::CreateBuilder(header, table_data)); + } else if (tag == Tag::name) { + builder_raw = static_cast( + NameTable::Builder::CreateBuilder(header, table_data)); + } else if (tag == Tag::OS_2) { + builder_raw = static_cast( + OS2Table::Builder::CreateBuilder(header, table_data)); + }/* else if (tag == Tag::PostScript) { + builder_raw = static_cast( + PostScriptTable::Builder::CreateBuilder(header, table_data)); + } else if (tag == Tag::cvt) { + builder_raw = static_cast( + ControlValueTable::Builder::CreateBuilder(header, table_data)); + }*/ else if (tag == Tag::glyf) { + builder_raw = static_cast( + GlyphTable::Builder::CreateBuilder(header, table_data)); + } else if (tag == Tag::loca) { + builder_raw = static_cast( + LocaTable::Builder::CreateBuilder(header, table_data)); + } else if (tag == Tag::EBDT || tag == Tag::bdat) { + builder_raw = static_cast( + EbdtTable::Builder::CreateBuilder(header, table_data)); + } else if (tag == Tag::EBLC || tag == Tag::bloc) { + builder_raw = static_cast( + EblcTable::Builder::CreateBuilder(header, table_data)); + } else if (tag == Tag::EBSC) { + builder_raw = static_cast( + EbscTable::Builder::CreateBuilder(header, table_data)); + } /* else if (tag == Tag::prep) { + builder_raw = static_cast( + ControlProgramTable::Builder::CreateBuilder(header, table_data)); + }*/ else if (tag == Tag::bhed) { + builder_raw = static_cast( + FontHeaderTable::Builder::CreateBuilder(header, table_data)); +#if defined (SFNTLY_EXPERIMENTAL) + } else if (tag == Tag::hdmx) { + builder_raw = static_cast( + HorizontalDeviceMetricsTable::Builder::CreateBuilder(header, + table_data)); +#endif // SFNTLY_EXPERIMENTAL + } else { + builder_raw = static_cast( + GenericTableBuilder::CreateBuilder(header, table_data)); + } + + return builder_raw; +} + +Table::Builder::Builder(Header* header, WritableFontData* data) + : FontDataTable::Builder(data) { + header_ = header; +} + +Table::Builder::Builder(Header* header, ReadableFontData* data) + : FontDataTable::Builder(data) { + header_ = header; +} + +Table::Builder::Builder(Header* header) { + header_ = header; +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/table.h b/src/sfntly/src/sfntly/table/table.h new file mode 100644 index 0000000000..6ebc22df8a --- /dev/null +++ b/src/sfntly/src/sfntly/table/table.h @@ -0,0 +1,119 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_TABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_TABLE_H_ + +#include +#include +#include +#include + +#include "sfntly/port/type.h" +#include "sfntly/table/font_data_table.h" +#include "sfntly/table/header.h" + +namespace sfntly { +class Font; + +// A concrete implementation of a root level table in the font. This is the base +// class used for all specific table implementations and is used as the generic +// table for all tables which have no specific implementations. +class Table : public FontDataTable { + public: + // Note: original version is Builder + // C++ template is not designed that way so plain old inheritance is + // chosen. + class Builder : public FontDataTable::Builder { + public: + virtual ~Builder(); + virtual Header* header() { return header_; } + virtual void NotifyPostTableBuild(FontDataTable* table); + + // Get a builder for the table type specified by the data in the header. + // @param header the header for the table + // @param tableData the data to be used to build the table from + // @return builder for the table specified + static CALLER_ATTACH Builder* GetBuilder(Header* header, + WritableFontData* table_data); + + // UNIMPLEMENTED: toString() + + protected: + Builder(Header* header, WritableFontData* data); + Builder(Header* header, ReadableFontData* data); + Builder(Header* header); + + private: + Ptr
header_; + }; + + // Note: GenericTableBuilder moved to table_based_table_builder.h to avoid + // circular inclusion. + + virtual ~Table(); + + // Get the calculated checksum for the data in the table. + virtual int64_t CalculatedChecksum(); + + // Get the header for the table. + virtual Header* header() { return header_; } + + // Get the tag for the table from the record header. + virtual int32_t header_tag() { return header_->tag(); } + + // Get the offset for the table from the record header. + virtual int32_t header_offset() { return header_->offset(); } + + // Get the length of the table from the record header. + virtual int32_t header_length() { return header_->length(); } + + // Get the checksum for the table from the record header. + virtual int64_t header_checksum() { return header_->checksum(); } + + // UNIMPLEMENTED: toString() + + virtual void SetFont(Font* font); + + protected: + Table(Header* header, ReadableFontData* data); + + private: + Ptr
header_; + Ptr font_; +}; + +// C++ port only +class GenericTable : public Table, public RefCounted { + public: + GenericTable(Header* header, ReadableFontData* data) : Table(header, data) {} + virtual ~GenericTable() {} +}; + +typedef Ptr TablePtr; +typedef std::vector TableHeaderList; +typedef Ptr TableBuilderPtr; +typedef std::map TableMap; +typedef std::pair TableMapEntry; + +typedef std::map DataBlockMap; +typedef std::pair DataBlockEntry; +typedef std::map TableBuilderMap; +typedef std::pair TableBuilderEntry; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_TABLE_H_ diff --git a/src/sfntly/src/sfntly/table/table_based_table_builder.cc b/src/sfntly/src/sfntly/table/table_based_table_builder.cc new file mode 100644 index 0000000000..b505704638 --- /dev/null +++ b/src/sfntly/src/sfntly/table/table_based_table_builder.cc @@ -0,0 +1,69 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/table_based_table_builder.h" + +namespace sfntly { + +/****************************************************************************** + * TableBasedTableBuilder class + ******************************************************************************/ +TableBasedTableBuilder::~TableBasedTableBuilder() {} + +int32_t TableBasedTableBuilder::SubSerialize(WritableFontData* data) { + UNREFERENCED_PARAMETER(data); + return 0; +} + +bool TableBasedTableBuilder::SubReadyToSerialize() { + return false; +} + +int32_t TableBasedTableBuilder::SubDataSizeToSerialize() { + return 0; +} + +void TableBasedTableBuilder::SubDataSet() { + table_ = NULL; +} + +CALLER_ATTACH FontDataTable* TableBasedTableBuilder::Build() { + FontDataTablePtr table = static_cast(GetTable()); + return table.Detach(); +} + +TableBasedTableBuilder::TableBasedTableBuilder(Header* header, + WritableFontData* data) + : Table::Builder(header, data) { +} + +TableBasedTableBuilder::TableBasedTableBuilder(Header* header, + ReadableFontData* data) + : Table::Builder(header, data) { +} + +TableBasedTableBuilder::TableBasedTableBuilder(Header* header) + : Table::Builder(header) { +} + +Table* TableBasedTableBuilder::GetTable() { + if (table_ == NULL) { + table_.Attach(down_cast(SubBuildTable(InternalReadData()))); + } + return table_; +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/table_based_table_builder.h b/src/sfntly/src/sfntly/table/table_based_table_builder.h new file mode 100644 index 0000000000..d88eefd11e --- /dev/null +++ b/src/sfntly/src/sfntly/table/table_based_table_builder.h @@ -0,0 +1,48 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_TABLE_BASED_TABLE_BUILDER_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_TABLE_BASED_TABLE_BUILDER_H_ + +#include "sfntly/table/table.h" + +namespace sfntly { + +class TableBasedTableBuilder : public Table::Builder { + public: + virtual ~TableBasedTableBuilder(); + + virtual int32_t SubSerialize(WritableFontData* new_data); + virtual bool SubReadyToSerialize(); + virtual int32_t SubDataSizeToSerialize(); + virtual void SubDataSet(); + virtual CALLER_ATTACH FontDataTable* Build(); + + protected: + TableBasedTableBuilder(Header* header, WritableFontData* data); + TableBasedTableBuilder(Header* header, ReadableFontData* data); + explicit TableBasedTableBuilder(Header* header); + + // C++ port: renamed table() to GetTable() + virtual Table* GetTable(); + + // TODO(arthurhsu): style guide violation: protected member, need refactor + TablePtr table_; +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_TABLE_BASED_TABLE_BUILDER_H_ diff --git a/src/sfntly/src/sfntly/table/truetype/glyph_table.cc b/src/sfntly/src/sfntly/table/truetype/glyph_table.cc new file mode 100644 index 0000000000..f38fac5c5c --- /dev/null +++ b/src/sfntly/src/sfntly/table/truetype/glyph_table.cc @@ -0,0 +1,679 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/truetype/glyph_table.h" + +#include + +#include "sfntly/port/exception_type.h" + +namespace sfntly { +/****************************************************************************** + * Constants + ******************************************************************************/ +const int32_t GlyphTable::SimpleGlyph::kFLAG_ONCURVE = 1; +const int32_t GlyphTable::SimpleGlyph::kFLAG_XSHORT = 1 << 1; +const int32_t GlyphTable::SimpleGlyph::kFLAG_YSHORT = 1 << 2; +const int32_t GlyphTable::SimpleGlyph::kFLAG_REPEAT = 1 << 3; +const int32_t GlyphTable::SimpleGlyph::kFLAG_XREPEATSIGN = 1 << 4; +const int32_t GlyphTable::SimpleGlyph::kFLAG_YREPEATSIGN = 1 << 5; + +const int32_t GlyphTable::CompositeGlyph::kFLAG_ARG_1_AND_2_ARE_WORDS = 1 << 0; +const int32_t GlyphTable::CompositeGlyph::kFLAG_ARGS_ARE_XY_VALUES = 1 << 1; +const int32_t GlyphTable::CompositeGlyph::kFLAG_ROUND_XY_TO_GRID = 1 << 2; +const int32_t GlyphTable::CompositeGlyph::kFLAG_WE_HAVE_A_SCALE = 1 << 3; +const int32_t GlyphTable::CompositeGlyph::kFLAG_RESERVED = 1 << 4; +const int32_t GlyphTable::CompositeGlyph::kFLAG_MORE_COMPONENTS = 1 << 5; +const int32_t GlyphTable::CompositeGlyph::kFLAG_WE_HAVE_AN_X_AND_Y_SCALE = 1 << 6; +const int32_t GlyphTable::CompositeGlyph::kFLAG_WE_HAVE_A_TWO_BY_TWO = 1 << 7; +const int32_t GlyphTable::CompositeGlyph::kFLAG_WE_HAVE_INSTRUCTIONS = 1 << 8; +const int32_t GlyphTable::CompositeGlyph::kFLAG_USE_MY_METRICS = 1 << 9; +const int32_t GlyphTable::CompositeGlyph::kFLAG_OVERLAP_COMPOUND = 1 << 10; +const int32_t GlyphTable::CompositeGlyph::kFLAG_SCALED_COMPONENT_OFFSET = 1 << 11; +const int32_t GlyphTable::CompositeGlyph::kFLAG_UNSCALED_COMPONENT_OFFSET = 1 << 12; + +/****************************************************************************** + * GlyphTable class + ******************************************************************************/ +GlyphTable::~GlyphTable() { +} + +GlyphTable::Glyph* GlyphTable::GetGlyph(int32_t offset, int32_t length) { + return GlyphTable::Glyph::GetGlyph(this, this->data_, offset, length); +} + +GlyphTable::GlyphTable(Header* header, ReadableFontData* data) + : SubTableContainerTable(header, data) { +} + +/****************************************************************************** + * GlyphTable::Builder class + ******************************************************************************/ +GlyphTable::Builder::Builder(Header* header, ReadableFontData* data) + : SubTableContainerTable::Builder(header, data) { +} + +GlyphTable::Builder::~Builder() { +} + +void GlyphTable::Builder::SetLoca(const IntegerList& loca) { + loca_ = loca; + set_model_changed(false); + glyph_builders_.clear(); +} + +void GlyphTable::Builder::GenerateLocaList(IntegerList* locas) { + assert(locas); + GlyphBuilderList* glyph_builders = GetGlyphBuilders(); + locas->push_back(0); + if (glyph_builders->size() == 0) { + locas->push_back(0); + } else { + int32_t total = 0; + for (GlyphBuilderList::iterator b = glyph_builders->begin(), + b_end = glyph_builders->end(); + b != b_end; ++b) { + int32_t size = (*b)->SubDataSizeToSerialize(); + locas->push_back(total + size); + total += size; + } + } +} + +CALLER_ATTACH GlyphTable::Builder* + GlyphTable::Builder::CreateBuilder(Header* header, WritableFontData* data) { + Ptr builder; + builder = new GlyphTable::Builder(header, data); + return builder.Detach(); +} + +GlyphTable::GlyphBuilderList* GlyphTable::Builder::GlyphBuilders() { + return GetGlyphBuilders(); +} + +void GlyphTable::Builder::SetGlyphBuilders(GlyphBuilderList* glyph_builders) { + glyph_builders_ = *glyph_builders; + set_model_changed(); +} + +CALLER_ATTACH GlyphTable::Glyph::Builder* + GlyphTable::Builder::GlyphBuilder(ReadableFontData* data) { + return Glyph::Builder::GetBuilder(this, data); +} + +CALLER_ATTACH FontDataTable* + GlyphTable::Builder::SubBuildTable(ReadableFontData* data) { + FontDataTablePtr table = new GlyphTable(header(), data); + return table.Detach(); +} + +void GlyphTable::Builder::SubDataSet() { + glyph_builders_.clear(); + set_model_changed(false); +} + +int32_t GlyphTable::Builder::SubDataSizeToSerialize() { + if (glyph_builders_.empty()) + return 0; + + bool variable = false; + int32_t size = 0; + + // Calculate size of each table. + for (GlyphBuilderList::iterator b = glyph_builders_.begin(), + end = glyph_builders_.end(); b != end; ++b) { + int32_t glyph_size = (*b)->SubDataSizeToSerialize(); + size += abs(glyph_size); + variable |= glyph_size <= 0; + } + return variable ? -size : size; +} + +bool GlyphTable::Builder::SubReadyToSerialize() { + return !glyph_builders_.empty(); +} + +int32_t GlyphTable::Builder::SubSerialize(WritableFontData* new_data) { + int32_t size = 0; + for (GlyphBuilderList::iterator b = glyph_builders_.begin(), + end = glyph_builders_.end(); b != end; ++b) { + FontDataPtr data; + data.Attach(new_data->Slice(size)); + size += (*b)->SubSerialize(down_cast(data.p_)); + } + return size; +} + +void GlyphTable::Builder::Initialize(ReadableFontData* data, + const IntegerList& loca) { + if (data != NULL) { + if (loca_.empty()) { + return; + } + int32_t loca_value; + int32_t last_loca_value = loca[0]; + for (size_t i = 1; i < loca.size(); ++i) { + loca_value = loca[i]; + GlyphBuilderPtr builder; + builder.Attach( + Glyph::Builder::GetBuilder(this, + data, + last_loca_value /*offset*/, + loca_value - last_loca_value /*length*/)); + glyph_builders_.push_back(builder); + last_loca_value = loca_value; + } + } +} + +GlyphTable::GlyphBuilderList* GlyphTable::Builder::GetGlyphBuilders() { + if (glyph_builders_.empty()) { + if (InternalReadData() && !loca_.empty()) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IllegalStateException( + "Loca values not set - unable to parse glyph data."); +#endif + return NULL; + } + Initialize(InternalReadData(), loca_); + set_model_changed(); + } + return &glyph_builders_; +} + +void GlyphTable::Builder::Revert() { + glyph_builders_.clear(); + set_model_changed(false); +} + +/****************************************************************************** + * GlyphTable::Glyph class + ******************************************************************************/ +GlyphTable::Glyph::~Glyph() {} + +CALLER_ATTACH GlyphTable::Glyph* + GlyphTable::Glyph::GetGlyph(GlyphTable* table, + ReadableFontData* data, + int32_t offset, + int32_t length) { + UNREFERENCED_PARAMETER(table); + int32_t type = GlyphType(data, offset, length); + GlyphPtr glyph; + + ReadableFontDataPtr sliced_data; + sliced_data.Attach(down_cast(data->Slice(offset, length))); + if (type == GlyphType::kSimple) { + glyph = new SimpleGlyph(sliced_data); + } else { + glyph = new CompositeGlyph(sliced_data); + } + return glyph.Detach(); +} + +int32_t GlyphTable::Glyph::Padding() { + Initialize(); + return SubTable::Padding(); +} + +int32_t GlyphTable::Glyph::GlyphType() { + return glyph_type_; +} + +int32_t GlyphTable::Glyph::NumberOfContours() { + return number_of_contours_; +} + +int32_t GlyphTable::Glyph::XMin() { + return data_->ReadShort(Offset::kXMin); +} + +int32_t GlyphTable::Glyph::XMax() { + return data_->ReadShort(Offset::kXMax); +} + +int32_t GlyphTable::Glyph::YMin() { + return data_->ReadShort(Offset::kYMin); +} + +int32_t GlyphTable::Glyph::YMax() { + return data_->ReadShort(Offset::kYMax); +} + +GlyphTable::Glyph::Glyph(ReadableFontData* data, int32_t glyph_type) + : SubTable(data), + glyph_type_(glyph_type) { + if (data_->Length() == 0) { + number_of_contours_ = 0; + } else { + // -1 if composite + number_of_contours_ = data_->ReadShort(Offset::kNumberOfContours); + } +} + +int32_t GlyphTable::Glyph::GlyphType(ReadableFontData* data, + int32_t offset, + int32_t length) { + if (length == 0) { + return GlyphType::kSimple; + } + int32_t number_of_contours = data->ReadShort(offset); + if (number_of_contours >= 0) { + return GlyphType::kSimple; + } + return GlyphType::kComposite; +} + +/****************************************************************************** + * GlyphTable::Glyph::Builder class + ******************************************************************************/ +GlyphTable::Glyph::Builder::~Builder() { +} + +GlyphTable::Glyph::Builder::Builder(WritableFontData* data) + : SubTable::Builder(data) { +} + +GlyphTable::Glyph::Builder::Builder(ReadableFontData* data) + : SubTable::Builder(data) { +} + +CALLER_ATTACH GlyphTable::Glyph::Builder* + GlyphTable::Glyph::Builder::GetBuilder( + GlyphTable::Builder* table_builder, + ReadableFontData* data) { + return GetBuilder(table_builder, data, 0, data->Length()); +} + +CALLER_ATTACH GlyphTable::Glyph::Builder* + GlyphTable::Glyph::Builder::GetBuilder( + GlyphTable::Builder* table_builder, + ReadableFontData* data, + int32_t offset, + int32_t length) { + UNREFERENCED_PARAMETER(table_builder); + int32_t type = Glyph::GlyphType(data, offset, length); + GlyphBuilderPtr builder; + ReadableFontDataPtr sliced_data; + sliced_data.Attach(down_cast(data->Slice(offset, length))); + if (type == GlyphType::kSimple) { + builder = new SimpleGlyph::SimpleGlyphBuilder(sliced_data); + } else { + builder = new CompositeGlyph::CompositeGlyphBuilder(sliced_data); + } + return builder.Detach(); +} + +void GlyphTable::Glyph::Builder::SubDataSet() { + // NOP +} + +int32_t GlyphTable::Glyph::Builder::SubDataSizeToSerialize() { + return InternalReadData()->Length(); +} + +bool GlyphTable::Glyph::Builder::SubReadyToSerialize() { + return true; +} + +int32_t GlyphTable::Glyph::Builder::SubSerialize(WritableFontData* new_data) { + return InternalReadData()->CopyTo(new_data); +} + +/****************************************************************************** + * GlyphTable::SimpleGlyph + ******************************************************************************/ +GlyphTable::SimpleGlyph::SimpleGlyph(ReadableFontData* data) + : GlyphTable::Glyph(data, GlyphType::kSimple), initialized_(false) { +} + +GlyphTable::SimpleGlyph::~SimpleGlyph() { +} + +int32_t GlyphTable::SimpleGlyph::InstructionSize() { + Initialize(); + return instruction_size_; +} + +CALLER_ATTACH ReadableFontData* GlyphTable::SimpleGlyph::Instructions() { + Initialize(); + return down_cast( + data_->Slice(instructions_offset_, InstructionSize())); +} + +int32_t GlyphTable::SimpleGlyph::NumberOfPoints(int32_t contour) { + Initialize(); + if (contour >= NumberOfContours()) { + return 0; + } + return contour_index_[contour + 1] - contour_index_[contour]; +} + +int32_t GlyphTable::SimpleGlyph::XCoordinate(int32_t contour, int32_t point) { + Initialize(); + return x_coordinates_[contour_index_[contour] + point]; +} + +int32_t GlyphTable::SimpleGlyph::YCoordinate(int32_t contour, int32_t point) { + Initialize(); + return y_coordinates_[contour_index_[contour] + point]; +} + +bool GlyphTable::SimpleGlyph::OnCurve(int32_t contour, int32_t point) { + Initialize(); + return on_curve_[contour_index_[contour] + point]; +} + +void GlyphTable::SimpleGlyph::Initialize() { + AutoLock lock(initialization_lock_); + if (initialized_) { + return; + } + + if (ReadFontData()->Length() == 0) { + instruction_size_ = 0; + number_of_points_ = 0; + instructions_offset_ = 0; + flags_offset_ = 0; + x_coordinates_offset_ = 0; + y_coordinates_offset_ = 0; + return; + } + + instruction_size_ = data_->ReadUShort(Offset::kSimpleEndPtsOfCountours + + NumberOfContours() * DataSize::kUSHORT); + instructions_offset_ = Offset::kSimpleEndPtsOfCountours + + (NumberOfContours() + 1) * DataSize::kUSHORT; + flags_offset_ = instructions_offset_ + instruction_size_ * DataSize::kBYTE; + number_of_points_ = ContourEndPoint(NumberOfContours() - 1) + 1; + x_coordinates_.resize(number_of_points_); + y_coordinates_.resize(number_of_points_); + on_curve_.resize(number_of_points_); + ParseData(false); + x_coordinates_offset_ = flags_offset_ + flag_byte_count_ * DataSize::kBYTE; + y_coordinates_offset_ = x_coordinates_offset_ + x_byte_count_ * + DataSize::kBYTE; + contour_index_.resize(NumberOfContours() + 1); + contour_index_[0] = 0; + for (uint32_t contour = 0; contour < contour_index_.size() - 1; ++contour) { + contour_index_[contour + 1] = ContourEndPoint(contour) + 1; + } + ParseData(true); + int32_t non_padded_data_length = + 5 * DataSize::kSHORT + + (NumberOfContours() * DataSize::kUSHORT) + + DataSize::kUSHORT + + (instruction_size_ * DataSize::kBYTE) + + (flag_byte_count_ * DataSize::kBYTE) + + (x_byte_count_ * DataSize::kBYTE) + + (y_byte_count_ * DataSize::kBYTE); + set_padding(DataLength() - non_padded_data_length); + initialized_ = true; +} + +void GlyphTable::SimpleGlyph::ParseData(bool fill_arrays) { + int32_t flag = 0; + int32_t flag_repeat = 0; + int32_t flag_index = 0; + int32_t x_byte_index = 0; + int32_t y_byte_index = 0; + + for (int32_t point_index = 0; point_index < number_of_points_; + ++point_index) { + // get the flag for the current point + if (flag_repeat == 0) { + flag = FlagAsInt(flag_index++); + if ((flag & kFLAG_REPEAT) == kFLAG_REPEAT) { + flag_repeat = FlagAsInt(flag_index++); + } + } else { + flag_repeat--; + } + + // on the curve? + if (fill_arrays) { + on_curve_[point_index] = ((flag & kFLAG_ONCURVE) == kFLAG_ONCURVE); + } + // get the x coordinate + if ((flag & kFLAG_XSHORT) == kFLAG_XSHORT) { + // single byte x coord value + if (fill_arrays) { + x_coordinates_[point_index] = + data_->ReadUByte(x_coordinates_offset_ + x_byte_index); + x_coordinates_[point_index] *= + ((flag & kFLAG_XREPEATSIGN) == kFLAG_XREPEATSIGN) ? 1 : -1; + } + x_byte_index++; + } else { + // double byte coord value + if (!((flag & kFLAG_XREPEATSIGN) == kFLAG_XREPEATSIGN)) { + if (fill_arrays) { + x_coordinates_[point_index] = + data_->ReadShort(x_coordinates_offset_ + x_byte_index); + } + x_byte_index += 2; + } + } + if (fill_arrays && point_index > 0) { + x_coordinates_[point_index] += x_coordinates_[point_index - 1]; + } + + // get the y coordinate + if ((flag & kFLAG_YSHORT) == kFLAG_YSHORT) { + if (fill_arrays) { + y_coordinates_[point_index] = + data_->ReadUByte(y_coordinates_offset_ + y_byte_index); + y_coordinates_[point_index] *= + ((flag & kFLAG_YREPEATSIGN) == kFLAG_YREPEATSIGN) ? 1 : -1; + } + y_byte_index++; + } else { + if (!((flag & kFLAG_YREPEATSIGN) == kFLAG_YREPEATSIGN)) { + if (fill_arrays) { + y_coordinates_[point_index] = + data_->ReadShort(y_coordinates_offset_ + y_byte_index); + } + y_byte_index += 2; + } + } + if (fill_arrays && point_index > 0) { + y_coordinates_[point_index] += y_coordinates_[point_index - 1]; + } + } + flag_byte_count_ = flag_index; + x_byte_count_ = x_byte_index; + y_byte_count_ = y_byte_index; +} + +int32_t GlyphTable::SimpleGlyph::FlagAsInt(int32_t index) { + return data_->ReadUByte(flags_offset_ + index * DataSize::kBYTE); +} + +int32_t GlyphTable::SimpleGlyph::ContourEndPoint(int32_t contour) { + return data_->ReadUShort(contour * DataSize::kUSHORT + + Offset::kSimpleEndPtsOfCountours); +} + +/****************************************************************************** + * GlyphTable::SimpleGlyph::Builder + ******************************************************************************/ +GlyphTable::SimpleGlyph::SimpleGlyphBuilder::~SimpleGlyphBuilder() { +} + +GlyphTable::SimpleGlyph::SimpleGlyphBuilder::SimpleGlyphBuilder( + WritableFontData* data) + : Glyph::Builder(data) { +} + +GlyphTable::SimpleGlyph::SimpleGlyphBuilder::SimpleGlyphBuilder( + ReadableFontData* data) + : Glyph::Builder(data) { +} + +CALLER_ATTACH FontDataTable* + GlyphTable::SimpleGlyph::SimpleGlyphBuilder::SubBuildTable( + ReadableFontData* data) { + FontDataTablePtr table = new SimpleGlyph(data); + return table.Detach(); +} + +/****************************************************************************** + * GlyphTable::CompositeGlyph + ******************************************************************************/ +GlyphTable::CompositeGlyph::CompositeGlyph(ReadableFontData* data) + : GlyphTable::Glyph(data, GlyphType::kComposite), + instruction_size_(0), + instructions_offset_(0), + initialized_(false) { + Initialize(); +} + +GlyphTable::CompositeGlyph::~CompositeGlyph() { +} + +int32_t GlyphTable::CompositeGlyph::Flags(int32_t contour) { + return data_->ReadUShort(contour_index_[contour]); +} + +int32_t GlyphTable::CompositeGlyph::NumGlyphs() { + return contour_index_.size(); +} + +int32_t GlyphTable::CompositeGlyph::GlyphIndex(int32_t contour) { + return data_->ReadUShort(DataSize::kUSHORT + contour_index_[contour]); +} + +int32_t GlyphTable::CompositeGlyph::Argument1(int32_t contour) { + int32_t index = 2 * DataSize::kUSHORT + contour_index_[contour]; + int32_t contour_flags = Flags(contour); + if ((contour_flags & kFLAG_ARG_1_AND_2_ARE_WORDS) == + kFLAG_ARG_1_AND_2_ARE_WORDS) { + return data_->ReadUShort(index); + } + return data_->ReadByte(index); +} + +int32_t GlyphTable::CompositeGlyph::Argument2(int32_t contour) { + int32_t index = 2 * DataSize::kUSHORT + contour_index_[contour]; + int32_t contour_flags = Flags(contour); + if ((contour_flags & kFLAG_ARG_1_AND_2_ARE_WORDS) == + kFLAG_ARG_1_AND_2_ARE_WORDS) { + return data_->ReadUShort(index + DataSize::kUSHORT); + } + return data_->ReadByte(index + DataSize::kUSHORT); +} + +int32_t GlyphTable::CompositeGlyph::TransformationSize(int32_t contour) { + int32_t contour_flags = Flags(contour); + if ((contour_flags & kFLAG_WE_HAVE_A_SCALE) == kFLAG_WE_HAVE_A_SCALE) { + return DataSize::kF2DOT14; + } else if ((contour_flags & kFLAG_WE_HAVE_AN_X_AND_Y_SCALE) == + kFLAG_WE_HAVE_AN_X_AND_Y_SCALE) { + return 2 * DataSize::kF2DOT14; + } else if ((contour_flags & kFLAG_WE_HAVE_A_TWO_BY_TWO) == + kFLAG_WE_HAVE_A_TWO_BY_TWO) { + return 4 * DataSize::kF2DOT14; + } + return 0; +} + +void GlyphTable::CompositeGlyph::Transformation(int32_t contour, + ByteVector* transformation) { + int32_t contour_flags = Flags(contour); + int32_t index = contour_index_[contour] + 2 * DataSize::kUSHORT; + if ((contour_flags & kFLAG_ARG_1_AND_2_ARE_WORDS) == + kFLAG_ARG_1_AND_2_ARE_WORDS) { + index += 2 * DataSize::kSHORT; + } else { + index += 2 * DataSize::kBYTE; + } + int32_t tsize = TransformationSize(contour); + transformation->resize(tsize); + data_->ReadBytes(index, &((*transformation)[0]), 0, tsize); +} + +int32_t GlyphTable::CompositeGlyph::InstructionSize() { + return instruction_size_; +} + +CALLER_ATTACH ReadableFontData* GlyphTable::CompositeGlyph::Instructions() { + return down_cast( + data_->Slice(instructions_offset_, InstructionSize())); +} + +void GlyphTable::CompositeGlyph::Initialize() { + AutoLock lock(initialization_lock_); + if (initialized_) { + return; + } + + int32_t index = 5 * DataSize::kUSHORT; + int32_t flags = kFLAG_MORE_COMPONENTS; + + while ((flags & kFLAG_MORE_COMPONENTS) == kFLAG_MORE_COMPONENTS) { + contour_index_.push_back(index); + flags = data_->ReadUShort(index); + index += 2 * DataSize::kUSHORT; // flags and glyphIndex + if ((flags & kFLAG_ARG_1_AND_2_ARE_WORDS) == kFLAG_ARG_1_AND_2_ARE_WORDS) { + index += 2 * DataSize::kSHORT; + } else { + index += 2 * DataSize::kBYTE; + } + if ((flags & kFLAG_WE_HAVE_A_SCALE) == kFLAG_WE_HAVE_A_SCALE) { + index += DataSize::kF2DOT14; + } else if ((flags & kFLAG_WE_HAVE_AN_X_AND_Y_SCALE) == + kFLAG_WE_HAVE_AN_X_AND_Y_SCALE) { + index += 2 * DataSize::kF2DOT14; + } else if ((flags & kFLAG_WE_HAVE_A_TWO_BY_TWO) == + kFLAG_WE_HAVE_A_TWO_BY_TWO) { + index += 4 * DataSize::kF2DOT14; + } + int32_t non_padded_data_length = index; + if ((flags & kFLAG_WE_HAVE_INSTRUCTIONS) == kFLAG_WE_HAVE_INSTRUCTIONS) { + instruction_size_ = data_->ReadUShort(index); + index += DataSize::kUSHORT; + instructions_offset_ = index; + non_padded_data_length = index + (instruction_size_ * DataSize::kBYTE); + } + set_padding(DataLength() - non_padded_data_length); + } + + initialized_ = true; +} + +/****************************************************************************** + * GlyphTable::CompositeGlyph::Builder + ******************************************************************************/ +GlyphTable::CompositeGlyph::CompositeGlyphBuilder::~CompositeGlyphBuilder() { +} + +GlyphTable::CompositeGlyph::CompositeGlyphBuilder::CompositeGlyphBuilder( + WritableFontData* data) + : Glyph::Builder(data) { +} + +GlyphTable::CompositeGlyph::CompositeGlyphBuilder::CompositeGlyphBuilder( + ReadableFontData* data) + : Glyph::Builder(data) { +} + +CALLER_ATTACH FontDataTable* + GlyphTable::CompositeGlyph::CompositeGlyphBuilder::SubBuildTable( + ReadableFontData* data) { + FontDataTablePtr table = new CompositeGlyph(data); + return table.Detach(); +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/truetype/glyph_table.h b/src/sfntly/src/sfntly/table/truetype/glyph_table.h new file mode 100644 index 0000000000..0836971894 --- /dev/null +++ b/src/sfntly/src/sfntly/table/truetype/glyph_table.h @@ -0,0 +1,335 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_TRUETYPE_GLYPH_TABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_TRUETYPE_GLYPH_TABLE_H_ + +#include + +#include "sfntly/table/table.h" +#include "sfntly/table/subtable.h" +#include "sfntly/table/subtable_container_table.h" + +namespace sfntly { + +struct GlyphType { + enum { + kSimple = 0, + kComposite = 1 + }; +}; + +class GlyphTable : public SubTableContainerTable, + public RefCounted { + public: + class Builder; + class Glyph : public SubTable { + public: + // Note: Contour is an empty class for the version ported + class Contour { + protected: + Contour() {} + virtual ~Contour() {} + }; + + class Builder : public SubTable::Builder { + public: + virtual ~Builder(); + + protected: + // Incoming table_builder is GlyphTable::Builder*. + // Note: constructor refactored in C++ to avoid heavy lifting. + // caller need to do data->Slice(offset, length) beforehand. + explicit Builder(WritableFontData* data); + explicit Builder(ReadableFontData* data); + + static CALLER_ATTACH Builder* + GetBuilder(GlyphTable::Builder* table_builder, + ReadableFontData* data); + static CALLER_ATTACH Builder* + GetBuilder(GlyphTable::Builder* table_builder, + ReadableFontData* data, + int32_t offset, + int32_t length); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + + private: + int32_t format_; + friend class GlyphTable::Builder; + }; + + virtual ~Glyph(); + static CALLER_ATTACH Glyph* GetGlyph(GlyphTable* table, + ReadableFontData* data, + int32_t offset, + int32_t length); + + virtual int32_t Padding(); + virtual int32_t GlyphType(); + virtual int32_t NumberOfContours(); + virtual int32_t XMin(); + virtual int32_t XMax(); + virtual int32_t YMin(); + virtual int32_t YMax(); + + virtual int32_t InstructionSize() = 0; + virtual ReadableFontData* Instructions() = 0; + + protected: + // Note: constructor refactored in C++ to avoid heavy lifting. + // caller need to do data->Slice(offset, length) beforehand. + Glyph(ReadableFontData* data, int32_t glyph_type); + virtual void Initialize() = 0; + // Note: Derived class to define initialization_lock_. + + private: + static int32_t GlyphType(ReadableFontData* data, + int32_t offset, + int32_t length); + + int32_t glyph_type_; + int32_t number_of_contours_; + }; // class GlyphTable::Glyph + typedef Ptr GlyphBuilderPtr; + typedef std::vector GlyphBuilderList; + + class Builder : public SubTableContainerTable::Builder, + public RefCounted { + public: + // Note: Constructor scope altered to public for base class to instantiate. + Builder(Header* header, ReadableFontData* data); + virtual ~Builder(); + + virtual void SetLoca(const IntegerList& loca); + virtual void GenerateLocaList(IntegerList* locas); + + static CALLER_ATTACH Builder* CreateBuilder(Header* header, + WritableFontData* data); + + // Gets the List of glyph builders for the glyph table builder. These may be + // manipulated in any way by the caller and the changes will be reflected in + // the final glyph table produced. + // If there is no current data for the glyph builder or the glyph builders + // have not been previously set then this will return an empty glyph builder + // List. If there is current data (i.e. data read from an existing font) and + // the loca list has not been set or is null, empty, or + // invalid, then an empty glyph builder List will be returned. + GlyphBuilderList* GlyphBuilders(); + + // Replace the internal glyph builders with the one provided. The provided + // list and all contained objects belong to this builder. + // This call is only required if the entire set of glyphs in the glyph + // table builder are being replaced. If the glyph builder list provided from + // the GlyphTable.Builder::GlyphBuilders() is being used and modified + // then those changes will already be reflected in the glyph table builder. + void SetGlyphBuilders(GlyphBuilderList* glyph_builders); + + // Glyph builder factories + CALLER_ATTACH Glyph::Builder* GlyphBuilder(ReadableFontData* data); + + protected: // internal API for building + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + + private: + void Initialize(ReadableFontData* data, const IntegerList& loca); + GlyphBuilderList* GetGlyphBuilders(); + void Revert(); + + GlyphBuilderList glyph_builders_; + IntegerList loca_; + }; + + class SimpleGlyph : public Glyph, public RefCounted { + public: + static const int32_t kFLAG_ONCURVE; + static const int32_t kFLAG_XSHORT; + static const int32_t kFLAG_YSHORT; + static const int32_t kFLAG_REPEAT; + static const int32_t kFLAG_XREPEATSIGN; + static const int32_t kFLAG_YREPEATSIGN; + + class SimpleContour : public Glyph::Contour { + protected: + SimpleContour() {} + virtual ~SimpleContour() {} + }; + + class SimpleGlyphBuilder : public Glyph::Builder, + public RefCounted { + public: + virtual ~SimpleGlyphBuilder(); + + protected: + // Note: constructor refactored in C++ to avoid heavy lifting. + // caller need to do data->Slice(offset, length) beforehand. + explicit SimpleGlyphBuilder(WritableFontData* data); + explicit SimpleGlyphBuilder(ReadableFontData* data); + virtual CALLER_ATTACH FontDataTable* + SubBuildTable(ReadableFontData* data); + + private: + friend class Glyph::Builder; + }; + + // Note: constructor refactored in C++ to avoid heavy lifting. + // caller need to do data->Slice(offset, length) beforehand. + explicit SimpleGlyph(ReadableFontData* data); + virtual ~SimpleGlyph(); + + virtual int32_t InstructionSize(); + virtual CALLER_ATTACH ReadableFontData* Instructions(); + virtual void Initialize(); + + int32_t NumberOfPoints(int32_t contour); + int32_t XCoordinate(int32_t contour, int32_t point); + int32_t YCoordinate(int32_t contour, int32_t point); + bool OnCurve(int32_t contour, int32_t point); + + private: + void ParseData(bool fill_arrays); + int32_t FlagAsInt(int32_t index); + int32_t ContourEndPoint(int32_t contour); + + bool initialized_; + Lock initialization_lock_; + int32_t instruction_size_; + int32_t number_of_points_; + + // start offsets of the arrays + int32_t instructions_offset_; + int32_t flags_offset_; + int32_t x_coordinates_offset_; + int32_t y_coordinates_offset_; + + int32_t flag_byte_count_; + int32_t x_byte_count_; + int32_t y_byte_count_; + + IntegerList x_coordinates_; + IntegerList y_coordinates_; + std::vector on_curve_; + IntegerList contour_index_; + }; + + class CompositeGlyph : public Glyph, public RefCounted { + public: + static const int32_t kFLAG_ARG_1_AND_2_ARE_WORDS; + static const int32_t kFLAG_ARGS_ARE_XY_VALUES; + static const int32_t kFLAG_ROUND_XY_TO_GRID; + static const int32_t kFLAG_WE_HAVE_A_SCALE; + static const int32_t kFLAG_RESERVED; + static const int32_t kFLAG_MORE_COMPONENTS; + static const int32_t kFLAG_WE_HAVE_AN_X_AND_Y_SCALE; + static const int32_t kFLAG_WE_HAVE_A_TWO_BY_TWO; + static const int32_t kFLAG_WE_HAVE_INSTRUCTIONS; + static const int32_t kFLAG_USE_MY_METRICS; + static const int32_t kFLAG_OVERLAP_COMPOUND; + static const int32_t kFLAG_SCALED_COMPONENT_OFFSET; + static const int32_t kFLAG_UNSCALED_COMPONENT_OFFSET; + + class CompositeGlyphBuilder : public Glyph::Builder, + public RefCounted { + public: + virtual ~CompositeGlyphBuilder(); + + protected: + // Note: constructor refactored in C++ to avoid heavy lifting. + // caller need to do data->Slice(offset, length) beforehand. + explicit CompositeGlyphBuilder(WritableFontData* data); + explicit CompositeGlyphBuilder(ReadableFontData* data); + + virtual CALLER_ATTACH FontDataTable* + SubBuildTable(ReadableFontData* data); + + private: + friend class Glyph::Builder; + }; + + // Note: constructor refactored in C++ to avoid heavy lifting. + // caller need to do data->Slice(offset, length) beforehand. + explicit CompositeGlyph(ReadableFontData* data); + virtual ~CompositeGlyph(); + + int32_t Flags(int32_t contour); + int32_t NumGlyphs(); + int32_t GlyphIndex(int32_t contour); + int32_t Argument1(int32_t contour); + int32_t Argument2(int32_t contour); + int32_t TransformationSize(int32_t contour); + void Transformation(int32_t contour, ByteVector* transformation); + virtual int32_t InstructionSize(); + virtual CALLER_ATTACH ReadableFontData* Instructions(); + + protected: + virtual void Initialize(); + + private: + IntegerList contour_index_; + int32_t instruction_size_; + int32_t instructions_offset_; + bool initialized_; + Lock initialization_lock_; + }; + + virtual ~GlyphTable(); + + // C++ port: rename glyph() to GetGlyph(). + Glyph* GetGlyph(int32_t offset, int32_t length); + + private: + struct Offset { + enum { + // header + kNumberOfContours = 0, + kXMin = 2, + kYMin = 4, + kXMax = 6, + kYMax = 8, + + // Simple Glyph Description + kSimpleEndPtsOfCountours = 10, + // offset from the end of the contours array + kSimpleInstructionLength = 0, + kSimpleInstructions = 2, + // flags + // xCoordinates + // yCoordinates + + // Composite Glyph Description + kCompositeFlags = 0, + kCompositeGyphIndexWithoutFlag = 0, + kCompositeGlyphIndexWithFlag = 2, + }; + }; + + GlyphTable(Header* header, ReadableFontData* data); +}; +typedef Ptr GlyphTablePtr; +typedef Ptr GlyphTableBuilderPtr; +typedef std::vector GlyphTableBuilderList; +typedef Ptr GlyphPtr; +typedef Ptr GlyphBuilderPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_TRUETYPE_GLYPH_TABLE_H_ diff --git a/src/sfntly/src/sfntly/table/truetype/loca_table.cc b/src/sfntly/src/sfntly/table/truetype/loca_table.cc new file mode 100644 index 0000000000..c692155da8 --- /dev/null +++ b/src/sfntly/src/sfntly/table/truetype/loca_table.cc @@ -0,0 +1,246 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/truetype/loca_table.h" +#include "sfntly/port/exception_type.h" + +namespace sfntly { +/****************************************************************************** + * LocaTable class + ******************************************************************************/ +LocaTable::~LocaTable() {} + +int32_t LocaTable::GlyphOffset(int32_t glyph_id) { + if (glyph_id < 0 || glyph_id >= num_glyphs_) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundException("Glyph ID is out of bounds."); +#endif + return 0; + } + return Loca(glyph_id); +} + +int32_t LocaTable::GlyphLength(int32_t glyph_id) { + if (glyph_id < 0 || glyph_id >= num_glyphs_) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundException("Glyph ID is out of bounds."); +#endif + return 0; + } + return Loca(glyph_id + 1) - Loca(glyph_id); +} + +int32_t LocaTable::NumLocas() { + return num_glyphs_ + 1; +} + +int32_t LocaTable::Loca(int32_t index) { + if (index > num_glyphs_) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundException(); +#endif + return 0; + } + if (format_version_ == IndexToLocFormat::kShortOffset) { + return 2 * data_->ReadUShort(index * DataSize::kUSHORT); + } + return data_->ReadULongAsInt(index * DataSize::kULONG); +} + +LocaTable::LocaTable(Header* header, + ReadableFontData* data, + int32_t format_version, + int32_t num_glyphs) + : Table(header, data), + format_version_(format_version), + num_glyphs_(num_glyphs) { +} + +/****************************************************************************** + * LocaTable::Iterator class + ******************************************************************************/ +LocaTable::LocaIterator::LocaIterator(LocaTable* table) + : PODIterator(table), index_(-1) { +} + +bool LocaTable::LocaIterator::HasNext() { + return index_ <= container()->num_glyphs_; +} + +int32_t LocaTable::LocaIterator::Next() { + return container()->Loca(index_++); +} + +/****************************************************************************** + * LocaTable::Builder class + ******************************************************************************/ +LocaTable::Builder::Builder(Header* header, WritableFontData* data) + : Table::Builder(header, data), + format_version_(IndexToLocFormat::kLongOffset), + num_glyphs_(-1) { +} + +LocaTable::Builder::Builder(Header* header, ReadableFontData* data) + : Table::Builder(header, data), + format_version_(IndexToLocFormat::kLongOffset), + num_glyphs_(-1) { +} + +LocaTable::Builder::~Builder() {} + +CALLER_ATTACH +LocaTable::Builder* LocaTable::Builder::CreateBuilder(Header* header, + WritableFontData* data) { + Ptr builder; + builder = new LocaTable::Builder(header, data); + return builder.Detach(); +} + +IntegerList* LocaTable::Builder::LocaList() { + return GetLocaList(); +} + +void LocaTable::Builder::SetLocaList(IntegerList* list) { + loca_.clear(); + if (list) { + loca_ = *list; + set_model_changed(); + } +} + +int32_t LocaTable::Builder::GlyphOffset(int32_t glyph_id) { + if (CheckGlyphRange(glyph_id) == -1) { + return 0; + } + return GetLocaList()->at(glyph_id); +} + +int32_t LocaTable::Builder::GlyphLength(int32_t glyph_id) { + if (CheckGlyphRange(glyph_id) == -1) { + return 0; + } + return GetLocaList()->at(glyph_id + 1) - GetLocaList()->at(glyph_id); +} + +void LocaTable::Builder::SetNumGlyphs(int32_t num_glyphs) { + num_glyphs_ = num_glyphs; +} + +int32_t LocaTable::Builder::NumGlyphs() { + return LastGlyphIndex() - 1; +} + +void LocaTable::Builder::Revert() { + loca_.clear(); + set_model_changed(false); +} + +int32_t LocaTable::Builder::NumLocas() { + return GetLocaList()->size(); +} + +int32_t LocaTable::Builder::Loca(int32_t index) { + return GetLocaList()->at(index); +} + +CALLER_ATTACH +FontDataTable* LocaTable::Builder::SubBuildTable(ReadableFontData* data) { + FontDataTablePtr table = + new LocaTable(header(), data, format_version_, num_glyphs_); + return table.Detach(); +} + +void LocaTable::Builder::SubDataSet() { + Initialize(InternalReadData()); +} + +int32_t LocaTable::Builder::SubDataSizeToSerialize() { + if (loca_.empty()) { + return 0; + } + if (format_version_ == IndexToLocFormat::kLongOffset) { + return loca_.size() * DataSize::kULONG; + } + return loca_.size() * DataSize::kUSHORT; +} + +bool LocaTable::Builder::SubReadyToSerialize() { + return !loca_.empty(); +} + +int32_t LocaTable::Builder::SubSerialize(WritableFontData* new_data) { + int32_t size = 0; + for (IntegerList::iterator l = loca_.begin(), end = loca_.end(); + l != end; ++l) { + if (format_version_ == IndexToLocFormat::kLongOffset) { + size += new_data->WriteULong(size, *l); + } else { + size += new_data->WriteUShort(size, *l / 2); + } + } + num_glyphs_ = loca_.size() - 1; + return size; +} + +void LocaTable::Builder::Initialize(ReadableFontData* data) { + ClearLoca(false); + if (data) { + if (NumGlyphs() < 0) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IllegalStateException("numglyphs not set on LocaTable Builder."); +#endif + return; + } + LocaTablePtr table = + new LocaTable(header(), data, format_version_, num_glyphs_); + Ptr loca_iter = + new LocaTable::LocaIterator(table); + while (loca_iter->HasNext()) { + loca_.push_back(loca_iter->Next()); + } + } +} + +int32_t LocaTable::Builder::CheckGlyphRange(int32_t glyph_id) { + if (glyph_id < 0 || glyph_id > LastGlyphIndex()) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundsException("Glyph ID is outside of the allowed range"); +#endif + return -1; + } + return glyph_id; +} + +int32_t LocaTable::Builder::LastGlyphIndex() { + return !loca_.empty() ? loca_.size() - 2 : num_glyphs_ - 1; +} + +IntegerList* LocaTable::Builder::GetLocaList() { + if (loca_.empty()) { + Initialize(InternalReadData()); + set_model_changed(); + } + return &loca_; +} + +void LocaTable::Builder::ClearLoca(bool nullify) { + // Note: in C++ port, nullify is not used at all. + UNREFERENCED_PARAMETER(nullify); + loca_.clear(); + set_model_changed(false); +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/truetype/loca_table.h b/src/sfntly/src/sfntly/table/truetype/loca_table.h new file mode 100644 index 0000000000..67c5749b05 --- /dev/null +++ b/src/sfntly/src/sfntly/table/truetype/loca_table.h @@ -0,0 +1,183 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_TRUETYPE_LOCA_TABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_TRUETYPE_LOCA_TABLE_H_ + +#include "sfntly/port/java_iterator.h" +#include "sfntly/table/table.h" +#include "sfntly/table/core/font_header_table.h" + +namespace sfntly { + +// A Loca table - 'loca'. +class LocaTable : public Table, public RefCounted { + public: + class LocaIterator : public PODIterator { + public: + explicit LocaIterator(LocaTable* table); + virtual ~LocaIterator() {} + + virtual bool HasNext(); + virtual int32_t Next(); + + private: + int32_t index_; + }; + + class Builder : public Table::Builder, public RefCounted { + public: + // Constructor scope altered to public for base class to instantiate. + Builder(Header* header, WritableFontData* data); + Builder(Header* header, ReadableFontData* data); + virtual ~Builder(); + + static CALLER_ATTACH Builder* CreateBuilder(Header* header, + WritableFontData* data); + + // Get the format version that will be used when the loca table is + // generated. + // @return the loca table format version + int32_t format_version() { return format_version_; } + void set_format_version(int32_t value) { format_version_ = value; } + + // Gets the List of locas for loca table builder. These may be manipulated + // in any way by the caller and the changes will be reflected in the final + // loca table produced as long as no subsequent call is made to the + // SetLocaList(List) method. + // If there is no current data for the loca table builder or the loca list + // have not been previously set then this will return an empty List. + IntegerList* LocaList(); + + // Set the list of locas to be used for building this table. If any existing + // list was already retrieved with the LocaList() method then the + // connection of that previous list to this builder will be broken. + void SetLocaList(IntegerList* list); + + // Return the offset for the given glyph id. Valid glyph ids are from 0 to + // one less than the number of glyphs. The zero entry is the special entry + // for the notdef glyph. The final entry beyond the last glyph id is used to + // calculate the size of the last glyph. + // @param glyphId the glyph id to get the offset for; must be less than or + // equal to one more than the number of glyph ids + // @return the offset in the glyph table to the specified glyph id + int32_t GlyphOffset(int32_t glyph_id); + + // Get the length of the data in the glyph table for the specified glyph id. + int32_t GlyphLength(int32_t glyph_id); + + // Set the number of glyphs. + // This method sets the number of glyphs that the builder will attempt to + // parse location data for from the raw binary data. This method only needs + // to be called (and must be) when the raw data for this builder has + // been changed. It does not by itself reset the data or clear any set loca + // list. + void SetNumGlyphs(int32_t num_glyphs); + + // Get the number of glyphs that this builder has support for. + int NumGlyphs(); + + // Revert the loca table builder to the state contained in the last raw data + // set on the builder. That raw data may be that read from a font file when + // the font builder was created, that set by a user of the loca table + // builder, or null data if this builder was created as a new empty builder. + void Revert(); + + // Get the number of locations or locas. This will be one more than the + // number of glyphs for this table since the last loca position is used to + // indicate the size of the final glyph. + int32_t NumLocas(); + + // Get the value from the loca table for the index specified. These are the + // raw values from the table that are used to compute the offset and size of + // a glyph in the glyph table. Valid index values run from 0 to the number + // of glyphs in the font. + int32_t Loca(int32_t index); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + + private: + // Initialize the internal state from the data. Done lazily since in many + // cases the builder will be just creating a table object with no parsing + // required. + // @param data the data to initialize from + void Initialize(ReadableFontData* data); + + // Checks that the glyph id is within the correct range. + // @return glyph_id if correct, -1 otherwise. + int32_t CheckGlyphRange(int32_t glyph_id); + + int32_t LastGlyphIndex(); + + // Internal method to get the loca list if already generated and if not to + // initialize the state of the builder. + // @return the loca list + IntegerList* GetLocaList(); + + void ClearLoca(bool nullify); + + int32_t format_version_; // Note: IndexToLocFormat + int32_t num_glyphs_; + IntegerList loca_; + }; + + virtual ~LocaTable(); + + int32_t format_version() { return format_version_; } + int32_t num_glyphs() { return num_glyphs_; } + + // Return the offset for the given glyph id. Valid glyph ids are from 0 to the + // one less than the number of glyphs. The zero entry is the special entry for + // the notdef glyph. The final entry beyond the last glyph id is used to + // calculate the size of the last glyph. + // @param glyphId the glyph id to get the offset for; must be less than or + // equal to one more than the number of glyph ids + // @return the offset in the glyph table to the specified glyph id + int32_t GlyphOffset(int32_t glyph_id); + + // Get the length of the data in the glyph table for the specified glyph id. + int32_t GlyphLength(int32_t glyph_id); + + // Get the number of locations or locas. This will be one more than the number + // of glyphs for this table since the last loca position is used to indicate + // the size of the final glyph. + int32_t NumLocas(); + + // Get the value from the loca table for the index specified. Valid index + // values run from 0 to the number of glyphs in the font. + int32_t Loca(int32_t index); + + private: + LocaTable(Header* header, + ReadableFontData* data, + int32_t format_version, + int32_t num_glyphs); + + int32_t format_version_; // Note: Java's version, renamed to format_version_ + int32_t num_glyphs_; + + friend class LocaIterator; +}; +typedef Ptr LocaTablePtr; +typedef Ptr LocaTableBuilderPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_TRUETYPE_LOCA_TABLE_H_ diff --git a/src/sfntly/src/sfntly/tag.cc b/src/sfntly/src/sfntly/tag.cc new file mode 100644 index 0000000000..c9d8c29878 --- /dev/null +++ b/src/sfntly/src/sfntly/tag.cc @@ -0,0 +1,110 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/tag.h" +#include "sfntly/port/endian.h" + +// Use a macro instead of GenerateTag() because gcc 4.4.3 creates static +// initializers in that case. +#define TAG(a, b, c, d) ((a << 24) | (b << 16) | (c << 8) | d); + +namespace sfntly { + +const int32_t Tag::ttcf = TAG('t', 't', 'c', 'f'); +const int32_t Tag::cmap = TAG('c', 'm', 'a', 'p'); +const int32_t Tag::head = TAG('h', 'e', 'a', 'd'); +const int32_t Tag::hhea = TAG('h', 'h', 'e', 'a'); +const int32_t Tag::hmtx = TAG('h', 'm', 't', 'x'); +const int32_t Tag::maxp = TAG('m', 'a', 'x', 'p'); +const int32_t Tag::name = TAG('n', 'a', 'm', 'e'); +const int32_t Tag::OS_2 = TAG('O', 'S', '/', '2'); +const int32_t Tag::post = TAG('p', 'o', 's', 't'); +const int32_t Tag::cvt = TAG('c', 'v', 't', ' '); +const int32_t Tag::fpgm = TAG('f', 'p', 'g', 'm'); +const int32_t Tag::glyf = TAG('g', 'l', 'y', 'f'); +const int32_t Tag::loca = TAG('l', 'o', 'c', 'a'); +const int32_t Tag::prep = TAG('p', 'r', 'e', 'p'); +const int32_t Tag::CFF = TAG('C', 'F', 'F', ' '); +const int32_t Tag::VORG = TAG('V', 'O', 'R', 'G'); +const int32_t Tag::EBDT = TAG('E', 'B', 'D', 'T'); +const int32_t Tag::EBLC = TAG('E', 'B', 'L', 'C'); +const int32_t Tag::EBSC = TAG('E', 'B', 'S', 'C'); +const int32_t Tag::BASE = TAG('B', 'A', 'S', 'E'); +const int32_t Tag::GDEF = TAG('G', 'D', 'E', 'F'); +const int32_t Tag::GPOS = TAG('G', 'P', 'O', 'S'); +const int32_t Tag::GSUB = TAG('G', 'S', 'U', 'B'); +const int32_t Tag::JSTF = TAG('J', 'S', 'T', 'F'); +const int32_t Tag::DSIG = TAG('D', 'S', 'I', 'G'); +const int32_t Tag::gasp = TAG('g', 'a', 's', 'p'); +const int32_t Tag::hdmx = TAG('h', 'd', 'm', 'x'); +const int32_t Tag::kern = TAG('k', 'e', 'r', 'n'); +const int32_t Tag::LTSH = TAG('L', 'T', 'S', 'H'); +const int32_t Tag::PCLT = TAG('P', 'C', 'L', 'T'); +const int32_t Tag::VDMX = TAG('V', 'D', 'M', 'X'); +const int32_t Tag::vhea = TAG('v', 'h', 'e', 'a'); +const int32_t Tag::vmtx = TAG('v', 'm', 't', 'x'); +const int32_t Tag::bsln = TAG('b', 's', 'l', 'n'); +const int32_t Tag::feat = TAG('f', 'e', 'a', 't'); +const int32_t Tag::lcar = TAG('l', 'c', 'a', 'r'); +const int32_t Tag::morx = TAG('m', 'o', 'r', 'x'); +const int32_t Tag::opbd = TAG('o', 'p', 'b', 'd'); +const int32_t Tag::prop = TAG('p', 'r', 'o', 'p'); +const int32_t Tag::Feat = TAG('F', 'e', 'a', 't'); +const int32_t Tag::Glat = TAG('G', 'l', 'a', 't'); +const int32_t Tag::Gloc = TAG('G', 'l', 'o', 'c'); +const int32_t Tag::Sile = TAG('S', 'i', 'l', 'e'); +const int32_t Tag::Silf = TAG('S', 'i', 'l', 'f'); +const int32_t Tag::bhed = TAG('b', 'h', 'e', 'd'); +const int32_t Tag::bdat = TAG('b', 'd', 'a', 't'); +const int32_t Tag::bloc = TAG('b', 'l', 'o', 'c'); + +const int32_t CFF_TABLE_ORDERING[] = { + Tag::head, + Tag::hhea, + Tag::maxp, + Tag::OS_2, + Tag::name, + Tag::cmap, + Tag::post, + Tag::CFF }; +const size_t CFF_TABLE_ORDERING_SIZE = + sizeof(CFF_TABLE_ORDERING) / sizeof(int32_t); + +const int32_t TRUE_TYPE_TABLE_ORDERING[] = { + Tag::head, + Tag::hhea, + Tag::maxp, + Tag::OS_2, + Tag::hmtx, + Tag::LTSH, + Tag::VDMX, + Tag::hdmx, + Tag::cmap, + Tag::fpgm, + Tag::prep, + Tag::cvt, + Tag::loca, + Tag::glyf, + Tag::kern, + Tag::name, + Tag::post, + Tag::gasp, + Tag::PCLT, + Tag::DSIG }; +const size_t TRUE_TYPE_TABLE_ORDERING_SIZE = + sizeof(TRUE_TYPE_TABLE_ORDERING) / sizeof(int32_t); + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/tag.h b/src/sfntly/src/sfntly/tag.h new file mode 100644 index 0000000000..0ecbab85b4 --- /dev/null +++ b/src/sfntly/src/sfntly/tag.h @@ -0,0 +1,123 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TAG_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TAG_H_ + +#include + +#include "sfntly/port/type.h" + +namespace sfntly { + +// Font identification tags used for tables, features, etc. +// Tag names are consistent with the OpenType and sfnt specs. +struct Tag { + static const int32_t ttcf; + + // Table Type Tags + // required tables + static const int32_t cmap; + static const int32_t head; + static const int32_t hhea; + static const int32_t hmtx; + static const int32_t maxp; + static const int32_t name; + static const int32_t OS_2; + static const int32_t post; + + // TrueType outline tables + static const int32_t cvt; + static const int32_t fpgm; + static const int32_t glyf; + static const int32_t loca; + static const int32_t prep; + + // PostScript outline tables + static const int32_t CFF; + static const int32_t VORG; + + // opentype bitmap glyph outlines + static const int32_t EBDT; + static const int32_t EBLC; + static const int32_t EBSC; + + // advanced typographic features + static const int32_t BASE; + static const int32_t GDEF; + static const int32_t GPOS; + static const int32_t GSUB; + static const int32_t JSTF; + + // other + static const int32_t DSIG; + static const int32_t gasp; + static const int32_t hdmx; + static const int32_t kern; + static const int32_t LTSH; + static const int32_t PCLT; + static const int32_t VDMX; + static const int32_t vhea; + static const int32_t vmtx; + + // AAT tables + static const int32_t bsln; + static const int32_t feat; + static const int32_t lcar; + static const int32_t morx; + static const int32_t opbd; + static const int32_t prop; + + // Graphite tables + static const int32_t Feat; + static const int32_t Glat; + static const int32_t Gloc; + static const int32_t Sile; + static const int32_t Silf; + + // truetype bitmap font tables + static const int32_t bhed; + static const int32_t bdat; + static const int32_t bloc; +}; + +// Create integer tag value for human readable tag name. +inline int32_t GenerateTag(int32_t a, int32_t b, int32_t c, int32_t d) { + return (a << 24) | (b << 16) | (c << 8) | d; +} + +// Translate tag to human readable string. +// The Caller must delete[] the returned value. +inline char* TagToString(int32_t tag) { + char *name = new char[5]; + name[0] = static_cast((tag & 0xff000000) >> 24); + name[1] = static_cast((tag & 0x00ff0000) >> 16); + name[2] = static_cast((tag & 0x0000ff00) >> 8); + name[3] = static_cast(tag & 0x000000ff); + name[4] = 0; + return name; +} + +// Note: For Java, these two orderings are in Font class. Moved here to avoid +// VC++ bug of not populating correct values. +extern const int32_t CFF_TABLE_ORDERING[]; +extern const size_t CFF_TABLE_ORDERING_SIZE; +extern const int32_t TRUE_TYPE_TABLE_ORDERING[]; +extern const size_t TRUE_TYPE_TABLE_ORDERING_SIZE; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TAG_H_ diff --git a/src/sfntly/src/sfntly/tools/subsetter/glyph_table_subsetter.cc b/src/sfntly/src/sfntly/tools/subsetter/glyph_table_subsetter.cc new file mode 100644 index 0000000000..b3d6b07e44 --- /dev/null +++ b/src/sfntly/src/sfntly/tools/subsetter/glyph_table_subsetter.cc @@ -0,0 +1,90 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/tools/subsetter/glyph_table_subsetter.h" + +#include "sfntly/table/truetype/glyph_table.h" +#include "sfntly/table/truetype/loca_table.h" +#include "sfntly/tag.h" +#include "sfntly/tools/subsetter/subsetter.h" +#include "sfntly/port/exception_type.h" + +namespace sfntly { + +const int32_t kGlyphTableSubsetterTags[2] = {Tag::glyf, Tag::loca}; + +GlyphTableSubsetter::GlyphTableSubsetter() + : TableSubsetterImpl(kGlyphTableSubsetterTags, 2) { +} + +GlyphTableSubsetter::~GlyphTableSubsetter() {} + +bool GlyphTableSubsetter::Subset(Subsetter* subsetter, + Font* font, + Font::Builder* font_builder) { + assert(font); + assert(subsetter); + assert(font_builder); + + IntegerList* permutation_table = subsetter->GlyphPermutationTable(); + if (!permutation_table || permutation_table->empty()) + return false; + + GlyphTablePtr glyph_table = down_cast(font->GetTable(Tag::glyf)); + LocaTablePtr loca_table = down_cast(font->GetTable(Tag::loca)); + if (glyph_table == NULL || loca_table == NULL) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw RuntimeException("Font to subset is not valid."); +#endif + return false; + } + + GlyphTableBuilderPtr glyph_table_builder = + down_cast + (font_builder->NewTableBuilder(Tag::glyf)); + LocaTableBuilderPtr loca_table_builder = + down_cast + (font_builder->NewTableBuilder(Tag::loca)); + if (glyph_table_builder == NULL || loca_table_builder == NULL) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw RuntimeException("Builder for subset is not valid."); +#endif + return false; + } + GlyphTable::GlyphBuilderList* glyph_builders = + glyph_table_builder->GlyphBuilders(); + for (IntegerList::iterator old_glyph_id = permutation_table->begin(), + old_glyph_id_end = permutation_table->end(); + old_glyph_id != old_glyph_id_end; ++old_glyph_id) { + int old_offset = loca_table->GlyphOffset(*old_glyph_id); + int old_length = loca_table->GlyphLength(*old_glyph_id); + GlyphPtr glyph; + glyph.Attach(glyph_table->GetGlyph(old_offset, old_length)); + ReadableFontDataPtr data = glyph->ReadFontData(); + WritableFontDataPtr copy_data; + copy_data.Attach(WritableFontData::CreateWritableFontData(data->Length())); + data->CopyTo(copy_data); + GlyphBuilderPtr glyph_builder; + glyph_builder.Attach(glyph_table_builder->GlyphBuilder(copy_data)); + glyph_builders->push_back(glyph_builder); + } + IntegerList loca_list; + glyph_table_builder->GenerateLocaList(&loca_list); + loca_table_builder->SetLocaList(&loca_list); + return true; +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/tools/subsetter/glyph_table_subsetter.h b/src/sfntly/src/sfntly/tools/subsetter/glyph_table_subsetter.h new file mode 100644 index 0000000000..88c704443f --- /dev/null +++ b/src/sfntly/src/sfntly/tools/subsetter/glyph_table_subsetter.h @@ -0,0 +1,37 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_GLYPH_TABLE_SUBSETTER_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_GLYPH_TABLE_SUBSETTER_H_ + +#include "sfntly/tools/subsetter/table_subsetter_impl.h" + +namespace sfntly { + +class GlyphTableSubsetter : public TableSubsetterImpl, + public RefCounted { + public: + GlyphTableSubsetter(); + virtual ~GlyphTableSubsetter(); + + virtual bool Subset(Subsetter* subsetter, + Font* font, + Font::Builder* font_builder); +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_GLYPH_TABLE_SUBSETTER_H_ diff --git a/src/sfntly/src/sfntly/tools/subsetter/subsetter.cc b/src/sfntly/src/sfntly/tools/subsetter/subsetter.cc new file mode 100644 index 0000000000..7d987796b9 --- /dev/null +++ b/src/sfntly/src/sfntly/tools/subsetter/subsetter.cc @@ -0,0 +1,102 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/tools/subsetter/subsetter.h" + +#include +#include + +#include "sfntly/tools/subsetter/glyph_table_subsetter.h" + +namespace sfntly { + +Subsetter::Subsetter(Font* font, FontFactory* font_factory) { + font_ = font; + font_factory_ = font_factory; + TableSubsetterPtr subsetter = new GlyphTableSubsetter(); + // TODO(arthurhsu): IMPLEMENT: CMap table subsetter + table_subsetters_.push_back(subsetter); +} + +Subsetter::~Subsetter() { + font_factory_.Release(); + font_.Release(); + table_subsetters_.clear(); +} + +void Subsetter::SetGlyphs(IntegerList* glyphs) { + new_to_old_glyphs_ = *glyphs; +} + +void Subsetter::SetCMaps(CMapIdList* cmap_ids, int32_t number) { + UNREFERENCED_PARAMETER(cmap_ids); + UNREFERENCED_PARAMETER(number); + // TODO(arthurhsu): IMPLEMENT +} + +void Subsetter::SetRemoveTables(IntegerSet* remove_tables) { + remove_tables_ = *remove_tables; +} + +CALLER_ATTACH Font::Builder* Subsetter::Subset() { + FontBuilderPtr font_builder; + font_builder.Attach(font_factory_->NewFontBuilder()); + + IntegerSet table_tags; + for (TableMap::const_iterator i = font_->GetTableMap()->begin(), + e = font_->GetTableMap()->end(); i != e; ++i) { + table_tags.insert(i->first); + } + if (!remove_tables_.empty()) { + IntegerSet result; + std::set_difference(table_tags.begin(), table_tags.end(), + remove_tables_.begin(), remove_tables_.end(), + std::inserter(result, result.end())); + table_tags = result; + } + for (TableSubsetterList::iterator + table_subsetter = table_subsetters_.begin(), + table_subsetter_end = table_subsetters_.end(); + table_subsetter != table_subsetter_end; ++table_subsetter) { + bool handled = (*table_subsetter)->Subset(this, font_, font_builder); + if (handled) { + IntegerSet* handled_tags = (*table_subsetter)->TagsHandled(); + IntegerSet result; + std::set_difference(table_tags.begin(), table_tags.end(), + handled_tags->begin(), handled_tags->end(), + std::inserter(result, result.end())); + table_tags = result; + } + } + for (IntegerSet::iterator tag = table_tags.begin(), + tag_end = table_tags.end(); tag != tag_end; ++tag) { + Table* table = font_->GetTable(*tag); + if (table) { + font_builder->NewTableBuilder(*tag, table->ReadFontData()); + } + } + return font_builder.Detach(); +} + +IntegerList* Subsetter::GlyphPermutationTable() { + return &new_to_old_glyphs_; +} + +CMapIdList* Subsetter::CMapId() { + return &cmap_ids_; +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/tools/subsetter/subsetter.h b/src/sfntly/src/sfntly/tools/subsetter/subsetter.h new file mode 100644 index 0000000000..85940a7928 --- /dev/null +++ b/src/sfntly/src/sfntly/tools/subsetter/subsetter.h @@ -0,0 +1,72 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_SUBSETTER_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_SUBSETTER_H_ + +#include + +#include "sfntly/font.h" +#include "sfntly/font_factory.h" +#include "sfntly/table/core/cmap_table.h" +#include "sfntly/tools/subsetter/table_subsetter.h" + +namespace sfntly { + +class Subsetter : public RefCounted { + public: + Subsetter(Font* font, FontFactory* font_factory); + virtual ~Subsetter(); + + virtual void SetGlyphs(IntegerList* glyphs); + + // Set the cmaps to be used in the subsetted font. The cmaps are listed in + // order of priority and the number parameter gives a count of how many of the + // list should be put into the subsetted font. If there are no matches in the + // font for any of the provided cmap ids which would lead to a font with no + // cmap then an error will be thrown during subsetting. + // The two most common cases would be: + // * a list of one or more cmap ids with a count setting of 1 + // This will use the list of cmap ids as an ordered priority and look for + // an available cmap in the font that matches the requests. Only the first + // such match will be placed in the subsetted font. + // * a list of one or more cmap ids with a count setting equal to the list + // length + // This will use the list of cmap ids and try to place each one specified + // into the subsetted font. + // @param cmapIds the cmap ids to use for the subsetted font + // @param number the maximum number of cmaps to place in the subsetted font + virtual void SetCMaps(CMapIdList* cmap_ids, int32_t number); + + virtual void SetRemoveTables(IntegerSet* remove_tables); + virtual CALLER_ATTACH Font::Builder* Subset(); + virtual IntegerList* GlyphPermutationTable(); + virtual CMapIdList* CMapId(); + + private: + FontPtr font_; + FontFactoryPtr font_factory_; + TableSubsetterList table_subsetters_; + + // Settings from user + IntegerSet remove_tables_; + IntegerList new_to_old_glyphs_; + CMapIdList cmap_ids_; +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_SUBSETTER_H_ diff --git a/src/sfntly/src/sfntly/tools/subsetter/table_subsetter.h b/src/sfntly/src/sfntly/tools/subsetter/table_subsetter.h new file mode 100644 index 0000000000..1336615b07 --- /dev/null +++ b/src/sfntly/src/sfntly/tools/subsetter/table_subsetter.h @@ -0,0 +1,39 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_TABLE_SUBSETTER_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_TABLE_SUBSETTER_H_ + +#include + +#include "sfntly/font.h" + +namespace sfntly { + +class Subsetter; +class TableSubsetter : virtual public RefCount { + public: + virtual IntegerSet* TagsHandled() = 0; + virtual bool TagHandled(int32_t tag) = 0; + virtual bool Subset(Subsetter* subsetter, Font* font, + Font::Builder* font_builder) = 0; +}; +typedef Ptr TableSubsetterPtr; +typedef std::vector TableSubsetterList; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_TABLE_SUBSETTER_H_ diff --git a/src/sfntly/src/sfntly/tools/subsetter/table_subsetter_impl.cc b/src/sfntly/src/sfntly/tools/subsetter/table_subsetter_impl.cc new file mode 100644 index 0000000000..f239c78e3c --- /dev/null +++ b/src/sfntly/src/sfntly/tools/subsetter/table_subsetter_impl.cc @@ -0,0 +1,38 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/tools/subsetter/table_subsetter_impl.h" + +namespace sfntly { + +TableSubsetterImpl::TableSubsetterImpl(const int32_t* tags, + size_t tags_length) { + for (size_t i = 0; i < tags_length; ++i) { + tags_.insert(tags[i]); + } +} + +TableSubsetterImpl::~TableSubsetterImpl() {} + +bool TableSubsetterImpl::TagHandled(int32_t tag) { + return tags_.find(tag) != tags_.end(); +} + +IntegerSet* TableSubsetterImpl::TagsHandled() { + return &tags_; +} + +} // namespace sfntly diff --git a/src/sfntly/src/sfntly/tools/subsetter/table_subsetter_impl.h b/src/sfntly/src/sfntly/tools/subsetter/table_subsetter_impl.h new file mode 100644 index 0000000000..de0d9a98ca --- /dev/null +++ b/src/sfntly/src/sfntly/tools/subsetter/table_subsetter_impl.h @@ -0,0 +1,37 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_TABLE_SUBSETTER_IMPL_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_TABLE_SUBSETTER_IMPL_H_ + +#include "sfntly/tools/subsetter/table_subsetter.h" + +namespace sfntly { + +class TableSubsetterImpl : public TableSubsetter { + public: + TableSubsetterImpl(const int32_t* tags, size_t tags_length); + virtual ~TableSubsetterImpl(); + virtual bool TagHandled(int32_t tag); + virtual IntegerSet* TagsHandled(); + + protected: + IntegerSet tags_; +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_TABLE_SUBSETTER_IMPL_H_ From 929ad31af970b7f6b39f3c18d4b0883bfd2f814f Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 30 Oct 2012 11:09:42 +0530 Subject: [PATCH 036/107] ... --- COPYRIGHT | 12 ++++++++++++ session.vim | 1 + 2 files changed, 13 insertions(+) diff --git a/COPYRIGHT b/COPYRIGHT index f6eeffc5cd..1a2c305ad2 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -28,6 +28,12 @@ License: LGPL-2.1+ The full text of the LGPL is distributed as in /usr/share/common-licenses/LGPL-2.1 on Debian systems. +Files: src/calibre/utils/fonts/woff/* +Copyright: Jonathan Kew? +License: LGPL-2.1 + The full text of the LGPL is distributed as in + /usr/share/common-licenses/LGPL-2.1 on Debian systems. + Files: src/calibre/ebooks/hyphenate.py Copyright: Copyright (C) 1990, 2004, 2005 Gerard D.C. Kuiken. License: other @@ -41,6 +47,12 @@ License: Apache 2.0 The full text of the Apache 2.0 license is available at: http://www.apache.org/licenses/LICENSE-2.0 +Files: src/sfntly/* +Copyright: Google Inc. +License: Apache 2.0 + The full text of the Apache 2.0 license is available at: + http://www.apache.org/licenses/LICENSE-2.0 + Files: resources/viewer/mathjax/* Copyright: Unknown License: Apache 2.0 diff --git a/session.vim b/session.vim index 079975f8d4..71c4313365 100644 --- a/session.vim +++ b/session.vim @@ -11,6 +11,7 @@ let g:syntastic_cpp_include_dirs = [ \'/usr/include/freetype2', \'/usr/include/fontconfig', \'src/qtcurve/common', 'src/qtcurve', + \'src/sfntly/src', 'src/sfntly/src/sample', \'/usr/include/ImageMagick', \] let g:syntastic_c_include_dirs = g:syntastic_cpp_include_dirs From d51de87c617ab8666e7b3a070ae88f6c1b7beb34 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 30 Oct 2012 11:33:46 +0530 Subject: [PATCH 037/107] Fixes to sfntly to get it to compile correctly with -fPIC and g++ (remove inline method definitions) --- .../src/sfntly/table/truetype/loca_table.cc | 18 ++++++++++++++++++ .../src/sfntly/table/truetype/loca_table.h | 8 ++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/sfntly/src/sfntly/table/truetype/loca_table.cc b/src/sfntly/src/sfntly/table/truetype/loca_table.cc index c692155da8..793f9a90ff 100644 --- a/src/sfntly/src/sfntly/table/truetype/loca_table.cc +++ b/src/sfntly/src/sfntly/table/truetype/loca_table.cc @@ -47,6 +47,17 @@ int32_t LocaTable::NumLocas() { return num_glyphs_ + 1; } +// Changed by Kovid: The following two methods must not have inline +// definitions, otherwise they give incorrect results when compiled with gcc +// and -fPIC, leading to corrupted font generation. +int32_t LocaTable::num_glyphs() { + return num_glyphs_; +} + +int32_t LocaTable::format_version() { + return format_version_; +} + int32_t LocaTable::Loca(int32_t index) { if (index > num_glyphs_) { #if !defined (SFNTLY_NO_EXCEPTION) @@ -101,6 +112,13 @@ LocaTable::Builder::Builder(Header* header, ReadableFontData* data) LocaTable::Builder::~Builder() {} +// Changed by Kovid: The following two methods must not have inline +// definitions, otherwise they give incorrect results when compiled with gcc +// and -fPIC, leading to corrupted font generation. +int32_t LocaTable::Builder::format_version() { return format_version_; } + +void LocaTable::Builder::set_format_version(int32_t value) { format_version_ = value; } + CALLER_ATTACH LocaTable::Builder* LocaTable::Builder::CreateBuilder(Header* header, WritableFontData* data) { diff --git a/src/sfntly/src/sfntly/table/truetype/loca_table.h b/src/sfntly/src/sfntly/table/truetype/loca_table.h index 67c5749b05..b4e1d3ceab 100644 --- a/src/sfntly/src/sfntly/table/truetype/loca_table.h +++ b/src/sfntly/src/sfntly/table/truetype/loca_table.h @@ -51,8 +51,8 @@ class LocaTable : public Table, public RefCounted { // Get the format version that will be used when the loca table is // generated. // @return the loca table format version - int32_t format_version() { return format_version_; } - void set_format_version(int32_t value) { format_version_ = value; } + int32_t format_version(); + void set_format_version(int32_t value); // Gets the List of locas for loca table builder. These may be manipulated // in any way by the caller and the changes will be reflected in the final @@ -140,8 +140,8 @@ class LocaTable : public Table, public RefCounted { virtual ~LocaTable(); - int32_t format_version() { return format_version_; } - int32_t num_glyphs() { return num_glyphs_; } + int32_t format_version(); + int32_t num_glyphs(); // Return the offset for the given glyph id. Valid glyph ids are from 0 to the // one less than the number of glyphs. The zero entry is the special entry for From d4854e20ecf3bfe967a36261a993c516215fe9f4 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 30 Oct 2012 15:52:32 +0530 Subject: [PATCH 038/107] sfntly working on linux 64bit --- setup/extensions.py | 26 +- setup/sfntly.py | 84 ++++ src/calibre/constants.py | 1 + src/calibre/debug.py | 7 + src/calibre/utils/fonts/sfntly.cpp | 606 +++++++++++++++++++++++++++++ src/calibre/utils/fonts/sfntly.h | 196 ++++++++++ src/calibre/utils/fonts/subset.py | 136 +++++++ 7 files changed, 1054 insertions(+), 2 deletions(-) create mode 100644 setup/sfntly.py create mode 100644 src/calibre/utils/fonts/sfntly.cpp create mode 100644 src/calibre/utils/fonts/sfntly.h create mode 100644 src/calibre/utils/fonts/subset.py diff --git a/setup/extensions.py b/setup/extensions.py index cfbb148873..9a8a6e20a6 100644 --- a/setup/extensions.py +++ b/setup/extensions.py @@ -19,6 +19,7 @@ from setup.build_environment import (chmlib_inc_dirs, magick_libs, chmlib_lib_dirs, sqlite_inc_dirs, icu_inc_dirs, icu_lib_dirs, win_ddk_lib_dirs, ft_libs, ft_lib_dirs, ft_inc_dirs, zlib_libs, zlib_lib_dirs, zlib_inc_dirs) +from setup.sfntly import SfntlyBuilderMixin MT isunix = islinux or isosx or isbsd @@ -48,6 +49,9 @@ class Extension(object): self.optional = kwargs.get('optional', False) self.needs_ddk = kwargs.get('needs_ddk', False) + def preflight(self, obj_dir, compiler, linker, builder, cflags, ldflags): + pass + reflow_sources = glob.glob(os.path.join(SRC, 'calibre', 'ebooks', 'pdf', '*.cpp')) reflow_headers = glob.glob(os.path.join(SRC, 'calibre', 'ebooks', 'pdf', '*.h')) @@ -59,9 +63,26 @@ if isosx: icu_libs = ['icucore'] icu_cflags = ['-DU_DISABLE_RENAMING'] # Needed to use system libicucore.dylib +class SfntlyExtension(Extension, SfntlyBuilderMixin): + + def __init__(self, *args, **kwargs): + Extension.__init__(self, *args, **kwargs) + SfntlyBuilderMixin.__init__(self) + + def preflight(self, *args, **kwargs): + self(*args, **kwargs) extensions = [ + SfntlyExtension('sfntly', + ['calibre/utils/fonts/sfntly.cpp'], + headers= ['calibre/utils/fonts/sfntly.h'], + libraries=icu_libs, + lib_dirs=icu_lib_dirs, + inc_dirs=icu_inc_dirs, + cflags=icu_cflags + ), + Extension('speedup', ['calibre/utils/speedup.c'], ), @@ -363,8 +384,9 @@ class Build(Command): compiler = cxx if ext.needs_cxx else cc linker = msvc.linker if iswindows else compiler objects = [] - einc = self.inc_dirs_to_cflags(ext.inc_dirs) obj_dir = self.j(self.obj_dir, ext.name) + ext.preflight(obj_dir, compiler, linker, self, cflags, ldflags) + einc = self.inc_dirs_to_cflags(ext.inc_dirs) if ext.needs_ddk: ddk_flags = ['-I'+x for x in win_ddk] cflags.extend(ddk_flags) @@ -385,7 +407,7 @@ class Build(Command): dest = self.dest(ext) elib = self.lib_dirs_to_ldflags(ext.lib_dirs) xlib = self.libraries_to_ldflags(ext.libraries) - if self.newer(dest, objects): + if self.newer(dest, objects+ext.extra_objs): print 'Linking', ext.name cmd = [linker] if iswindows: diff --git a/setup/sfntly.py b/setup/sfntly.py new file mode 100644 index 0000000000..60d7808d5f --- /dev/null +++ b/setup/sfntly.py @@ -0,0 +1,84 @@ +#!/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 ' +__docformat__ = 'restructuredtext en' + +import shlex, os +from glob import glob + +from setup import iswindows + +class Group(object): + + def __init__(self, name, base, build_base, cflags): + self.name = name + self.cflags = cflags + self.headers = frozenset(glob(os.path.join(base, '*.h'))) + self.src_files = glob(os.path.join(base, '*.cc')) + self.bdir = os.path.abspath(os.path.join(build_base, name)) + if not os.path.exists(self.bdir): + os.makedirs(self.bdir) + self.objects = [os.path.join(self.bdir, + os.path.basename(x).rpartition('.')[0] + ('.obj' if iswindows else + '.o')) for x in self.src_files] + + def __call__(self, compiler, linker, builder, all_headers): + for src, obj in zip(self.src_files, self.objects): + if builder.newer(obj, [src] + list(all_headers)): + sinc = ['/Tp'+src] if iswindows else ['-c', src] + oinc = ['/Fo'+obj] if iswindows else ['-o', obj] + cmd = [compiler] + self.cflags + sinc + oinc + builder.info(' '.join(cmd)) + builder.check_call(cmd) + +class SfntlyBuilderMixin(object): + + def __init__(self): + self.sfntly_cflags = [ + '-DSFNTLY_NO_EXCEPTION', + '-DSFNTLY_EXPERIMENTAL', + ] + if iswindows: + self.sfntly_cflags += [ + '-D_UNICODE', '-DUNICODE', + ] + shlex.split('/Zi /nologo /W4 /WX /O2 /Ob2 /Oy /GF /Gm- /MT /GS /Gy ' + '/fp:precise /Zc:wchar_t /Zc:forScope /GR-') + else: + self.sfntly_cflags += [ + '-Werror', + '-fno-exceptions', + ] + if len(self.libraries) > 1: + self.libraries = ['icuuc'] + if not iswindows: + self.libraries += ['pthread'] + + def __call__(self, obj_dir, compiler, linker, builder, cflags, ldflags): + self.sfntly_build_dir = os.path.join(obj_dir, 'sfntly') + + groups = [] + all_headers = set() + all_objects = [] + src_dir = self.absolutize([os.path.join('sfntly', 'src')])[0] + inc_dirs = [src_dir] + self.inc_dirs += inc_dirs + inc_flags = builder.inc_dirs_to_cflags(inc_dirs) + for loc in ('', 'port', 'data', 'math', 'table', 'table/bitmap', + 'table/core', 'table/truetype'): + path = os.path.join(src_dir, 'sfntly', *loc.split('/')) + gr = Group(loc, path, self.sfntly_build_dir, cflags+ + inc_flags+self.sfntly_cflags+self.cflags) + groups.append(gr) + all_headers |= gr.headers + all_objects.extend(gr.objects) + + for group in groups: + group(compiler, linker, builder, all_headers) + + self.extra_objs = all_objects + + diff --git a/src/calibre/constants.py b/src/calibre/constants.py index 3c89db2d1a..953749c92b 100644 --- a/src/calibre/constants.py +++ b/src/calibre/constants.py @@ -90,6 +90,7 @@ class Plugins(collections.Mapping): 'speedup', 'freetype', 'woff', + 'sfntly', ] if iswindows: plugins.extend(['winutil', 'wpd', 'winfonts']) diff --git a/src/calibre/debug.py b/src/calibre/debug.py index 22871cab9e..f7fd6f2d72 100644 --- a/src/calibre/debug.py +++ b/src/calibre/debug.py @@ -19,6 +19,8 @@ Run an embedded python interpreter. ''') parser.add_option('-c', '--command', help='Run python code.', default=None) parser.add_option('-e', '--exec-file', default=None, help='Run the python code in file.') + parser.add_option('-f', '--subset-font', default=False, + action='store_true', help='Subset the specified font') parser.add_option('-d', '--debug-device-driver', default=False, action='store_true', help='Debug the specified device driver.') parser.add_option('-g', '--gui', default=False, action='store_true', @@ -209,6 +211,11 @@ def main(args=sys.argv): execfile(ef, g) return + if len(args) > 1 and args[1] in ('-f', '--subset-font'): + from calibre.utils.fonts.subset import main + main(['subset-font']+args[2:]) + return + opts, args = option_parser().parse_args(args) if opts.gui: from calibre.gui2.main import main diff --git a/src/calibre/utils/fonts/sfntly.cpp b/src/calibre/utils/fonts/sfntly.cpp new file mode 100644 index 0000000000..f156611909 --- /dev/null +++ b/src/calibre/utils/fonts/sfntly.cpp @@ -0,0 +1,606 @@ +/* + * sfntly.cpp + * Copyright (C) 2012 Kovid Goyal + * + * Distributed under terms of the GPL3 license. + */ + +#define _UNICODE +#define UNICODE +#define PY_SSIZE_T_CLEAN +#include +#include "sfntly.h" + +#include + +#include +#include + +static PyObject *Error = NULL; +static PyObject *NoGlyphs = NULL; + +// Predicates {{{ +CompositePredicate::CompositePredicate(IntegerSet &chars, IntegerList &ranges) : + chars(chars), ranges(ranges) {} + +CompositePredicate::~CompositePredicate() {} + +bool CompositePredicate::operator()(int32_t character) const { + for (size_t i = 0; i < ranges.size()/2; i++) { + if (ranges[2*i] <= character && character <= ranges[2*i+1]) return true; + } + return chars.count(character) > 0; +} + +// }}} + +// Font Info {{{ + +GlyphId::GlyphId(int32_t glyph_id, FontId font_id) : glyph_id_(glyph_id), font_id_(font_id) {} + +GlyphId::~GlyphId() {} + +bool GlyphId::operator==(const GlyphId& other) const { return glyph_id_ == other.glyph_id(); } + +bool GlyphId::operator<(const GlyphId& other) const { return glyph_id_ < other.glyph_id(); } + +int32_t GlyphId::glyph_id() const { return glyph_id_; } + +void GlyphId::set_glyph_id(const int32_t glyph_id) { glyph_id_ = glyph_id; } + +FontId GlyphId::font_id() const { return font_id_; } + +void GlyphId::set_font_id(const FontId font_id) { font_id_ = font_id; } + +FontInfo::FontInfo() : chars_to_glyph_ids_(new CharacterMap), + resolved_glyph_ids_(new GlyphIdSet), fonts_(new FontIdMap) { } + +FontInfo::FontInfo(CharacterMap* chars_to_glyph_ids, + GlyphIdSet* resolved_glyph_ids, + FontIdMap* fonts) { + chars_to_glyph_ids_ = new CharacterMap(chars_to_glyph_ids->begin(), + chars_to_glyph_ids->end()); + resolved_glyph_ids_ = new GlyphIdSet(resolved_glyph_ids->begin(), + resolved_glyph_ids->end()); + fonts_ = new FontIdMap(fonts->begin(), fonts->end()); +} + +FontInfo::~FontInfo() { + delete chars_to_glyph_ids_; + delete resolved_glyph_ids_; + delete fonts_; +} + +FontDataTable* FontInfo::GetTable(FontId font_id, int32_t tag) { + if (!fonts_) + return NULL; + FontIdMap::iterator it = fonts_->find(font_id); + if (it == fonts_->end()) + return NULL; + return it->second->GetTable(tag); +} + +const TableMap* FontInfo::GetTableMap(FontId font_id) { + if (!fonts_) + return NULL; + FontIdMap::iterator it = fonts_->find(font_id); + if (it == fonts_->end()) + return NULL; + return it->second->GetTableMap(); +} + +CharacterMap* FontInfo::chars_to_glyph_ids() const { return chars_to_glyph_ids_; } + +void FontInfo::set_chars_to_glyph_ids(CharacterMap* chars_to_glyph_ids) { *chars_to_glyph_ids_ = *chars_to_glyph_ids; } + +GlyphIdSet* FontInfo::resolved_glyph_ids() const { return resolved_glyph_ids_; } + +void FontInfo::set_resolved_glyph_ids(GlyphIdSet* resolved_glyph_ids) { *resolved_glyph_ids_ = *resolved_glyph_ids; } + +FontIdMap* FontInfo::fonts() const { return fonts_; } + +void FontInfo::set_fonts(FontIdMap* fonts) { *fonts_ = *fonts; } + +FontSourcedInfoBuilder::FontSourcedInfoBuilder(Font* font, FontId font_id) : font_(font), font_id_(font_id), +predicate_(NULL) { Initialize(); } + +FontSourcedInfoBuilder::FontSourcedInfoBuilder(Font* font, + FontId font_id, + CharacterPredicate* predicate) : + font_(font), font_id_(font_id), predicate_(predicate) { Initialize(); } + +FontSourcedInfoBuilder::~FontSourcedInfoBuilder() { } + +CALLER_ATTACH FontInfo* FontSourcedInfoBuilder::GetFontInfo() { + CharacterMap* chars_to_glyph_ids = new CharacterMap; + bool success = GetCharacterMap(chars_to_glyph_ids); + if (!success) { + delete chars_to_glyph_ids; + PyErr_SetString(Error, "Error creating character map.\n"); + return NULL; + } + GlyphIdSet* resolved_glyph_ids = new GlyphIdSet; + success = ResolveCompositeGlyphs(chars_to_glyph_ids, resolved_glyph_ids); + if (!success) { + delete chars_to_glyph_ids; + delete resolved_glyph_ids; + PyErr_SetString(Error, "Error resolving composite glyphs.\n"); + return NULL; + } + Ptr font_info = new FontInfo; + font_info->set_chars_to_glyph_ids(chars_to_glyph_ids); + font_info->set_resolved_glyph_ids(resolved_glyph_ids); + FontIdMap* font_id_map = new FontIdMap; + font_id_map->insert(std::make_pair(font_id_, font_)); + font_info->set_fonts(font_id_map); + delete chars_to_glyph_ids; + delete resolved_glyph_ids; + delete font_id_map; + return font_info.Detach(); +} + +bool FontSourcedInfoBuilder::GetCharacterMap(CharacterMap* chars_to_glyph_ids) { + if (!cmap_ || !chars_to_glyph_ids) + return false; + chars_to_glyph_ids->clear(); + CMapTable::CMap::CharacterIterator* character_iterator = cmap_->Iterator(); + if (!character_iterator) + return false; + while (character_iterator->HasNext()) { + int32_t character = character_iterator->Next(); + if (!predicate_ || (*predicate_)(character)) { + chars_to_glyph_ids->insert + (std::make_pair(character, + GlyphId(cmap_->GlyphId(character), font_id_))); + } + } + delete character_iterator; + return true; +} + +bool FontSourcedInfoBuilder::ResolveCompositeGlyphs(CharacterMap* chars_to_glyph_ids, + GlyphIdSet* resolved_glyph_ids) { + if (!chars_to_glyph_ids || !resolved_glyph_ids) + return false; + resolved_glyph_ids->clear(); + resolved_glyph_ids->insert(GlyphId(0, font_id_)); + IntegerSet* unresolved_glyph_ids = new IntegerSet; + // Since composite glyph elements might themselves be composite, we would need + // to recursively resolve the elements too. To avoid the recursion we + // create two sets, |unresolved_glyph_ids| for the unresolved glyphs, + // initially containing all the ids and |resolved_glyph_ids|, initially empty. + // We'll remove glyph ids from |unresolved_glyph_ids| until it is empty and, + // if the glyph is composite, add its elements to the unresolved set. + for (CharacterMap::iterator it = chars_to_glyph_ids->begin(), + e = chars_to_glyph_ids->end(); it != e; ++it) { + unresolved_glyph_ids->insert(it->second.glyph_id()); + } + // As long as there are unresolved glyph ids. + while (!unresolved_glyph_ids->empty()) { + // Get the corresponding glyph. + int32_t glyph_id = *(unresolved_glyph_ids->begin()); + unresolved_glyph_ids->erase(unresolved_glyph_ids->begin()); + if (glyph_id < 0 || glyph_id > loca_table_->num_glyphs()) { + continue; + } + int32_t length = loca_table_->GlyphLength(glyph_id); + if (length == 0) { + continue; + } + int32_t offset = loca_table_->GlyphOffset(glyph_id); + GlyphPtr glyph; + glyph.Attach(glyph_table_->GetGlyph(offset, length)); + if (glyph == NULL) { + continue; + } + // Mark the glyph as resolved. + resolved_glyph_ids->insert(GlyphId(glyph_id, font_id_)); + // If it is composite, add all its components to the unresolved glyph set. + if (glyph->GlyphType() == GlyphType::kComposite) { + Ptr composite_glyph = + down_cast(glyph.p_); + int32_t num_glyphs = composite_glyph->NumGlyphs(); + for (int32_t i = 0; i < num_glyphs; ++i) { + int32_t glyph_id = composite_glyph->GlyphIndex(i); + if (resolved_glyph_ids->find(GlyphId(glyph_id, -1)) + == resolved_glyph_ids->end()) { + unresolved_glyph_ids->insert(glyph_id); + } + } + } + } + delete unresolved_glyph_ids; + return true; +} + +void FontSourcedInfoBuilder::Initialize() { + Ptr cmap_table = down_cast(font_->GetTable(Tag::cmap)); + // We prefer Windows BMP format 4 cmaps. + cmap_.Attach(cmap_table->GetCMap(CMapTable::WINDOWS_BMP)); + // But if none is found, + if (!cmap_) { + return; + } + loca_table_ = down_cast(font_->GetTable(Tag::loca)); + glyph_table_ = down_cast(font_->GetTable(Tag::glyf)); +} + + +// }}} + +// Font Assembler {{{ + +FontAssembler::FontAssembler(FontInfo* font_info, IntegerSet* table_blacklist) : + table_blacklist_(table_blacklist) { + font_info_ = font_info; + Initialize(); + } + +FontAssembler::FontAssembler(FontInfo* font_info) : table_blacklist_(NULL) { + font_info_ = font_info; + Initialize(); +} + +FontAssembler::~FontAssembler() { } + +// Assemble a new font from the font info object. +CALLER_ATTACH Font* FontAssembler::Assemble() { + // Assemble tables we can subset. + if (!AssembleCMapTable() || !AssembleGlyphAndLocaTables()) { + return NULL; + } + // For all other tables, either include them unmodified or don't at all. + const TableMap* common_table_map = + font_info_->GetTableMap(font_info_->fonts()->begin()->first); + for (TableMap::const_iterator it = common_table_map->begin(), + e = common_table_map->end(); it != e; ++it) { + if (table_blacklist_ + && table_blacklist_->find(it->first) != table_blacklist_->end()) { + continue; + } + font_builder_->NewTableBuilder(it->first, it->second->ReadFontData()); + } + return font_builder_->Build(); +} + +IntegerSet* FontAssembler::table_blacklist() const { return table_blacklist_; } + +void FontAssembler::set_table_blacklist(IntegerSet* table_blacklist) { + table_blacklist_ = table_blacklist; +} + +bool FontAssembler::AssembleCMapTable() { + // Creating the new CMapTable and the new format 4 CMap + Ptr cmap_table_builder = + down_cast + (font_builder_->NewTableBuilder(Tag::cmap)); + if (!cmap_table_builder) + return false; + Ptr cmap_builder = + down_cast + (cmap_table_builder->NewCMapBuilder(CMapFormat::kFormat4, + CMapTable::WINDOWS_BMP)); + if (!cmap_builder) + return false; + // Creating the segments and the glyph id array + CharacterMap* chars_to_glyph_ids = font_info_->chars_to_glyph_ids(); + SegmentList* segment_list = new SegmentList; + IntegerList* glyph_id_array = new IntegerList; + int32_t last_chararacter = -2; + int32_t last_offset = 0; + Ptr current_segment; + + // For simplicity, we will have one segment per contiguous range. + // To test the algorithm, we've replaced the original CMap with the CMap + // generated by this code without removing any character. + // Tuffy.ttf: CMap went from 3146 to 3972 bytes (1.7% to 2.17% of file) + // AnonymousPro.ttf: CMap went from 1524 to 1900 bytes (0.96% to 1.2%) + for (CharacterMap::iterator it = chars_to_glyph_ids->begin(), + e = chars_to_glyph_ids->end(); it != e; ++it) { + int32_t character = it->first; + int32_t glyph_id = it->second.glyph_id(); + if (character != last_chararacter + 1) { // new segment + if (current_segment != NULL) { + current_segment->set_end_count(last_chararacter); + segment_list->push_back(current_segment); + } + // start_code = character + // end_code = -1 (unknown for now) + // id_delta = 0 (we don't use id_delta for this representation) + // id_range_offset = last_offset (offset into the glyph_id_array) + current_segment = + new CMapTable::CMapFormat4::Builder:: + Segment(character, -1, 0, last_offset); + } + glyph_id_array->push_back(glyph_id); + last_offset += DataSize::kSHORT; + last_chararacter = character; + } + // The last segment is still open. + if (glyph_id_array->size() < 1) { + PyErr_SetString(NoGlyphs, "No glyphs for the specified characters found"); + return false; + } + current_segment->set_end_count(last_chararacter); + segment_list->push_back(current_segment); + // Updating the id_range_offset for every segment. + for (int32_t i = 0, num_segs = segment_list->size(); i < num_segs; ++i) { + Ptr segment = segment_list->at(i); + segment->set_id_range_offset(segment->id_range_offset() + + (num_segs - i + 1) * DataSize::kSHORT); + } + // Adding the final, required segment. + current_segment = + new CMapTable::CMapFormat4::Builder::Segment(0xffff, 0xffff, 1, 0); + segment_list->push_back(current_segment); + // Writing the segments and glyph id array to the CMap + cmap_builder->set_segments(segment_list); + cmap_builder->set_glyph_id_array(glyph_id_array); + delete segment_list; + delete glyph_id_array; + return true; +} + +bool FontAssembler::AssembleGlyphAndLocaTables() { + Ptr loca_table_builder = + down_cast + (font_builder_->NewTableBuilder(Tag::loca)); + Ptr glyph_table_builder = + down_cast + (font_builder_->NewTableBuilder(Tag::glyf)); + + GlyphIdSet* resolved_glyph_ids = font_info_->resolved_glyph_ids(); + IntegerList loca_list; + // Basic sanity check: all LOCA tables are of the same size + // This is necessary but not sufficient! + int32_t previous_size = -1; + for (FontIdMap::iterator it = font_info_->fonts()->begin(); + it != font_info_->fonts()->end(); ++it) { + Ptr loca_table = + down_cast(font_info_->GetTable(it->first, Tag::loca)); + int32_t current_size = loca_table->header_length(); + if (previous_size != -1 && current_size != previous_size) { + return false; + } + previous_size = current_size; + } + + // Assuming all fonts referenced by the FontInfo are the subsets of the same + // font, their loca tables should all have the same sizes. + // We'll just get the size of the first font's LOCA table for simplicty. + Ptr first_loca_table = + down_cast + (font_info_->GetTable(font_info_->fonts()->begin()->first, Tag::loca)); + int32_t num_loca_glyphs = first_loca_table->num_glyphs(); + loca_list.resize(num_loca_glyphs); + loca_list.push_back(0); + int32_t last_glyph_id = 0; + int32_t last_offset = 0; + GlyphTable::GlyphBuilderList* glyph_builders = + glyph_table_builder->GlyphBuilders(); + + for (GlyphIdSet::iterator it = resolved_glyph_ids->begin(), + e = resolved_glyph_ids->end(); it != e; ++it) { + // Get the glyph for this resolved_glyph_id. + int32_t resolved_glyph_id = it->glyph_id(); + int32_t font_id = it->font_id(); + // Get the LOCA table for the current glyph id. + Ptr loca_table = + down_cast + (font_info_->GetTable(font_id, Tag::loca)); + int32_t length = loca_table->GlyphLength(resolved_glyph_id); + int32_t offset = loca_table->GlyphOffset(resolved_glyph_id); + + // Get the GLYF table for the current glyph id. + Ptr glyph_table = + down_cast + (font_info_->GetTable(font_id, Tag::glyf)); + GlyphPtr glyph; + glyph.Attach(glyph_table->GetGlyph(offset, length)); + + // The data reference by the glyph is copied into a new glyph and + // added to the glyph_builders belonging to the glyph_table_builder. + // When Build gets called, all the glyphs will be built. + Ptr data = glyph->ReadFontData(); + Ptr copy_data; + copy_data.Attach(WritableFontData::CreateWritableFontData(data->Length())); + data->CopyTo(copy_data); + GlyphBuilderPtr glyph_builder; + glyph_builder.Attach(glyph_table_builder->GlyphBuilder(copy_data)); + glyph_builders->push_back(glyph_builder); + + // If there are missing glyphs between the last glyph_id and the + // current resolved_glyph_id, since the LOCA table needs to have the same + // size, the offset is kept the same. + for (int32_t i = last_glyph_id + 1; i <= resolved_glyph_id; ++i) + loca_list[i] = last_offset; + last_offset += length; + loca_list[resolved_glyph_id + 1] = last_offset; + last_glyph_id = resolved_glyph_id + 1; + } + // If there are missing glyph ids, their loca entries must all point + // to the same offset as the last valid glyph id making them all zero length. + for (int32_t i = last_glyph_id + 1; i <= num_loca_glyphs; ++i) + loca_list[i] = last_offset; + loca_table_builder->SetLocaList(&loca_list); + return true; +} + +void FontAssembler::Initialize() { + font_factory_.Attach(FontFactory::GetInstance()); + font_builder_.Attach(font_factory_->NewFontBuilder()); +} + + +// }}} + +// Subsetters {{{ +// Subsets a given font using a character predicate. + +PredicateSubsetter::PredicateSubsetter(Font* font, CharacterPredicate* predicate) : font_(font), predicate_(predicate) {} + +PredicateSubsetter::~PredicateSubsetter() { } + +// Performs subsetting returning the subsetted font. +CALLER_ATTACH Font* PredicateSubsetter::Subset() { + Ptr info_builder = + new FontSourcedInfoBuilder(font_, 0, predicate_); + + Ptr font_info; + font_info.Attach(info_builder->GetFontInfo()); + if (!font_info) { + PyErr_SetString(Error, "Could not create font info"); + return NULL; + } + + IntegerSet* table_blacklist = new IntegerSet; + table_blacklist->insert(Tag::DSIG); + Ptr font_assembler = new FontAssembler(font_info, + table_blacklist); + Ptr font_subset; + font_subset.Attach(font_assembler->Assemble()); + delete table_blacklist; + if (!font_subset) { if (!PyErr_Occurred()) PyErr_SetString(Error, "Could not subset font"); } + return font_subset.Detach(); +} + + +// }}} + +static void get_stats(Font *font, PyObject *dict) { + PyObject *t; + const TableMap* tables = font->GetTableMap(); + for (TableMap::const_iterator it = tables->begin(), + e = tables->end(); it != e; ++it) { + t = PyInt_FromLong(it->second->DataLength()); + if (t != NULL) { + PyDict_SetItemString(dict, TagToString(it->first), t); + Py_DECREF(t); + } + } +} + +static PyObject* +do_subset(const char *data, Py_ssize_t sz, Ptr &predicate) { + FontPtr font; + Ptr font_factory; + FontArray fonts; + MemoryInputStream stream; + PyObject *stats, *stats2; + + if (!stream.Attach(reinterpret_cast(data), sz)) + return PyErr_NoMemory(); + font_factory.Attach(FontFactory::GetInstance()); + font_factory->LoadFonts(&stream, &fonts); + if (fonts.empty() || fonts[0] == NULL) { + PyErr_SetString(Error, "Failed to load font from provided data."); + return NULL; + } + + font = fonts[0].Detach(); + if (font->num_tables() == 0) { + PyErr_SetString(Error, "Loaded font has 0 tables."); + return NULL; + } + Ptr subsetter = new PredicateSubsetter(font, predicate); + Ptr new_font; + new_font.Attach(subsetter->Subset()); + if (!new_font) return NULL; + + Ptr ff; + ff.Attach(FontFactory::GetInstance()); + MemoryOutputStream output_stream; + ff->SerializeFont(new_font, &output_stream); + + stats = PyDict_New(); stats2 = PyDict_New(); + if (stats == NULL || stats2 == NULL) return PyErr_NoMemory(); + get_stats(font, stats); + get_stats(new_font, stats2); + return Py_BuildValue("s#NN", (char*)output_stream.Get(), output_stream.Size(), stats, stats2); +} + +static PyObject* +subset(PyObject *self, PyObject *args) { + const char *data; + Py_ssize_t sz; + PyObject *individual_chars, *ranges, *t; + int32_t temp; + + if (!PyArg_ParseTuple(args, "s#OO", &data, &sz, &individual_chars, &ranges)) return NULL; + + if (!PyTuple_Check(individual_chars) || !PyTuple_Check(ranges)) { + PyErr_SetString(PyExc_TypeError, "individual_chars and ranges must be tuples"); + return NULL; + } + + if (PyTuple_Size(ranges) < 1 && PyTuple_Size(individual_chars) < 1) { + PyErr_SetString(NoGlyphs, "No characters specified"); + return NULL; + } + + IntegerSet chars; + for (Py_ssize_t i = 0; i < PyTuple_Size(individual_chars); i++) { + temp = (int32_t)PyInt_AsLong(PyTuple_GET_ITEM(individual_chars, i)); + if (temp == -1 && PyErr_Occurred()) return NULL; + chars.insert(temp); + } + + IntegerList cranges; + cranges.resize(2*PyTuple_Size(ranges)); + for (Py_ssize_t i = 0; i < PyTuple_Size(ranges); i++) { + t = PyTuple_GET_ITEM(ranges, i); + if (!PyTuple_Check(t) || PyTuple_Size(t) != 2) { + PyErr_SetString(PyExc_TypeError, "ranges must contain only 2-tuples"); + return NULL; + } + for (Py_ssize_t j = 0; j < 2; j++) { + cranges[2*i+j] = (int32_t)PyInt_AsLong(PyTuple_GET_ITEM(t, j)); + if (cranges[2*i+j] == -1 && PyErr_Occurred()) return NULL; + } + } + + Ptr predicate = new (std::nothrow) CompositePredicate(chars, cranges); + if (predicate == NULL) return PyErr_NoMemory(); + + try { + return do_subset(data, sz, predicate); + } catch (std::exception &e) { + PyErr_SetString(Error, e.what()); + return NULL; + } catch (...) { + PyErr_SetString(Error, "An unknown exception occurred while subsetting"); + return NULL; + } + +} + +static +PyMethodDef methods[] = { + {"subset", (PyCFunction)subset, METH_VARARGS, + "subset(bytestring, individual_chars, ranges) -> Subset the sfnt in bytestring, keeping only characters specified by individual_chars and ranges. Returns the subset font as a bytestring and the sizes of all font tables in the old and new fonts." + }, + + {NULL, NULL, 0, NULL} +}; + +PyMODINIT_FUNC +initsfntly(void) { + PyObject *m; + + m = Py_InitModule3( + "sfntly", methods, + "Wrapper for the Google sfntly library" + ); + if (m == NULL) return; + + Error = PyErr_NewException((char*)"sfntly.Error", NULL, NULL); + if (Error == NULL) return; + PyModule_AddObject(m, "Error", Error); + + NoGlyphs = PyErr_NewException((char*)"sfntly.NoGlyphs", NULL, NULL); + if (NoGlyphs == NULL) return; + PyModule_AddObject(m, "NoGlyphs", NoGlyphs); +} + + + diff --git a/src/calibre/utils/fonts/sfntly.h b/src/calibre/utils/fonts/sfntly.h new file mode 100644 index 0000000000..8b015d3dd3 --- /dev/null +++ b/src/calibre/utils/fonts/sfntly.h @@ -0,0 +1,196 @@ +/* + * sfntly.h + * Copyright (C) 2012 Kovid Goyal + * + * Distributed under terms of the GPL3 license. + */ +#pragma once + + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace sfntly; + +typedef int32_t FontId; +typedef std::map > FontIdMap; + +class CharacterPredicate : virtual public RefCount { + public: + CharacterPredicate() {} + virtual ~CharacterPredicate() {} + virtual bool operator()(int32_t character) const = 0; +}; + +class CompositePredicate : public CharacterPredicate, + public RefCounted { + public: + CompositePredicate(IntegerSet &chars, IntegerList &ranges); + ~CompositePredicate(); + virtual bool operator()(int32_t character) const; + private: + IntegerSet chars; + IntegerList ranges; +}; + + + +// Glyph id pair that contains the loca table glyph id as well as the +// font id that has the glyph table this glyph belongs to. +class GlyphId { + public: + GlyphId(int32_t glyph_id, FontId font_id); + ~GlyphId(); + + bool operator==(const GlyphId& other) const; + bool operator<(const GlyphId& other) const; + + int32_t glyph_id() const; + void set_glyph_id(const int32_t glyph_id); + FontId font_id() const; + void set_font_id(const FontId font_id); + + private: + int32_t glyph_id_; + FontId font_id_; +}; + +typedef std::map CharacterMap; +typedef std::set GlyphIdSet; + + +// Font information used for FontAssembler in the construction of a new font. +// Will make copies of character map, glyph id set and font id map. +class FontInfo : public RefCounted { + public: + // Empty FontInfo object. + FontInfo(); + + // chars_to_glyph_ids maps characters to GlyphIds for CMap construction + // resolved_glyph_ids defines GlyphIds which should be in the final font + // fonts is a map of font ids to fonts to reference any needed table + FontInfo(CharacterMap* chars_to_glyph_ids, + GlyphIdSet* resolved_glyph_ids, + FontIdMap* fonts); + + virtual ~FontInfo(); + + // Gets the table with the specified tag from the font corresponding to + // font_id or NULL if there is no such font/table. + // font_id is the id of the font that contains the table + // tag identifies the table to be obtained + virtual FontDataTable* GetTable(FontId font_id, int32_t tag); + + // Gets the table map of the font whose id is font_id + virtual const TableMap* GetTableMap(FontId font_id); + + CharacterMap* chars_to_glyph_ids() const; + // Takes ownership of the chars_to_glyph_ids CharacterMap. + void set_chars_to_glyph_ids(CharacterMap* chars_to_glyph_ids); + + GlyphIdSet* resolved_glyph_ids() const; + // Takes ownership of the glyph_ids GlyphIdSet. + void set_resolved_glyph_ids(GlyphIdSet* resolved_glyph_ids); + + FontIdMap* fonts() const; + + // Takes ownership of the fonts FontIdMap. + void set_fonts(FontIdMap* fonts); + + private: + CharacterMap* chars_to_glyph_ids_; + GlyphIdSet* resolved_glyph_ids_; + FontIdMap* fonts_; +}; + + +// FontSourcedInfoBuilder is used to create a FontInfo object from a Font +// optionally specifying a CharacterPredicate to filter out some of +// the font's characters. +// It does not take ownership or copy the values its constructor receives. +class FontSourcedInfoBuilder : + public RefCounted { + public: + FontSourcedInfoBuilder(Font* font, FontId font_id); + + FontSourcedInfoBuilder(Font* font, + FontId font_id, + CharacterPredicate* predicate); + + virtual ~FontSourcedInfoBuilder(); + + virtual CALLER_ATTACH FontInfo* GetFontInfo(); + + protected: + bool GetCharacterMap(CharacterMap* chars_to_glyph_ids); + + bool ResolveCompositeGlyphs(CharacterMap* chars_to_glyph_ids, + GlyphIdSet* resolved_glyph_ids); + + void Initialize(); + + private: + Ptr font_; + FontId font_id_; + CharacterPredicate* predicate_; + + Ptr cmap_; + Ptr loca_table_; + Ptr glyph_table_; + }; + + +// Assembles FontInfo into font builders. +// Does not take ownership of data passed to it. +class FontAssembler : public RefCounted { + public: + // font_info is the FontInfo which will be used for the new font + // table_blacklist is used to decide which tables to exclude from the + // final font. + FontAssembler(FontInfo* font_info, IntegerSet* table_blacklist); + + explicit FontAssembler(FontInfo* font_info); + + ~FontAssembler(); + + // Assemble a new font from the font info object. + virtual CALLER_ATTACH Font* Assemble(); + + IntegerSet* table_blacklist() const; + + void set_table_blacklist(IntegerSet* table_blacklist); + + protected: + virtual bool AssembleCMapTable(); + + virtual bool AssembleGlyphAndLocaTables(); + + virtual void Initialize(); + + private: + Ptr font_info_; + Ptr font_factory_; + Ptr font_builder_; + IntegerSet* table_blacklist_; +}; + +class PredicateSubsetter : public RefCounted { + public: + PredicateSubsetter(Font* font, CharacterPredicate* predicate); + virtual ~PredicateSubsetter(); + + // Performs subsetting returning the subsetted font. + virtual CALLER_ATTACH Font* Subset(); + + private: + Ptr font_; + Ptr predicate_; +}; diff --git a/src/calibre/utils/fonts/subset.py b/src/calibre/utils/fonts/subset.py new file mode 100644 index 0000000000..51b64af6b2 --- /dev/null +++ b/src/calibre/utils/fonts/subset.py @@ -0,0 +1,136 @@ +#!/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 ' +__docformat__ = 'restructuredtext en' + +from future_builtins import map + +class NoGlyphs(ValueError): + pass + +def load_sfntly(): + from calibre.constants import plugins + sfntly, err = plugins['sfntly'] + if err: + raise RuntimeError('Failed to load sfntly: %s'%err) + return sfntly + +def subset(font_data, individual_chars, ranges): + individual = tuple(sorted(map(ord, individual_chars))) + cranges = [] + for s, e in ranges: + sc, ec = map(ord, (s, e)) + if ec <= sc: + raise ValueError('The start character %s is after the end' + ' character %s'%(s, e)) + cranges.append((sc, ec)) + sfntly = load_sfntly() + try: + return sfntly.subset(font_data, individual, tuple(cranges)) + except sfntly.NoGlyphs: + raise NoGlyphs('No glyphs were found in this font for the' + ' specified characters. Subsetting is pointless') + +def option_parser(): + import textwrap + from calibre.utils.config import OptionParser + parser = OptionParser(usage=textwrap.dedent('''\ + %prog [options] input_font_file output_font_file characters_to_keep + + Subset the specified font, keeping only the glyphs for the characters in + characters_to_keep. characters_to_keep is a comma separated list of characters of + the form: a,b,c,A-Z,0-9,xyz + + You can specify ranges in the list of characters, as shown above. + ''')) + parser.add_option('-c', '--codes', default=False, action='store_true', + help='If specified, the list of characters is interpreted as ' + 'numeric unicode codes instead of characters. So to specify the ' + 'characters a,b you would use 97,98') + parser.prog = 'subset-font' + return parser + +def print_stats(old_stats, new_stats): + from calibre import prints + prints('========= Table comparison (original vs. subset) =========') + prints('Table', ' ', '%10s'%'Size', ' ', 'Percent', ' ', '%10s'%'New Size', + ' New Percent') + prints('='*80) + old_total = sum(old_stats.itervalues()) + new_total = sum(new_stats.itervalues()) + tables = sorted(old_stats.iterkeys(), key=lambda x:old_stats[x], + reverse=True) + for table in tables: + osz = old_stats[table] + op = osz/old_total * 100 + nsz = new_stats.get(table, 0) + np = nsz/new_total * 100 + suffix = ' | same size' + if nsz != osz: + suffix = ' | reduced to %.1f %%'%(nsz/osz * 100) + prints('%4s'%table, ' ', '%10s'%osz, ' ', '%5.1f %%'%op, ' ', + '%10s'%nsz, ' ', '%5.1f %%'%np, suffix) + prints('='*80) + +def main(args): + import sys, time + from calibre import prints + parser = option_parser() + opts, args = parser.parse_args(args) + if len(args) < 4 or len(args) > 4: + parser.print_help() + raise SystemExit(1) + iff, off, chars = args[1:] + with open(iff, 'rb') as f: + orig = f.read() + + chars = [x.strip() for x in chars.split(',')] + individual, ranges = set(), set() + + def not_single(c): + if len(c) > 1: + prints(c, 'is not a single character', file=sys.stderr) + raise SystemExit(1) + + for c in chars: + if '-' in c: + parts = [x.strip() for x in c.split('-')] + if len(parts) != 2: + prints('Invalid range:', c, file=sys.stderr) + raise SystemExit(1) + if opts.codes: + parts = tuple(map(unichr, map(int, parts))) + map(not_single, parts) + ranges.add(tuple(parts)) + else: + if opts.codes: + c = unichr(int(c)) + not_single(c) + individual.add(c) + st = time.time() + sf, old_stats, new_stats = subset(orig, individual, ranges) + taken = time.time() - st + reduced = (len(sf)/len(orig)) * 100 + def sz(x): + return '%gKB'%(len(x)/1024.) + print_stats(old_stats, new_stats) + prints('Original size:', sz(orig), 'Subset size:', sz(sf), 'Reduced to: %g%%'%(reduced)) + prints('Subsetting took %g seconds'%taken) + with open(off, 'wb') as f: + f.write(sf) + prints('Subset font written to:', off) + +if __name__ == '__main__': + try: + import init_calibre + init_calibre + except ImportError: + pass + import sys + main(sys.argv) + + From f8d9dead205dc32ab5c8d25ba9eec5928bf2356e Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 30 Oct 2012 16:09:45 +0530 Subject: [PATCH 039/107] Fix mem leak in sfntly --- src/calibre/utils/fonts/sfntly.cpp | 2 +- src/calibre/utils/fonts/subset.py | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/calibre/utils/fonts/sfntly.cpp b/src/calibre/utils/fonts/sfntly.cpp index f156611909..8f74bdddfa 100644 --- a/src/calibre/utils/fonts/sfntly.cpp +++ b/src/calibre/utils/fonts/sfntly.cpp @@ -497,7 +497,7 @@ do_subset(const char *data, Py_ssize_t sz, Ptr &predicate) { return NULL; } - font = fonts[0].Detach(); + font = fonts[0]; if (font->num_tables() == 0) { PyErr_SetString(Error, "Loaded font has 0 tables."); return NULL; diff --git a/src/calibre/utils/fonts/subset.py b/src/calibre/utils/fonts/subset.py index 51b64af6b2..cf4d66193a 100644 --- a/src/calibre/utils/fonts/subset.py +++ b/src/calibre/utils/fonts/subset.py @@ -76,6 +76,21 @@ def print_stats(old_stats, new_stats): '%10s'%nsz, ' ', '%5.1f %%'%np, suffix) prints('='*80) +def test_mem(): + load_sfntly() + from calibre.utils.mem import memory + import gc + gc.collect() + start_mem = memory() + raw = P('fonts/liberation/LiberationSerif-Regular.ttf', data=True) + calls = 1000 + for i in xrange(calls): + subset(raw, (), (('a', 'z'),)) + del raw + for i in xrange(3): gc.collect() + print ('Leaked memory per call:', (memory() - start_mem)/calls*1024, 'KB') + + def main(args): import sys, time from calibre import prints From c3c64c452a9f58d97059baa8f68e95f94f3693af Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 30 Oct 2012 16:29:29 +0530 Subject: [PATCH 040/107] Do not pass obviously invalid data to sfntly (invalid data tends to cause sfntly to segfault) --- src/calibre/utils/fonts/subset.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/calibre/utils/fonts/subset.py b/src/calibre/utils/fonts/subset.py index cf4d66193a..30d0109b30 100644 --- a/src/calibre/utils/fonts/subset.py +++ b/src/calibre/utils/fonts/subset.py @@ -20,6 +20,9 @@ def load_sfntly(): return sfntly def subset(font_data, individual_chars, ranges): + if font_data[:4] not in {b'\x00\x01\x00\x00', b'OTTO', b'true', b'typ1'}: + raise ValueError('Not a supported font file. sfnt_version not recognized: %r'% + font_data[:4]) individual = tuple(sorted(map(ord, individual_chars))) cranges = [] for s, e in ranges: From 8a08e13f7367b9e3fbe5962630ba93513bced255 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 30 Oct 2012 16:30:02 +0530 Subject: [PATCH 041/107] Another fix for compiling with -fPIC --- src/sfntly/src/sfntly/font.cc | 11 +++++++++++ src/sfntly/src/sfntly/font.h | 8 ++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/sfntly/src/sfntly/font.cc b/src/sfntly/src/sfntly/font.cc index 347e0c13e9..f326bccea2 100644 --- a/src/sfntly/src/sfntly/font.cc +++ b/src/sfntly/src/sfntly/font.cc @@ -54,6 +54,17 @@ bool Font::HasTable(int32_t tag) { return (result != end); } +// Changed by Kovid: these four methods cannot be inlined, if they are they +// return incorrect values when compiled with -fPIC +int32_t Font::sfnt_version() { return sfnt_version_; } + +ByteVector* Font::digest() { return &digest_; } + +int64_t Font::checksum() { return checksum_; } + +int32_t Font::num_tables() { return (int32_t)tables_.size(); } + + Table* Font::GetTable(int32_t tag) { if (!HasTable(tag)) { return NULL; diff --git a/src/sfntly/src/sfntly/font.h b/src/sfntly/src/sfntly/font.h index 975e8cc52c..ef8b97f854 100644 --- a/src/sfntly/src/sfntly/font.h +++ b/src/sfntly/src/sfntly/font.h @@ -232,17 +232,17 @@ class Font : public RefCounted { virtual ~Font(); // Gets the sfnt version set in the sfnt wrapper of the font. - int32_t sfnt_version() { return sfnt_version_; } + int32_t sfnt_version(); // Gets a copy of the fonts digest that was created when the font was read. If // no digest was set at creation time then the return result will be null. - ByteVector* digest() { return &digest_; } + ByteVector* digest(); // Get the checksum for this font. - int64_t checksum() { return checksum_; } + int64_t checksum(); // Get the number of tables in this font. - int32_t num_tables() { return (int32_t)tables_.size(); } + int32_t num_tables(); // Whether the font has a particular table. bool HasTable(int32_t tag); From 8cf35971ae333566c68d89c8f8b1a2dfba1f18a4 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 30 Oct 2012 17:30:03 +0530 Subject: [PATCH 042/107] Add build test for sfntly and remove unneccessary compiler flags on windows --- setup/sfntly.py | 9 +++++++-- src/calibre/test_build.py | 6 ++++++ src/calibre/utils/fonts/subset.py | 5 +++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/setup/sfntly.py b/setup/sfntly.py index 60d7808d5f..79a25a53f0 100644 --- a/setup/sfntly.py +++ b/setup/sfntly.py @@ -45,9 +45,9 @@ class SfntlyBuilderMixin(object): if iswindows: self.sfntly_cflags += [ '-D_UNICODE', '-DUNICODE', - ] + shlex.split('/Zi /nologo /W4 /WX /O2 /Ob2 /Oy /GF /Gm- /MT /GS /Gy ' - '/fp:precise /Zc:wchar_t /Zc:forScope /GR-') + ] + shlex.split('/W4 /WX /Gm- /Gy /GR-') else: + # Possibly add -fno-inline (slower, but more robust) self.sfntly_cflags += [ '-Werror', '-fno-exceptions', @@ -59,6 +59,11 @@ class SfntlyBuilderMixin(object): def __call__(self, obj_dir, compiler, linker, builder, cflags, ldflags): self.sfntly_build_dir = os.path.join(obj_dir, 'sfntly') + if '/Ox' in cflags: + cflags.remove('/Ox') + if '-O3' in cflags: + cflags.remove('-O3') + cflags.insert(0, '/O2' if iswindows else '-O2') groups = [] all_headers = set() diff --git a/src/calibre/test_build.py b/src/calibre/test_build.py index d6b3c9a400..2b00d63163 100644 --- a/src/calibre/test_build.py +++ b/src/calibre/test_build.py @@ -37,6 +37,11 @@ def test_freetype(): test() print ('FreeType OK!') +def test_sfntly(): + from calibre.utils.fonts.subset import test + test() + print ('sfntly OK!') + def test_winutil(): from calibre.devices.scanner import win_pnp_drives matches = win_pnp_drives.scanner() @@ -115,6 +120,7 @@ def test(): test_plugins() test_lxml() test_freetype() + test_sfntly() test_sqlite() test_qt() test_imaging() diff --git a/src/calibre/utils/fonts/subset.py b/src/calibre/utils/fonts/subset.py index 30d0109b30..41f0365cdf 100644 --- a/src/calibre/utils/fonts/subset.py +++ b/src/calibre/utils/fonts/subset.py @@ -93,6 +93,11 @@ def test_mem(): for i in xrange(3): gc.collect() print ('Leaked memory per call:', (memory() - start_mem)/calls*1024, 'KB') +def test(): + raw = P('fonts/liberation/LiberationSerif-Regular.ttf', data=True) + sf, old_stats, new_stats = subset(raw, set(('a', 'b', 'c')), ()) + if len(sf) > 0.3 * len(raw): + raise Exception('Subsetting failed') def main(args): import sys, time From 18805c4c689dc9f09d0028ac46669a4674752f7b Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 30 Oct 2012 22:41:15 +0530 Subject: [PATCH 043/107] Dont scan font files in worker processes --- src/calibre/constants.py | 1 + src/calibre/utils/fonts/scanner.py | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/calibre/constants.py b/src/calibre/constants.py index 953749c92b..4ae0005b0d 100644 --- a/src/calibre/constants.py +++ b/src/calibre/constants.py @@ -36,6 +36,7 @@ isunix = isosx or islinux isportable = os.environ.get('CALIBRE_PORTABLE_BUILD', None) is not None ispy3 = sys.version_info.major > 2 isxp = iswindows and sys.getwindowsversion().major < 6 +isworker = os.environ.has_key('CALIBRE_WORKER') or os.environ.has_key('CALIBRE_SIMPLE_WORKER') try: preferred_encoding = locale.getpreferredencoding() diff --git a/src/calibre/utils/fonts/scanner.py b/src/calibre/utils/fonts/scanner.py index e90448726d..f3bfd027cf 100644 --- a/src/calibre/utils/fonts/scanner.py +++ b/src/calibre/utils/fonts/scanner.py @@ -12,7 +12,8 @@ from collections import defaultdict from threading import Thread from calibre import walk, prints, as_unicode -from calibre.constants import config_dir, iswindows, isosx, plugins, DEBUG +from calibre.constants import (config_dir, iswindows, isosx, plugins, DEBUG, + isworker) from calibre.utils.fonts.metadata import FontMetadata, UnsupportedFont from calibre.utils.fonts.utils import panose_to_css_generic_family from calibre.utils.icu import sort_key @@ -150,7 +151,8 @@ class Scanner(Thread): if not hasattr(self, 'cache'): from calibre.utils.config import JSONConfig self.cache = JSONConfig('fonts/scanner_cache') - self.cache.refresh() + else: + self.cache.refresh() if self.cache.get('version', None) != self.CACHE_VERSION: self.cache.clear() self.cached_fonts = self.cache.get('fonts', {}) @@ -162,6 +164,10 @@ class Scanner(Thread): self.reload_cache() num = 0 for folder in self.folders: + if isworker: + # Dont scan font files in worker processes, use whatever is + # cached. + continue if not os.path.isdir(folder): continue try: From 062dbe2bbee71dbedd441b83ed9151368bcfb4dc Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 30 Oct 2012 23:40:26 +0530 Subject: [PATCH 044/107] sfntly: Do not segfault for fonts that dont have loca tables. Also nicer error messages for such fonts. --- src/calibre/utils/fonts/sfntly.cpp | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/calibre/utils/fonts/sfntly.cpp b/src/calibre/utils/fonts/sfntly.cpp index 8f74bdddfa..adbdbd779a 100644 --- a/src/calibre/utils/fonts/sfntly.cpp +++ b/src/calibre/utils/fonts/sfntly.cpp @@ -18,6 +18,7 @@ static PyObject *Error = NULL; static PyObject *NoGlyphs = NULL; +static PyObject *UnsupportedFont = NULL; // Predicates {{{ CompositePredicate::CompositePredicate(IntegerSet &chars, IntegerList &ranges) : @@ -112,11 +113,15 @@ FontSourcedInfoBuilder::FontSourcedInfoBuilder(Font* font, FontSourcedInfoBuilder::~FontSourcedInfoBuilder() { } CALLER_ATTACH FontInfo* FontSourcedInfoBuilder::GetFontInfo() { + if (!cmap_) { + PyErr_SetString(Error, "This font has no cmap table!"); + return NULL; + } CharacterMap* chars_to_glyph_ids = new CharacterMap; bool success = GetCharacterMap(chars_to_glyph_ids); if (!success) { delete chars_to_glyph_ids; - PyErr_SetString(Error, "Error creating character map.\n"); + if (!PyErr_Occurred()) PyErr_SetString(Error, "Error creating character map.\n"); return NULL; } GlyphIdSet* resolved_glyph_ids = new GlyphIdSet; @@ -124,7 +129,7 @@ CALLER_ATTACH FontInfo* FontSourcedInfoBuilder::GetFontInfo() { if (!success) { delete chars_to_glyph_ids; delete resolved_glyph_ids; - PyErr_SetString(Error, "Error resolving composite glyphs.\n"); + if (!PyErr_Occurred()) PyErr_SetString(Error, "Error resolving composite glyphs.\n"); return NULL; } Ptr font_info = new FontInfo; @@ -178,6 +183,10 @@ bool FontSourcedInfoBuilder::ResolveCompositeGlyphs(CharacterMap* chars_to_glyph // As long as there are unresolved glyph ids. while (!unresolved_glyph_ids->empty()) { // Get the corresponding glyph. + if (!loca_table_) { + PyErr_SetString(UnsupportedFont, "This font does not have a loca table. Subsetting is not supported for fonts without loca tables (usually OTF fonts with PostScript (CFF) outlines)."); + return false; + } int32_t glyph_id = *(unresolved_glyph_ids->begin()); unresolved_glyph_ids->erase(unresolved_glyph_ids->begin()); if (glyph_id < 0 || glyph_id > loca_table_->num_glyphs()) { @@ -189,6 +198,10 @@ bool FontSourcedInfoBuilder::ResolveCompositeGlyphs(CharacterMap* chars_to_glyph } int32_t offset = loca_table_->GlyphOffset(glyph_id); GlyphPtr glyph; + if (!glyph_table_) { + PyErr_SetString(UnsupportedFont, "This font does not have a glyf table. Subsetting is not supported for fonts without glyf tables (usually OTF fonts with PostScript (CFF) outlines)."); + return false; + } glyph.Attach(glyph_table_->GetGlyph(offset, length)); if (glyph == NULL) { continue; @@ -449,7 +462,7 @@ CALLER_ATTACH Font* PredicateSubsetter::Subset() { Ptr font_info; font_info.Attach(info_builder->GetFontInfo()); if (!font_info) { - PyErr_SetString(Error, "Could not create font info"); + if (!PyErr_Occurred()) PyErr_SetString(Error, "Could not create font info"); return NULL; } @@ -600,6 +613,10 @@ initsfntly(void) { NoGlyphs = PyErr_NewException((char*)"sfntly.NoGlyphs", NULL, NULL); if (NoGlyphs == NULL) return; PyModule_AddObject(m, "NoGlyphs", NoGlyphs); + + UnsupportedFont = PyErr_NewException((char*)"sfntly.UnsupportedFont", NULL, NULL); + if (UnsupportedFont == NULL) return; + PyModule_AddObject(m, "UnsupportedFont", UnsupportedFont); } From 5efd38eb4b4d8bb5c84eef7437020d91399d5b4a Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 30 Oct 2012 23:41:05 +0530 Subject: [PATCH 045/107] sfntly builds on windows --- setup/extensions.py | 1 + setup/sfntly.py | 8 +++++-- src/calibre/utils/fonts/subset.py | 35 ++++++++++++++++++++++++++++++- 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/setup/extensions.py b/setup/extensions.py index 9a8a6e20a6..ebc258d7bd 100644 --- a/setup/extensions.py +++ b/setup/extensions.py @@ -257,6 +257,7 @@ if isunix: cc = os.environ.get('CC', 'gcc') cxx = os.environ.get('CXX', 'g++') cflags = os.environ.get('OVERRIDE_CFLAGS', + # '-Wall -DNDEBUG -ggdb -fno-strict-aliasing -pipe') '-O3 -Wall -DNDEBUG -fno-strict-aliasing -pipe') cflags = shlex.split(cflags) + ['-fPIC'] ldflags = os.environ.get('OVERRIDE_LDFLAGS', '-Wall') diff --git a/setup/sfntly.py b/setup/sfntly.py index 79a25a53f0..298d0044f0 100644 --- a/setup/sfntly.py +++ b/setup/sfntly.py @@ -46,6 +46,7 @@ class SfntlyBuilderMixin(object): self.sfntly_cflags += [ '-D_UNICODE', '-DUNICODE', ] + shlex.split('/W4 /WX /Gm- /Gy /GR-') + self.cflags += ['-DWIN32'] else: # Possibly add -fno-inline (slower, but more robust) self.sfntly_cflags += [ @@ -63,7 +64,10 @@ class SfntlyBuilderMixin(object): cflags.remove('/Ox') if '-O3' in cflags: cflags.remove('-O3') - cflags.insert(0, '/O2' if iswindows else '-O2') + if '/W3' in cflags: + cflags.remove('/W3') + if '-ggdb' not in cflags: + cflags.insert(0, '/O2' if iswindows else '-O2') groups = [] all_headers = set() @@ -71,7 +75,7 @@ class SfntlyBuilderMixin(object): src_dir = self.absolutize([os.path.join('sfntly', 'src')])[0] inc_dirs = [src_dir] self.inc_dirs += inc_dirs - inc_flags = builder.inc_dirs_to_cflags(inc_dirs) + inc_flags = builder.inc_dirs_to_cflags(self.inc_dirs) for loc in ('', 'port', 'data', 'math', 'table', 'table/bitmap', 'table/core', 'table/truetype'): path = os.path.join(src_dir, 'sfntly', *loc.split('/')) diff --git a/src/calibre/utils/fonts/subset.py b/src/calibre/utils/fonts/subset.py index 41f0365cdf..4fbadee955 100644 --- a/src/calibre/utils/fonts/subset.py +++ b/src/calibre/utils/fonts/subset.py @@ -10,6 +10,12 @@ __docformat__ = 'restructuredtext en' from future_builtins import map class NoGlyphs(ValueError): + 'Raised when the font has no glyphs for the specified characters' + pass + +class UnsupportedFont(ValueError): + 'Raised when the font is not supported for subsetting ' + '(usually an OTF font with PostScript outlines).' pass def load_sfntly(): @@ -19,7 +25,7 @@ def load_sfntly(): raise RuntimeError('Failed to load sfntly: %s'%err) return sfntly -def subset(font_data, individual_chars, ranges): +def subset(font_data, individual_chars, ranges=()): if font_data[:4] not in {b'\x00\x01\x00\x00', b'OTTO', b'true', b'typ1'}: raise ValueError('Not a supported font file. sfnt_version not recognized: %r'% font_data[:4]) @@ -37,6 +43,8 @@ def subset(font_data, individual_chars, ranges): except sfntly.NoGlyphs: raise NoGlyphs('No glyphs were found in this font for the' ' specified characters. Subsetting is pointless') + except sfntly.UnsupportedFont as e: + raise UnsupportedFont(type('')(e)) def option_parser(): import textwrap @@ -99,6 +107,31 @@ def test(): if len(sf) > 0.3 * len(raw): raise Exception('Subsetting failed') +def all(): + from calibre.utils.fonts.scanner import font_scanner + failed = [] + for family in font_scanner.find_font_families(): + for font in font_scanner.fonts_for_family(family): + raw = font_scanner.get_font_data(font) + print ('Subsetting', font['full_name']) + try: + sf, old_stats, new_stats = subset(raw, set(('a', 'b', 'c')), ()) + except (NoGlyphs, UnsupportedFont) as e: + continue + except Exception as e: + print ('Failed!') + failed.append((font['full_name'], font['path'], unicode(e))) + else: + print ('Reduced to:', '%.1f'%( + sum(new_stats.itervalues())/sum(old_stats.itervalues()) + * 100), '%') + if failed: + print ('\n\nFailures:') + for name, path, err in failed: + print (name, path, err) + print() + + def main(args): import sys, time from calibre import prints From 3fd03f45d723473d9f9ddd57cea569ef7790a435 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 30 Oct 2012 23:50:16 +0530 Subject: [PATCH 046/107] Correct error message for fonts with no format 4 cmap tables --- src/calibre/utils/fonts/sfntly.cpp | 7 ++++++- src/calibre/utils/fonts/subset.py | 14 ++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/calibre/utils/fonts/sfntly.cpp b/src/calibre/utils/fonts/sfntly.cpp index adbdbd779a..d8a3b37a60 100644 --- a/src/calibre/utils/fonts/sfntly.cpp +++ b/src/calibre/utils/fonts/sfntly.cpp @@ -114,7 +114,7 @@ FontSourcedInfoBuilder::~FontSourcedInfoBuilder() { } CALLER_ATTACH FontInfo* FontSourcedInfoBuilder::GetFontInfo() { if (!cmap_) { - PyErr_SetString(Error, "This font has no cmap table!"); + PyErr_SetString(UnsupportedFont, "This font has no format 4 cmap table (usually symbol or asian fonts), subsetting is not supported"); return NULL; } CharacterMap* chars_to_glyph_ids = new CharacterMap; @@ -515,6 +515,11 @@ do_subset(const char *data, Py_ssize_t sz, Ptr &predicate) { PyErr_SetString(Error, "Loaded font has 0 tables."); return NULL; } + Ptr cmap_table = down_cast(font->GetTable(Tag::cmap)); + if (!cmap_table) { + PyErr_SetString(Error, "Loaded font has no cmap table."); + return NULL; + } Ptr subsetter = new PredicateSubsetter(font, predicate); Ptr new_font; new_font.Attach(subsetter->Subset()); diff --git a/src/calibre/utils/fonts/subset.py b/src/calibre/utils/fonts/subset.py index 4fbadee955..ffe09475ee 100644 --- a/src/calibre/utils/fonts/subset.py +++ b/src/calibre/utils/fonts/subset.py @@ -110,13 +110,18 @@ def test(): def all(): from calibre.utils.fonts.scanner import font_scanner failed = [] + unsupported = [] for family in font_scanner.find_font_families(): for font in font_scanner.fonts_for_family(family): raw = font_scanner.get_font_data(font) - print ('Subsetting', font['full_name']) + print ('Subsetting', font['full_name'], end='\t') try: sf, old_stats, new_stats = subset(raw, set(('a', 'b', 'c')), ()) - except (NoGlyphs, UnsupportedFont) as e: + except NoGlyphs: + continue + except UnsupportedFont as e: + unsupported.append((font['full_name'], font['path'], unicode(e))) + print ('Unsupported!') continue except Exception as e: print ('Failed!') @@ -125,6 +130,11 @@ def all(): print ('Reduced to:', '%.1f'%( sum(new_stats.itervalues())/sum(old_stats.itervalues()) * 100), '%') + if unsupported: + print ('\n\nUnsupported:') + for name, path, err in unsupported: + print (name, path, err) + print() if failed: print ('\n\nFailures:') for name, path, err in failed: From 609724c65b16747d3c4ea496eb9ed9a5e4fbcbc2 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 31 Oct 2012 08:14:34 +0530 Subject: [PATCH 047/107] ... --- manual/faq.rst | 21 +++++++++++++++++++++ src/calibre/utils/fonts/scanner.py | 9 +++++++++ 2 files changed, 30 insertions(+) diff --git a/manual/faq.rst b/manual/faq.rst index d7d6367f69..d46011d8d8 100644 --- a/manual/faq.rst +++ b/manual/faq.rst @@ -557,6 +557,27 @@ There can be two reasons why |app| is showing a empty list of books: * Your metadata.db file was deleted/corrupted. In this case, you can ask |app| to rebuild the metadata.db from its backups. Right click the |app| icon in the |app| toolbar (it will say 0 books underneath it) and select Library maintenance->Restore database. |app| will automatically rebuild metadata.db. +I am getting errors with my calibre library on a networked drive/NAS? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Do not put your calibre library on a networked drive**. + +A filesystem is a complex beast. Most network filesystems lack various +filesystem features that |app| uses. Some dont support file locking, some dont +support hardlinking, some are just flaky. Additionally, |app| is a single user +application, if you accidentally run two copies of |app| on the same networked +library, bad things will happen. Finally, different OSes impose different +limitations on filesystems, so if you share your networked drive across OSes, +once again, bad things *will happen*. + +Consider using the |app| Content Server to make your books available on other +computers. Run |app| on a single computer and access it via the Content Server +or a Remote Desktop solution. + +If you must share the actual library, use a file syncing tool like +DropBox or rsync or Microsoft SkyDrive instead of a networked drive. Even with +these tools there is danger of data corruption/loss, so only do this if you are +willing to live with that risk. Content From The Web --------------------- diff --git a/src/calibre/utils/fonts/scanner.py b/src/calibre/utils/fonts/scanner.py index f3bfd027cf..ade0b41d8b 100644 --- a/src/calibre/utils/fonts/scanner.py +++ b/src/calibre/utils/fonts/scanner.py @@ -271,6 +271,10 @@ class Scanner(Thread): self.cache['version'] = self.CACHE_VERSION self.cache['fonts'] = self.cached_fonts + def force_rescan(self): + self.cached_fonts = {} + self.write_cache() + def read_font_metadata(self, path, fileid): with lopen(path, 'rb') as f: try: @@ -301,6 +305,11 @@ class Scanner(Thread): font_scanner = Scanner() font_scanner.start() +def force_rescan(): + font_scanner.join() + font_scanner.force_rescan() + font_scanner.run() + if __name__ == '__main__': font_scanner.dump_fonts() From 6b644e1b8797b3f5ae63ee0a8d8398407be24707 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 31 Oct 2012 08:24:39 +0530 Subject: [PATCH 048/107] ... --- src/calibre/utils/fonts/subset.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/calibre/utils/fonts/subset.py b/src/calibre/utils/fonts/subset.py index ffe09475ee..f000f2d608 100644 --- a/src/calibre/utils/fonts/subset.py +++ b/src/calibre/utils/fonts/subset.py @@ -111,10 +111,12 @@ def all(): from calibre.utils.fonts.scanner import font_scanner failed = [] unsupported = [] + total = 0 for family in font_scanner.find_font_families(): for font in font_scanner.fonts_for_family(family): raw = font_scanner.get_font_data(font) print ('Subsetting', font['full_name'], end='\t') + total += 1 try: sf, old_stats, new_stats = subset(raw, set(('a', 'b', 'c')), ()) except NoGlyphs: @@ -141,6 +143,9 @@ def all(): print (name, path, err) print() + print('Total:', total, 'Unsupported:', len(unsupported), 'Failed:', + len(failed)) + def main(args): import sys, time From e7397f60d58d39b0ac2f05f858c9421ff4b58ab0 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 31 Oct 2012 13:33:13 +0530 Subject: [PATCH 049/107] Put fontconfig back in the OS X build since poppler uses it --- setup/installer/osx/app/main.py | 28 +++++++++++++++++++++++----- src/calibre/test_build.py | 2 +- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/setup/installer/osx/app/main.py b/setup/installer/osx/app/main.py index a101c574b7..cf1918abaf 100644 --- a/setup/installer/osx/app/main.py +++ b/setup/installer/osx/app/main.py @@ -15,6 +15,8 @@ from setup import __version__ as VERSION, __appname__ as APPNAME, basenames, \ LICENSE = open('LICENSE', 'rb').read() MAGICK_HOME='@executable_path/../Frameworks/ImageMagick' ENV = dict( + FONTCONFIG_PATH='@executable_path/../Resources/fonts', + FONTCONFIG_FILE='@executable_path/../Resources/fonts/fonts.conf', MAGICK_CONFIGURE_PATH=MAGICK_HOME+'/config', MAGICK_CODER_MODULE_PATH=MAGICK_HOME+'/modules-Q16/coders', MAGICK_CODER_FILTER_PATH=MAGICK_HOME+'/modules-Q16/filter', @@ -178,7 +180,7 @@ class Py2App(object): self.add_poppler() self.add_libjpeg() self.add_libpng() - self.add_freetype() + self.add_fontconfig() self.add_imagemagick() self.add_misc_libraries() @@ -377,7 +379,7 @@ class Py2App(object): @flush def add_poppler(self): info('\nAdding poppler') - for x in ('libpoppler.27.dylib',): + for x in ('libpoppler.28.dylib',): self.install_dylib(os.path.join(SW, 'lib', x)) for x in ('pdftohtml', 'pdftoppm', 'pdfinfo'): self.install_dylib(os.path.join(SW, 'bin', x), False) @@ -395,11 +397,27 @@ class Py2App(object): @flush - def add_freetype(self): - info('\nAdding freetype') - for x in ('freetype.6', 'expat.1'): + def add_fontconfig(self): + info('\nAdding fontconfig') + for x in ('fontconfig.1', 'freetype.6', 'expat.1'): src = os.path.join(SW, 'lib', 'lib'+x+'.dylib') self.install_dylib(src) + dst = os.path.join(self.resources_dir, 'fonts') + if os.path.exists(dst): + shutil.rmtree(dst) + src = os.path.join(SW, 'etc', 'fonts') + shutil.copytree(src, dst, symlinks=False) + fc = os.path.join(dst, 'fonts.conf') + raw = open(fc, 'rb').read() + raw = raw.replace('/usr/share/fonts', '''\ + /Library/Fonts + /System/Library/Fonts + /usr/X11R6/lib/X11/fonts + /usr/share/fonts + /var/root/Library/Fonts + /usr/share/fonts + ''') + open(fc, 'wb').write(raw) @flush def add_imagemagick(self): diff --git a/src/calibre/test_build.py b/src/calibre/test_build.py index 2b00d63163..c80352229e 100644 --- a/src/calibre/test_build.py +++ b/src/calibre/test_build.py @@ -122,11 +122,11 @@ def test(): test_freetype() test_sfntly() test_sqlite() - test_qt() test_imaging() test_unrar() test_icu() test_woff() + test_qt() if iswindows: test_win32() test_winutil() From 9977bafa6799bf949b0b08401e23cd634fdc86f6 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 31 Oct 2012 13:36:10 +0530 Subject: [PATCH 050/107] Do not scan the system for fonts on viewer startup, only on main GUI startup --- src/calibre/gui2/__init__.py | 13 +++++++------ src/calibre/gui2/main.py | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index c1a088bcac..0a725e450a 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -764,7 +764,7 @@ qt_app = None class Application(QApplication): def __init__(self, args, force_calibre_style=False, - override_program_name=None): + override_program_name=None, scan_for_fonts=False): self.file_event_hook = None if override_program_name: args = [override_program_name] + args[1:] @@ -780,7 +780,7 @@ class Application(QApplication): qt_app = self self._file_open_paths = [] self._file_open_lock = RLock() - self.load_builtin_fonts() + self.load_builtin_fonts(scan_for_fonts=scan_for_fonts) self.setup_styles(force_calibre_style) if DEBUG: @@ -793,11 +793,12 @@ class Application(QApplication): self.redirect_notify = True return ret - def load_builtin_fonts(self): + def load_builtin_fonts(self, scan_for_fonts=False): global _rating_font - from calibre.utils.fonts.scanner import font_scanner - # Start scanning the users computer for fonts - font_scanner + if scan_for_fonts: + from calibre.utils.fonts.scanner import font_scanner + # Start scanning the users computer for fonts + font_scanner # Load the builtin fonts and any fonts added to calibre by the user to # Qt diff --git a/src/calibre/gui2/main.py b/src/calibre/gui2/main.py index 0b4a755679..f2b09b3a79 100644 --- a/src/calibre/gui2/main.py +++ b/src/calibre/gui2/main.py @@ -95,7 +95,7 @@ def init_qt(args): QCoreApplication.setOrganizationName(ORG_NAME) QCoreApplication.setApplicationName(APP_UID) override = 'calibre-gui' if islinux else None - app = Application(args, override_program_name=override) + app = Application(args, override_program_name=override, scan_for_fonts=True) actions = tuple(Main.create_application_menubar()) app.setWindowIcon(QIcon(I('lt.png'))) return app, opts, args, actions From d69b24371d4cf8999e728399b0f3bd7d4232dc7f Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 31 Oct 2012 16:48:03 +0530 Subject: [PATCH 051/107] Much faster custom implementation for checking if a font supports some unicode text --- src/calibre/utils/fonts/free_type.py | 36 ++------ src/calibre/utils/fonts/freetype.cpp | 12 +++ src/calibre/utils/fonts/scanner.py | 11 ++- src/calibre/utils/fonts/utils.py | 125 +++++++++++++++++++++++++-- 4 files changed, 143 insertions(+), 41 deletions(-) diff --git a/src/calibre/utils/fonts/free_type.py b/src/calibre/utils/fonts/free_type.py index 6be782dc79..980bff0f7c 100644 --- a/src/calibre/utils/fonts/free_type.py +++ b/src/calibre/utils/fonts/free_type.py @@ -7,7 +7,7 @@ __license__ = 'GPL v3' __copyright__ = '2012, Kovid Goyal ' __docformat__ = 'restructuredtext en' -import threading, unicodedata +import threading from functools import wraps from future_builtins import map @@ -20,10 +20,6 @@ class ThreadingViolation(Exception): 'You cannot use the MTP driver from a thread other than the ' ' thread in which startup() was called') -def get_printable_characters(text): - return u''.join(x for x in unicodedata.normalize('NFC', text) - if unicodedata.category(x)[0] not in {'C', 'Z', 'M'}) - def same_thread(func): @wraps(func) def check_thread(self, *args, **kwargs): @@ -55,10 +51,18 @@ class Face(object): if not isinstance(text, unicode): raise TypeError('%r is not a unicode object'%text) if has_non_printable_chars: + from calibre.utils.fonts.utils import get_printable_characters text = get_printable_characters(text) chars = tuple(frozenset(map(ord, text))) return self.face.supports_text(chars) + @same_thread + def glyph_ids(self, text): + if not isinstance(text, unicode): + raise TypeError('%r is not a unicode object'%text) + for char in text: + yield self.face.glyph_id(ord(char)) + class FreeType(object): def __init__(self): @@ -73,26 +77,4 @@ class FreeType(object): def load_font(self, data): return Face(self.ft.load_font(data)) -def test(): - data = P('fonts/calibreSymbols.otf', data=True) - ft = FreeType() - font = ft.load_font(data) - if not font.supports_text('.\u2605★'): - raise RuntimeError('Incorrectly returning that text is not supported') - if font.supports_text('abc'): - raise RuntimeError('Incorrectly claiming that text is supported') - -def test_find_font(): - from calibre.utils.fonts.scanner import font_scanner - abcd = '诶比西迪' - family = font_scanner.find_font_for_text(abcd)[0] - print ('Family for Chinese text:', family) - family = font_scanner.find_font_for_text(abcd)[0] - abcd = 'لوحة المفاتيح العربية' - print ('Family for Arabic text:', family) - - -if __name__ == '__main__': - test() - test_find_font() diff --git a/src/calibre/utils/fonts/freetype.cpp b/src/calibre/utils/fonts/freetype.cpp index 9086ae0377..58d014c6b9 100644 --- a/src/calibre/utils/fonts/freetype.cpp +++ b/src/calibre/utils/fonts/freetype.cpp @@ -115,6 +115,14 @@ supports_text(Face *self, PyObject *args) { return ret; } +static PyObject* +glyph_id(Face *self, PyObject *args) { + unsigned long code; + + if (!PyArg_ParseTuple(args, "k", &code)) return NULL; + return Py_BuildValue("k", (unsigned long)FT_Get_Char_Index(self->face, (FT_ULong)code)); +} + static PyGetSetDef Face_getsetters[] = { {(char *)"family_name", (getter)family_name, NULL, @@ -134,6 +142,10 @@ static PyMethodDef Face_methods[] = { "supports_text(sequence of unicode character codes) -> Return True iff this font has glyphs for all the specified characters." }, + {"glyph_id", (PyCFunction)glyph_id, METH_VARARGS, + "glyph_id(character code) -> Returns the glyph id for the specified character code." + }, + {NULL} /* Sentinel */ }; diff --git a/src/calibre/utils/fonts/scanner.py b/src/calibre/utils/fonts/scanner.py index ade0b41d8b..564018e062 100644 --- a/src/calibre/utils/fonts/scanner.py +++ b/src/calibre/utils/fonts/scanner.py @@ -15,7 +15,6 @@ from calibre import walk, prints, as_unicode from calibre.constants import (config_dir, iswindows, isosx, plugins, DEBUG, isworker) from calibre.utils.fonts.metadata import FontMetadata, UnsupportedFont -from calibre.utils.fonts.utils import panose_to_css_generic_family from calibre.utils.icu import sort_key class NoFonts(ValueError): @@ -117,17 +116,17 @@ class Scanner(Thread): :return: (family name, faces) or None, None ''' - from calibre.utils.fonts.free_type import FreeType, get_printable_characters - ft = FreeType() - found = {} + from calibre.utils.fonts.utils import (supports_text, + panose_to_css_generic_family, get_printable_characters) if not isinstance(text, unicode): raise TypeError(u'%r is not unicode'%text) text = get_printable_characters(text) + found = {} def filter_faces(font): try: - ftface = ft.load_font(self.get_font_data(font)) - return ftface.supports_text(text, has_non_printable_chars=False) + raw = self.get_font_data(font) + return supports_text(raw, text) except: pass return False diff --git a/src/calibre/utils/fonts/utils.py b/src/calibre/utils/fonts/utils.py index 29b39bbefd..8aeaccc16a 100644 --- a/src/calibre/utils/fonts/utils.py +++ b/src/calibre/utils/fonts/utils.py @@ -14,6 +14,11 @@ from collections import defaultdict class UnsupportedFont(ValueError): pass +def get_printable_characters(text): + import unicodedata + return u''.join(x for x in unicodedata.normalize('NFC', text) + if unicodedata.category(x)[0] not in {'C', 'Z', 'M'}) + def is_truetype_font(raw): sfnt_version = raw[:4] return (sfnt_version in {b'\x00\x01\x00\x00', b'OTTO'}, sfnt_version) @@ -267,16 +272,87 @@ def remove_embed_restriction(raw): verify_checksums(raw) return raw +def get_bmp_glyph_ids(table, bmp, codes): + length, language, segcount = struct.unpack_from(b'>3H', table, bmp+2) + array_len = segcount //2 + offset = bmp + 7*2 + array_sz = 2*array_len + array = b'>%dH'%array_len + end_count = struct.unpack_from(array, table, offset) + offset += array_sz + 2 + start_count = struct.unpack_from(array, table, offset) + offset += array_sz + id_delta = struct.unpack_from(array.replace(b'H', b'h'), table, offset) + offset += array_sz + range_offset = struct.unpack_from(array, table, offset) + if length + bmp < offset + array_sz: + raise ValueError('cmap subtable length is too small') + glyph_id_len = (length + bmp - (offset + array_sz))//2 + glyph_id_map = struct.unpack_from(b'>%dH'%glyph_id_len, table, offset + + array_sz) + + for code in codes: + found = False + for i, ec in enumerate(end_count): + if ec >= code: + sc = start_count[i] + if sc <= code: + found = True + ro = range_offset[i] + if ro == 0: + glyph_id = id_delta[i] + code + else: + idx = ro//2 + (code - sc) + i - array_len + glyph_id = glyph_id_map[idx] + if glyph_id != 0: + glyph_id += id_delta[i] + yield glyph_id % 0x1000 + break + if not found: + yield 0 + +def get_glyph_ids(raw, text, raw_is_table=False): + if not isinstance(text, unicode): + raise TypeError('%r is not a unicode object'%text) + if raw_is_table: + table = raw + else: + table = get_table(raw, 'cmap')[0] + if table is None: + raise UnsupportedFont('Not a supported font, has no cmap table') + version, num_tables = struct.unpack_from(b'>HH', table) + bmp_table = None + for i in xrange(num_tables): + platform_id, encoding_id, offset = struct.unpack_from(b'>HHL', table, + 4 + (i*8)) + if platform_id == 3 and encoding_id == 1: + table_format = struct.unpack_from(b'>H', table, offset)[0] + if table_format == 4: + bmp_table = offset + break + if bmp_table is None: + raise UnsupportedFont('Not a supported font, has no format 4 cmap table') + + for glyph_id in get_bmp_glyph_ids(table, bmp_table, map(ord, text)): + yield glyph_id + +def supports_text(raw, text, has_only_printable_chars=False): + if not isinstance(text, unicode): + raise TypeError('%r is not a unicode object'%text) + if not has_only_printable_chars: + text = get_printable_characters(text) + try: + for glyph_id in get_glyph_ids(raw, text): + if glyph_id == 0: + return False + except: + return False + return True + def get_font_for_text(text, candidate_font_data=None): ok = False if candidate_font_data is not None: - from calibre.utils.fonts.free_type import FreeType, FreeTypeError - ft = FreeType() - try: - font = ft.load_font(candidate_font_data) - ok = font.supports_text(text) - except FreeTypeError: - ok = True + ok = supports_text(candidate_font_data, text) if not ok: from calibre.utils.fonts.scanner import font_scanner family, faces = font_scanner.find_font_for_text(text) @@ -285,7 +361,40 @@ def get_font_for_text(text, candidate_font_data=None): candidate_font_data = f.read() return candidate_font_data +def test_glyph_ids(): + from calibre.utils.fonts.free_type import FreeType + data = P('fonts/liberation/LiberationSerif-Regular.ttf', data=True) + ft = FreeType() + font = ft.load_font(data) + text = u'诶йab' + ft_glyphs = tuple(font.glyph_ids(text)) + glyphs = tuple(get_glyph_ids(data, text)) + if ft_glyphs != glyphs: + raise Exception('My code and FreeType differ on the glyph ids') + +def test_supports_text(): + data = P('fonts/calibreSymbols.otf', data=True) + if not supports_text(data, '.\u2605★'): + raise RuntimeError('Incorrectly returning that text is not supported') + if supports_text(data, 'abc'): + raise RuntimeError('Incorrectly claiming that text is supported') + +def test_find_font(): + from calibre.utils.fonts.scanner import font_scanner + abcd = '诶比西迪' + family = font_scanner.find_font_for_text(abcd)[0] + print ('Family for Chinese text:', family) + family = font_scanner.find_font_for_text(abcd)[0] + abcd = 'لوحة المفاتيح العربية' + print ('Family for Arabic text:', family) + + def test(): + test_glyph_ids() + test_supports_text() + test_find_font() + +def main(): import sys, os for f in sys.argv[1:]: print (os.path.basename(f)) @@ -299,5 +408,5 @@ def test(): if __name__ == '__main__': - test() + main() From e45cc99e98389bf4b03497aa5acf7eb97c0079fe Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 31 Oct 2012 19:29:52 +0530 Subject: [PATCH 052/107] Fix #1073558 (Doesn`t recognize tablet woo) --- src/calibre/devices/android/driver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/devices/android/driver.py b/src/calibre/devices/android/driver.py index 6159d1b065..db318e5df2 100644 --- a/src/calibre/devices/android/driver.py +++ b/src/calibre/devices/android/driver.py @@ -212,7 +212,7 @@ class ANDROID(USBMS): 'VIZIO', 'GOOGLE', 'FREESCAL', 'KOBO_INC', 'LENOVO', 'ROCKCHIP', 'POCKET', 'ONDA_MID', 'ZENITHIN', 'INGENIC', 'PMID701C', 'PD', 'PMP5097C', 'MASS', 'NOVO7', 'ZEKI', 'COBY', 'SXZ', 'USB_2.0', - 'COBY_MID', 'VS', 'AINOL', 'TOPWISE'] + 'COBY_MID', 'VS', 'AINOL', 'TOPWISE', 'PAD703'] WINDOWS_MAIN_MEM = ['ANDROID_PHONE', 'A855', 'A853', 'INC.NEXUS_ONE', '__UMS_COMPOSITE', '_MB200', 'MASS_STORAGE', '_-_CARD', 'SGH-I897', 'GT-I9000', 'FILE-STOR_GADGET', 'SGH-T959_CARD', 'SGH-T959', 'SAMSUNG_ANDROID', From a63397353efe19e49f63c9397069db1e48897a31 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 31 Oct 2012 22:16:56 +0530 Subject: [PATCH 053/107] Do not scan system for fonts in viewer processes and on multiple calibre invocations --- src/calibre/gui2/__init__.py | 3 +-- src/calibre/gui2/main.py | 3 ++- src/calibre/gui2/viewer/main.py | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index 0a725e450a..895bb5a6b2 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -764,7 +764,7 @@ qt_app = None class Application(QApplication): def __init__(self, args, force_calibre_style=False, - override_program_name=None, scan_for_fonts=False): + override_program_name=None): self.file_event_hook = None if override_program_name: args = [override_program_name] + args[1:] @@ -780,7 +780,6 @@ class Application(QApplication): qt_app = self self._file_open_paths = [] self._file_open_lock = RLock() - self.load_builtin_fonts(scan_for_fonts=scan_for_fonts) self.setup_styles(force_calibre_style) if DEBUG: diff --git a/src/calibre/gui2/main.py b/src/calibre/gui2/main.py index f2b09b3a79..7a73f12294 100644 --- a/src/calibre/gui2/main.py +++ b/src/calibre/gui2/main.py @@ -95,7 +95,7 @@ def init_qt(args): QCoreApplication.setOrganizationName(ORG_NAME) QCoreApplication.setApplicationName(APP_UID) override = 'calibre-gui' if islinux else None - app = Application(args, override_program_name=override, scan_for_fonts=True) + app = Application(args, override_program_name=override) actions = tuple(Main.create_application_menubar()) app.setWindowIcon(QIcon(I('lt.png'))) return app, opts, args, actions @@ -291,6 +291,7 @@ def run_in_debug_mode(logpath=None): def run_gui(opts, args, actions, listener, app, gui_debug=None): initialize_file_icon_provider() + app.load_builtin_fonts(scan_for_fonts=True) if not dynamic.get('welcome_wizard_was_run', False): from calibre.gui2.wizard import wizard wizard().exec_() diff --git a/src/calibre/gui2/viewer/main.py b/src/calibre/gui2/viewer/main.py index be332ec207..7b624f170a 100644 --- a/src/calibre/gui2/viewer/main.py +++ b/src/calibre/gui2/viewer/main.py @@ -1137,6 +1137,7 @@ def main(args=sys.argv): if pid <= 0: override = 'calibre-ebook-viewer' if islinux else None app = Application(args, override_program_name=override) + app.load_builtin_fonts() app.setWindowIcon(QIcon(I('viewer.png'))) QApplication.setOrganizationName(ORG_NAME) QApplication.setApplicationName(APP_UID) From 62422b2d797cb89854660da1ed2e57042bdbf2df Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 1 Nov 2012 09:19:59 +0530 Subject: [PATCH 054/107] Kobo driver: When using a SD card do not delete shelves that contain on books on the card (there might be books in the shelf in the main mmeory). Fixes #1073792 (Shelves where being deleted when using an SD Card in Kobo Touch) --- src/calibre/devices/kobo/books.py | 10 +++++-- src/calibre/devices/kobo/driver.py | 43 +++++++++++++++++++++--------- 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/src/calibre/devices/kobo/books.py b/src/calibre/devices/kobo/books.py index ca51d67e1d..43b06185a2 100644 --- a/src/calibre/devices/kobo/books.py +++ b/src/calibre/devices/kobo/books.py @@ -58,7 +58,8 @@ class Book(Book_): self.datetime = time.gmtime() self.contentID = None - self.current_shelves = [] + self.current_shelves = [] + self.kobo_collections = [] if thumbnail_name is not None: self.thumbnail = ImageWrapper(thumbnail_name) @@ -99,6 +100,10 @@ class KTCollectionsBookList(CollectionsBookList): lpath = getattr(book, 'lpath', None) if lpath is None: continue + # If the book is not in the current library, we don't want to use the metadtaa for the collections + if book.application_id is None: +# debug_print("KTCollectionsBookList:get_collections - Book not in current library") + continue # Decide how we will build the collections. The default: leave the # book in all existing collections. Do not add any new ones. attrs = ['device_collections'] @@ -115,7 +120,8 @@ class KTCollectionsBookList(CollectionsBookList): elif prefs['manage_device_metadata'] == 'on_connect': # For existing books, modify the collections only if the user # specified 'on_connect' - attrs += collection_attributes + attrs = collection_attributes + book.device_collections = [] if show_debug: debug_print("KTCollectionsBookList:get_collections - attrs=", attrs) diff --git a/src/calibre/devices/kobo/driver.py b/src/calibre/devices/kobo/driver.py index dcab3026ec..34ddf21ed3 100644 --- a/src/calibre/devices/kobo/driver.py +++ b/src/calibre/devices/kobo/driver.py @@ -33,7 +33,7 @@ class KOBO(USBMS): gui_name = 'Kobo Reader' description = _('Communicate with the Kobo Reader') author = 'Timothy Legge and David Forrester' - version = (2, 0, 2) + version = (2, 0, 3) dbversion = 0 fwversion = 0 @@ -653,6 +653,7 @@ class KOBO(USBMS): @classmethod def book_from_path(cls, prefix, lpath, title, authors, mime, date, ContentType, ImageID): +# debug_print("KOBO:book_from_path - title=%s"%title) from calibre.ebooks.metadata import MetaInformation if cls.settings().read_metadata or cls.MUST_READ_METADATA: @@ -1199,7 +1200,7 @@ class KOBOTOUCH(KOBO): author = 'David Forrester' description = 'Communicate with the Kobo Touch, Glo and Mini firmware. Based on the existing Kobo driver by %s.' % (KOBO.author) - supported_dbversion = 65 + supported_dbversion = 70 min_supported_dbversion = 53 booklist_class = KTCollectionsBookList @@ -1408,9 +1409,14 @@ class KOBOTOUCH(KOBO): debug_print("KoboTouch:update_booklist - have a deleted book") # Label Previews if accessibility == 6: - playlist_map[lpath].append('Preview') + if isdownloaded == 'false': + playlist_map[lpath].append('Recommendation') + else: + playlist_map[lpath].append('Preview') elif accessibility == 4: playlist_map[lpath].append('Recommendation') + + kobo_collections = playlist_map[lpath][:] if len(bookshelves) > 0: playlist_map[lpath].extend(bookshelves) @@ -1428,6 +1434,7 @@ class KOBOTOUCH(KOBO): debug_print('KoboTouch:update_booklist - bl[idx].device_collections=', bl[idx].device_collections) debug_print('KoboTouch:update_booklist - playlist_map=', playlist_map) debug_print('KoboTouch:update_booklist - bookshelves=', bookshelves) + debug_print('KoboTouch:update_booklist - kobo_collections=', kobo_collections) debug_print('KoboTouch:update_booklist - series="%s"' % bl[idx].series) debug_print('KoboTouch:update_booklist - the book=', bl[idx]) debug_print('KoboTouch:update_booklist - the authors=', bl[idx].authors) @@ -1454,8 +1461,9 @@ class KOBOTOUCH(KOBO): if lpath in playlist_map: bl[idx].device_collections = playlist_map.get(lpath,[]) + bl[idx].current_shelves = bookshelves + bl[idx].kobo_collections = kobo_collections changed = True - bl[idx].current_shelves = bookshelves if show_debug: debug_print('KoboTouch:update_booklist - updated bl[idx].device_collections=', bl[idx].device_collections) @@ -1490,10 +1498,12 @@ class KOBOTOUCH(KOBO): debug_print(" the book:", book) debug_print(" author_sort:'%s'"%book.author_sort) debug_print(" bookshelves:", bookshelves) + debug_print(" kobo_collections:", kobo_collections) # print 'Update booklist' book.device_collections = playlist_map.get(lpath,[])# if lpath in playlist_map else [] book.current_shelves = bookshelves + book.kobo_collections = kobo_collections book.contentID = ContentID # debug_print('KoboTouch:update_booklist - title=', title, 'book.device_collections', book.device_collections) @@ -1630,7 +1640,8 @@ class KOBOTOUCH(KOBO): #print "count found in cache: %d, count of files in metadata: %d, need_sync: %s" % \ # (len(bl_cache), len(bl), need_sync) # Bypassing the KOBO sync_booklists as that does things we don't need to do - if need_sync: #self.count_found_in_bl != len(bl) or need_sync: + # Also forcing sync to see if this solves issues with updating shelves and matching books. + if need_sync or True: #self.count_found_in_bl != len(bl) or need_sync: debug_print("KoboTouch:books - about to sync_booklists") if oncard == 'cardb': USBMS.sync_booklists(self, (None, None, bl)) @@ -1948,7 +1959,6 @@ class KOBOTOUCH(KOBO): debug_print("Booklists=", booklists) if self.dbversion < 53: self.reset_readstatus(connection, oncard) - self.remove_from_bookshelves(connection, oncard) if self.dbversion >= 14: debug_print("No Collections - reseting FavouritesIndex") self.reset_favouritesindex(connection, oncard) @@ -1961,6 +1971,7 @@ class KOBOTOUCH(KOBO): if book.application_id is not None: # debug_print("KoboTouch:update_device_database_collections - about to remove a book from shelves book.title=%s" % book.title) self.remove_book_from_device_bookshelves(connection, book) + book.device_collections.extend(book.kobo_collections) if not prefs['manage_device_metadata'] == 'manual' and delete_empty_shelves: debug_print("KoboTouch:update_device_database_collections - about to clear empty bookshelves") self.delete_empty_bookshelves(connection) @@ -2096,7 +2107,7 @@ class KOBOTOUCH(KOBO): def remove_book_from_device_bookshelves(self, connection, book): show_debug = self.is_debugging_title(book.title)# or True - remove_shelf_list = set(book.current_shelves) - set(book.device_collections)# - set(["Im_Reading", "Read", "Closed"]) + remove_shelf_list = set(book.current_shelves) - set(book.device_collections) if show_debug: debug_print('KoboTouch:remove_book_from_device_bookshelves - book.application_id="%s"'%book.application_id) @@ -2212,11 +2223,8 @@ class KOBOTOUCH(KOBO): debug_print('KoboTouch:check_for_bookshelf bookshelf_name="%s"'%bookshelf_name) test_query = 'SELECT InternalName, Name, _IsDeleted FROM Shelf WHERE Name = ?' test_values = (bookshelf_name, ) - addquery = 'INSERT INTO "main"."Shelf"'\ - ' ("CreationDate","InternalName","LastModified","Name","_IsDeleted","_IsVisible","_IsSynced")'\ - ' VALUES (?, ?, ?, ?, ?, ?, ?)' - add_values = ( - time.strftime(self.TIMESTAMP_STRING, time.gmtime()), + addquery = 'INSERT INTO "main"."Shelf"' + add_values = (time.strftime(self.TIMESTAMP_STRING, time.gmtime()), bookshelf_name, time.strftime(self.TIMESTAMP_STRING, time.gmtime()), bookshelf_name, @@ -2224,6 +2232,17 @@ class KOBOTOUCH(KOBO): "true", "false", ) + if self.dbversion < 64: + addquery += ' ("CreationDate","InternalName","LastModified","Name","_IsDeleted","_IsVisible","_IsSynced")'\ + ' VALUES (?, ?, ?, ?, ?, ?, ?)' + else: + addquery += ' ("CreationDate", "InternalName","LastModified","Name","_IsDeleted","_IsVisible","_IsSynced", "Id")'\ + ' VALUES (?, ?, ?, ?, ?, ?, ?, ?)' + add_values = add_values +(bookshelf_name,) + + if show_debug: + debug_print('KoboTouch:check_for_bookshelf addquery=', addquery) + debug_print('KoboTouch:check_for_bookshelf add_values=', add_values) updatequery = 'UPDATE Shelf SET _IsDeleted = "false" WHERE Name = ?' cursor = connection.cursor() From 3ee82b499599331daea35098234ea34d96dc85f7 Mon Sep 17 00:00:00 2001 From: Translators <> Date: Thu, 1 Nov 2012 04:36:10 +0000 Subject: [PATCH 055/107] Launchpad automatic translations update. --- src/calibre/translations/ar.po | 16 ++++++------ src/calibre/translations/de.po | 45 ++++++++++++++++++++++++++++++---- src/calibre/translations/fr.po | 19 +++++++++++--- src/calibre/translations/ko.po | 28 ++++++++++----------- 4 files changed, 78 insertions(+), 30 deletions(-) diff --git a/src/calibre/translations/ar.po b/src/calibre/translations/ar.po index 94aef7bfc1..254efbc4b7 100644 --- a/src/calibre/translations/ar.po +++ b/src/calibre/translations/ar.po @@ -9,16 +9,16 @@ msgstr "" "Project-Id-Version: iso_639_3\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/calibre\n" "POT-Creation-Date: 2012-10-26 05:12+0000\n" -"PO-Revision-Date: 2012-05-24 09:38+0000\n" -"Last-Translator: abbas \n" +"PO-Revision-Date: 2012-10-31 19:43+0000\n" +"Last-Translator: mourad \n" "Language-Team: awadh alghaamdi \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n % 100 >= " "3 && n % 100 <= 10 ? 3 : n % 100 >= 11 && n % 100 <= 99 ? 4 : 5;\n" -"X-Launchpad-Export-Date: 2012-10-27 04:38+0000\n" -"X-Generator: Launchpad (build 16194)\n" +"X-Launchpad-Export-Date: 2012-11-01 04:35+0000\n" +"X-Generator: Launchpad (build 16218)\n" "X-Poedit-Country: SAUDI ARABIA\n" "Language: ar\n" "X-Poedit-Language: Arabic\n" @@ -64,7 +64,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" -msgstr "لا يفعل شيئًا" +msgstr "" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:59 #: /home/kovid/work/calibre/src/calibre/db/cache.py:106 @@ -235,11 +235,11 @@ msgstr "لا يفعل شيئًا" #: /home/kovid/work/calibre/src/calibre/web/feeds/recipes/collection.py:45 #: /home/kovid/work/calibre/src/calibre/web/feeds/recipes/collection.py:53 msgid "Unknown" -msgstr "غير محدّد" +msgstr "مجهول" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:77 msgid "Base" -msgstr "أساس" +msgstr "قاعدة" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:148 #: /home/kovid/work/calibre/src/calibre/ebooks/html/to_zip.py:81 @@ -272,7 +272,7 @@ msgstr "مولّد الفهرس" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:527 msgid "User Interface Action" -msgstr "واجهة المستخدم" +msgstr "العمليات على واجهة المستخدم" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:561 #: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:20 diff --git a/src/calibre/translations/de.po b/src/calibre/translations/de.po index c937fa38e9..4ca05ba497 100644 --- a/src/calibre/translations/de.po +++ b/src/calibre/translations/de.po @@ -8,15 +8,15 @@ msgstr "" "Project-Id-Version: de\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-10-26 05:12+0000\n" -"PO-Revision-Date: 2012-10-28 20:09+0000\n" +"PO-Revision-Date: 2012-10-31 14:34+0000\n" "Last-Translator: Patrick Haake \n" "Language-Team: American English \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-10-29 04:59+0000\n" -"X-Generator: Launchpad (build 16194)\n" +"X-Launchpad-Export-Date: 2012-11-01 04:35+0000\n" +"X-Generator: Launchpad (build 16218)\n" "X-Poedit-Bookmarks: 3327,-1,-1,-1,-1,-1,-1,-1,-1,-1\n" "Generated-By: pygettext.py 1.5\n" @@ -19412,7 +19412,7 @@ msgstr "Gespeichertes Theme löschen:" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config_ui.py:436 msgid "&Theming" -msgstr "Themes" +msgstr "&Themes" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/dictionary.py:53 msgid "No results found for:" @@ -23883,7 +23883,42 @@ msgid "" "metadata\n" "from books and the import plugin produces a value, than that value will\n" "be used irrespective of the setting of the tweak." -msgstr "♠" +msgstr "" +"The algorithm used to assign a book added to an existing series a series " +"number.\n" +"New series numbers assigned using this tweak are always integer values, " +"except\n" +"if a constant non-integer is specified.\n" +"Possible values are:\n" +"next - First available integer larger than the largest existing number\n" +"first_free - First available integer larger than 0\n" +"next_free - First available integer larger than the smallest existing " +"number\n" +"last_free - First available integer smaller than the largest existing " +"number\n" +"Return largest existing + 1 if no free number is found\n" +"const - Assign the number 1 always\n" +"no_change - Do not change the series index\n" +"a number - Assign that number always. The number is not in quotes. Note " +"that\n" +"0.0 can be used here.\n" +"Examples:\n" +"series_index_auto_increment = 'next'\n" +"series_index_auto_increment = 'next_free'\n" +"series_index_auto_increment = 16.5\n" +"\n" +"Set the use_series_auto_increment_tweak_when_importing tweak to True to\n" +"use the above values when importing/adding books. If this tweak is set to\n" +"False (the default) then the series number will be set to 1 if it is not\n" +"explicitly set to during the import. If set to True, then the\n" +"series index will be set according to the series_index_auto_increment " +"setting.\n" +"Note that the use_series_auto_increment_tweak_when_importing tweak is used\n" +"only when a value is not provided during import. If the importing regular\n" +"expression produces a value for series_index, or if you are reading " +"metadata\n" +"from books and the import plugin produces a value, than that value will\n" +"be used irrespective of the setting of the tweak." #: /home/kovid/work/calibre/resources/default_tweaks.py:44 msgid "Add separator after completing an author name" diff --git a/src/calibre/translations/fr.po b/src/calibre/translations/fr.po index a435e699e4..f11886ab86 100644 --- a/src/calibre/translations/fr.po +++ b/src/calibre/translations/fr.po @@ -8,15 +8,15 @@ msgstr "" "Project-Id-Version: calibre 0.4.22\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-10-26 05:12+0000\n" -"PO-Revision-Date: 2012-10-29 20:09+0000\n" +"PO-Revision-Date: 2012-10-31 20:23+0000\n" "Last-Translator: Arnaud \n" "Language-Team: PCGen\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Launchpad-Export-Date: 2012-10-30 04:43+0000\n" -"X-Generator: Launchpad (build 16206)\n" +"X-Launchpad-Export-Date: 2012-11-01 04:35+0000\n" +"X-Generator: Launchpad (build 16218)\n" "Language: fr\n" "X-Poedit-Bookmarks: 1177,1104,-1,-1,-1,-1,-1,-1,-1,-1\n" "Generated-By: pygettext.py 1.5\n" @@ -24396,6 +24396,19 @@ msgid "" "interface language is used. The setting title_sort_articles is ignored\n" "(present only for legacy reasons)." msgstr "" +"Définit la liste des mots à considérer comme des 'articles' quand les " +"chaînes de tri sur les titres sont construits. Les articles sont différents " +"en fonction de la langue. Par défaut, calibre utilise une combinaison " +"d'articles en anglais, et ce quelque soit la langue utilisée dans " +"l'interface Calibre. En compléments, dans certains contextes où la langue du " +"livre est disponible, la langue de ce livre est alors utilisée. Vous pouvez " +"modifier la liste des articles pour un langage particulier ou ajouter une " +"nouvelle langue en éditant per_language_title_sort_articles. Pour indiquer à " +"calibre d'utiliser une autre langue que celle de l'interface utilisateur, " +"modifiez default_language_for_title_sort. Par exemple, pour l'allemand, " +"modifiez sa valeur à 'deu'. Une valeur nulle signifie que la langue de " +"l'interface utilisateur est utilisée. Le paramètre title_sort_articles est " +"ignoré (présent uniquement pour des raisons historiques." #: /home/kovid/work/calibre/resources/default_tweaks.py:258 msgid "Specify a folder calibre should connect to at startup" diff --git a/src/calibre/translations/ko.po b/src/calibre/translations/ko.po index 27f924c947..b417c3b6dc 100644 --- a/src/calibre/translations/ko.po +++ b/src/calibre/translations/ko.po @@ -8,15 +8,15 @@ msgstr "" "Project-Id-Version: calibre\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-10-26 05:12+0000\n" -"PO-Revision-Date: 2012-05-04 11:13+0000\n" -"Last-Translator: Hyun-ho Noh \n" +"PO-Revision-Date: 2012-10-31 11:49+0000\n" +"Last-Translator: halcyonera \n" "Language-Team: Korean \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Launchpad-Export-Date: 2012-10-27 04:46+0000\n" -"X-Generator: Launchpad (build 16194)\n" +"X-Launchpad-Export-Date: 2012-11-01 04:36+0000\n" +"X-Generator: Launchpad (build 16218)\n" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:56 msgid "Does absolutely nothing" @@ -327,7 +327,7 @@ msgstr "책은 calibre 프로그램이나 연결된 장치에 추가됩니다." #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:780 msgid "Fetch annotations from a connected Kindle (experimental)" -msgstr "" +msgstr "연결된 Kindle로부터 주석을 가져옵니다 (시험중)" #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:785 msgid "Generate a catalog of the books in your calibre library" @@ -363,7 +363,7 @@ msgstr "calibre 저장소에서 책을 하드디스크에 저장합니다." #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:825 msgid "Show book details in a separate popup" -msgstr "" +msgstr "세부 정보를 별개의 팝업창으로 표시합니다" #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:830 msgid "Restart calibre" @@ -390,11 +390,11 @@ msgstr "calibre 사용자 메뉴얼 찾아보기" #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:857 msgid "Customize calibre" -msgstr "" +msgstr "calibre 커스터마이즈" #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:862 msgid "Easily find books similar to the currently selected one" -msgstr "" +msgstr "현재 선택된 것과 유사한 책을 쉽게 찾기" #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:867 msgid "" @@ -403,7 +403,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:873 msgid "Copy books from the devce to your calibre library" -msgstr "" +msgstr "기기에서 calibre 저장소로 책 복사하기" #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:878 msgid "Edit the collections in which books are placed on your device" @@ -411,11 +411,11 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:883 msgid "Copy a book from one calibre library to another" -msgstr "" +msgstr "한 저장소에서 다른 저장소로 책 복사하기" #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:888 msgid "Make small tweaks to epub or htmlz files in your calibre library" -msgstr "" +msgstr "calibre 저장소에 있는 epub 또는 htmlz 파일을 일부 개조하기" #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:893 msgid "" @@ -425,7 +425,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:899 msgid "Choose a random book from your calibre library" -msgstr "" +msgstr "calibre 저장소에서 무작위로 책 선택하기" #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:906 msgid "Search for books from different book sellers" @@ -433,7 +433,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:922 msgid "Get new calibre plugins or update your existing ones" -msgstr "" +msgstr "calibre 플러그인을 새로 설치하거나 기존 플러그인을 업데이트하기" #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:941 msgid "Look and Feel" @@ -470,7 +470,7 @@ msgstr "자신의 서평이나 시평을 Calibre 책 리스트에 첨가 또는 #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:975 msgid "Toolbar" -msgstr "" +msgstr "도구모음" #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:981 msgid "" From f8af6aacdeac1e49b10e5df5df20f3cc8fdea93c Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 1 Nov 2012 12:06:54 +0530 Subject: [PATCH 056/107] E-book viewer: Add the ability to rotate images to the popup image viewer. Fixes #1073513 ([enhancement] possibilty to rotate picture) --- resources/images/rotate-right.png | Bin 0 -> 6095 bytes resources/images/view-image.png | Bin 0 -> 24905 bytes src/calibre/gui2/viewer/documentview.py | 2 +- src/calibre/gui2/viewer/image_popup.py | 14 +++++++++++++- 4 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 resources/images/rotate-right.png create mode 100644 resources/images/view-image.png diff --git a/resources/images/rotate-right.png b/resources/images/rotate-right.png new file mode 100644 index 0000000000000000000000000000000000000000..664eb88f00355f0de99b33a1abb8e152ef1deb70 GIT binary patch literal 6095 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�jRSr>Rz}?B2bb*IarjZ+zpM*na+Y?!W&b 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 M07*qoM6N<$f~P4+xc~qF literal 0 HcmV?d00001 diff --git a/src/calibre/gui2/viewer/documentview.py b/src/calibre/gui2/viewer/documentview.py index 33b36cf6ec..81ee82f2b6 100644 --- a/src/calibre/gui2/viewer/documentview.py +++ b/src/calibre/gui2/viewer/documentview.py @@ -485,7 +485,7 @@ class DocumentView(QWebView): # {{{ self.dictionary_action.triggered.connect(self.lookup) self.addAction(self.dictionary_action) self.image_popup = ImagePopup(self) - self.view_image_action = QAction(_('View &image...'), self) + self.view_image_action = QAction(QIcon(I('view-image.png')), _('View &image...'), self) self.view_image_action.triggered.connect(self.image_popup) self.search_action = QAction(QIcon(I('dictionary.png')), _('&Search for next occurrence'), self) diff --git a/src/calibre/gui2/viewer/image_popup.py b/src/calibre/gui2/viewer/image_popup.py index 67e9831a52..b0842a7d9c 100644 --- a/src/calibre/gui2/viewer/image_popup.py +++ b/src/calibre/gui2/viewer/image_popup.py @@ -8,7 +8,8 @@ __copyright__ = '2012, Kovid Goyal ' __docformat__ = 'restructuredtext en' from PyQt4.Qt import (QDialog, QPixmap, QUrl, QScrollArea, QLabel, QSizePolicy, - QDialogButtonBox, QVBoxLayout, QPalette, QApplication, QSize, QIcon, Qt) + QDialogButtonBox, QVBoxLayout, QPalette, QApplication, QSize, QIcon, + Qt, QTransform) from calibre.gui2 import choose_save_file, gprefs @@ -37,12 +38,15 @@ class ImageView(QDialog): self.zi_button = zi = bb.addButton(_('Zoom &in'), bb.ActionRole) self.zo_button = zo = bb.addButton(_('Zoom &out'), bb.ActionRole) self.save_button = so = bb.addButton(_('&Save as'), bb.ActionRole) + self.rotate_button = ro = bb.addButton(_('&Rotate'), bb.ActionRole) zi.setIcon(QIcon(I('plus.png'))) zo.setIcon(QIcon(I('minus.png'))) so.setIcon(QIcon(I('save.png'))) + ro.setIcon(QIcon(I('rotate-right.png'))) zi.clicked.connect(self.zoom_in) zo.clicked.connect(self.zoom_out) so.clicked.connect(self.save_image) + ro.clicked.connect(self.rotate_image) self.l = l = QVBoxLayout() self.setLayout(l) @@ -76,6 +80,14 @@ class ImageView(QDialog): self.scrollarea.verticalScrollBar()): sb.setValue(int(factor*sb.value()) + ((factor - 1) * sb.pageStep()/2)) + def rotate_image(self): + pm = self.label.pixmap() + t = QTransform() + t.rotate(90) + pm = pm.transformed(t) + self.label.setPixmap(pm) + self.label.adjustSize() + def __call__(self): geom = self.avail_geom self.label.setPixmap(self.current_img) From 765f5030455a9a897d8d1677a40935079a2baeec Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 1 Nov 2012 12:44:35 +0530 Subject: [PATCH 057/107] Ebook viewer image popup: ALlow using the mouse wheel to zoom the image --- src/calibre/gui2/viewer/image_popup.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/calibre/gui2/viewer/image_popup.py b/src/calibre/gui2/viewer/image_popup.py index b0842a7d9c..075143f3c3 100644 --- a/src/calibre/gui2/viewer/image_popup.py +++ b/src/calibre/gui2/viewer/image_popup.py @@ -105,6 +105,14 @@ class ImageView(QDialog): gprefs['viewer_image_popup_geometry'] = bytearray(self.saveGeometry()) return QDialog.done(self, e) + def wheelEvent(self, event): + if event.delta() < -14: + self.zoom_out() + event.accept() + elif event.delta() > 14: + event.accept() + self.zoom_in() + class ImagePopup(object): def __init__(self, parent): @@ -126,3 +134,12 @@ class ImagePopup(object): if not d.isVisible(): self.dialogs.remove(d) +if __name__ == '__main__': + import sys + app = QApplication([]) + p = QPixmap() + p.load(sys.argv[-1]) + u = QUrl.fromLocalFile(sys.argv[-1]) + d = ImageView(None, p, u) + d() + app.exec_() From d6c15c3b5c6fd33252635b835955afc17bb04200 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 1 Nov 2012 23:44:23 +0530 Subject: [PATCH 058/107] Delco Times by Krittika Goyal --- recipes/delco_times.recipe | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 recipes/delco_times.recipe diff --git a/recipes/delco_times.recipe b/recipes/delco_times.recipe new file mode 100644 index 0000000000..6c163bd3e5 --- /dev/null +++ b/recipes/delco_times.recipe @@ -0,0 +1,26 @@ +from calibre.web.feeds.news import BasicNewsRecipe + +class HindustanTimes(BasicNewsRecipe): + title = u'Delcoe Times' + language = 'en' + __author__ = 'Krittika Goyal' + oldest_article = 1 #days + max_articles_per_feed = 25 + #encoding = 'cp1252' + use_embedded_content = False + + no_stylesheets = True + auto_cleanup = True + + + feeds = [ +('News', + 'http://www.delcotimes.com/?rss=news'), +('Sports', + 'http://www.delcotimes.com/?rss=sports'), +('Business', + 'http://business-news.thestreet.com/the-delaware-county-daily-times/rss/109393'), +('Entertainment', + 'http://www.delcotimes.com/?rss=entertainment'), +] + From 9dfe03c86bed274a2e1af7e19efb43c57c6c334a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20D=C5=82ugosz?= Date: Thu, 1 Nov 2012 22:07:18 +0100 Subject: [PATCH 059/107] fix empik plugin --- src/calibre/gui2/store/stores/empik_plugin.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/calibre/gui2/store/stores/empik_plugin.py b/src/calibre/gui2/store/stores/empik_plugin.py index da8ca3fe56..16a7ee13e3 100644 --- a/src/calibre/gui2/store/stores/empik_plugin.py +++ b/src/calibre/gui2/store/stores/empik_plugin.py @@ -25,14 +25,14 @@ class EmpikStore(BasicStoreConfig, StorePlugin): def open(self, parent=None, detail_item=None, external=False): plain_url = 'http://www.empik.com/ebooki' - url = 'https://ssl.afiliant.com/affskrypt,,2f9de2,,11483,,,?u=(' + plain_url + ')' + url = 'https://ssl.afiliant.com/affskrypt,,2f9de2,,23c7f,,,?u=(' + plain_url + ')' detail_url = None if detail_item: - detail_url = 'https://ssl.afiliant.com/affskrypt,,2f9de2,,11483,,,?u=(' + detail_item + ')' + detail_url = 'https://ssl.afiliant.com/affskrypt,,2f9de2,,23c7f,,,?u=(' + detail_item + ')' if external or self.config.get('open_external', False): - open_url(QUrl(url_slash_cleaner(detail_item if detail_item else url))) + open_url(QUrl(url_slash_cleaner(detail_url if detail_url else url))) else: d = WebStoreDialog(self.gui, url, parent, detail_url) d.setWindowTitle(self.name) From b47b53bdba962027973b6b39cebd6b2a4bbc5f1f Mon Sep 17 00:00:00 2001 From: John Schember Date: Thu, 1 Nov 2012 21:01:40 -0400 Subject: [PATCH 060/107] ... --- src/calibre/gui2/store/stores/kobo_plugin.py | 29 +++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/calibre/gui2/store/stores/kobo_plugin.py b/src/calibre/gui2/store/stores/kobo_plugin.py index 0b2fc1c9a1..9489188ba2 100644 --- a/src/calibre/gui2/store/stores/kobo_plugin.py +++ b/src/calibre/gui2/store/stores/kobo_plugin.py @@ -24,20 +24,23 @@ from calibre.gui2.store.web_store_dialog import WebStoreDialog class KoboStore(BasicStoreConfig, StorePlugin): def open(self, parent=None, detail_item=None, external=False): - m_url = 'http://www.dpbolvw.net/' - h_click = 'click-4879827-10762497' - d_click = 'click-4879827-10772898' - # Use Kovid's affiliate id 30% of the time. - if random.randint(1, 10) in (1, 2, 3): - h_click = 'click-4913808-10762497' - d_click = 'click-4913808-10772898' + pub_id = 'sHa5EXvYOwA' + # Use Kovid's affiliate id 30% of the time. + if random.randint(1, 10) in (1, 2, 3): + pub_id = '0dsO3kDu/AU' - url = m_url + h_click - detail_url = None - if detail_item: - detail_url = m_url + d_click + detail_item + murl = 'http://click.linksynergy.com/fs-bin/click?id=%s&offerid=268429.4&type=3&subid=0' % pub_id - if external or self.config.get('open_external', False): + if detail_item: + purl = 'http://click.linksynergy.com/fs-bin/click?id=%s&subid=&offerid=268429.1&type=10&tmpid=9310&RD_PARM1=%s' % urllib.quote_plus(pub_id, detail_item) + url = purl + else: + purl = None + url = murl + + print(url) + + if external or self.config.get('open_external', False): open_url(QUrl(url_slash_cleaner(detail_url if detail_url else url))) else: d = WebStoreDialog(self.gui, url, parent, detail_url) @@ -78,7 +81,7 @@ class KoboStore(BasicStoreConfig, StorePlugin): s.title = title.strip() s.author = author.strip() s.price = price.strip() - s.detail_item = '?url=http://www.kobobooks.com/' + id.strip() + s.detail_item = 'http://www.kobobooks.com/' + id.strip() s.drm = SearchResult.DRM_LOCKED if drm else SearchResult.DRM_UNLOCKED s.formats = 'EPUB' From 3084be061d39d8329ec78d48c9fea4664819c074 Mon Sep 17 00:00:00 2001 From: John Schember Date: Thu, 1 Nov 2012 21:04:06 -0400 Subject: [PATCH 061/107] ... --- src/calibre/gui2/store/stores/kobo_plugin.py | 31 ++++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/calibre/gui2/store/stores/kobo_plugin.py b/src/calibre/gui2/store/stores/kobo_plugin.py index 9489188ba2..f829ea2127 100644 --- a/src/calibre/gui2/store/stores/kobo_plugin.py +++ b/src/calibre/gui2/store/stores/kobo_plugin.py @@ -24,29 +24,28 @@ from calibre.gui2.store.web_store_dialog import WebStoreDialog class KoboStore(BasicStoreConfig, StorePlugin): def open(self, parent=None, detail_item=None, external=False): - pub_id = 'sHa5EXvYOwA' - # Use Kovid's affiliate id 30% of the time. - if random.randint(1, 10) in (1, 2, 3): - pub_id = '0dsO3kDu/AU' + pub_id = 'sHa5EXvYOwA' + # Use Kovid's affiliate id 30% of the time. + if random.randint(1, 10) in (1, 2, 3): + pub_id = '0dsO3kDu/AU' - murl = 'http://click.linksynergy.com/fs-bin/click?id=%s&offerid=268429.4&type=3&subid=0' % pub_id + murl = 'http://click.linksynergy.com/fs-bin/click?id=%s&offerid=268429.4&type=3&subid=0' % pub_id - if detail_item: - purl = 'http://click.linksynergy.com/fs-bin/click?id=%s&subid=&offerid=268429.1&type=10&tmpid=9310&RD_PARM1=%s' % urllib.quote_plus(pub_id, detail_item) - url = purl - else: - purl = None - url = murl + if detail_item: + purl = 'http://click.linksynergy.com/fs-bin/click?id=%s&subid=&offerid=268429.1&type=10&tmpid=9310&RD_PARM1=%s' % urllib.quote_plus(pub_id, detail_item) url = purl + else: + purl = None + url = murl - print(url) + print(url) - if external or self.config.get('open_external', False): + if external or self.config.get('open_external', False): open_url(QUrl(url_slash_cleaner(detail_url if detail_url else url))) else: d = WebStoreDialog(self.gui, url, parent, detail_url) - d.setWindowTitle(self.name) - d.set_tags(self.config.get('tags', '')) - d.exec_() + d.setWindowTitle(self.name) + d.set_tags(self.config.get('tags', '')) + d.exec_() def search(self, query, max_results=10, timeout=60): url = 'http://www.kobobooks.com/search/search.html?q=' + urllib2.quote(query) From d711d273d986c06ae4eb2a76df9b05d57f75fcc7 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 2 Nov 2012 06:49:13 +0530 Subject: [PATCH 062/107] Pravda in english, ittalian and portuguese by DM. Fixes #1074106 (New set of recipes for Pravda) --- recipes/icons/pravda_en.png | Bin 0 -> 538 bytes recipes/icons/pravda_it.png | Bin 0 -> 538 bytes recipes/icons/pravda_por.png | Bin 0 -> 538 bytes recipes/icons/pravda_ru.png | Bin 0 -> 538 bytes recipes/pravda_en.recipe | 53 +++++++++++++++++++++++++++++++++++ recipes/pravda_it.recipe | 52 ++++++++++++++++++++++++++++++++++ recipes/pravda_por.recipe | 51 +++++++++++++++++++++++++++++++++ recipes/pravda_ru.recipe | 50 +++++++++++++++++++++++++++++++++ 8 files changed, 206 insertions(+) create mode 100644 recipes/icons/pravda_en.png create mode 100644 recipes/icons/pravda_it.png create mode 100644 recipes/icons/pravda_por.png create mode 100644 recipes/icons/pravda_ru.png create mode 100644 recipes/pravda_en.recipe create mode 100644 recipes/pravda_it.recipe create mode 100644 recipes/pravda_por.recipe create mode 100644 recipes/pravda_ru.recipe diff --git a/recipes/icons/pravda_en.png b/recipes/icons/pravda_en.png new file mode 100644 index 0000000000000000000000000000000000000000..f91f59c554b0f9cd6e370a04fd4e07910980b8f2 GIT binary patch literal 538 zcmV+#0_FXQP)nzNZIE(JRTV@a$@j5%}3-NksG&-e1YKaIcPaqsv0e1E_1@p}SFA|N5Jk%{Nu z4og7i6Z3bY)8%RDKT(9Pdd_jDkLs%lhLk*~8&b+zbt z?M$%gk&x^Wg~j$q!gf+>t?;exk@vmMz`1>l`9!ye)@l!>2ZA!n;0vYTDR)=NXlHT4 zdnzNZIE(JRTV@a$@j5%}3-NksG&-e1YKaIcPaqsv0e1E_1@p}SFA|N5Jk%{Nu z4og7i6Z3bY)8%RDKT(9Pdd_jDkLs%lhLk*~8&b+zbt z?M$%gk&x^Wg~j$q!gf+>t?;exk@vmMz`1>l`9!ye)@l!>2ZA!n;0vYTDR)=NXlHT4 zdnzNZIE(JRTV@a$@j5%}3-NksG&-e1YKaIcPaqsv0e1E_1@p}SFA|N5Jk%{Nu z4og7i6Z3bY)8%RDKT(9Pdd_jDkLs%lhLk*~8&b+zbt z?M$%gk&x^Wg~j$q!gf+>t?;exk@vmMz`1>l`9!ye)@l!>2ZA!n;0vYTDR)=NXlHT4 zdnzNZIE(JRTV@a$@j5%}3-NksG&-e1YKaIcPaqsv0e1E_1@p}SFA|N5Jk%{Nu z4og7i6Z3bY)8%RDKT(9Pdd_jDkLs%lhLk*~8&b+zbt z?M$%gk&x^Wg~j$q!gf+>t?;exk@vmMz`1>l`9!ye)@l!>2ZA!n;0vYTDR)=NXlHT4 zd Date: Fri, 2 Nov 2012 07:02:38 +0530 Subject: [PATCH 063/107] Kobo driver: Fix a bug that could cause the on device book matching to fail in certain circumstances. Fixes #1072437 (Books in devices are not recognized as 'in library') --- src/calibre/devices/kobo/driver.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/calibre/devices/kobo/driver.py b/src/calibre/devices/kobo/driver.py index 34ddf21ed3..dbc89d071c 100644 --- a/src/calibre/devices/kobo/driver.py +++ b/src/calibre/devices/kobo/driver.py @@ -1440,8 +1440,9 @@ class KOBOTOUCH(KOBO): debug_print('KoboTouch:update_booklist - the authors=', bl[idx].authors) debug_print('KoboTouch:update_booklist - application_id=', bl[idx].application_id) bl_cache[lpath] = None - if bl[idx].title_sort is not None: - bl[idx].title = bl[idx].title_sort + # removed to allow recognizing of ePub with an UUID inside + # if bl[idx].title_sort is not None: + # bl[idx].title = bl[idx].title_sort if ImageID is not None: imagename = self.imagefilename_from_imageID(ImageID) if imagename is not None: From a2f8b3a46b9f9fac88256e361f96b11f61d1650a Mon Sep 17 00:00:00 2001 From: John Schember Date: Thu, 1 Nov 2012 21:34:22 -0400 Subject: [PATCH 064/107] Store: Fix Kobo --- src/calibre/gui2/store/stores/kobo_plugin.py | 26 +++++++++++--------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/calibre/gui2/store/stores/kobo_plugin.py b/src/calibre/gui2/store/stores/kobo_plugin.py index f829ea2127..5a8b5618d5 100644 --- a/src/calibre/gui2/store/stores/kobo_plugin.py +++ b/src/calibre/gui2/store/stores/kobo_plugin.py @@ -7,6 +7,7 @@ __copyright__ = '2011, John Schember ' __docformat__ = 'restructuredtext en' import random +import urllib import urllib2 from contextlib import closing @@ -32,20 +33,19 @@ class KoboStore(BasicStoreConfig, StorePlugin): murl = 'http://click.linksynergy.com/fs-bin/click?id=%s&offerid=268429.4&type=3&subid=0' % pub_id if detail_item: - purl = 'http://click.linksynergy.com/fs-bin/click?id=%s&subid=&offerid=268429.1&type=10&tmpid=9310&RD_PARM1=%s' % urllib.quote_plus(pub_id, detail_item) url = purl + purl = 'http://click.linksynergy.com/link?id=%s&offerid=268429&type=2&murl=%s' % (pub_id, urllib.quote_plus(detail_item)) + url = purl else: purl = None url = murl - print(url) - if external or self.config.get('open_external', False): - open_url(QUrl(url_slash_cleaner(detail_url if detail_url else url))) + open_url(QUrl(url_slash_cleaner(url))) else: - d = WebStoreDialog(self.gui, url, parent, detail_url) - d.setWindowTitle(self.name) - d.set_tags(self.config.get('tags', '')) - d.exec_() + d = WebStoreDialog(self.gui, murl, parent, purl) + d.setWindowTitle(self.name) + d.set_tags(self.config.get('tags', '')) + d.exec_() def search(self, query, max_results=10, timeout=60): url = 'http://www.kobobooks.com/search/search.html?q=' + urllib2.quote(query) @@ -62,15 +62,19 @@ class KoboStore(BasicStoreConfig, StorePlugin): id = ''.join(data.xpath('.//div[@class="SearchImageContainer"]/a[1]/@href')) if not id: continue + try: + id = id.split('?', 1)[0] + except: + continue - price = ''.join(data.xpath('.//span[@class="OurPrice"]/strong/text()')) + price = ''.join(data.xpath('.//span[@class="KV2OurPrice"]/strong/text()')) if not price: price = '$0.00' cover_url = ''.join(data.xpath('.//div[@class="SearchImageContainer"]//img[1]/@src')) - title = ''.join(data.xpath('.//div[@class="SCItemHeader"]/h1/a[1]/text()')) - author = ', '.join(data.xpath('.//div[@class="SCItemSummary"]//span//a/text()')) + title = ''.join(data.xpath('.//div[@class="SCItemHeader"]//a[1]/text()')) + author = ', '.join(data.xpath('.//div[@class="SCItemSummary"]//span[contains(@class, "Author")]//a/text()')) drm = data.xpath('boolean(.//span[@class="SCAvailibilityFormatsText" and not(contains(text(), "DRM-Free"))])') counter -= 1 From 0f02ccc7156d9bad5a684d4d39b589ab61bfe963 Mon Sep 17 00:00:00 2001 From: John Schember Date: Thu, 1 Nov 2012 21:51:26 -0400 Subject: [PATCH 065/107] Store: Fix eharlequin --- .../gui2/store/stores/eharlequin_plugin.py | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/calibre/gui2/store/stores/eharlequin_plugin.py b/src/calibre/gui2/store/stores/eharlequin_plugin.py index daa67e801c..ec85ccf1d3 100644 --- a/src/calibre/gui2/store/stores/eharlequin_plugin.py +++ b/src/calibre/gui2/store/stores/eharlequin_plugin.py @@ -6,7 +6,6 @@ __license__ = 'GPL 3' __copyright__ = '2011, John Schember ' __docformat__ = 'restructuredtext en' -import random import re import urllib2 from contextlib import closing @@ -25,23 +24,12 @@ from calibre.gui2.store.web_store_dialog import WebStoreDialog class EHarlequinStore(BasicStoreConfig, StorePlugin): def open(self, parent=None, detail_item=None, external=False): - m_url = 'http://www.dpbolvw.net/' - h_click = 'click-4879827-534091' - d_click = 'click-4879827-10375439' - # Use Kovid's affiliate id 30% of the time. - if random.randint(1, 10) in (1, 2, 3): - h_click = 'click-4913808-534091' - d_click = 'click-4913808-10375439' - - url = m_url + h_click - detail_url = None - if detail_item: - detail_url = m_url + d_click + detail_item + url = 'http://www.harlequin.com/' if external or self.config.get('open_external', False): - open_url(QUrl(url_slash_cleaner(detail_url if detail_url else url))) + open_url(QUrl(url_slash_cleaner(detail_item if detail_item else url))) else: - d = WebStoreDialog(self.gui, url, parent, detail_url) + d = WebStoreDialog(self.gui, url, parent, detail_item) d.setWindowTitle(self.name) d.set_tags(self.config.get('tags', '')) d.exec_() @@ -74,7 +62,7 @@ class EHarlequinStore(BasicStoreConfig, StorePlugin): s.title = title.strip() s.author = author.strip() s.price = price.strip() - s.detail_item = '?url=http://ebooks.eharlequin.com/' + id.strip() + s.detail_item = 'http://ebooks.eharlequin.com/' + id.strip() s.formats = 'EPUB' yield s From 0d9ea03fd480735de52b93b200012d95cf12e024 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 2 Nov 2012 07:47:39 +0530 Subject: [PATCH 066/107] Fix font scanner not detecting when fonts are removed from the system --- src/calibre/utils/fonts/scanner.py | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/calibre/utils/fonts/scanner.py b/src/calibre/utils/fonts/scanner.py index 564018e062..827e5536d5 100644 --- a/src/calibre/utils/fonts/scanner.py +++ b/src/calibre/utils/fonts/scanner.py @@ -161,12 +161,17 @@ class Scanner(Thread): def do_scan(self): self.reload_cache() - num = 0 + + if isworker: + # Dont scan font files in worker processes, use whatever is + # cached. Font files typically dont change frequently enough to + # justify a rescan in a worker process. + self.build_families() + return + + cached_fonts = self.cached_fonts.copy() + self.cached_fonts.clear() for folder in self.folders: - if isworker: - # Dont scan font files in worker processes, use whatever is - # cached. - continue if not os.path.isdir(folder): continue try: @@ -186,7 +191,10 @@ class Scanner(Thread): except EnvironmentError: continue fileid = '{0}||{1}:{2}'.format(candidate, s.st_size, s.st_mtime) - if fileid in self.cached_fonts: + if fileid in cached_fonts: + # Use previously cached metadata, since the file size and + # last modified timestamp have not changed. + self.cached_fonts[fileid] = cached_fonts[fileid] continue try: self.read_font_metadata(candidate, fileid) @@ -195,12 +203,11 @@ class Scanner(Thread): prints('Failed to read metadata from font file:', candidate, as_unicode(e)) continue - num += 1 - if num >= 10: - num = 0 - self.write_cache() - if num > 0: + + if frozenset(cached_fonts) != frozenset(self.cached_fonts): + # Write out the cache only if some font files have changed self.write_cache() + self.build_families() def font_priority(self, font): From 54cf1ae8005b26f92b91590146d479d01ee72bfb Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 2 Nov 2012 08:14:57 +0530 Subject: [PATCH 067/107] Embedding fonts: Allow adding ttf/otf font files to calibre directly to be used for embedding. That way the fonts do not have to be installed system wide. You can add a font to calibre via the 'Add fonts' button in the font chooser dialog for embedding fonts. --- src/calibre/gui2/font_family_chooser.py | 69 +++++++++++++++++++++---- 1 file changed, 59 insertions(+), 10 deletions(-) diff --git a/src/calibre/gui2/font_family_chooser.py b/src/calibre/gui2/font_family_chooser.py index 93682e3966..72240636c1 100644 --- a/src/calibre/gui2/font_family_chooser.py +++ b/src/calibre/gui2/font_family_chooser.py @@ -7,12 +7,17 @@ __license__ = 'GPL v3' __copyright__ = '2012, Kovid Goyal ' __docformat__ = 'restructuredtext en' +import os, shutil + from PyQt4.Qt import (QFontInfo, QFontMetrics, Qt, QFont, QFontDatabase, QPen, QStyledItemDelegate, QSize, QStyle, QStringListModel, pyqtSignal, QDialog, QVBoxLayout, QApplication, QFontComboBox, QPushButton, QToolButton, QGridLayout, QListView, QWidget, QDialogButtonBox, QIcon, QHBoxLayout, QLabel, QModelIndex) +from calibre.constants import config_dir +from calibre.gui2 import choose_files, error_dialog, info_dialog + def writing_system_for_font(font): has_latin = True systems = QFontDatabase().writingSystems(font.family()) @@ -167,19 +172,12 @@ class FontFamilyDialog(QDialog): self.setWindowIcon(QIcon(I('font.png'))) from calibre.utils.fonts.scanner import font_scanner self.font_scanner = font_scanner - try: - self.families = list(font_scanner.find_font_families()) - except: - self.families = [] - print ('WARNING: Could not load fonts') - import traceback - traceback.print_exc() - self.families.insert(0, _('None')) + self.m = QStringListModel(self) + self.build_font_list() self.l = l = QGridLayout() self.setLayout(l) self.view = FontsView(self) - self.m = QStringListModel(self.families) self.view.setModel(self.m) self.view.setCurrentIndex(self.m.index(0)) if current_family: @@ -194,9 +192,12 @@ class FontFamilyDialog(QDialog): self.bb = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel) self.bb.accepted.connect(self.accept) self.bb.rejected.connect(self.reject) + self.add_fonts_button = afb = self.bb.addButton(_('Add &fonts'), + self.bb.ActionRole) + afb.setIcon(QIcon(I('plus.png'))) + afb.clicked.connect(self.add_fonts) self.ml = QLabel(_('Choose a font family from the list below:')) - l.addWidget(self.ml, 0, 0, 1, 2) l.addWidget(self.view, 1, 0, 1, 1) l.addWidget(self.faces, 1, 1, 1, 1) @@ -205,6 +206,54 @@ class FontFamilyDialog(QDialog): self.resize(800, 600) + def build_font_list(self): + try: + self.families = list(self.font_scanner.find_font_families()) + except: + self.families = [] + print ('WARNING: Could not load fonts') + import traceback + traceback.print_exc() + self.families.insert(0, _('None')) + self.m.setStringList(self.families) + + def add_fonts(self): + from calibre.utils.fonts.metadata import FontMetadata + files = choose_files(self, 'add fonts to calibre', + _('Select font files'), filters=[(_('TrueType/OpenType Fonts'), + ['ttf', 'otf'])], all_files=False) + if not files: return + families = set() + for f in files: + try: + with open(f, 'rb') as stream: + fm = FontMetadata(stream) + except: + import traceback + error_dialog(self, _('Corrupt font'), + _('Failed to read metadata from the font file: %s')% + f, det_msg=traceback.format_exc(), show=True) + return + families.add(fm.font_family) + families = sorted(families) + + dest = os.path.join(config_dir, 'fonts') + for f in files: + shutil.copyfile(f, os.path.join(dest, os.path.basename(f))) + self.font_scanner.do_scan() + self.build_font_list() + self.m.reset() + self.view.setCurrentIndex(self.m.index(0)) + if families: + for i, val in enumerate(self.families): + if icu_lower(val) == icu_lower(families[0]): + self.view.setCurrentIndex(self.m.index(i)) + break + + info_dialog(self, _('Added fonts'), + _('Added font families: %s')%( + ', '.join(families)), show=True) + @property def font_family(self): idx = self.view.currentIndex().row() From 557258570a4082114b7105f6334a4c890ec55309 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 2 Nov 2012 08:38:59 +0530 Subject: [PATCH 068/107] Sharing by email: Allow specifying a 'alias' or friendly name by which to identify each email recipient. Fixes #1069076 ([Enhancement] Email Labels) --- src/calibre/gui2/actions/device.py | 8 +++++--- src/calibre/gui2/preferences/emailp.py | 21 +++++++++++++++++---- src/calibre/utils/smtp.py | 1 + 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/calibre/gui2/actions/device.py b/src/calibre/gui2/actions/device.py index 5fa44bd7ae..9be0aaaf0c 100644 --- a/src/calibre/gui2/actions/device.py +++ b/src/calibre/gui2/actions/device.py @@ -120,17 +120,19 @@ class ShareConnMenu(QMenu): # {{{ for account in keys: formats, auto, default = opts.accounts[account] subject = opts.subjects.get(account, '') + alias = opts.aliases.get(account, '') dest = 'mail:'+account+';'+formats+';'+subject action1 = DeviceAction(dest, False, False, I('mail.png'), - account) + alias or account) action2 = DeviceAction(dest, True, False, I('mail.png'), - account + ' ' + _('(delete from library)')) + (alias or account) + ' ' + _('(delete from library)')) self.email_to_menu.addAction(action1) self.email_to_and_delete_menu.addAction(action2) map(self.memory.append, (action1, action2)) if default: ac = DeviceAction(dest, False, False, - I('mail.png'), _('Email to') + ' ' +account) + I('mail.png'), _('Email to') + ' ' +(alias or + account)) self.addAction(ac) self.email_actions.append(ac) ac.a_s.connect(sync_menu.action_triggered) diff --git a/src/calibre/gui2/preferences/emailp.py b/src/calibre/gui2/preferences/emailp.py index 892b01f095..7f348030c0 100644 --- a/src/calibre/gui2/preferences/emailp.py +++ b/src/calibre/gui2/preferences/emailp.py @@ -19,12 +19,14 @@ from calibre.utils.smtp import config as smtp_prefs class EmailAccounts(QAbstractTableModel): # {{{ - def __init__(self, accounts, subjects): + def __init__(self, accounts, subjects, aliases={}): QAbstractTableModel.__init__(self) self.accounts = accounts self.subjects = subjects + self.aliases = aliases self.account_order = sorted(self.accounts.keys()) - self.headers = map(QVariant, [_('Email'), _('Formats'), _('Subject'), _('Auto send')]) + self.headers = map(QVariant, [_('Email'), _('Formats'), _('Subject'), + _('Auto send'), _('Alias')]) self.default_font = QFont() self.default_font.setBold(True) self.default_font = QVariant(self.default_font) @@ -36,7 +38,9 @@ class EmailAccounts(QAbstractTableModel): # {{{ '{author_sort} can be used here.'), '

'+_('If checked, downloaded news will be automatically ' 'mailed
to this email address ' - '(provided it is in one of the listed formats).')]))) + '(provided it is in one of the listed formats).'), + _('Friendly name to use for this email address') + ]))) def rowCount(self, *args): return len(self.account_order) @@ -67,6 +71,8 @@ class EmailAccounts(QAbstractTableModel): # {{{ return QVariant(self.accounts[account][0]) if col == 2: return QVariant(self.subjects.get(account, '')) + if col == 4: + return QVariant(self.aliases.get(account, '')) if role == Qt.FontRole and self.accounts[account][2]: return self.default_font if role == Qt.CheckStateRole and col == 3: @@ -88,6 +94,11 @@ class EmailAccounts(QAbstractTableModel): # {{{ self.accounts[account][1] ^= True elif col == 2: self.subjects[account] = unicode(value.toString()) + elif col == 4: + self.aliases.pop(account, None) + aval = unicode(value.toString()).strip() + if aval: + self.aliases[account] = aval elif col == 1: self.accounts[account][0] = unicode(value.toString()).upper() elif col == 0: @@ -156,7 +167,8 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): self.send_email_widget.initialize(self.preferred_to_address) self.send_email_widget.changed_signal.connect(self.changed_signal.emit) opts = self.send_email_widget.smtp_opts - self._email_accounts = EmailAccounts(opts.accounts, opts.subjects) + self._email_accounts = EmailAccounts(opts.accounts, opts.subjects, + opts.aliases) self._email_accounts.dataChanged.connect(lambda x,y: self.changed_signal.emit()) self.email_view.setModel(self._email_accounts) @@ -184,6 +196,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): raise AbortCommit('abort') self.proxy['accounts'] = self._email_accounts.accounts self.proxy['subjects'] = self._email_accounts.subjects + self.proxy['aliases'] = self._email_accounts.aliases return ConfigWidgetBase.commit(self) diff --git a/src/calibre/utils/smtp.py b/src/calibre/utils/smtp.py index e15afbd56d..9fef6b8e6d 100644 --- a/src/calibre/utils/smtp.py +++ b/src/calibre/utils/smtp.py @@ -259,6 +259,7 @@ def config(defaults=None): c.add_opt('from_') c.add_opt('accounts', default={}) c.add_opt('subjects', default={}) + c.add_opt('aliases', default={}) c.add_opt('relay_host') c.add_opt('relay_port', default=25) c.add_opt('relay_username') From cf16fff6b167807f38240011434f48bed7cc8770 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 2 Nov 2012 09:19:22 +0530 Subject: [PATCH 069/107] version 0.9.5 --- Changelog.yaml | 49 ++++++++++++++++++++++++++++++++++++++++ src/calibre/constants.py | 2 +- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/Changelog.yaml b/Changelog.yaml index 31908315f3..f4c5e25cb4 100644 --- a/Changelog.yaml +++ b/Changelog.yaml @@ -19,6 +19,55 @@ # new recipes: # - title: +- version: 0.9.5 + date: 2012-11-02 + + new features: + - title: "Font embedding: Add support for the CSS 3 Fonts module, which means you can embed font families that have more that the usual four faces, with the full set of font-stretch and font-weight variations. Of course, whether the fonts actually show up on a reader will depend on the readers' support for CSS 3." + + - title: "Sharing by email: Allow specifying an 'alias' or friendly name by which to identify each email recipient." + tickets: [1069076] + + - title: "Embedding fonts: Allow adding ttf/otf font files to calibre directly to be used for embedding. That way the fonts do not have to be installed system wide. You can add a font to calibre via the 'Add fonts' button in the font chooser dialog for embedding fonts." + + - title: "E-book viewer: Add the ability to rotate images to the popup image viewer." + tickets: [1073513] + + - title: "Generate cover: Speedup searching the system for a font that can render special characters" + + - title: "A new custom font scanner to locate all fonts on the system. Faster and less crash prone that fontconfig/freetype" + + - title: "Font family chooser: Show the faces available for a family when clicking on the family" + + bug fixes: + - title: "Get Books: Fix eHarlequin and Kobo stores." + tickets: [1072702] + + - title: "Kobo driver: Fix a bug that could cause the on device book matching to fail in certain circumstances." + tickets: [1072437] + + - title: "Kobo driver: When using a SD card do not delete shelves that contain on books on the card (there might be books in the shelf in the main memory)." + tickets: [1073792] + + - title: "Workaround for bug in the windows API CreateHardLink function that breaks using calibre libraries on some networked filesystems." + + - title: "Template editor: Use dummy metadata instead of blank/unknown values" + + - title: "Windows: abort setting of title/author if any of the books' files are in use. Results in less surprising behavior than before, when the title/author would be changed, but the on disk location would not." + + improved recipes: + - Financial Times UK + - Science AAAS + - The Atlantic + + new recipes: + - title: "Pravda in english, italian and portuguese" + author: Darko Miletic + + - title: "Delco Times" + author: Krittika Goyal + + - version: 0.9.4 date: 2012-10-26 diff --git a/src/calibre/constants.py b/src/calibre/constants.py index 4ae0005b0d..fae9b4c87f 100644 --- a/src/calibre/constants.py +++ b/src/calibre/constants.py @@ -4,7 +4,7 @@ __license__ = 'GPL v3' __copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net' __docformat__ = 'restructuredtext en' __appname__ = u'calibre' -numeric_version = (0, 9, 4) +numeric_version = (0, 9, 5) __version__ = u'.'.join(map(unicode, numeric_version)) __author__ = u"Kovid Goyal " From 88174088642971c1565810e05274a1586854f8cc Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 2 Nov 2012 09:53:54 +0530 Subject: [PATCH 070/107] IGN:Tag release --- src/calibre/translations/calibre.pot | 675 +++++++++++++++------------ 1 file changed, 368 insertions(+), 307 deletions(-) diff --git a/src/calibre/translations/calibre.pot b/src/calibre/translations/calibre.pot index 8648b192c0..d1214829a5 100644 --- a/src/calibre/translations/calibre.pot +++ b/src/calibre/translations/calibre.pot @@ -4,9 +4,9 @@ # msgid "" msgstr "" -"Project-Id-Version: calibre 0.9.4\n" -"POT-Creation-Date: 2012-10-26 09:57+IST\n" -"PO-Revision-Date: 2012-10-26 09:57+IST\n" +"Project-Id-Version: calibre 0.9.5\n" +"POT-Creation-Date: 2012-11-02 09:21+IST\n" +"PO-Revision-Date: 2012-11-02 09:21+IST\n" "Last-Translator: Automatically generated\n" "Language-Team: LANGUAGE\n" "MIME-Version: 1.0\n" @@ -30,7 +30,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/hanvon/driver.py:101 #: /home/kovid/work/calibre/src/calibre/devices/jetbook/driver.py:74 #: /home/kovid/work/calibre/src/calibre/devices/kindle/driver.py:77 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:666 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:667 #: /home/kovid/work/calibre/src/calibre/devices/mtp/books.py:45 #: /home/kovid/work/calibre/src/calibre/devices/mtp/books.py:69 #: /home/kovid/work/calibre/src/calibre/devices/mtp/unix/driver.py:229 @@ -131,8 +131,8 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/pdb/ztxt/writer.py:27 #: /home/kovid/work/calibre/src/calibre/ebooks/pdf/writer.py:108 #: /home/kovid/work/calibre/src/calibre/ebooks/pdf/writer.py:109 -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:443 -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:451 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:444 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:452 #: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:166 #: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:411 #: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:414 @@ -154,15 +154,15 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/email.py:193 #: /home/kovid/work/calibre/src/calibre/gui2/email.py:208 #: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:408 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1062 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1273 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1276 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1068 #: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1279 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1367 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1282 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1285 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1373 #: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:85 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:246 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:257 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:397 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:250 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:261 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:398 #: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:174 #: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:178 #: /home/kovid/work/calibre/src/calibre/gui2/store/search/models.py:204 @@ -173,12 +173,12 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2274 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2428 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2858 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3505 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3507 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3644 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2276 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2430 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2879 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3526 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3528 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3665 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -905,12 +905,12 @@ msgstr "" msgid "Card B" msgstr "" -#: /home/kovid/work/calibre/src/calibre/debug.py:65 +#: /home/kovid/work/calibre/src/calibre/debug.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/main.py:47 msgid "Cause a running calibre instance, if any, to be shutdown. Note that if there are running jobs, they will be silently aborted, so use with care." msgstr "" -#: /home/kovid/work/calibre/src/calibre/debug.py:187 +#: /home/kovid/work/calibre/src/calibre/debug.py:189 msgid "Debug log" msgstr "" @@ -1048,14 +1048,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3362 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3383 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3318 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3336 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3339 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3357 msgid "Catalog" msgstr "" @@ -1099,10 +1099,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1316 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1320 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1324 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1654 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 @@ -1438,47 +1438,47 @@ msgid "Upload covers for books (newer readers)" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:70 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1219 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1220 msgid "Normally, the KOBO readers get the cover image from the ebook file itself. With this option, calibre will send a separate cover image to the reader, useful if you have modified the cover." msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:74 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1223 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1224 msgid "Upload Black and White Covers" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:75 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1227 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1228 msgid "Show expired books" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:76 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1228 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1229 msgid "A bug in an earlier version left non kepubs book records in the database. With this option Calibre will show the expired records and allow you to delete them with the new delete logic." msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:80 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1232 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1233 msgid "Show Previews" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:81 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1233 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1234 msgid "Kobo previews are included on the Touch and some other versions by default they are no longer displayed as there is no good reason to see them. Enable if you wish to see/delete them." msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:84 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1236 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1237 msgid "Show Recommendations" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:85 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1237 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1238 msgid "Kobo now shows recommendations on the device. In some case these have files but in other cases they are just pointers to the web site to buy. Enable if you wish to see/delete them." msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:88 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1240 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1241 msgid "Attempt to support newer firmware" msgstr "" @@ -1503,73 +1503,73 @@ msgstr "" msgid "\".kobo\" files do not exist on the device as books instead, they are rows in the sqlite database. Currently they cannot be exported or viewed." msgstr "" -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1093 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1099 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1094 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1100 #, python-format msgid "


Book Last Read: %(time)s
Percentage Read: %(pr)d%%
" msgstr "" -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1117 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1118 #, python-format msgid "Chapter %(chapter)d: %(chapter_title)s
%(typ)s
Chapter Progress: %(chapter_progress)s%%
%(annotation)s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1126 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1127 #, python-format msgid "Chapter %(chapter)d: %(chapter_title)s
%(typ)s
Chapter Progress: %(chapter_progress)s%%
Highlight: %(text)s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1135 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1145 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1136 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1146 #, python-format msgid "Chapter %(chapter)d: %(chapter_title)s
%(typ)s
Chapter Progress: %(chapter_progress)s%%
Highlight: %(text)s
Notes: %(annotation)s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1211 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1212 msgid "The Kobo Touch from firmware V2.0.0 supports bookshelves." msgstr "" -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1213 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1214 msgid "Specify a tags type column for automatic management" msgstr "" -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1214 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1215 msgid "Create Bookshelves" msgstr "" -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1215 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1216 msgid "Create new bookshelves on the Kobo Touch if they do not exist. This is only for firmware V2.0.0 or later." msgstr "" -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1216 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1217 msgid "Delete Empty Bookshelves" msgstr "" -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1217 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1218 msgid "Delete any empty bookshelves from the Kobo Touch when syncing is finished. This is only for firmware V2.0.0 or later." msgstr "" -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1218 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1219 msgid "Upload covers for books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1224 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1225 msgid "Always upload covers" msgstr "" -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1225 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1226 msgid "If the Upload covers option is selected, the driver will only replace covers already on the device. Select this option if you want covers uploaded the first time you send the book to the device." msgstr "" -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1241 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1242 msgid "Kobo routinely updates the firmware and the database version. With this option Calibre will attempt to perform full read-write functionality - Here be Dragons!! Enable only if you are comfortable with restoring your kobo to factory defaults and testing software. This driver supports firmware V2.0.x and DBVersion up to " msgstr "" -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1247 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1248 msgid "Title to test when debugging" msgstr "" -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1248 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1249 msgid "Part of title of a book that can be used when doing some tests for debugging. The test is to see if the string is contained in the title of a book. The better the match, the less extraneous output." msgstr "" @@ -3401,8 +3401,9 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:769 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/delete_matching_from_device.py:76 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/quickview.py:85 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog.py:222 #: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:58 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1067 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1073 #: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:146 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/metadata_sources.py:162 #: /home/kovid/work/calibre/src/calibre/gui2/store/search/models.py:41 @@ -3415,7 +3416,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:770 #: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:60 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1068 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1074 #: /home/kovid/work/calibre/src/calibre/gui2/store/stores/mobileread/models.py:23 msgid "Author(s)" msgstr "" @@ -3431,7 +3432,7 @@ msgid "Producer" msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:773 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:946 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:948 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/metadata_sources.py:157 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:245 msgid "Comments" @@ -3452,6 +3453,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/oeb/transforms/jacket.py:184 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/quickview.py:89 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories.py:60 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog.py:224 #: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/create_custom_column.py:70 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/metadata_sources.py:163 @@ -3579,7 +3581,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/opf2.py:1487 #: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1279 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:958 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:960 #: /home/kovid/work/calibre/src/calibre/gui2/store/search/models.py:41 msgid "Cover" msgstr "" @@ -3787,7 +3789,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/oeb/transforms/cover.py:98 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:186 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:958 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:966 #, python-format msgid "Book %(sidx)s of %(series)s" msgstr "" @@ -3846,159 +3848,159 @@ msgstr "" msgid "Table of Contents:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:117 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:118 msgid "Send file to storage card instead of main memory by default" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:119 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:120 msgid "Confirm before deleting" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:121 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:122 msgid "Main window geometry" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:123 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:124 msgid "Notify when a new version is available" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:125 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:126 msgid "Use Roman numerals for series number" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:127 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:128 msgid "Sort tags list by name, popularity, or rating" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:129 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:130 msgid "Match tags by any or all." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:131 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:132 msgid "Number of covers to show in the cover browsing mode" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:133 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:134 msgid "Defaults for conversion to LRF" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:135 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:136 msgid "Options for the LRF ebook viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:139 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:140 msgid "Formats that are viewed using the internal viewer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:141 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:142 msgid "Columns to be displayed in the book list" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:142 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:143 msgid "Automatically launch content server on application startup" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:143 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:144 msgid "Oldest news kept in database" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:144 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:145 msgid "Show system tray icon" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:146 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:147 msgid "Upload downloaded news to device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:148 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:149 msgid "Delete news books from library after uploading to device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:150 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:151 msgid "Show the cover flow in a separate window instead of in the main calibre window" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:152 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:153 msgid "Disable notifications from the system tray icon" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:154 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:155 msgid "Default action to perform when send to device button is clicked" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:159 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:160 msgid "Start searching as you type. If this is disabled then search will only take place when the Enter or Return key is pressed." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:162 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:163 msgid "When searching, show all books with search results highlighted instead of showing only the matches. You can use the N or F3 keys to go to the next match." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:187 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:188 msgid "Maximum number of simultaneous conversion/news download jobs. This number is twice the actual value for historical reasons." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:190 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:191 msgid "Download social metadata (tags/rating/etc.)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:192 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:193 msgid "Overwrite author and title with new metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:194 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:195 msgid "Automatically download the cover, if available" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:196 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:197 msgid "Limit max simultaneous jobs to number of CPUs" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:198 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:199 msgid "The layout of the user interface. Wide has the book details panel on the right and narrow has it at the bottom." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:202 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:203 msgid "Show the average rating per item indication in the tag browser" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:204 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:205 msgid "Disable UI animations" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:209 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:210 msgid "tag browser categories not to display" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:275 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:276 msgid "WARNING:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:285 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:286 msgid "ERROR:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:297 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:298 #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:258 msgid "Show this confirmation again" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:336 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:337 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/server.py:134 msgid "Restart needed" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:338 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:339 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/plugin_updater.py:741 msgid "Restart calibre now" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:567 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:568 msgid "Choose Files" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:28 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:754 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:762 msgid "Books" msgstr "" @@ -4779,7 +4781,7 @@ msgid "Stop Content Server" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:114 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:133 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:134 msgid "Email to" msgstr "" @@ -4787,45 +4789,45 @@ msgstr "" msgid "Email to and delete from library" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:127 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:128 msgid "(delete from library)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:142 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:144 msgid "Setup email based sharing of books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:160 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:162 msgid "D" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:160 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:162 msgid "Send to device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:178 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:180 msgid "Connect/share" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:216 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:218 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/server.py:85 msgid "Stopping" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:217 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:219 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/server.py:86 msgid "Stopping server, this could take upto a minute, please wait..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:236 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:238 msgid "Disable autostart" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:237 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:239 msgid "Do you want wireless device connections to be started automatically when calibre starts?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:260 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:262 msgid "Many IP addresses. See Start/Stop dialog." msgstr "" @@ -5325,7 +5327,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/tweak_epub.py:105 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comments_dialog.py:25 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog.py:242 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog.py:248 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/main.py:234 #: /usr/src/qt-everywhere-opensource-src-4.8.2/src/gui/widgets/qdialogbuttonbox.cpp:667 msgid "&Cancel" @@ -5504,7 +5506,7 @@ msgid "No books found" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/add.py:288 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:794 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:802 msgid "No permission" msgstr "" @@ -5721,7 +5723,7 @@ msgid "Book %(sidx)s of %(series)s" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:232 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1071 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1077 msgid "Collections" msgstr "" @@ -5977,7 +5979,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:791 #: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:601 -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:4665 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:4663 msgid "False" msgstr "" @@ -6908,44 +6910,44 @@ msgid "Set the metadata. The output file will contain as much of this metadata a msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:99 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1000 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1008 msgid "This book has no cover" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:105 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1002 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1010 #, python-format msgid "Cover size: %(width)d x %(height)d pixels" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:172 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:901 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:909 msgid "Choose cover for " msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:179 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:909 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:917 msgid "Cannot read" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:180 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:910 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:918 msgid "You do not have permission to read the file: " msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:188 #: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:195 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:918 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:926 msgid "Error reading file" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:189 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:919 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:927 msgid "

There was an error reading from file:
" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:196 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:929 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:937 msgid " is not a valid picture" msgstr "" @@ -6998,14 +7000,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:171 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:561 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1092 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1100 msgid "Tags categorize the book. This is particularly useful while searching.

They can be any words or phrases, separated by commas." msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:172 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:568 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:198 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:450 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:458 msgid "&Series:" msgstr "" @@ -7013,7 +7015,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:174 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:569 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:570 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:449 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:457 msgid "List of known series. You can add new series." msgstr "" @@ -7377,7 +7379,7 @@ msgid "Remove the currently selected expression" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/convert/search_and_replace_ui.py:153 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:871 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:879 msgid "&Remove" msgstr "" @@ -7752,7 +7754,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:233 #: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:290 #: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:294 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1404 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1412 msgid "Undefined" msgstr "" @@ -8596,7 +8598,7 @@ msgid "&Title:" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:98 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:211 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:215 msgid "&Author(s):" msgstr "" @@ -8605,7 +8607,7 @@ msgid "&Profile:" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comments_dialog.py:24 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog.py:241 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog.py:247 #: /usr/src/qt-everywhere-opensource-src-4.8.2/src/gui/widgets/qdialogbuttonbox.cpp:658 msgid "&OK" msgstr "" @@ -8649,6 +8651,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/delete_matching_from_device.py:76 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/edit_authors_dialog.py:49 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/plugin_updater.py:305 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog.py:222 msgid "Author" msgstr "" @@ -8658,7 +8661,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/delete_matching_from_device.py:77 #: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:62 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1069 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1075 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/create_custom_column.py:35 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/create_custom_column.py:76 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:365 @@ -8764,36 +8767,36 @@ msgid "No matches found" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/edit_authors_dialog.py:160 -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:436 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:433 msgid "Change Case" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/edit_authors_dialog.py:161 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:300 -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:437 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:434 msgid "Upper Case" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/edit_authors_dialog.py:162 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:299 -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:438 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:435 msgid "Lower Case" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/edit_authors_dialog.py:163 -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:439 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:436 msgid "Swap Case" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/edit_authors_dialog.py:164 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:301 -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:440 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:437 msgid "Title Case" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/edit_authors_dialog.py:165 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:302 -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:441 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:438 msgid "Capitalize" msgstr "" @@ -8956,7 +8959,7 @@ msgid "Standard metadata" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:62 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:928 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:930 msgid "Custom metadata" msgstr "" @@ -9095,13 +9098,13 @@ msgid "Specify how the author(s) of this book should be sorted. For example Char msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:554 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1050 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1058 msgid "&Rating:" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:555 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:556 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1051 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1059 msgid "Rating of this book. 0-5 stars" msgstr "" @@ -9168,7 +9171,7 @@ msgid "&Force numbers to start with:" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:582 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1386 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1394 msgid "&Date:" msgstr "" @@ -9190,7 +9193,7 @@ msgid "Clear published date" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:591 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1155 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1163 msgid "&Languages:" msgstr "" @@ -9252,13 +9255,13 @@ msgid "Set from &ebook file(s)" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:609 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:569 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:734 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:571 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:736 msgid "&Basic metadata" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:610 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:576 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:578 msgid "&Custom metadata" msgstr "" @@ -9780,7 +9783,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/store/config/chooser/chooser_widget_ui.py:80 #: /home/kovid/work/calibre/src/calibre/gui2/store/search/search_ui.py:144 #: /home/kovid/work/calibre/src/calibre/gui2/store/stores/mobileread/store_dialog_ui.py:76 -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:679 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:676 #: /home/kovid/work/calibre/src/calibre/library/server/browse.py:281 msgid "Search" msgstr "" @@ -10224,7 +10227,7 @@ msgid "&Author:" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:199 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1091 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1099 msgid "Ta&gs:" msgstr "" @@ -10525,31 +10528,44 @@ msgstr "" msgid "Copy the selected color name to the clipboard" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog.py:263 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog.py:223 +#: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:223 +msgid "Author Sort" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog.py:227 +msgid "Tag 1" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog.py:227 +msgid "Tag 2" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog.py:269 msgid "Template language tutorial" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog.py:267 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog.py:273 msgid "Template function reference" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog.py:285 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog.py:291 msgid "EXCEPTION: " msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog.py:312 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog.py:318 msgid "No column chosen" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog.py:313 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog.py:319 msgid "You must specify a column to be colored" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog.py:316 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog.py:322 msgid "No template provided" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog.py:317 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog.py:323 msgid "The template box cannot be empty" msgstr "" @@ -10949,7 +10965,7 @@ msgid "Regular expression (?P)" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:149 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1288 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1296 msgid "ISBN:" msgstr "" @@ -10973,11 +10989,28 @@ msgstr "" msgid "Regular expression (?P)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:122 +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:123 +msgid "Choose a font family" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:136 +#, python-format +msgid "Available faces for %s" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:171 msgid "Choose font family" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:137 +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:195 +msgid "Add &fonts" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:199 +msgid "Choose a font family from the list below:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:217 #: /home/kovid/work/calibre/src/calibre/gui2/keyboard.py:377 #: /home/kovid/work/calibre/src/calibre/gui2/keyboard.py:406 #: /home/kovid/work/calibre/src/calibre/gui2/keyboard.py:409 @@ -10989,19 +11022,41 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/shortcuts_ui.py:83 #: /home/kovid/work/calibre/src/calibre/gui2/store/config/chooser/chooser_widget_ui.py:83 #: /home/kovid/work/calibre/src/calibre/gui2/store/search/search_ui.py:148 -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:366 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:363 msgid "None" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:159 -msgid "Choose a font family from the list below:" +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:223 +msgid "Select font files" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:187 +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:223 +msgid "TrueType/OpenType Fonts" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:233 +msgid "Corrupt font" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:234 +#, python-format +msgid "Failed to read metadata from the font file: %s" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:253 +msgid "Added fonts" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:254 +#, python-format +msgid "Added font families: %s" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:279 msgid "Choose &font family" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196 +#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:288 msgid "Clear the font family" msgstr "" @@ -11277,7 +11332,7 @@ msgid "Copy current search text (instead of search name)" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:42 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1058 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1066 msgid "stars" msgstr "" @@ -11300,50 +11355,55 @@ msgid "Modified" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:785 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1405 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1411 #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:312 msgid "The lookup/search name is \"{0}\"" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:791 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1407 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1413 msgid "This book's UUID is \"{0}\"" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:876 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:104 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:272 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:878 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:108 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:280 #: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:320 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:448 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:450 msgid "Permission denied" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:877 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:879 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:109 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:281 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:451 msgid "Could not change the on disk location of this book. Is it open in another program?" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:883 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:889 msgid "Failed to set data" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:884 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:890 msgid "Could not set data, click Show Details to see why." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1066 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1072 msgid "In Library" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1070 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1076 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:355 msgid "Size" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1387 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1393 msgid "Marked for deletion" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1390 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1396 msgid "Double click to edit me

" msgstr "" @@ -11564,49 +11624,49 @@ msgstr "" msgid "Starting %s: Loading books..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/main.py:333 +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:334 msgid "If you are sure it is not running" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/main.py:336 +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:337 msgid "may be running in the system tray, in the" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/main.py:338 +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:339 msgid "upper right region of the screen." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/main.py:340 +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:341 msgid "lower right region of the screen." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/main.py:343 +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:344 msgid "try rebooting your computer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/main.py:345 -#: /home/kovid/work/calibre/src/calibre/gui2/main.py:362 +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:346 +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:363 msgid "try deleting the file" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/main.py:348 +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:349 msgid "Cannot Start " msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/main.py:349 +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:350 #, python-format msgid "%s is already running." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/main.py:370 +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:371 msgid "No running calibre found" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/main.py:374 +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:375 msgid "Shutdown command sent, waiting for shutdown..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/main.py:379 +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:380 msgid "Failed to shutdown running calibre instance" msgstr "" @@ -11626,65 +11686,53 @@ msgstr "" msgid "Unhandled exception" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:105 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:321 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:449 -#, python-format -msgid "Could not open %s. Is it being used by another program?" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:138 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:142 msgid "Specify how this book should be sorted when by title. For example, The Exorcist might be sorted as Exorcist, The." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:140 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:144 msgid "Title &sort:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:149 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:153 msgid " The green color indicates that the current title sort matches the current title" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:152 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:156 msgid " The red color warns that the current title sort does not match the current title. No action is required if this is what you want." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:226 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:230 msgid "Authors changed" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:227 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:231 msgid "You have changed the authors for this book. You must save these changes before you can use Manage authors. Do you want to save these changes?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:273 -#, python-format -msgid "Could not open \"%s\". Is it being used by another program?" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:306 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:314 msgid "" "Specify how the author(s) of this book should be sorted. For example Charles Dickens should be sorted as Dickens, Charles.\n" "If the box is colored green, then text matches the individual author's sort strings. If it is colored red, then the authors and this text do not match." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:311 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:319 msgid "Author s&ort:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:321 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:329 msgid " The green color indicates that the current author sort matches the current author" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:324 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:332 msgid " The red color indicates that the current author sort does not match the current author. No action is required if this is what you want." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:503 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:511 msgid "&Number:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:603 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:611 #, python-format msgid "" "Last modified: %s\n" @@ -11692,113 +11740,113 @@ msgid "" "Double click to view" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:613 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:621 #, python-format msgid "Restore %s from the original" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:659 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:667 msgid "Set the cover for the book from the selected format" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:667 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:675 msgid "Set metadata for the book from the selected format" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:674 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:682 msgid "Add a format to this book" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:681 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:689 msgid "Remove the selected format from this book" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:752 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:760 msgid "Choose formats for " msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:795 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:803 msgid "You do not have permission to read the following files:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:825 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:826 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:833 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:834 msgid "No format selected" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:838 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:846 msgid "Could not read metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:839 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:847 #, python-format msgid "Could not read metadata from %s format" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:867 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:875 msgid "&Browse" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:869 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:877 msgid "T&rim" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:877 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:885 msgid "Download co&ver" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:878 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:886 msgid "&Generate cover" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:928 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:936 msgid "Not a valid picture" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:952 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:960 msgid "Specify title and author" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:953 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:961 msgid "You must specify a title and author before generating a cover" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:972 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:980 msgid "Invalid cover" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:973 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:981 msgid "Could not change cover as the image is invalid." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1127 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1135 msgid "Tags changed" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1128 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1136 msgid "You have changed the tags. In order to use the tags editor, you must either discard or apply these changes. Apply changes?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1156 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1164 msgid "A comma separated list of languages for this book" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1179 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1187 msgid "Unknown language" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1180 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1188 #, python-format msgid "The language %s is not recognized" msgid_plural "The languages %s are not recognized" msgstr[0] "" msgstr[1] "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1192 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1200 msgid "I&ds:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1193 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1201 #, python-format msgid "" "Edit the identifiers for this book. For example: \n" @@ -11806,38 +11854,38 @@ msgid "" "%s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1257 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1319 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1265 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1327 msgid "This ISBN number is valid" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1260 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1322 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1268 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1330 msgid "This ISBN number is invalid" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1285 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1307 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1293 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1315 msgid "Invalid ISBN" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1286 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1294 msgid "Enter an ISBN" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1308 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1316 msgid "The ISBN you entered is not valid. Try again." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1332 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1340 msgid "&Publisher:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1407 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1415 msgid "Clear date" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1441 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:1449 msgid "Publishe&d:" msgstr "" @@ -11983,54 +12031,59 @@ msgstr "" msgid " [%(num)d of %(tot)d]" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:333 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:340 -msgid "Could not read cover" +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:321 +#, python-format +msgid "Could not open %s. Is it being used by another program?" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:334 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:341 +msgid "Could not read cover" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:335 #, python-format msgid "Could not read cover from %s format" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:341 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:342 #, python-format msgid "The cover in the %s format is invalid" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:516 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:521 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:518 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:523 #, python-format msgid "Save changes and edit the metadata of %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:619 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:822 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:621 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:824 msgid "Change cover" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:677 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:679 msgid "Co&mments" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:717 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:863 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:719 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:865 msgid "&Metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:722 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:724 msgid "&Cover and formats" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:792 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:794 msgid "C&ustom metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:803 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:805 msgid "&Comments" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:869 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:871 msgid "Basic metadata" msgstr "" @@ -12674,7 +12727,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/create_custom_column.py:68 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/create_custom_column.py:175 -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/emailp.py:27 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/emailp.py:28 #: /home/kovid/work/calibre/src/calibre/gui2/store/config/chooser/models.py:21 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:152 msgid "Formats" @@ -13000,31 +13053,39 @@ msgstr "" msgid "&Remove email" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/emailp.py:27 -msgid "Auto send" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/emailp.py:27 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/emailp.py:28 msgid "Email" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/emailp.py:27 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/emailp.py:28 msgid "Subject" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/emailp.py:32 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/emailp.py:29 +msgid "Alias" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/emailp.py:29 +msgid "Auto send" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/emailp.py:34 msgid "Formats to email. The first matching format will be sent." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/emailp.py:33 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/emailp.py:35 msgid "Subject of the email to use when sending. When left blank the title will be used for the subject. Also, the same templates used for \"Save to disk\" such as {title} and {author_sort} can be used here." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/emailp.py:37 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/emailp.py:39 msgid "If checked, downloaded news will be automatically mailed
to this email address (provided it is in one of the listed formats)." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/emailp.py:117 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/emailp.py:42 +msgid "Friendly name to use for this email address" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/emailp.py:128 msgid "new email address" msgstr "" @@ -15657,23 +15718,27 @@ msgstr "" msgid "Section End" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/image_popup.py:37 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/image_popup.py:38 msgid "Zoom &in" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/image_popup.py:38 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/image_popup.py:39 msgid "Zoom &out" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/image_popup.py:39 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/image_popup.py:40 msgid "&Save as" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/image_popup.py:63 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/image_popup.py:41 +msgid "&Rotate" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/image_popup.py:67 msgid "Choose a file to save to" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/viewer/image_popup.py:88 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/image_popup.py:100 #, python-format msgid "View Image: %s" msgstr "" @@ -15983,19 +16048,19 @@ msgstr "" msgid "The name %r does not appear to end with a file extension. The name must end with a file extension like .epub or .mobi" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:950 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:947 msgid "Drag to resize" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:978 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:975 msgid "Show" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:985 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:982 msgid "Hide" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:1022 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:1019 msgid "Toggle" msgstr "" @@ -16688,81 +16753,81 @@ msgstr "" msgid "Description HTML" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:2814 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:2812 msgid "NCX header" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:2893 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:2891 msgid "NCX for Descriptions" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3020 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3018 msgid "NCX for Series" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3102 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3100 #, python-format msgid "Series beginning with %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3104 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3102 #, python-format msgid "Series beginning with '%s'" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3148 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3146 msgid "NCX for Titles" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3232 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3230 #, python-format msgid "Titles beginning with %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3234 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3232 #, python-format msgid "Titles beginning with '%s'" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3276 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3274 msgid "NCX for Authors" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3352 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3350 #, python-format msgid "Authors beginning with %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3354 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3352 #, python-format msgid "Authors beginning with '%s'" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3395 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3393 msgid "NCX for Recently Added" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3588 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3586 msgid "NCX for Recently Read" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3730 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3728 msgid "NCX for Genres" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3853 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3851 msgid "Generating OPF" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:4233 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:4231 msgid "Thumbnails" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:4239 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:4237 msgid "Thumbnail" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:4755 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:4753 msgid "Saving NCX" msgstr "" @@ -17362,17 +17427,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3670 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3691 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3699 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3720 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3716 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3737 msgid "Compacting database" msgstr "" @@ -17380,10 +17445,6 @@ msgstr "" msgid "Identifiers" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:223 -msgid "Author Sort" -msgstr "" - #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:335 msgid "Series Sort" msgstr "" @@ -17883,7 +17944,7 @@ msgstr "" msgid "Characters typed in the search box will match their accented versions, based on the language you have chosen for the calibre interface. For example, in English, searching for n will match %s and n, but if your language is Spanish it will only match n. Note that this is much slower than a simple search on very large libraries." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/filenames.py:284 +#: /home/kovid/work/calibre/src/calibre/utils/filenames.py:289 msgid "File is open in another process" msgstr "" From 1ca3b13a6c8baecd85bbad1624901f9def19973e Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 2 Nov 2012 10:15:09 +0530 Subject: [PATCH 071/107] ... --- manual/develop.rst | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/manual/develop.rst b/manual/develop.rst index a6f1a1308e..b9fba195d3 100644 --- a/manual/develop.rst +++ b/manual/develop.rst @@ -72,13 +72,21 @@ After installing Bazaar, you can get the |app| source code with the command:: bzr branch lp:calibre -On Windows you will need the complete path name, that will be something like :file:`C:\\Program Files\\Bazaar\\bzr.exe`. To update a branch -to the latest code, use the command:: +On Windows you will need the complete path name, that will be something like :file:`C:\\Program Files\\Bazaar\\bzr.exe`. + +To update a branch to the latest code, use the command:: bzr merge -The calibre repository is huge so the branch operation above takes along time (about an hour). If you want to get the code faster, the sourcecode for the latest release is always available as an -`archive `_. +|app| is a very large project with a very long source control history, so the +above can take a while (10mins to an hour depending on your internet speed). + +If you want to get the code faster, the sourcecode for the latest release is +always available as an `archive `_. +You can also use bzr to just download the source code, without the history, +using:: + + bzr branch --stacked lp:calibre Submitting your changes to be included ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -109,7 +117,7 @@ Whenever you commit changes to your branch with the command:: bzr commit -m "Comment describing your change" Kovid can merge it directly from your branch into the main |app| source tree. You should also keep an eye on the |app| -`development forum `. Before making major changes, you should +`development forum `_. Before making major changes, you should discuss them in the forum or contact Kovid directly (his email address is all over the source code). Windows development environment From e42140cdc928942a3158fe766ec29ccea8a472c3 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 2 Nov 2012 10:51:27 +0530 Subject: [PATCH 072/107] Sigh --- src/calibre/utils/filenames.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/calibre/utils/filenames.py b/src/calibre/utils/filenames.py index 0960a50c1c..ee86088da1 100644 --- a/src/calibre/utils/filenames.py +++ b/src/calibre/utils/filenames.py @@ -341,6 +341,11 @@ class WindowsAtomicFolderMove(object): def delete_originals(self): import win32file for path in self.handle_map.iterkeys(): + try: + # Ensure the file is not read-only + win32file.SetFileAttributes(path, win32file.FILE_ATTRIBUTE_NORMAL) + except: + pass win32file.DeleteFile(path) self.close_handles() From ab44713d96ecd52fa400b39fdd5a127052d6954f Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 2 Nov 2012 11:38:23 +0530 Subject: [PATCH 073/107] Update Yemen Times --- recipes/yementimes.recipe | 96 +++------------------------------------ 1 file changed, 6 insertions(+), 90 deletions(-) diff --git a/recipes/yementimes.recipe b/recipes/yementimes.recipe index 426c9a748c..fa327d21cd 100644 --- a/recipes/yementimes.recipe +++ b/recipes/yementimes.recipe @@ -1,5 +1,4 @@ from calibre.web.feeds.news import BasicNewsRecipe -from calibre.ebooks.BeautifulSoup import BeautifulSoup, Tag class YemenTimesRecipe(BasicNewsRecipe): __license__ = 'GPL v3' @@ -13,7 +12,7 @@ class YemenTimesRecipe(BasicNewsRecipe): category = u'News, Opinion, Yemen' description = u'Award winning weekly from Yemen, promoting press freedom, professional journalism and the defense of human rights.' - oldest_article = 7 + oldest_article = 10 max_articles_per_feed = 100 use_embedded_content = False encoding = 'utf-8' @@ -21,27 +20,13 @@ class YemenTimesRecipe(BasicNewsRecipe): remove_empty_feeds = True no_stylesheets = True remove_javascript = True + auto_cleanup = True - keep_only_tags = [] - keep_only_tags.append(dict(name = 'div', attrs = {'id': 'ctl00_ContentPlaceHolder1_MAINNEWS0_Panel1', - 'class': 'DMAIN2'})) - remove_attributes = ['style'] - INDEX = 'http://www.yementimes.com/' - feeds = [] - feeds.append((u'Our Viewpoint', u'http://www.yementimes.com/DEFAULTSUB.ASPX?pnc=6&pnm=OUR%20VIEWPOINT')) - feeds.append((u'Local News', u'http://www.yementimes.com/DEFAULTSUB.ASPX?pnc=3&pnm=Local%20news')) - feeds.append((u'Their News', u'http://www.yementimes.com/DEFAULTSUB.ASPX?pnc=80&pnm=Their%20News')) - feeds.append((u'Report', u'http://www.yementimes.com/DEFAULTSUB.ASPX?pnc=8&pnm=report')) - feeds.append((u'Health', u'http://www.yementimes.com/DEFAULTSUB.ASPX?pnc=51&pnm=health')) - feeds.append((u'Interview', u'http://www.yementimes.com/DEFAULTSUB.ASPX?pnc=77&pnm=interview')) - feeds.append((u'Opinion', u'http://www.yementimes.com/DEFAULTSUB.ASPX?pnc=7&pnm=opinion')) - feeds.append((u'Business', u'http://www.yementimes.com/DEFAULTSUB.ASPX?pnc=5&pnm=business')) - feeds.append((u'Op-Ed', u'http://www.yementimes.com/DEFAULTSUB.ASPX?pnc=81&pnm=Op-Ed')) - feeds.append((u'Culture', u'http://www.yementimes.com/DEFAULTSUB.ASPX?pnc=75&pnm=Culture')) - feeds.append((u'Readers View', u'http://www.yementimes.com/DEFAULTSUB.ASPX?pnc=4&pnm=Readers%20View')) - feeds.append((u'Variety', u'http://www.yementimes.com/DEFAULTSUB.ASPX?pnc=9&pnm=Variety')) - feeds.append((u'Education', u'http://www.yementimes.com/DEFAULTSUB.ASPX?pnc=57&pnm=Education')) + feeds = [ +('News', + 'http://www.yementimes.com/?tpl=1341'), +] extra_css = ''' body {font-family:verdana, arial, helvetica, geneva, sans-serif;} @@ -53,73 +38,4 @@ class YemenTimesRecipe(BasicNewsRecipe): conversion_options = {'comments': description, 'tags': category, 'language': 'en', 'publisher': publisher, 'linearize_tables': True} - def get_browser(self): - br = BasicNewsRecipe.get_browser() - br.set_handle_gzip(True) - return br - - def parse_index(self): - answer = [] - for feed_title, feed in self.feeds: - soup = self.index_to_soup(feed) - - newsbox = soup.find('div', 'newsbox') - main = newsbox.findNextSibling('table') - - articles = [] - for li in main.findAll('li'): - title = self.tag_to_string(li.a) - url = self.INDEX + li.a['href'] - articles.append({'title': title, 'date': None, 'url': url, 'description': '
 '}) - - answer.append((feed_title, articles)) - - return answer - - def preprocess_html(self, soup): - freshSoup = self.getFreshSoup(soup) - - headline = soup.find('div', attrs = {'id': 'DVMTIT'}) - if headline: - div = headline.findNext('div', attrs = {'id': 'DVTOP'}) - img = None - if div: - img = div.find('img') - - headline.name = 'h1' - freshSoup.body.append(headline) - if img is not None: - freshSoup.body.append(img) - - byline = soup.find('div', attrs = {'id': 'DVTIT'}) - if byline: - date_el = byline.find('span') - if date_el: - pub_date = self.tag_to_string(date_el) - date = Tag(soup, 'div', attrs = [('class', 'yemen_date')]) - date.append(pub_date) - date_el.extract() - - raw = '
'.join(['%s' % (part) for part in byline.findAll(text = True)]) - author = BeautifulSoup('') - - if date is not None: - freshSoup.body.append(date) - freshSoup.body.append(author) - - story = soup.find('div', attrs = {'id': 'DVDET'}) - if story: - for table in story.findAll('table'): - if table.find('img'): - table['class'] = 'yemen_caption' - - freshSoup.body.append(story) - - return freshSoup - - def getFreshSoup(self, oldSoup): - freshSoup = BeautifulSoup('') - if oldSoup.head.title: - freshSoup.head.title.append(self.tag_to_string(oldSoup.head.title)) - return freshSoup From 190c2259669b33e42cc51f8d04f5bfabfc5f8ffd Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 2 Nov 2012 12:02:58 +0530 Subject: [PATCH 074/107] ... --- src/calibre/utils/filenames.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/calibre/utils/filenames.py b/src/calibre/utils/filenames.py index ee86088da1..22ae1a9306 100644 --- a/src/calibre/utils/filenames.py +++ b/src/calibre/utils/filenames.py @@ -278,6 +278,12 @@ class WindowsAtomicFolderMove(object): for x in os.listdir(path): f = os.path.normcase(os.path.abspath(os.path.join(path, x))) if not os.path.isfile(f): continue + try: + # Ensure the file is not read-only + win32file.SetFileAttributes(f, win32file.FILE_ATTRIBUTE_NORMAL) + except: + pass + try: h = win32file.CreateFile(f, win32file.GENERIC_READ, win32file.FILE_SHARE_DELETE, None, @@ -341,11 +347,6 @@ class WindowsAtomicFolderMove(object): def delete_originals(self): import win32file for path in self.handle_map.iterkeys(): - try: - # Ensure the file is not read-only - win32file.SetFileAttributes(path, win32file.FILE_ATTRIBUTE_NORMAL) - except: - pass win32file.DeleteFile(path) self.close_handles() From 5a17a1ca320538bdf50ab5c89336fad34d51af2d Mon Sep 17 00:00:00 2001 From: John Schember Date: Fri, 2 Nov 2012 22:21:45 -0400 Subject: [PATCH 075/107] Store: Fix Amazon plugin. --- .../gui2/store/stores/amazon_plugin.py | 49 ++++++------------- 1 file changed, 14 insertions(+), 35 deletions(-) diff --git a/src/calibre/gui2/store/stores/amazon_plugin.py b/src/calibre/gui2/store/stores/amazon_plugin.py index bc1fa641bf..4bd1a42c9d 100644 --- a/src/calibre/gui2/store/stores/amazon_plugin.py +++ b/src/calibre/gui2/store/stores/amazon_plugin.py @@ -127,35 +127,14 @@ class AmazonKindleStore(StorePlugin): counter = max_results with closing(br.open(url, timeout=timeout)) as f: doc = html.fromstring(f.read().decode('latin-1', 'replace')) - - # Amazon has two results pages. - is_shot = doc.xpath('boolean(//div[@id="shotgunMainResults"])') - # Horizontal grid of books. Search "Paolo Bacigalupi" - if is_shot: - data_xpath = '//div[contains(@class, "result")]' - format_xpath = './/div[@class="productTitle"]//text()' - asin_xpath = './/div[@class="productTitle"]//a' - cover_xpath = './/div[@class="productTitle"]//img/@src' - title_xpath = './/div[@class="productTitle"]/a//text()' - price_xpath = './/div[@class="newPrice"]/span/text()' - # Vertical list of books. - else: - # New style list. Search "Paolo Bacigalupi" - if doc.xpath('boolean(//div[@class="image"])'): - data_xpath = '//div[contains(@class, "results")]//div[contains(@class, "result")]' - format_xpath = './/span[@class="binding"]//text()' - asin_xpath = './/div[@class="image"]/a[1]' - cover_xpath = './/img[@class="productImage"]/@src' - title_xpath = './/a[@class="title"]/text()' - price_xpath = './/span[contains(@class, "price")]/text()' - # Old style list. Search "martin" - else: - data_xpath = '//div[contains(@class, "result")]' - format_xpath = './/span[@class="format"]//text()' - asin_xpath = './/div[@class="productImage"]/a[1]' - cover_xpath = './/div[@class="productImage"]//img/@src' - title_xpath = './/div[@class="productTitle"]/a/text()' - price_xpath = './/div[@class="newPrice"]//span//text()' + + data_xpath = '//div[contains(@class, "prod")]' + format_xpath = './/ul[contains(@class, "rsltL")]//span[contains(@class, "lrg") and not(contains(@class, "bld"))]/text()' + asin_xpath = './/div[@class="image"]/a[1]' + cover_xpath = './/img[@class="productImage"]/@src' + title_xpath = './/h3[@class="newaps"]/a//text()' + author_xpath = './/h3[@class="newaps"]//span[contains(@class, "reg")]/text()' + price_xpath = './/ul[contains(@class, "rsltL")]//span[contains(@class, "lrg") and contains(@class, "bld")]/text()' for data in doc.xpath(data_xpath): if counter <= 0: @@ -186,14 +165,14 @@ class AmazonKindleStore(StorePlugin): cover_url = ''.join(data.xpath(cover_xpath)) title = ''.join(data.xpath(title_xpath)) + author = ''.join(data.xpath(author_xpath)) + try: + author = author.split('by ', 1)[1].split(" (")[0] + except: + pass + price = ''.join(data.xpath(price_xpath)) - if is_shot: - author = format.split(' by ')[-1] - else: - author = ''.join(data.xpath('.//span[@class="ptBrand"]/text()')) - author = author.split('by ')[-1] - counter -= 1 s = SearchResult() From 7916569e0430bc01595a9fedfb83e48c79a77007 Mon Sep 17 00:00:00 2001 From: John Schember Date: Fri, 2 Nov 2012 22:30:31 -0400 Subject: [PATCH 076/107] Store: Fix Google plugin. --- src/calibre/gui2/store/stores/google_books_plugin.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/calibre/gui2/store/stores/google_books_plugin.py b/src/calibre/gui2/store/stores/google_books_plugin.py index 60b78e3f7d..63fc3ef942 100644 --- a/src/calibre/gui2/store/stores/google_books_plugin.py +++ b/src/calibre/gui2/store/stores/google_books_plugin.py @@ -68,10 +68,10 @@ class GoogleBooksStore(BasicStoreConfig, StorePlugin): continue title = ''.join(data.xpath('.//h3/a//text()')) - authors = data.xpath('.//span[@class="f"]//a//text()') - if authors and authors[-1].strip().lower() in ('preview', 'read'): + authors = data.xpath('.//div[@class="f"]//a//text()') + while authors and authors[-1].strip().lower() in ('preview', 'read', 'more editions'): authors = authors[:-1] - else: + if not authors: continue author = ', '.join(authors) From ca11b4f691c4c5c125151b411b0c186943f9ac4a Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 3 Nov 2012 08:17:39 +0530 Subject: [PATCH 077/107] ... --- manual/faq.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/manual/faq.rst b/manual/faq.rst index d46011d8d8..8163861863 100644 --- a/manual/faq.rst +++ b/manual/faq.rst @@ -659,6 +659,9 @@ There are three possible things I know of, that can cause this: * You are using a Wacom branded mouse. There is an incompatibility between Wacom mice and the graphics toolkit |app| uses. Try using a non-Wacom mouse. + * If you use RoboForm, it is known to cause |app| to crash. Add |app| to + the blacklist of programs inside RoboForm to fix this. + * Sometimes if some software has installed lots of new files in your fonts folder, |app| can crash until it finishes indexing them. Just start |app|, then leave it alone for about 20 minutes, without clicking on anything. After that you should be able to use |app| as normal. From 97f13810639cb6759d46e2f643e1fd368da71c01 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 3 Nov 2012 08:29:13 +0530 Subject: [PATCH 078/107] Fix regression that broke the Template Editor --- src/calibre/gui2/dialogs/template_dialog.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/gui2/dialogs/template_dialog.py b/src/calibre/gui2/dialogs/template_dialog.py index ef95b03fc2..fc8a528830 100644 --- a/src/calibre/gui2/dialogs/template_dialog.py +++ b/src/calibre/gui2/dialogs/template_dialog.py @@ -225,7 +225,7 @@ class TemplateDialog(QDialog, Ui_TemplateDialog): self.mi.series_index = 3 self.mi.rating = 4.0 self.mi.tags = [_('Tag 1'), _('Tag 2')] - self.mi.language = ['eng'] + self.mi.languages = ['eng'] # Remove help icon on title bar icon = self.windowIcon() From 570b2e58244bfde4c780aa12629a6ca2bc93cb6e Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 3 Nov 2012 08:43:56 +0530 Subject: [PATCH 079/107] When updating a previously broken plugin, do not show an error message because the previous version of the plugin cannot be loaded --- src/calibre/gui2/preferences/plugins.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/calibre/gui2/preferences/plugins.py b/src/calibre/gui2/preferences/plugins.py index 382b07260b..912518568a 100644 --- a/src/calibre/gui2/preferences/plugins.py +++ b/src/calibre/gui2/preferences/plugins.py @@ -403,7 +403,12 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): return all_locations = OrderedDict(ConfigWidget.LOCATIONS) - plugin_action = plugin.load_actual_plugin(self.gui) + try: + plugin_action = plugin.load_actual_plugin(self.gui) + except: + # Broken plugin, fails to initialize. Given that, it's probably + # already configured, so we can just quit. + return installed_actions = OrderedDict([ (key, list(gprefs.get('action-layout-'+key, []))) for key in all_locations]) From d1cf14703d2b6644f6c25613dec14e60f88e0d20 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 3 Nov 2012 11:06:56 +0530 Subject: [PATCH 080/107] Add search to the font family chooser dialog and get rid of the obsolete fontfamilymodel --- src/calibre/gui2/font_family_chooser.py | 51 ++++++++++++++++++++++--- src/calibre/gui2/widgets.py | 49 +++--------------------- 2 files changed, 51 insertions(+), 49 deletions(-) diff --git a/src/calibre/gui2/font_family_chooser.py b/src/calibre/gui2/font_family_chooser.py index 72240636c1..e3a2662ac4 100644 --- a/src/calibre/gui2/font_family_chooser.py +++ b/src/calibre/gui2/font_family_chooser.py @@ -13,7 +13,7 @@ from PyQt4.Qt import (QFontInfo, QFontMetrics, Qt, QFont, QFontDatabase, QPen, QStyledItemDelegate, QSize, QStyle, QStringListModel, pyqtSignal, QDialog, QVBoxLayout, QApplication, QFontComboBox, QPushButton, QToolButton, QGridLayout, QListView, QWidget, QDialogButtonBox, QIcon, - QHBoxLayout, QLabel, QModelIndex) + QHBoxLayout, QLabel, QModelIndex, QLineEdit) from calibre.constants import config_dir from calibre.gui2 import choose_files, error_dialog, info_dialog @@ -197,15 +197,56 @@ class FontFamilyDialog(QDialog): afb.setIcon(QIcon(I('plus.png'))) afb.clicked.connect(self.add_fonts) self.ml = QLabel(_('Choose a font family from the list below:')) + self.search = QLineEdit(self) + self.search.setPlaceholderText(_('Search')) + self.search.returnPressed.connect(self.find) + self.nb = QToolButton(self) + self.nb.setIcon(QIcon(I('arrow-down.png'))) + self.nb.setToolTip(_('Find Next')) + self.pb = QToolButton(self) + self.pb.setIcon(QIcon(I('arrow-up.png'))) + self.pb.setToolTip(_('Find Previous')) + self.nb.clicked.connect(self.find_next) + self.pb.clicked.connect(self.find_previous) - l.addWidget(self.ml, 0, 0, 1, 2) - l.addWidget(self.view, 1, 0, 1, 1) - l.addWidget(self.faces, 1, 1, 1, 1) - l.addWidget(self.bb, 2, 0, 1, 2) + l.addWidget(self.ml, 0, 0, 1, 4) + l.addWidget(self.search, 1, 0, 1, 1) + l.addWidget(self.nb, 1, 1, 1, 1) + l.addWidget(self.pb, 1, 2, 1, 1) + l.addWidget(self.view, 2, 0, 1, 3) + l.addWidget(self.faces, 1, 3, 2, 1) + l.addWidget(self.bb, 3, 0, 1, 4) l.setAlignment(self.faces, Qt.AlignTop) self.resize(800, 600) + def set_current(self, i): + self.view.setCurrentIndex(self.m.index(i)) + + def keyPressEvent(self, e): + if e.key() == Qt.Key_Return: + return + return QDialog.keyPressEvent(self, e) + + def find(self, backwards=False): + i = self.view.currentIndex().row() + if i < 0: i = 0 + q = icu_lower(unicode(self.search.text())).strip() + if not q: return + r = (xrange(i-1, -1, -1) if backwards else xrange(i+1, + len(self.families))) + for j in r: + f = self.families[j] + if q in icu_lower(f): + self.set_current(j) + return + + def find_next(self): + self.find() + + def find_previous(self): + self.find(backwards=True) + def build_font_list(self): try: self.families = list(self.font_scanner.find_font_families()) diff --git a/src/calibre/gui2/widgets.py b/src/calibre/gui2/widgets.py index dfbcbdcbf0..7730d2d733 100644 --- a/src/calibre/gui2/widgets.py +++ b/src/calibre/gui2/widgets.py @@ -3,18 +3,16 @@ __copyright__ = '2008, Kovid Goyal ' ''' Miscellaneous widgets used in the GUI ''' -import re, traceback, os +import re, os from PyQt4.Qt import (QIcon, QFont, QLabel, QListWidget, QAction, QListWidgetItem, QTextCharFormat, QApplication, QSyntaxHighlighter, QCursor, QColor, QWidget, QPixmap, QSplitterHandle, QToolButton, - QAbstractListModel, QVariant, Qt, SIGNAL, pyqtSignal, QRegExp, QSize, - QSplitter, QPainter, QLineEdit, QComboBox, QPen, QGraphicsScene, QMenu, - QStringListModel, QCompleter, QStringList, QTimer, QRect, - QGraphicsView, QByteArray) + QVariant, Qt, SIGNAL, pyqtSignal, QRegExp, QSize, QSplitter, QPainter, + QLineEdit, QComboBox, QPen, QGraphicsScene, QMenu, QStringListModel, + QCompleter, QStringList, QTimer, QRect, QGraphicsView, QByteArray) -from calibre.constants import iswindows -from calibre.gui2 import (NONE, error_dialog, pixmap_to_data, gprefs, +from calibre.gui2 import (error_dialog, pixmap_to_data, gprefs, warning_dialog) from calibre.gui2.filename_pattern_ui import Ui_Form from calibre import fit_image @@ -348,43 +346,6 @@ class CoverView(QGraphicsView, ImageDropMixin): # {{{ # }}} -class FontFamilyModel(QAbstractListModel): # {{{ - - def __init__(self, *args): - QAbstractListModel.__init__(self, *args) - from calibre.utils.fonts.scanner import font_scanner - try: - self.families = font_scanner.find_font_families() - except: - self.families = [] - print 'WARNING: Could not load fonts' - traceback.print_exc() - # Restrict to Qt families as Qt tends to crash - self.families[:0] = [_('None')] - self.font = QFont('Arial' if iswindows else 'sansserif') - - def rowCount(self, *args): - return len(self.families) - - def data(self, index, role): - try: - family = self.families[index.row()] - except: - traceback.print_exc() - return NONE - if role == Qt.DisplayRole: - return QVariant(family) - if role == Qt.FontRole: - # If a user chooses some non standard font as the interface font, - # rendering some font names causes Qt to crash, so return what is - # hopefully a "safe" font - return QVariant(self.font) - return NONE - - def index_of(self, family): - return self.families.index(family.strip()) -# }}} - # BasicList {{{ class BasicListItem(QListWidgetItem): From b306cfb3ae91ca7c14f0eadbeda464c945d4b826 Mon Sep 17 00:00:00 2001 From: GRiker Date: Sat, 3 Nov 2012 08:23:08 -0700 Subject: [PATCH 081/107] Fixed regression with tags used for catalog prefixes --- src/calibre/library/catalogs/epub_mobi_builder.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/calibre/library/catalogs/epub_mobi_builder.py b/src/calibre/library/catalogs/epub_mobi_builder.py index fb7bda13cf..a04e1bd868 100644 --- a/src/calibre/library/catalogs/epub_mobi_builder.py +++ b/src/calibre/library/catalogs/epub_mobi_builder.py @@ -582,7 +582,10 @@ class CatalogBuilder(object): if rule['field'].lower() == 'tags': if rule['pattern'].lower() in map(unicode.lower,record['tags']): if self.opts.verbose: - _log_prefix_rule_match_info(rule, record, rule['pattern']) + self.opts.log.info(" %s '%s' by %s (%s: Tags includes '%s')" % + (rule['prefix'],record['title'], + record['authors'][0], rule['name'], + rule['pattern'])) return rule['prefix'] # Regex match for custom field From ace82b046f77711268e11ddd5ccee387130c4722 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 4 Nov 2012 09:33:48 +0530 Subject: [PATCH 082/107] Nicer error message when search query string is too long --- src/calibre/utils/search_query_parser.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/calibre/utils/search_query_parser.py b/src/calibre/utils/search_query_parser.py index a937e055ac..4beae97a41 100644 --- a/src/calibre/utils/search_query_parser.py +++ b/src/calibre/utils/search_query_parser.py @@ -212,7 +212,10 @@ class SearchQueryParser(object): # another search. def _parse(self, query, candidates=None): self.recurse_level += 1 - res = self._parser.parseString(query)[0] + try: + res = self._parser.parseString(query)[0] + except RuntimeError: + raise ParseException('Failed to parse query, recursion limit reached: %r'%query) if candidates is None: candidates = self.universal_set() t = self.evaluate(res, candidates) From c590706bed55ee2908bad0d84d8cda7b151342bf Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 4 Nov 2012 09:35:22 +0530 Subject: [PATCH 083/107] ... --- src/calibre/utils/search_query_parser.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/calibre/utils/search_query_parser.py b/src/calibre/utils/search_query_parser.py index 4beae97a41..cbf1e1b245 100644 --- a/src/calibre/utils/search_query_parser.py +++ b/src/calibre/utils/search_query_parser.py @@ -215,7 +215,8 @@ class SearchQueryParser(object): try: res = self._parser.parseString(query)[0] except RuntimeError: - raise ParseException('Failed to parse query, recursion limit reached: %r'%query) + import repr + raise ParseException('Failed to parse query, recursion limit reached: %s'%repr(query)) if candidates is None: candidates = self.universal_set() t = self.evaluate(res, candidates) From 4fa4a7d9e02616ff695312c9935532e4bc86b5da Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 4 Nov 2012 09:46:59 +0530 Subject: [PATCH 084/107] Edit metadata dialog: Add a clear tags button to remove all tags with a single click --- src/calibre/gui2/metadata/single.py | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/calibre/gui2/metadata/single.py b/src/calibre/gui2/metadata/single.py index af56e2e657..a736f9fb27 100644 --- a/src/calibre/gui2/metadata/single.py +++ b/src/calibre/gui2/metadata/single.py @@ -188,6 +188,10 @@ class MetadataSingleDialogBase(ResizableDialog): self.tags_editor_button.setToolTip(_('Open Tag Editor')) self.tags_editor_button.setIcon(QIcon(I('chapters.png'))) self.tags_editor_button.clicked.connect(self.tags_editor) + self.clear_tags_button = QToolButton(self) + self.clear_tags_button.setToolTip(_('Clear all tags')) + self.clear_tags_button.setIcon(QIcon(I('trash.png'))) + self.clear_tags_button.clicked.connect(self.tags.clear) self.basic_metadata_widgets.append(self.tags) self.identifiers = IdentifiersEdit(self) @@ -656,9 +660,10 @@ class MetadataSingleDialog(MetadataSingleDialogBase): # {{{ l.addItem(self.tabs[0].spc_one, 1, 0, 1, 3) sto(self.cover.buttons[-1], self.rating) create_row2(1, self.rating) - sto(self.rating, self.tags) - create_row2(2, self.tags, self.tags_editor_button) - sto(self.tags_editor_button, self.paste_isbn_button) + sto(self.rating, self.tags_editor_button) + sto(self.tags_editor_button, self.tags) + create_row2(2, self.tags, self.clear_tags_button, front_button=self.tags_editor_button) + sto(self.clear_tags_button, self.paste_isbn_button) sto(self.paste_isbn_button, self.identifiers) create_row2(3, self.identifiers, self.clear_identifiers_button, front_button=self.paste_isbn_button) @@ -761,6 +766,7 @@ class MetadataSingleDialogAlt1(MetadataSingleDialogBase): # {{{ tl.addWidget(self.swap_title_author_button, 0, 0, 2, 1) tl.addWidget(self.manage_authors_button, 2, 0, 1, 1) tl.addWidget(self.paste_isbn_button, 12, 0, 1, 1) + tl.addWidget(self.tags_editor_button, 6, 0, 1, 1) create_row(0, self.title, self.title_sort, button=self.deduce_title_sort_button, span=2, @@ -773,7 +779,7 @@ class MetadataSingleDialogAlt1(MetadataSingleDialogBase): # {{{ create_row(4, self.series, self.series_index, button=self.clear_series_button, icon='trash.png') create_row(5, self.series_index, self.tags) - create_row(6, self.tags, self.rating, button=self.tags_editor_button) + create_row(6, self.tags, self.rating, button=self.clear_tags_button) create_row(7, self.rating, self.pubdate) create_row(8, self.pubdate, self.publisher, button=self.pubdate.clear_button, icon='trash.png') @@ -785,7 +791,8 @@ class MetadataSingleDialogAlt1(MetadataSingleDialogBase): # {{{ button=self.clear_identifiers_button, icon='trash.png') sto(self.clear_identifiers_button, self.swap_title_author_button) sto(self.swap_title_author_button, self.manage_authors_button) - sto(self.manage_authors_button, self.paste_isbn_button) + sto(self.manage_authors_button, self.tags_editor_button) + sto(self.tags_editor_button, self.paste_isbn_button) tl.addItem(QSpacerItem(1, 1, QSizePolicy.Fixed, QSizePolicy.Expanding), 13, 1, 1 ,1) @@ -896,6 +903,7 @@ class MetadataSingleDialogAlt2(MetadataSingleDialogBase): # {{{ tl.addWidget(self.swap_title_author_button, 0, 0, 2, 1) tl.addWidget(self.manage_authors_button, 2, 0, 2, 1) tl.addWidget(self.paste_isbn_button, 12, 0, 1, 1) + tl.addWidget(self.tags_editor_button, 6, 0, 1, 1) create_row(0, self.title, self.title_sort, button=self.deduce_title_sort_button, span=2, @@ -908,7 +916,7 @@ class MetadataSingleDialogAlt2(MetadataSingleDialogBase): # {{{ create_row(4, self.series, self.series_index, button=self.clear_series_button, icon='trash.png') create_row(5, self.series_index, self.tags) - create_row(6, self.tags, self.rating, button=self.tags_editor_button) + create_row(6, self.tags, self.rating, button=self.clear_tags_button) create_row(7, self.rating, self.pubdate) create_row(8, self.pubdate, self.publisher, button=self.pubdate.clear_button, icon='trash.png') @@ -920,7 +928,8 @@ class MetadataSingleDialogAlt2(MetadataSingleDialogBase): # {{{ button=self.clear_identifiers_button, icon='trash.png') sto(self.clear_identifiers_button, self.swap_title_author_button) sto(self.swap_title_author_button, self.manage_authors_button) - sto(self.manage_authors_button, self.paste_isbn_button) + sto(self.manage_authors_button, self.tags_editor_button) + sto(self.tags_editor_button, self.paste_isbn_button) tl.addItem(QSpacerItem(1, 1, QSizePolicy.Fixed, QSizePolicy.Expanding), 13, 1, 1 ,1) From 023ad0f43be35a149dad8087ae7eb211dfca0693 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 5 Nov 2012 11:26:28 +0530 Subject: [PATCH 085/107] Implement font subsetting. calibre can now subset all embedded fonts (i.e. reduce every embedded font to contain only the data for characters used in the book). This can often greatly reduce the size of the ebook file. Note that currently only fonts with TrueType outlines are supported not PostScript (CFF) outlines --- src/calibre/ebooks/conversion/cli.py | 1 + src/calibre/ebooks/conversion/plumber.py | 15 ++ src/calibre/ebooks/oeb/transforms/subset.py | 284 ++++++++++++++++++++ src/calibre/gui2/convert/look_and_feel.py | 2 +- src/calibre/gui2/convert/look_and_feel.ui | 9 +- 5 files changed, 309 insertions(+), 2 deletions(-) create mode 100644 src/calibre/ebooks/oeb/transforms/subset.py diff --git a/src/calibre/ebooks/conversion/cli.py b/src/calibre/ebooks/conversion/cli.py index 2aa0add3ee..d68c16c559 100644 --- a/src/calibre/ebooks/conversion/cli.py +++ b/src/calibre/ebooks/conversion/cli.py @@ -133,6 +133,7 @@ def add_pipeline_options(parser, plumber): [ 'base_font_size', 'disable_font_rescaling', 'font_size_mapping', 'embed_font_family', + 'subset_embedded_fonts', 'line_height', 'minimum_line_height', 'linearize_tables', 'extra_css', 'filter_css', diff --git a/src/calibre/ebooks/conversion/plumber.py b/src/calibre/ebooks/conversion/plumber.py index bfd2e36359..8d6a6e22f8 100644 --- a/src/calibre/ebooks/conversion/plumber.py +++ b/src/calibre/ebooks/conversion/plumber.py @@ -204,6 +204,17 @@ OptionRecommendation(name='embed_font_family', 'with some output formats, principally EPUB and AZW3.') ), +OptionRecommendation(name='subset_embedded_fonts', + recommended_value=False, level=OptionRecommendation.LOW, + help=_( + 'Subset all embedded fonts. Every embedded font is reduced ' + 'to contain only the glyphs used in this document. This decreases ' + 'the size of the font files. Useful if you are embedding a ' + 'particularly large font with lots of unused glyphs. Note that ' + 'subsetting is only supported for fonts that contain TrueType ' + 'outlines, not Postscript outlines.') + ), + OptionRecommendation(name='linearize_tables', recommended_value=False, level=OptionRecommendation.LOW, help=_('Some badly designed documents use tables to control the ' @@ -1112,6 +1123,10 @@ OptionRecommendation(name='search_replace', RemoveFakeMargins()(self.oeb, self.log, self.opts) RemoveAdobeMargins()(self.oeb, self.log, self.opts) + if self.opts.subset_embedded_fonts: + from calibre.ebooks.oeb.transforms.subset import SubsetFonts + SubsetFonts()(self.oeb, self.log, self.opts) + pr(0.9) self.flush() diff --git a/src/calibre/ebooks/oeb/transforms/subset.py b/src/calibre/ebooks/oeb/transforms/subset.py new file mode 100644 index 0000000000..a3e1b3bd10 --- /dev/null +++ b/src/calibre/ebooks/oeb/transforms/subset.py @@ -0,0 +1,284 @@ +#!/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 ' +__docformat__ = 'restructuredtext en' + +from collections import defaultdict + +from calibre.ebooks.oeb.base import urlnormalize +from calibre.utils.fonts.subset import subset, NoGlyphs, UnsupportedFont + +class SubsetFonts(object): + + ''' + Subset all embedded fonts. Must be run after CSS flattening, as it requires + CSS normalization and flattening to work. + ''' + + def __call__(self, oeb, log, opts): + self.oeb, self.log, self.opts = oeb, log, opts + + self.find_embedded_fonts() + if not self.embedded_fonts: + self.log.debug('No embedded fonts found') + return + self.find_style_rules() + self.find_font_usage() + + totals = [0, 0] + + def remove(font): + totals[1] += len(font['item'].data) + self.oeb.manifest.remove(font['item']) + font['rule'].parentStyleSheet.deleteRule(font['rule']) + + for font in self.embedded_fonts: + if not font['chars']: + self.log('The font %s is unused. Removing it.'%font['src']) + remove(font) + continue + try: + raw, old_stats, new_stats = subset(font['item'].data, font['chars']) + except NoGlyphs: + self.log('The font %s has no used glyphs. Removing it.'%font['src']) + remove(font) + continue + except UnsupportedFont as e: + self.log.warn('The font %s is unsupported for subsetting. %s'%( + font['src'], e)) + sz = len(font['item'].data) + totals[0] += sz + totals[1] += sz + else: + font['item'].data = raw + nlen = sum(new_stats.itervalues()) + olen = sum(old_stats.itervalues()) + self.log('Decreased the font %s to %.1f%% of its original size'% + (font['src'], nlen/olen *100)) + totals[0] += nlen + totals[1] += olen + + font['item'].unload_data_from_memory() + + if totals[0]: + self.log('Reduced total font size to %.1f%% of original'% + (totals[0]/totals[1] * 100)) + + def get_font_properties(self, rule, default=None): + ''' + Given a CSS rule, extract normalized font properties from + it. Note that shorthand font property should already have been expanded + by the CSS flattening code. + ''' + props = {} + s = rule.style + for q in ('font-family', 'src', 'font-weight', 'font-stretch', + 'font-style'): + g = 'uri' if q == 'src' else 'value' + try: + val = s.getProperty(q).propertyValue[0] + val = getattr(val, g) + if q == 'font-family': + val = [x.value for x in s.getProperty(q).propertyValue] + if val and val[0] == 'inherit': + val = None + except (IndexError, KeyError, AttributeError, TypeError, ValueError): + val = None if q in {'src', 'font-family'} else default + if q in {'font-weight', 'font-stretch', 'font-style'}: + val = val.lower() if val else val + if val == 'inherit': + val = default + if q == 'font-weight': + val = {'normal':'400', 'bold':'700'}.get(val, val) + if val not in {'100', '200', '300', '400', '500', '600', '700', + '800', '900', 'bolder', 'lighter'}: + val = default + if val == 'normal': val = '400' + elif q == 'font-style': + if val not in {'normal', 'italic', 'oblique'}: + val = default + elif q == 'font-stretch': + if val not in { 'normal', 'ultra-condensed', 'extra-condensed', + 'condensed', 'semi-condensed', 'semi-expanded', + 'expanded', 'extra-expanded', 'ultra-expanded'}: + val = default + props[q] = val + return props + + def find_embedded_fonts(self): + ''' + Find all @font-face rules and extract the relevant info from them. + ''' + self.embedded_fonts = [] + for item in self.oeb.manifest: + if not hasattr(item.data, 'cssRules'): continue + for i, rule in enumerate(item.data.cssRules): + if rule.type != rule.FONT_FACE_RULE: + continue + props = self.get_font_properties(rule, default='normal') + if not props['font-family'] or not props['src']: + continue + + path = item.abshref(props['src']) + ff = self.oeb.manifest.hrefs.get(urlnormalize(path), None) + if not ff: + continue + props['item'] = ff + if props['font-weight'] in {'bolder', 'lighter'}: + props['font-weight'] = '400' + props['weight'] = int(props['font-weight']) + props['chars'] = set() + props['rule'] = rule + self.embedded_fonts.append(props) + + def find_style_rules(self): + ''' + Extract all font related style information from all stylesheets into a + dict mapping classes to font properties specified by that class. All + the heavy lifting has already been done by the CSS flattening code. + ''' + rules = defaultdict(dict) + for item in self.oeb.manifest: + if not hasattr(item.data, 'cssRules'): continue + for i, rule in enumerate(item.data.cssRules): + if rule.type != rule.STYLE_RULE: + continue + props = {k:v for k,v in + self.get_font_properties(rule).iteritems() if v} + if not props: + continue + for sel in rule.selectorList: + sel = sel.selectorText + if sel and sel.startswith('.'): + # We dont care about pseudo-selectors as the worst that + # can happen is some extra characters will remain in + # the font + sel = sel.partition(':')[0] + rules[sel[1:]].update(props) + + self.style_rules = dict(rules) + + def find_font_usage(self): + for item in self.oeb.manifest: + if not hasattr(item.data, 'xpath'): continue + for body in item.data.xpath('//*[local-name()="body"]'): + base = {'font-family':['serif'], 'font-weight': '400', + 'font-style':'normal', 'font-stretch':'normal'} + self.find_usage_in(body, base) + + def elem_style(self, cls, inherited_style): + ''' + Find the effective style for the given element. + ''' + classes = cls.split() + style = inherited_style.copy() + for cls in classes: + style.update(self.style_rules.get(cls, {})) + wt = style.get('font-weight', None) + pwt = inherited_style.get('font-weight', '400') + if wt == 'bolder': + style['font-weight'] = { + '100':'400', + '200':'400', + '300':'400', + '400':'700', + '500':'700', + }.get(pwt, '900') + elif wt == 'lighter': + style['font-weight'] = { + '600':'400', '700':'400', + '800':'700', '900':'700'}.get(pwt, '100') + + return style + + def used_font(self, style): + ''' + Given a style find the embedded font that matches it. Returns None if + no match is found ( can happen if not family matches). + ''' + ff = style.get('font-family', []) + lnames = {x.lower() for x in ff} + matching_set = [] + + # Filter on font-family + for ef in self.embedded_fonts: + flnames = {x.lower() for x in ef.get('font-family', [])} + if not lnames.intersection(flnames): + continue + matching_set.append(ef) + if not matching_set: + return None + + # Filter on font-stretch + widths = {x:i for i, x in enumerate(( 'ultra-condensed', + 'extra-condensed', 'condensed', 'semi-condensed', 'normal', + 'semi-expanded', 'expanded', 'extra-expanded', 'ultra-expanded' + ))} + + width = widths[style.get('font-stretch', 'normal')] + for f in matching_set: + f['width'] = widths[style.get('font-stretch', 'normal')] + + min_dist = min(abs(width-f['width']) for f in matching_set) + nearest = [f for f in matching_set if abs(width-f['width']) == + min_dist] + if width <= 4: + lmatches = [f for f in nearest if f['width'] <= width] + else: + lmatches = [f for f in nearest if f['width'] >= width] + matching_set = (lmatches or nearest) + + # Filter on font-style + fs = style.get('font-style', 'normal') + order = { + 'oblique':['oblique', 'italic', 'normal'], + 'normal':['normal', 'oblique', 'italic'] + }.get(fs, ['italic', 'oblique', 'normal']) + for q in order: + matches = [f for f in matching_set if f.get('font-style', 'normal') + == q] + if matches: + matching_set = matches + break + + # Filter on font weight + fw = int(style.get('font-weight', '400')) + if fw == 400: + q = [400, 500, 300, 200, 100, 600, 700, 800, 900] + elif fw == 500: + q = [500, 400, 300, 200, 100, 600, 700, 800, 900] + elif fw < 400: + q = [fw] + list(xrange(fw-100, -100, -100)) + list(xrange(fw+100, + 100, 1000)) + else: + q = [fw] + list(xrange(fw+100, 100, 1000)) + list(xrange(fw-100, + -100, -100)) + for wt in q: + matches = [f for f in matching_set if f['weight'] == wt] + if matches: + return matches[0] + + def find_chars(self, elem): + ans = set() + if elem.text: + ans |= set(elem.text) + for child in elem: + if child.tail: + ans |= set(child.tail) + return ans + + def find_usage_in(self, elem, inherited_style): + style = self.elem_style(elem.get('class', ''), inherited_style) + for child in elem: + self.find_usage_in(child, style) + font = self.used_font(style) + if font: + chars = self.find_chars(elem) + if chars: + font['chars'] |= chars + + diff --git a/src/calibre/gui2/convert/look_and_feel.py b/src/calibre/gui2/convert/look_and_feel.py index 1609a0add3..24ee288cc6 100644 --- a/src/calibre/gui2/convert/look_and_feel.py +++ b/src/calibre/gui2/convert/look_and_feel.py @@ -32,7 +32,7 @@ class LookAndFeelWidget(Widget, Ui_Form): Widget.__init__(self, parent, ['change_justification', 'extra_css', 'base_font_size', 'font_size_mapping', 'line_height', 'minimum_line_height', - 'embed_font_family', + 'embed_font_family', 'subset_embedded_fonts', 'smarten_punctuation', 'unsmarten_punctuation', 'disable_font_rescaling', 'insert_blank_line', 'remove_paragraph_spacing', diff --git a/src/calibre/gui2/convert/look_and_feel.ui b/src/calibre/gui2/convert/look_and_feel.ui index 1d3d1c1db3..16f781cb2c 100644 --- a/src/calibre/gui2/convert/look_and_feel.ui +++ b/src/calibre/gui2/convert/look_and_feel.ui @@ -406,7 +406,14 @@ - + + + + + + &Subset all embedded fonts + + From 7b4fe7f8ee063d4fd550cef0ed5227cb8aad5af6 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 5 Nov 2012 13:39:40 +0530 Subject: [PATCH 086/107] Round-tripping for the sfnt container format --- src/calibre/utils/fonts/sfnt/__init__.py | 21 +++++ src/calibre/utils/fonts/sfnt/container.py | 102 ++++++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 src/calibre/utils/fonts/sfnt/__init__.py create mode 100644 src/calibre/utils/fonts/sfnt/container.py diff --git a/src/calibre/utils/fonts/sfnt/__init__.py b/src/calibre/utils/fonts/sfnt/__init__.py new file mode 100644 index 0000000000..6e7efced5a --- /dev/null +++ b/src/calibre/utils/fonts/sfnt/__init__.py @@ -0,0 +1,21 @@ +#!/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 ' +__docformat__ = 'restructuredtext en' + + +def align_block(raw, multiple=4, pad=b'\0'): + ''' + Return raw with enough pad bytes append to ensure its length is a multiple + of 4. + ''' + extra = len(raw) % multiple + if extra == 0: return raw + return raw + pad*(multiple - extra) + + + diff --git a/src/calibre/utils/fonts/sfnt/container.py b/src/calibre/utils/fonts/sfnt/container.py new file mode 100644 index 0000000000..61f3af7c0f --- /dev/null +++ b/src/calibre/utils/fonts/sfnt/container.py @@ -0,0 +1,102 @@ +#!/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 ' +__docformat__ = 'restructuredtext en' + +from math import log +from struct import pack, calcsize +from io import BytesIO + +from calibre.utils.fonts.utils import (get_tables, checksum_of_block, + verify_checksums) +from calibre.utils.fonts.sfnt import align_block + +class UnsupportedFont(ValueError): + pass + +class UnknownTable(object): + + def __init__(self, raw): + self.raw = raw + + def __call__(self): + return self.raw + +class Sfnt(object): + + def __init__(self, raw): + self.sfnt_version = raw[:4] + if self.sfnt_version not in {b'\x00\x01\x00\x00', b'OTTO', b'true', + b'type1'}: + raise UnsupportedFont('Font has unknown sfnt version: %r'%self.sfnt_version) + self.read_tables(raw) + + def read_tables(self, raw): + self.tables = {} + for table_tag, table, table_index, table_offset, table_checksum in get_tables(raw): + self.tables[table_tag] = { + }.get(table_tag, UnknownTable)(table) + + def __call__(self): + stream = BytesIO() + + def spack(*args): + stream.write(pack(*args)) + + stream.seek(0) + + # Write header + num_tables = len(self.tables) + ln2 = int(log(num_tables, 2)) + srange = (2**ln2) * 16 + spack(b'>4s4H', + self.sfnt_version, num_tables, srange, ln2, num_tables * 16 - srange) + + # Write tables + head_offset = None + table_data = [] + offset = stream.tell() + ( calcsize(b'>4s3L') * num_tables ) + for tag in sorted(self.tables): + table = self.tables[tag] + raw = table() + table_len = len(raw) + if tag == b'head': + head_offset = offset + raw = raw[:8] + b'\0\0\0\0' + raw[12:] + raw = align_block(raw) + checksum = checksum_of_block(raw) + spack(b'>4s3L', tag, checksum, offset, table_len) + offset += len(raw) + table_data.append(raw) + + for x in table_data: + stream.write(x) + + checksum = checksum_of_block(stream.getvalue()) + q = (0xB1B0AFBA - checksum) & 0xffffffff + stream.seek(head_offset + 8) + spack(b'>L', q) + + return stream.getvalue() + +def test_roundtrip(ff=None): + if ff is None: + data = P('fonts/liberation/LiberationSerif-Regular.ttf', data=True) + else: + with open(ff, 'rb') as f: + data = f.read() + rd = Sfnt(data)() + verify_checksums(rd) + if data[:12] != rd[:12]: + raise ValueError('Roundtripping failed, font header not the same') + if len(data) != len(rd): + raise ValueError('Roundtripping failed, size different') + +if __name__ == '__main__': + import sys + test_roundtrip(sys.argv[-1]) + From f2e6dd1cce4f15f488077ea66e6450b5138307dc Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 5 Nov 2012 13:40:38 +0530 Subject: [PATCH 087/107] ... --- src/calibre/utils/fonts/sfnt/container.py | 4 +--- src/calibre/utils/fonts/sfnt/errors.py | 12 ++++++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 src/calibre/utils/fonts/sfnt/errors.py diff --git a/src/calibre/utils/fonts/sfnt/container.py b/src/calibre/utils/fonts/sfnt/container.py index 61f3af7c0f..30c5970392 100644 --- a/src/calibre/utils/fonts/sfnt/container.py +++ b/src/calibre/utils/fonts/sfnt/container.py @@ -14,9 +14,7 @@ from io import BytesIO from calibre.utils.fonts.utils import (get_tables, checksum_of_block, verify_checksums) from calibre.utils.fonts.sfnt import align_block - -class UnsupportedFont(ValueError): - pass +from calibre.utils.fonts.sfnt.errors import UnsupportedFont class UnknownTable(object): diff --git a/src/calibre/utils/fonts/sfnt/errors.py b/src/calibre/utils/fonts/sfnt/errors.py new file mode 100644 index 0000000000..a002192863 --- /dev/null +++ b/src/calibre/utils/fonts/sfnt/errors.py @@ -0,0 +1,12 @@ +#!/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 ' +__docformat__ = 'restructuredtext en' + +class UnsupportedFont(ValueError): + pass + From a7f054ec5cce155131935a96c7157d2450f69348 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 5 Nov 2012 23:42:07 +0530 Subject: [PATCH 088/107] Start work on pure python implementation of font subsetting, since I really dont like sfntly --- src/calibre/utils/fonts/sfnt/__init__.py | 44 ++++ src/calibre/utils/fonts/sfnt/cmap.py | 235 ++++++++++++++++++++++ src/calibre/utils/fonts/sfnt/container.py | 30 ++- src/calibre/utils/fonts/sfnt/head.py | 53 +++++ src/calibre/utils/fonts/sfnt/loca.py | 31 +++ src/calibre/utils/fonts/sfnt/maxp.py | 58 ++++++ src/calibre/utils/fonts/sfnt/subset.py | 50 +++++ 7 files changed, 491 insertions(+), 10 deletions(-) create mode 100644 src/calibre/utils/fonts/sfnt/cmap.py create mode 100644 src/calibre/utils/fonts/sfnt/head.py create mode 100644 src/calibre/utils/fonts/sfnt/loca.py create mode 100644 src/calibre/utils/fonts/sfnt/maxp.py create mode 100644 src/calibre/utils/fonts/sfnt/subset.py diff --git a/src/calibre/utils/fonts/sfnt/__init__.py b/src/calibre/utils/fonts/sfnt/__init__.py index 6e7efced5a..7a40e7fd15 100644 --- a/src/calibre/utils/fonts/sfnt/__init__.py +++ b/src/calibre/utils/fonts/sfnt/__init__.py @@ -7,6 +7,7 @@ __license__ = 'GPL v3' __copyright__ = '2012, Kovid Goyal ' __docformat__ = 'restructuredtext en' +from datetime import datetime, timedelta def align_block(raw, multiple=4, pad=b'\0'): ''' @@ -17,5 +18,48 @@ def align_block(raw, multiple=4, pad=b'\0'): if extra == 0: return raw return raw + pad*(multiple - extra) +class UnknownTable(object): + + def __init__(self, raw): + self.raw = raw + + def __call__(self): + return self.raw + +class DateTimeProperty(object): + + def __init__(self, name): + self.name = name + + def __get__(self, obj, type=None): + return datetime(1904, 1, 1) + timedelta(seconds=getattr(obj, + self.name)) + + def __set__(self, obj, val): + td = val - datetime(1904, 1, 1) + setattr(obj, self.name, int(td.total_seconds())) + +class FixedProperty(object): + + def __init__(self, name): + self.name = name + + def __get__(self, obj, type=None): + val = getattr(obj, self.name) + return val * (2**-16) + + def __set__(self, obj, val): + return int(round(val*(2**16))) + +def max_power_of_two(x): + """ + Return the highest exponent of two, so that + (2 ** exponent) <= x + """ + exponent = 0 + while x: + x = x >> 1 + exponent += 1 + return max(exponent - 1, 0) diff --git a/src/calibre/utils/fonts/sfnt/cmap.py b/src/calibre/utils/fonts/sfnt/cmap.py new file mode 100644 index 0000000000..94b0e0eaf5 --- /dev/null +++ b/src/calibre/utils/fonts/sfnt/cmap.py @@ -0,0 +1,235 @@ +#!/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 ' +__docformat__ = 'restructuredtext en' + +# Note that the code for creating a BMP table (cmap format 4) is taken with +# thanks from the fonttools project (BSD licensed). + +from struct import unpack_from, calcsize, pack +from collections import OrderedDict + +from calibre.utils.fonts.utils import get_bmp_glyph_ids +from calibre.utils.fonts.sfnt import UnknownTable, max_power_of_two +from calibre.utils.fonts.sfnt.errors import UnsupportedFont + +def split_range(start_code, end_code, cmap): # {{{ + # Try to split a range of character codes into subranges with consecutive + # glyph IDs in such a way that the cmap4 subtable can be stored "most" + # efficiently. + if start_code == end_code: + return [], [end_code] + + last_id = cmap[start_code] + last_code = start_code + in_order = None + ordered_begin = None + sub_ranges = [] + + # Gather subranges in which the glyph IDs are consecutive. + for code in range(start_code + 1, end_code + 1): + glyph_id = cmap[code] + + if glyph_id - 1 == last_id: + if in_order is None or not in_order: + in_order = 1 + ordered_begin = last_code + else: + if in_order: + in_order = 0 + sub_ranges.append((ordered_begin, last_code)) + ordered_begin = None + + last_id = glyph_id + last_code = code + + if in_order: + sub_ranges.append((ordered_begin, last_code)) + assert last_code == end_code + + # Now filter out those new subranges that would only make the data bigger. + # A new segment cost 8 bytes, not using a new segment costs 2 bytes per + # character. + new_ranges = [] + for b, e in sub_ranges: + if b == start_code and e == end_code: + break # the whole range, we're fine + if b == start_code or e == end_code: + threshold = 4 # split costs one more segment + else: + threshold = 8 # split costs two more segments + if (e - b + 1) > threshold: + new_ranges.append((b, e)) + sub_ranges = new_ranges + + if not sub_ranges: + return [], [end_code] + + if sub_ranges[0][0] != start_code: + sub_ranges.insert(0, (start_code, sub_ranges[0][0] - 1)) + if sub_ranges[-1][1] != end_code: + sub_ranges.append((sub_ranges[-1][1] + 1, end_code)) + + # Fill the "holes" in the segments list -- those are the segments in which + # the glyph IDs are _not_ consecutive. + i = 1 + while i < len(sub_ranges): + if sub_ranges[i-1][1] + 1 != sub_ranges[i][0]: + sub_ranges.insert(i, (sub_ranges[i-1][1] + 1, sub_ranges[i][0] - 1)) + i = i + 1 + i = i + 1 + + # Transform the ranges into start_code/end_code lists. + start = [] + end = [] + for b, e in sub_ranges: + start.append(b) + end.append(e) + start.pop(0) + + assert len(start) + 1 == len(end) + return start, end +# }}} + +def set_id_delta(id_delta): # {{{ + # The lowest gid in glyphIndexArray, after subtracting id_delta, must be 1. + # id_delta is a short, and must be between -32K and 32K + # startCode can be between 0 and 64K-1, and the first glyph index can be between 1 and 64K-1 + # This means that we have a problem because we can need to assign to + # id_delta values + # between -(64K-2) and 64K -1. + # Since the final gi is reconstructed from the glyphArray GID by: + # (short)finalGID = (gid + id_delta) % 0x10000), + # we can get from a startCode of 0 to a final GID of 64 -1K by subtracting 1, and casting the + # negative number to an unsigned short. + # Similarly , we can get from a startCode of 64K-1 to a final GID of 1 by adding 2, because of + # the modulo arithmetic. + + if id_delta > 0x7FFF: + id_delta = id_delta - 0x10000 + elif id_delta < -0x7FFF: + id_delta = id_delta + 0x10000 + + return id_delta +# }}} + +class CmapTable(UnknownTable): + + def __init__(self, *args, **kwargs): + super(CmapTable, self).__init__(*args, **kwargs) + + self.version, self.num_tables = unpack_from(b'>HH', self.raw) + + self.tables = {} + + offset = 4 + sz = calcsize(b'>HHL') + recs = [] + for i in xrange(self.num_tables): + platform, encoding, table_offset = unpack_from(b'>HHL', self.raw, + offset) + offset += sz + recs.append((platform, encoding, table_offset)) + + self.bmp_table = None + + for i in xrange(len(recs)): + platform, encoding, offset = recs[i] + try: + next_offset = recs[i+1][-1] + except IndexError: + next_offset = len(self.raw) + table = self.raw[offset:next_offset] + fmt = unpack_from(b'>H', table)[0] + if platform == 3 and encoding == 1 and fmt == 4: + self.bmp_table = table + + def get_character_map(self, chars): + ''' + Get a mapping of character codes to glyph ids in the font. + ''' + if self.bmp_table is None: + raise UnsupportedFont('This font has no Windows BMP cmap subtable.' + ' Most likely a special purpose font.') + chars = list(set(chars)) + chars.sort() + ans = OrderedDict() + for i, glyph_id in enumerate(get_bmp_glyph_ids(self.bmp_table, 0, + chars)): + if glyph_id > 0: + ans[chars[i]] = glyph_id + return ans + + def set_character_map(self, cmap): + self.version, self.num_tables = 0, 1 + fmt = b'>7H' + codes = list(cmap.iterkeys()) + codes.sort() + + if not codes: + start_code = [0xffff] + end_code = [0xffff] + else: + last_code = codes[0] + end_code = [] + start_code = [last_code] + + for code in codes[1:]: + if code == last_code + 1: + last_code = code + continue + start, end = split_range(start_code[-1], last_code, cmap) + start_code.extend(start) + end_code.extend(end) + start_code.append(code) + last_code = code + end_code.append(last_code) + start_code.append(0xffff) + end_code.append(0xffff) + + id_delta = [] + id_range_offset = [] + glyph_index_array = [] + for i in xrange(len(end_code)-1): # skip the closing codes (0xffff) + indices = [] + for char_code in xrange(start_code[i], end_code[i] + 1): + indices.append(cmap[char_code]) + if (indices == xrange(indices[0], indices[0] + len(indices))): + id_delta_temp = set_id_delta(indices[0] - start_code[i]) + id_delta.append(id_delta_temp) + id_range_offset.append(0) + else: + id_delta.append(0) + id_range_offset.append(2 * (len(end_code) + + len(glyph_index_array) - i)) + glyph_index_array.extend(indices) + id_delta.append(1) # 0xffff + 1 == 0. So this end code maps to .notdef + id_range_offset.append(0) + + seg_count = len(end_code) + max_exponent = max_power_of_two(seg_count) + search_range = 2 * (2 ** max_exponent) + entry_selector = max_exponent + range_shift = 2 * seg_count - search_range + + char_code_array = end_code + [0] + start_code + char_code_array = pack(b'>%dH'%len(char_code_array), *char_code_array) + id_delta_array = pack(b'>%dh'%len(id_delta), *id_delta) + rest_array = id_range_offset + glyph_index_array + rest_array = pack(b'>%dH'%len(rest_array), *rest_array) + data = char_code_array + id_delta_array + rest_array + + length = calcsize(fmt) + len(data) + header = pack(fmt, 4, length, 0, + 2*seg_count, search_range, entry_selector, range_shift) + self.bmp_table = header + data + + fmt = b'>4HL' + offset = calcsize(fmt) + self.raw = pack(fmt, self.version, self.num_tables, 3, 1, offset) + \ + self.bmp_table + diff --git a/src/calibre/utils/fonts/sfnt/container.py b/src/calibre/utils/fonts/sfnt/container.py index 30c5970392..6b4be41739 100644 --- a/src/calibre/utils/fonts/sfnt/container.py +++ b/src/calibre/utils/fonts/sfnt/container.py @@ -7,22 +7,17 @@ __license__ = 'GPL v3' __copyright__ = '2012, Kovid Goyal ' __docformat__ = 'restructuredtext en' -from math import log from struct import pack, calcsize from io import BytesIO from calibre.utils.fonts.utils import (get_tables, checksum_of_block, verify_checksums) -from calibre.utils.fonts.sfnt import align_block +from calibre.utils.fonts.sfnt import align_block, UnknownTable, max_power_of_two from calibre.utils.fonts.sfnt.errors import UnsupportedFont -class UnknownTable(object): - - def __init__(self, raw): - self.raw = raw - - def __call__(self): - return self.raw +from calibre.utils.fonts.sfnt.head import HeadTable +from calibre.utils.fonts.sfnt.maxp import MaxpTable +from calibre.utils.fonts.sfnt.loca import LocaTable class Sfnt(object): @@ -37,8 +32,23 @@ class Sfnt(object): self.tables = {} for table_tag, table, table_index, table_offset, table_checksum in get_tables(raw): self.tables[table_tag] = { + b'head' : HeadTable, + b'maxp' : MaxpTable, + b'loca' : LocaTable, }.get(table_tag, UnknownTable)(table) + def __getitem__(self, key): + return self.tables[key] + + def __contains__(self, key): + return key in self.tables + + def __delitem__(self, key): + del self.tables[key] + + def pop(self, key, default=None): + return self.tables.pop(key, default) + def __call__(self): stream = BytesIO() @@ -49,7 +59,7 @@ class Sfnt(object): # Write header num_tables = len(self.tables) - ln2 = int(log(num_tables, 2)) + ln2 = max_power_of_two(num_tables) srange = (2**ln2) * 16 spack(b'>4s4H', self.sfnt_version, num_tables, srange, ln2, num_tables * 16 - srange) diff --git a/src/calibre/utils/fonts/sfnt/head.py b/src/calibre/utils/fonts/sfnt/head.py new file mode 100644 index 0000000000..8b9c732e14 --- /dev/null +++ b/src/calibre/utils/fonts/sfnt/head.py @@ -0,0 +1,53 @@ +#!/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 ' +__docformat__ = 'restructuredtext en' + +from itertools import izip +from struct import unpack_from, pack + +from calibre.utils.fonts.sfnt import UnknownTable, DateTimeProperty + +class HeadTable(UnknownTable): + + created = DateTimeProperty('_created') + modified = DateTimeProperty('_modified') + + def __init__(self, *args, **kwargs): + super(HeadTable, self).__init__(*args, **kwargs) + + field_types = ( + 'version_number' , 'L', + 'font_revision' , 'L', + 'checksum_adjustment' , 'L', + 'magic_number' , 'L', + 'flags' , 'H', + 'units_per_em' , 'H', + '_created' , 'q', + '_modified' , 'q', + 'x_min' , 'H', + 'y_min' , 'H', + 'x_max' , 'H', + 'y_max' , 'H', + 'mac_style' , 'H', + 'lowest_rec_ppem' , 'H', + 'font_direction_hint' , 'h', + 'index_to_loc_format' , 'h', + 'glyph_data_format' , 'h' + ) + + self._fmt = ('>%s'%(''.join(field_types[1::2]))).encode('ascii') + self._fields = field_types[0::2] + + for f, val in izip(self._fields, unpack_from(self._fmt, self.raw)): + setattr(self, f, val) + + def update(self): + vals = [getattr(self, f) for f in self._fields] + self.raw = pack(self._fmt, *vals) + + diff --git a/src/calibre/utils/fonts/sfnt/loca.py b/src/calibre/utils/fonts/sfnt/loca.py new file mode 100644 index 0000000000..f6ca903b83 --- /dev/null +++ b/src/calibre/utils/fonts/sfnt/loca.py @@ -0,0 +1,31 @@ +#!/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 ' +__docformat__ = 'restructuredtext en' + +from struct import calcsize, unpack_from + +from calibre.utils.fonts.sfnt import UnknownTable + +class LocaTable(UnknownTable): + + def load_offsets(self, head_table, maxp_table): + fmt = 'H' if head_table.index_to_loc_format == 0 else 'L' + num_glyphs = maxp_table.num_glyphs + sz = calcsize(('>%s'%fmt).encode('ascii')) + num = len(self.raw)//sz + self.offset_map = unpack_from(('>%d%s'%(num, fmt)).encode('ascii'), + self.raw) + self.offset_map = self.offset_map[:num_glyphs+1] + if fmt == 'H': + self.offset_map = [2*i for i in self.offset_map] + + def glyph_location(self, glyph_id): + offset = self.offset_map[glyph_id] + next_offset = self.offset_map[glyph_id+1] + return offset, next_offset - offset + diff --git a/src/calibre/utils/fonts/sfnt/maxp.py b/src/calibre/utils/fonts/sfnt/maxp.py new file mode 100644 index 0000000000..0e3450c699 --- /dev/null +++ b/src/calibre/utils/fonts/sfnt/maxp.py @@ -0,0 +1,58 @@ +#!/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 ' +__docformat__ = 'restructuredtext en' + +from itertools import izip +from struct import unpack_from, pack + +from calibre.utils.fonts.sfnt import UnknownTable +from calibre.utils.fonts.sfnt.errors import UnsupportedFont + +class MaxpTable(UnknownTable): + + def __init__(self, *args, **kwargs): + super(MaxpTable, self).__init__(*args, **kwargs) + + self._fmt = b'>LH' + self._version, self.num_glyphs = unpack_from(self._fmt, self.raw) + self.fields = ('_version', 'num_glyphs') + + if self._version >= 0x10000: + self.version = 0x10000 + vals = unpack_from(self._fmt, self.raw) + for f, val in izip(self.fields, vals): + setattr(self, f, val) + + @dynamic_property + def version(self): + def fget(self): + return self._version + def fset(self, val): + if val == 0x5000: + self._fmt = b'>LH' + self._fields = ('_version', 'num_glyphs') + elif val == 0x10000: + self.fields = ('_version', 'num_glyphs', 'max_points', + 'max_contours', 'max_composite_points', + 'max_composite_contours', 'max_zones', + 'max_twilight_points', 'max_storage', 'max_function_defs', + 'max_instruction_defs', 'max_stack_elements', + 'max_size_of_instructions', 'max_component_elements', + 'max_component_depth') + self._fmt = b'>LH' + b'H'*(len(self.fields)-2) + self._version = val + return property(fget=fget, fset=fset) + + def update(self): + if self._version > 0x10000: + raise UnsupportedFont('maxp table with version > 0x10000 not modifiable') + vals = [getattr(self, f) for f in self._fields] + self.raw = pack(self._fmt, *vals) + + + diff --git a/src/calibre/utils/fonts/sfnt/subset.py b/src/calibre/utils/fonts/sfnt/subset.py new file mode 100644 index 0000000000..085b6255e4 --- /dev/null +++ b/src/calibre/utils/fonts/sfnt/subset.py @@ -0,0 +1,50 @@ +#!/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 ' +__docformat__ = 'restructuredtext en' + +from calibre.utils.fonts.sfnt.container import Sfnt +from calibre.utils.fonts.sfnt.errors import UnsupportedFont + +def subset_truetype(sfnt, character_map): + loca = sfnt[b'loca'] + try: + head, maxp = sfnt[b'head'], sfnt[b'maxp'] + except KeyError: + raise UnsupportedFont('This font does not contain head and/or maxp tables') + loca.load_offsets(head, maxp) + +def subset(raw, individual_chars, ranges=()): + chars = list(map(ord, individual_chars)) + for r in ranges: + chars += list(xrange(ord(r[0]), ord(r[1])+1)) + + sfnt = Sfnt(raw) + # Remove the Digital Signature table since it is useless in a subset + # font anyway + sfnt.pop(b'DSIG', None) + + try: + cmap = sfnt[b'cmap'] + except KeyError: + raise UnsupportedFont('This font has no cmap table') + + # Get mapping of chars to glyph ids for all specified chars + character_map = cmap.get_character_map(chars) + # Restrict the cmap table to only contain entries for the specified chars + cmap.set_character_map(character_map) + + if b'loca' in sfnt and b'glyf' in sfnt: + subset_truetype(sfnt, character_map) + elif b'CFF ' in sfnt: + raise UnsupportedFont('This font contains PostScript outlines, ' + 'subsetting not supported') + else: + raise UnsupportedFont('This font does not contain TrueType ' + 'or PostScript outlines') + + From 5cdbd831af155fafdbf90d2f3f0f1e1f56f6d655 Mon Sep 17 00:00:00 2001 From: GRiker Date: Mon, 5 Nov 2012 15:10:25 -0700 Subject: [PATCH 089/107] Normalized genre names truncated to available width. --- .bzrignore | 1 + .../library/catalogs/epub_mobi_builder.py | 161 ++++++++++++------ 2 files changed, 110 insertions(+), 52 deletions(-) diff --git a/.bzrignore b/.bzrignore index aaacc9f58a..99d307fddc 100644 --- a/.bzrignore +++ b/.bzrignore @@ -35,3 +35,4 @@ nbproject/ .settings/ *.DS_Store calibre_plugins/ +./src/calibre/gui2/catalog/catalog_csv_xml.ui.autosave diff --git a/src/calibre/library/catalogs/epub_mobi_builder.py b/src/calibre/library/catalogs/epub_mobi_builder.py index a04e1bd868..58712cf3d3 100644 --- a/src/calibre/library/catalogs/epub_mobi_builder.py +++ b/src/calibre/library/catalogs/epub_mobi_builder.py @@ -14,11 +14,12 @@ from calibre.customize.conversion import DummyReporter from calibre.customize.ui import output_profiles from calibre.ebooks.BeautifulSoup import BeautifulSoup, BeautifulStoneSoup, Tag, NavigableString from calibre.ebooks.chardet import substitute_entites +from calibre.ebooks.metadata import author_to_author_sort from calibre.library.catalogs import AuthorSortMismatchException, EmptyCatalogException from calibre.ptempfile import PersistentTemporaryDirectory from calibre.utils.config import config_dir from calibre.utils.date import format_date, is_date_undefined, now as nowf -from calibre.utils.filenames import ascii_text +from calibre.utils.filenames import ascii_text, shorten_components_to from calibre.utils.icu import capitalize, collation_order, sort_key from calibre.utils.magick.draw import thumbnail from calibre.utils.zipfile import ZipFile @@ -109,6 +110,7 @@ class CatalogBuilder(object): self.stylesheet = stylesheet self.cache_dir = os.path.join(config_dir, 'caches', 'catalog') self.catalog_path = PersistentTemporaryDirectory("_epub_mobi_catalog", prefix='') + self.content_dir = os.path.join(self.catalog_path, "content") self.excluded_tags = self.get_excluded_tags() self.generate_for_kindle_azw3 = True if (_opts.fmt == 'azw3' and _opts.output_profile and @@ -127,12 +129,13 @@ class CatalogBuilder(object): self.books_by_title = None self.books_by_title_no_series_prefix = None self.books_to_catalog = None - self.content_dir = os.path.join(self.catalog_path, "content") self.current_step = 0.0 self.error = [] self.generate_recently_read = False self.genres = [] - self.genre_tags_dict = None + self.genre_tags_dict = \ + self.filter_db_tags(max_len = 245 - len("%s/Genre_.html" % self.content_dir)) \ + if self.opts.generate_genres else None self.html_filelist_1 = [] self.html_filelist_2 = [] self.merge_comments_rule = dict(zip(['field','position','hr'], @@ -505,7 +508,7 @@ class CatalogBuilder(object): if not os.path.isdir(images_path): os.makedirs(images_path) - def detect_author_sort_mismatches(self): + def detect_author_sort_mismatches(self, books_to_test): """ Detect author_sort mismatches. Sort by author, look for inconsistencies in author_sort among @@ -513,17 +516,18 @@ class CatalogBuilder(object): annoyance for EPUB. Inputs: - self.books_to_catalog (list): list of books to catalog + books_by_author (list): list of books to test, possibly unsorted Output: - self.books_by_author (list): sorted by author + (none) Exceptions: AuthorSortMismatchException: author_sort mismatch detected """ - self.books_by_author = sorted(list(self.books_to_catalog), key=self._kf_books_by_author_sorter_author) - authors = [(record['author'], record['author_sort']) for record in self.books_by_author] + books_by_author = sorted(list(books_to_test), key=self._kf_books_by_author_sorter_author) + + authors = [(record['author'], record['author_sort']) for record in books_by_author] current_author = authors[0] for (i,author) in enumerate(authors): if author != current_author and i: @@ -701,6 +705,7 @@ class CatalogBuilder(object): def fetch_books_by_author(self): """ Generate a list of books sorted by author. + For books with multiple authors, relist book with additional authors. Sort the database by author. Report author_sort inconsistencies as warning when building EPUB or MOBI, error when building MOBI. Collect a list of unique authors to self.authors. @@ -720,25 +725,29 @@ class CatalogBuilder(object): self.update_progress_full_step(_("Sorting database")) - self.detect_author_sort_mismatches() + books_by_author = list(self.books_to_catalog) + self.detect_author_sort_mismatches(books_by_author) + books_by_author = self.relist_multiple_authors(books_by_author) + + #books_by_author = sorted(list(books_by_author), key=self._kf_books_by_author_sorter_author) - # Sort authors using sort_key to normalize accented letters # Determine the longest author_sort length before sorting - asl = [i['author_sort'] for i in self.books_by_author] + asl = [i['author_sort'] for i in books_by_author] las = max(asl, key=len) - self.books_by_author = sorted(self.books_to_catalog, + + books_by_author = sorted(books_by_author, key=lambda x: sort_key(self._kf_books_by_author_sorter_author_sort(x, len(las)))) if self.DEBUG and self.opts.verbose: - tl = [i['title'] for i in self.books_by_author] + tl = [i['title'] for i in books_by_author] lt = max(tl, key=len) fs = '{:<6}{:<%d} {:<%d} {!s}' % (len(lt),len(las)) print(fs.format('','Title','Author','Series')) - for i in self.books_by_author: + for i in books_by_author: print(fs.format('', i['title'],i['author_sort'],i['series'])) # Build the unique_authors set from existing data - authors = [(record['author'], capitalize(record['author_sort'])) for record in self.books_by_author] + authors = [(record['author'], capitalize(record['author_sort'])) for record in books_by_author] # authors[] contains a list of all book authors, with multiple entries for multiple books by author # authors[]: (([0]:friendly [1]:sort)) @@ -776,6 +785,7 @@ class CatalogBuilder(object): author[2])).encode('utf-8')) self.authors = unique_authors + self.books_by_author = books_by_author return True def fetch_books_by_title(self): @@ -863,15 +873,15 @@ class CatalogBuilder(object): this_title['series_index'] = 0.0 this_title['title_sort'] = self.generate_sort_title(this_title['title']) - if 'authors' in record: - # from calibre.ebooks.metadata import authors_to_string - # return authors_to_string(self.authors) + if 'authors' in record: this_title['authors'] = record['authors'] + # Synthesize author attribution from authors list if record['authors']: this_title['author'] = " & ".join(record['authors']) else: - this_title['author'] = 'Unknown' + this_title['author'] = _('Unknown') + this_title['authors'] = [this_title['author']] if 'author_sort' in record and record['author_sort'].strip(): this_title['author_sort'] = record['author_sort'] @@ -1093,7 +1103,7 @@ class CatalogBuilder(object): self.bookmarked_books = bookmarks - def filter_db_tags(self): + def filter_db_tags(self, max_len): """ Remove excluded tags from data set, return normalized genre list. Filter all db tags, removing excluded tags supplied in opts. @@ -1101,13 +1111,13 @@ class CatalogBuilder(object): tags are flattened to alphanumeric ascii_text. Args: - (none) + max_len: maximum length of normalized tag to fit within OS constraints Return: genre_tags_dict (dict): dict of filtered, normalized tags in data set """ - def _format_tag_list(tags, indent=2, line_break=70, header='Tag list'): + def _format_tag_list(tags, indent=1, line_break=70, header='Tag list'): def _next_tag(sorted_tags): for (i, tag) in enumerate(sorted_tags): if i < len(tags) - 1: @@ -1126,6 +1136,31 @@ class CatalogBuilder(object): out_str = ' ' * (indent + 1) return ans + out_str + def _normalize_tag(tag, max_len): + """ Generate an XHTML-legal anchor string from tag. + + Parse tag for non-ascii, convert to unicode name. + + Args: + tags (str): tag name possible containing symbols + max_len (int): maximum length of tag + + Return: + normalized (str): unicode names substituted for non-ascii chars, + clipped to max_len + """ + + normalized = massaged = re.sub('\s','',ascii_text(tag).lower()) + if re.search('\W',normalized): + normalized = '' + for c in massaged: + if re.search('\W',c): + normalized += self.generate_unicode_name(c) + else: + normalized += c + shortened = shorten_components_to(max_len, [normalized])[0] + return shortened + # Entry point normalized_tags = [] friendly_tags = [] @@ -1144,7 +1179,7 @@ class CatalogBuilder(object): if tag == ' ': continue - normalized_tags.append(self.normalize_tag(tag)) + normalized_tags.append(_normalize_tag(tag, max_len)) friendly_tags.append(tag) genre_tags_dict = dict(zip(friendly_tags,normalized_tags)) @@ -1941,8 +1976,6 @@ class CatalogBuilder(object): self.update_progress_full_step(_("Genres HTML")) - self.genre_tags_dict = self.filter_db_tags() - # Extract books matching filtered_tags genre_list = [] for friendly_tag in sorted(self.genre_tags_dict, key=sort_key): @@ -2024,10 +2057,11 @@ class CatalogBuilder(object): books_by_current_author += 1 # Write the genre book list as an article - titles_spanned = self.generate_html_by_genre(genre, True if index==0 else False, - genre_tag_set[genre], - "%s/Genre_%s.html" % (self.content_dir, - genre)) + outfile = "%s/Genre_%s.html" % (self.content_dir, genre) + titles_spanned = self.generate_html_by_genre(genre, + True if index==0 else False, + genre_tag_set[genre], + outfile) tag_file = "content/Genre_%s.html" % genre master_genre_list.append({'tag':genre, @@ -2549,7 +2583,7 @@ class CatalogBuilder(object): for (i, tag) in enumerate(sorted(book.get('tags', []))): aTag = Tag(_soup,'a') if self.opts.generate_genres: - aTag['href'] = "Genre_%s.html" % self.normalize_tag(tag) + aTag['href'] = "Genre_%s.html" % self.genre_tags_dict[tag] aTag.insert(0,escape(NavigableString(tag))) genresTag.insert(gtc, aTag) gtc += 1 @@ -4603,28 +4637,6 @@ class CatalogBuilder(object): return merged - def normalize_tag(self, tag): - """ Generate an XHTML-legal anchor string from tag. - - Parse tag for non-ascii, convert to unicode name. - - Args: - tags (str): tag name possible containing symbols - - Return: - normalized (str): unicode names substituted for non-ascii chars - """ - - normalized = massaged = re.sub('\s','',ascii_text(tag).lower()) - if re.search('\W',normalized): - normalized = '' - for c in massaged: - if re.search('\W',c): - normalized += self.generate_unicode_name(c) - else: - normalized += c - return normalized - def process_exclusions(self, data_set): """ Filter data_set based on exclusion_rules. @@ -4697,6 +4709,51 @@ class CatalogBuilder(object): else: return data_set + def relist_multiple_authors(self, books_by_author): + """ Create multiple entries for books with multiple authors + + Given a list of books by author, scan list for books with multiple + authors. Add a cloned copy of the book per additional author. + + Args: + books_by_author (list): book list possibly containing books + with multiple authors + + Return: + (list): books_by_author with additional entries for books with + multiple authors + """ + + # Scan list looking for entries with len(authors) > 1 + # Clone multiples, swapping additional author into first place, + # computing author_sort to match + + # from calibre.ebooks.metadata import authors_to_string + # return authors_to_string(self.authors) + + multiple_author_books = [] + + # Find the multiple author books + for book in books_by_author: + if len(book['authors']) > 1: + multiple_author_books.append(book) + + for book in multiple_author_books: + cloned_authors = list(book['authors']) + for x, author in enumerate(book['authors']): + if x: + first_author = cloned_authors.pop(0) + cloned_authors.append(first_author) + new_book = deepcopy(book) + new_book['author'] = ' & '.join(cloned_authors) + new_book['authors'] = list(cloned_authors) + asl = [author_to_author_sort(auth) for auth in cloned_authors] + new_book['author_sort'] = ' & '.join(asl) + #print("'%s' (%s) (%s)" % (new_book['title'], new_book['authors'], new_book['author_sort'])) + books_by_author.append(new_book) + + return books_by_author + def update_progress_full_step(self, description): """ Update calibre's job status UI. From 18db66fd77f4e1e42b86d724ad302035804a0593 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 6 Nov 2012 08:26:09 +0530 Subject: [PATCH 090/107] Fix London Review of Books --- recipes/lrb.recipe | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipes/lrb.recipe b/recipes/lrb.recipe index 4a203c80ae..6453e78724 100644 --- a/recipes/lrb.recipe +++ b/recipes/lrb.recipe @@ -40,6 +40,6 @@ class LondonReviewOfBooks(BasicNewsRecipe): soup = self.index_to_soup('http://www.lrb.co.uk/') cover_item = soup.find('p',attrs={'class':'cover'}) if cover_item: - cover_url = 'http://www.lrb.co.uk' + cover_item.a.img['src'] + cover_url = cover_item.a.img['src'] return cover_url From f54843c5470c60bd02e8add0e6562271fac0e8f8 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 6 Nov 2012 11:39:48 +0530 Subject: [PATCH 091/107] Switch to a pure python implementation of font subsetting --- src/calibre/debug.py | 2 +- src/calibre/ebooks/oeb/transforms/subset.py | 2 +- src/calibre/utils/fonts/sfnt/__init__.py | 13 +- src/calibre/utils/fonts/sfnt/cmap.py | 7 +- src/calibre/utils/fonts/sfnt/container.py | 17 +- src/calibre/utils/fonts/sfnt/errors.py | 3 + src/calibre/utils/fonts/sfnt/glyf.py | 88 ++++++++ src/calibre/utils/fonts/sfnt/loca.py | 37 +++- src/calibre/utils/fonts/sfnt/subset.py | 226 +++++++++++++++++++- src/calibre/utils/fonts/subset.py | 1 + 10 files changed, 383 insertions(+), 13 deletions(-) create mode 100644 src/calibre/utils/fonts/sfnt/glyf.py diff --git a/src/calibre/debug.py b/src/calibre/debug.py index f7fd6f2d72..a06096c593 100644 --- a/src/calibre/debug.py +++ b/src/calibre/debug.py @@ -212,7 +212,7 @@ def main(args=sys.argv): return if len(args) > 1 and args[1] in ('-f', '--subset-font'): - from calibre.utils.fonts.subset import main + from calibre.utils.fonts.sfnt.subset import main main(['subset-font']+args[2:]) return diff --git a/src/calibre/ebooks/oeb/transforms/subset.py b/src/calibre/ebooks/oeb/transforms/subset.py index a3e1b3bd10..9b10aaad06 100644 --- a/src/calibre/ebooks/oeb/transforms/subset.py +++ b/src/calibre/ebooks/oeb/transforms/subset.py @@ -10,7 +10,7 @@ __docformat__ = 'restructuredtext en' from collections import defaultdict from calibre.ebooks.oeb.base import urlnormalize -from calibre.utils.fonts.subset import subset, NoGlyphs, UnsupportedFont +from calibre.utils.fonts.sfnt.subset import subset, NoGlyphs, UnsupportedFont class SubsetFonts(object): diff --git a/src/calibre/utils/fonts/sfnt/__init__.py b/src/calibre/utils/fonts/sfnt/__init__.py index 7a40e7fd15..f3e0a2eae8 100644 --- a/src/calibre/utils/fonts/sfnt/__init__.py +++ b/src/calibre/utils/fonts/sfnt/__init__.py @@ -26,6 +26,9 @@ class UnknownTable(object): def __call__(self): return self.raw + def __len__(self): + return len(self.raw) + class DateTimeProperty(object): def __init__(self, name): @@ -46,10 +49,10 @@ class FixedProperty(object): def __get__(self, obj, type=None): val = getattr(obj, self.name) - return val * (2**-16) + return val / 0x10000 def __set__(self, obj, val): - return int(round(val*(2**16))) + return int(round(val*(0x10000))) def max_power_of_two(x): """ @@ -62,4 +65,10 @@ def max_power_of_two(x): exponent += 1 return max(exponent - 1, 0) +def load_font(stream_or_path): + raw = stream_or_path + if hasattr(raw, 'read'): + raw = raw.read() + from calibre.utils.fonts.sfnt.container import Sfnt + return Sfnt(raw) diff --git a/src/calibre/utils/fonts/sfnt/cmap.py b/src/calibre/utils/fonts/sfnt/cmap.py index 94b0e0eaf5..a00eb56d6f 100644 --- a/src/calibre/utils/fonts/sfnt/cmap.py +++ b/src/calibre/utils/fonts/sfnt/cmap.py @@ -144,9 +144,10 @@ class CmapTable(UnknownTable): except IndexError: next_offset = len(self.raw) table = self.raw[offset:next_offset] - fmt = unpack_from(b'>H', table)[0] - if platform == 3 and encoding == 1 and fmt == 4: - self.bmp_table = table + if table: + fmt = unpack_from(b'>H', table)[0] + if platform == 3 and encoding == 1 and fmt == 4: + self.bmp_table = table def get_character_map(self, chars): ''' diff --git a/src/calibre/utils/fonts/sfnt/container.py b/src/calibre/utils/fonts/sfnt/container.py index 6b4be41739..73bb787810 100644 --- a/src/calibre/utils/fonts/sfnt/container.py +++ b/src/calibre/utils/fonts/sfnt/container.py @@ -9,6 +9,7 @@ __docformat__ = 'restructuredtext en' from struct import pack, calcsize from io import BytesIO +from collections import OrderedDict from calibre.utils.fonts.utils import (get_tables, checksum_of_block, verify_checksums) @@ -18,6 +19,8 @@ from calibre.utils.fonts.sfnt.errors import UnsupportedFont from calibre.utils.fonts.sfnt.head import HeadTable from calibre.utils.fonts.sfnt.maxp import MaxpTable from calibre.utils.fonts.sfnt.loca import LocaTable +from calibre.utils.fonts.sfnt.glyf import GlyfTable +from calibre.utils.fonts.sfnt.cmap import CmapTable class Sfnt(object): @@ -35,6 +38,8 @@ class Sfnt(object): b'head' : HeadTable, b'maxp' : MaxpTable, b'loca' : LocaTable, + b'glyf' : GlyfTable, + b'cmap' : CmapTable, }.get(table_tag, UnknownTable)(table) def __getitem__(self, key): @@ -49,6 +54,12 @@ class Sfnt(object): def pop(self, key, default=None): return self.tables.pop(key, default) + def sizes(self): + ans = OrderedDict() + for tag in sorted(self.tables): + ans[tag] = len(self[tag]) + return ans + def __call__(self): stream = BytesIO() @@ -68,6 +79,7 @@ class Sfnt(object): head_offset = None table_data = [] offset = stream.tell() + ( calcsize(b'>4s3L') * num_tables ) + sizes = OrderedDict() for tag in sorted(self.tables): table = self.tables[tag] raw = table() @@ -80,6 +92,7 @@ class Sfnt(object): spack(b'>4s3L', tag, checksum, offset, table_len) offset += len(raw) table_data.append(raw) + sizes[tag] = table_len for x in table_data: stream.write(x) @@ -89,7 +102,7 @@ class Sfnt(object): stream.seek(head_offset + 8) spack(b'>L', q) - return stream.getvalue() + return stream.getvalue(), sizes def test_roundtrip(ff=None): if ff is None: @@ -97,7 +110,7 @@ def test_roundtrip(ff=None): else: with open(ff, 'rb') as f: data = f.read() - rd = Sfnt(data)() + rd = Sfnt(data)()[0] verify_checksums(rd) if data[:12] != rd[:12]: raise ValueError('Roundtripping failed, font header not the same') diff --git a/src/calibre/utils/fonts/sfnt/errors.py b/src/calibre/utils/fonts/sfnt/errors.py index a002192863..c2a918d78b 100644 --- a/src/calibre/utils/fonts/sfnt/errors.py +++ b/src/calibre/utils/fonts/sfnt/errors.py @@ -10,3 +10,6 @@ __docformat__ = 'restructuredtext en' class UnsupportedFont(ValueError): pass +class NoGlyphs(ValueError): + pass + diff --git a/src/calibre/utils/fonts/sfnt/glyf.py b/src/calibre/utils/fonts/sfnt/glyf.py new file mode 100644 index 0000000000..55c2a13767 --- /dev/null +++ b/src/calibre/utils/fonts/sfnt/glyf.py @@ -0,0 +1,88 @@ +#!/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 ' +__docformat__ = 'restructuredtext en' + +from struct import unpack_from +from collections import OrderedDict + +from calibre.utils.fonts.sfnt import UnknownTable + +ARG_1_AND_2_ARE_WORDS = 0x0001 # if set args are words otherwise they are bytes +ARGS_ARE_XY_VALUES = 0x0002 # if set args are xy values, otherwise they are points +ROUND_XY_TO_GRID = 0x0004 # for the xy values if above is true +WE_HAVE_A_SCALE = 0x0008 # Sx = Sy, otherwise scale == 1.0 +NON_OVERLAPPING = 0x0010 # set to same value for all components (obsolete!) +MORE_COMPONENTS = 0x0020 # indicates at least one more glyph after this one +WE_HAVE_AN_X_AND_Y_SCALE = 0x0040 # Sx, Sy +WE_HAVE_A_TWO_BY_TWO = 0x0080 # t00, t01, t10, t11 +WE_HAVE_INSTRUCTIONS = 0x0100 # instructions follow +USE_MY_METRICS = 0x0200 # apply these metrics to parent glyph +OVERLAP_COMPOUND = 0x0400 # used by Apple in GX fonts +SCALED_COMPONENT_OFFSET = 0x0800 # composite designed to have the component offset scaled (designed for Apple) +UNSCALED_COMPONENT_OFFSET = 0x1000 # composite designed not to have the component offset scaled (designed for MS) + +class SimpleGlyph(object): + + def __init__(self, num_of_countours, raw): + self.num_of_countours = num_of_countours + self.raw = raw + # The list of glyph indices referred to by this glyph, will always be + # empty for a simple glyph and not empty for a composite glyph + self.glyph_indices = [] + self.is_composite = False + + def __len__(self): + return len(self.raw) + + def __call__(self): + return self.raw + +class CompositeGlyph(SimpleGlyph): + + def __init__(self, num_of_countours, raw): + super(CompositeGlyph, self).__init__(num_of_countours, raw) + self.is_composite = True + + flags = MORE_COMPONENTS + offset = 0 + while flags & MORE_COMPONENTS: + flags, glyph_index = unpack_from(b'>HH', raw, offset) + self.glyph_indices.append(glyph_index) + offset += 4 + if flags & ARG_1_AND_2_ARE_WORDS: + offset += 4 + else: + offset += 2 + if flags & WE_HAVE_A_SCALE: + offset += 2 + elif flags & WE_HAVE_AN_X_AND_Y_SCALE: + offset += 4 + elif flags & WE_HAVE_A_TWO_BY_TWO: + offset += 8 + +class GlyfTable(UnknownTable): + + def glyph_data(self, offset, length): + raw = self.raw[offset:offset+length] + num_of_countours = unpack_from(b'>h', raw)[0] if raw else 0 + if num_of_countours >= 0: + return SimpleGlyph(num_of_countours, raw) + return CompositeGlyph(num_of_countours, raw) + + def update(self, sorted_glyph_map): + ans = OrderedDict() + offset = 0 + block = [] + for glyph_id, glyph in sorted_glyph_map.iteritems(): + raw = glyph() + ans[glyph_id] = (offset, len(raw)) + offset += len(raw) + block.append(raw) + self.raw = b''.join(block) + return ans + diff --git a/src/calibre/utils/fonts/sfnt/loca.py b/src/calibre/utils/fonts/sfnt/loca.py index f6ca903b83..062cf561aa 100644 --- a/src/calibre/utils/fonts/sfnt/loca.py +++ b/src/calibre/utils/fonts/sfnt/loca.py @@ -7,7 +7,8 @@ __license__ = 'GPL v3' __copyright__ = '2012, Kovid Goyal ' __docformat__ = 'restructuredtext en' -from struct import calcsize, unpack_from +from struct import calcsize, unpack_from, pack +from operator import itemgetter from calibre.utils.fonts.sfnt import UnknownTable @@ -23,9 +24,43 @@ class LocaTable(UnknownTable): self.offset_map = self.offset_map[:num_glyphs+1] if fmt == 'H': self.offset_map = [2*i for i in self.offset_map] + self.fmt = fmt def glyph_location(self, glyph_id): offset = self.offset_map[glyph_id] next_offset = self.offset_map[glyph_id+1] return offset, next_offset - offset + def subset(self, resolved_glyph_map): + ''' + Update this table to contain pointers only to the glyphs in + resolved_glyph_map which must be a map of glyph_ids to (offset, sz) + ''' + self.offset_map = [0 for i in self.offset_map] + glyphs = [(glyph_id, x[0], x[1]) for glyph_id, x in + resolved_glyph_map.iteritems()] + glyphs.sort(key=itemgetter(1)) + for glyph_id, offset, sz in glyphs: + self.offset_map[glyph_id] = offset + self.offset_map[glyph_id+1] = offset + sz + # Fix all zero entries to be the same as the previous entry, which + # means that if the ith entry is zero, the i-1 glyph is not present. + for i in xrange(1, len(self.offset_map)): + if self.offset_map[i] == 0: + self.offset_map[i] = self.offset_map[i-1] + + vals = self.offset_map + if self.fmt == 'H': + vals = [i//2 for i in self.offset_map] + + self.raw = pack(('>%d%s'%(len(vals), self.fmt)).encode('ascii'), *vals) + + def dump_glyphs(self, sfnt): + if not hasattr(self, 'offset_map'): + self.load_offsets(sfnt[b'head'], sfnt[b'maxp']) + for i in xrange(len(self.offset_map)-1): + off, noff = self.offset_map[i], self.offset_map[i+1] + if noff != off: + print ('Glyph id:', i, 'size:', noff-off) + + diff --git a/src/calibre/utils/fonts/sfnt/subset.py b/src/calibre/utils/fonts/sfnt/subset.py index 085b6255e4..e3883c180d 100644 --- a/src/calibre/utils/fonts/sfnt/subset.py +++ b/src/calibre/utils/fonts/sfnt/subset.py @@ -7,23 +7,73 @@ __license__ = 'GPL v3' __copyright__ = '2012, Kovid Goyal ' __docformat__ = 'restructuredtext en' +from collections import OrderedDict +from operator import itemgetter + from calibre.utils.fonts.sfnt.container import Sfnt -from calibre.utils.fonts.sfnt.errors import UnsupportedFont +from calibre.utils.fonts.sfnt.errors import UnsupportedFont, NoGlyphs + +# TrueType outlines {{{ + +def resolve_glyphs(loca, glyf, character_map): + unresolved_glyphs = set(character_map.itervalues()) + unresolved_glyphs.add(0) # We always want the .notdef glyph + resolved_glyphs = {} + + while unresolved_glyphs: + glyph_id = unresolved_glyphs.pop() + try: + offset, length = loca.glyph_location(glyph_id) + except (IndexError, ValueError, KeyError, TypeError): + continue + if length < 1: + continue + glyph = glyf.glyph_data(offset, length) + if len(glyph) == 0: + continue + resolved_glyphs[glyph_id] = glyph + for gid in glyph.glyph_indices: + if gid not in resolved_glyphs: + unresolved_glyphs.add(gid) + + return OrderedDict(sorted(resolved_glyphs.iteritems(), key=itemgetter(0))) def subset_truetype(sfnt, character_map): loca = sfnt[b'loca'] + glyf = sfnt[b'glyf'] + try: head, maxp = sfnt[b'head'], sfnt[b'maxp'] except KeyError: raise UnsupportedFont('This font does not contain head and/or maxp tables') loca.load_offsets(head, maxp) + resolved_glyphs = resolve_glyphs(loca, glyf, character_map) + if not resolved_glyphs or set(resolved_glyphs) == {0}: + raise NoGlyphs('This font has no glyphs for the specified character ' + 'set, subsetting it is pointless') + + # Keep only character codes that have resolved glyphs + for code, glyph_id in tuple(character_map.iteritems()): + if glyph_id not in resolved_glyphs: + del character_map[code] + + # Update the glyf table + glyph_offset_map = glyf.update(resolved_glyphs) + + # Update the loca table + loca.subset(glyph_offset_map) + +# }}} + def subset(raw, individual_chars, ranges=()): chars = list(map(ord, individual_chars)) for r in ranges: chars += list(xrange(ord(r[0]), ord(r[1])+1)) sfnt = Sfnt(raw) + old_sizes = sfnt.sizes() + # Remove the Digital Signature table since it is useless in a subset # font anyway sfnt.pop(b'DSIG', None) @@ -35,16 +85,186 @@ def subset(raw, individual_chars, ranges=()): # Get mapping of chars to glyph ids for all specified chars character_map = cmap.get_character_map(chars) - # Restrict the cmap table to only contain entries for the specified chars - cmap.set_character_map(character_map) if b'loca' in sfnt and b'glyf' in sfnt: + # TrueType Outlines subset_truetype(sfnt, character_map) elif b'CFF ' in sfnt: + # PostScript Outlines raise UnsupportedFont('This font contains PostScript outlines, ' 'subsetting not supported') else: raise UnsupportedFont('This font does not contain TrueType ' 'or PostScript outlines') + # Restrict the cmap table to only contain entries for the resolved glyphs + cmap.set_character_map(character_map) + + raw, new_sizes = sfnt() + return raw, old_sizes, new_sizes + +# CLI {{{ +def option_parser(): + import textwrap + from calibre.utils.config import OptionParser + parser = OptionParser(usage=textwrap.dedent('''\ + %prog [options] input_font_file output_font_file characters_to_keep + + Subset the specified font, keeping only the glyphs for the characters in + characters_to_keep. characters_to_keep is a comma separated list of characters of + the form: a,b,c,A-Z,0-9,xyz + + You can specify ranges in the list of characters, as shown above. + ''')) + parser.add_option('-c', '--codes', default=False, action='store_true', + help='If specified, the list of characters is interpreted as ' + 'numeric unicode codes instead of characters. So to specify the ' + 'characters a,b you would use 97,98') + parser.prog = 'subset-font' + return parser + +def print_stats(old_stats, new_stats): + from calibre import prints + prints('========= Table comparison (original vs. subset) =========') + prints('Table', ' ', '%10s'%'Size', ' ', 'Percent', ' ', '%10s'%'New Size', + ' New Percent') + prints('='*80) + old_total = sum(old_stats.itervalues()) + new_total = sum(new_stats.itervalues()) + tables = sorted(old_stats.iterkeys(), key=lambda x:old_stats[x], + reverse=True) + for table in tables: + osz = old_stats[table] + op = osz/old_total * 100 + nsz = new_stats.get(table, 0) + np = nsz/new_total * 100 + suffix = ' | same size' + if nsz != osz: + suffix = ' | reduced to %.1f %%'%(nsz/osz * 100) + prints('%4s'%table, ' ', '%10s'%osz, ' ', '%5.1f %%'%op, ' ', + '%10s'%nsz, ' ', '%5.1f %%'%np, suffix) + prints('='*80) + + +def main(args): + import sys, time + from calibre import prints + parser = option_parser() + opts, args = parser.parse_args(args) + if len(args) < 4 or len(args) > 4: + parser.print_help() + raise SystemExit(1) + iff, off, chars = args[1:] + with open(iff, 'rb') as f: + orig = f.read() + + chars = [x.strip() for x in chars.split(',')] + individual, ranges = set(), set() + + def not_single(c): + if len(c) > 1: + prints(c, 'is not a single character', file=sys.stderr) + raise SystemExit(1) + + for c in chars: + if '-' in c: + parts = [x.strip() for x in c.split('-')] + if len(parts) != 2: + prints('Invalid range:', c, file=sys.stderr) + raise SystemExit(1) + if opts.codes: + parts = tuple(map(unichr, map(int, parts))) + map(not_single, parts) + ranges.add(tuple(parts)) + else: + if opts.codes: + c = unichr(int(c)) + not_single(c) + individual.add(c) + st = time.time() + sf, old_stats, new_stats = subset(orig, individual, ranges) + taken = time.time() - st + reduced = (len(sf)/len(orig)) * 100 + def sz(x): + return '%gKB'%(len(x)/1024.) + print_stats(old_stats, new_stats) + prints('Original size:', sz(orig), 'Subset size:', sz(sf), 'Reduced to: %g%%'%(reduced)) + prints('Subsetting took %g seconds'%taken) + with open(off, 'wb') as f: + f.write(sf) + prints('Subset font written to:', off) + +if __name__ == '__main__': + try: + import init_calibre + init_calibre + except ImportError: + pass + import sys + main(sys.argv) +# }}} + +# Tests {{{ +def test_mem(): + from calibre.utils.mem import memory + import gc + gc.collect() + start_mem = memory() + raw = P('fonts/liberation/LiberationSerif-Regular.ttf', data=True) + calls = 1000 + for i in xrange(calls): + subset(raw, (), (('a', 'z'),)) + del raw + for i in xrange(3): gc.collect() + print ('Leaked memory per call:', (memory() - start_mem)/calls*1024, 'KB') + +def test(): + raw = P('fonts/liberation/LiberationSerif-Regular.ttf', data=True) + sf, old_stats, new_stats = subset(raw, set(('a', 'b', 'c')), ()) + if len(sf) > 0.3 * len(raw): + raise Exception('Subsetting failed') + +def all(): + from calibre.utils.fonts.scanner import font_scanner + failed = [] + unsupported = [] + total = 0 + for family in font_scanner.find_font_families(): + for font in font_scanner.fonts_for_family(family): + raw = font_scanner.get_font_data(font) + print ('Subsetting', font['full_name'], end='\t') + total += 1 + try: + sf, old_stats, new_stats = subset(raw, set(('a', 'b', 'c')), ()) + except NoGlyphs: + print('No glyphs!') + continue + except UnsupportedFont as e: + unsupported.append((font['full_name'], font['path'], unicode(e))) + print ('Unsupported!') + continue + except Exception as e: + print ('Failed!') + failed.append((font['full_name'], font['path'], unicode(e))) + else: + print ('Reduced to:', '%.1f'%( + sum(new_stats.itervalues())/sum(old_stats.itervalues()) + * 100), '%') + if unsupported: + print ('\n\nUnsupported:') + for name, path, err in unsupported: + print (name, path, err) + print() + if failed: + print ('\n\nFailures:') + for name, path, err in failed: + print (name, path, err) + print() + + print('Total:', total, 'Unsupported:', len(unsupported), 'Failed:', + len(failed)) + + +# }}} + diff --git a/src/calibre/utils/fonts/subset.py b/src/calibre/utils/fonts/subset.py index f000f2d608..777d72971d 100644 --- a/src/calibre/utils/fonts/subset.py +++ b/src/calibre/utils/fonts/subset.py @@ -120,6 +120,7 @@ def all(): try: sf, old_stats, new_stats = subset(raw, set(('a', 'b', 'c')), ()) except NoGlyphs: + print ('No glyphs!') continue except UnsupportedFont as e: unsupported.append((font['full_name'], font['path'], unicode(e))) From d169599f631159f1ba0b86a52b693f070d7cda27 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 6 Nov 2012 12:14:55 +0530 Subject: [PATCH 092/107] Fix handling of Fixed property --- src/calibre/utils/fonts/sfnt/head.py | 8 ++++-- src/calibre/utils/fonts/sfnt/maxp.py | 43 +++++++++++----------------- 2 files changed, 22 insertions(+), 29 deletions(-) diff --git a/src/calibre/utils/fonts/sfnt/head.py b/src/calibre/utils/fonts/sfnt/head.py index 8b9c732e14..584d685cc5 100644 --- a/src/calibre/utils/fonts/sfnt/head.py +++ b/src/calibre/utils/fonts/sfnt/head.py @@ -10,19 +10,21 @@ __docformat__ = 'restructuredtext en' from itertools import izip from struct import unpack_from, pack -from calibre.utils.fonts.sfnt import UnknownTable, DateTimeProperty +from calibre.utils.fonts.sfnt import UnknownTable, DateTimeProperty, FixedProperty class HeadTable(UnknownTable): created = DateTimeProperty('_created') modified = DateTimeProperty('_modified') + version_number = FixedProperty('_version_number') + font_revision = FixedProperty('_font_revision') def __init__(self, *args, **kwargs): super(HeadTable, self).__init__(*args, **kwargs) field_types = ( - 'version_number' , 'L', - 'font_revision' , 'L', + '_version_number' , 'l', + '_font_revision' , 'l', 'checksum_adjustment' , 'L', 'magic_number' , 'L', 'flags' , 'H', diff --git a/src/calibre/utils/fonts/sfnt/maxp.py b/src/calibre/utils/fonts/sfnt/maxp.py index 0e3450c699..443d01b79e 100644 --- a/src/calibre/utils/fonts/sfnt/maxp.py +++ b/src/calibre/utils/fonts/sfnt/maxp.py @@ -10,47 +10,38 @@ __docformat__ = 'restructuredtext en' from itertools import izip from struct import unpack_from, pack -from calibre.utils.fonts.sfnt import UnknownTable +from calibre.utils.fonts.sfnt import UnknownTable, FixedProperty from calibre.utils.fonts.sfnt.errors import UnsupportedFont class MaxpTable(UnknownTable): + version = FixedProperty('_version') + def __init__(self, *args, **kwargs): super(MaxpTable, self).__init__(*args, **kwargs) - self._fmt = b'>LH' + self._fmt = b'>lH' self._version, self.num_glyphs = unpack_from(self._fmt, self.raw) self.fields = ('_version', 'num_glyphs') - if self._version >= 0x10000: - self.version = 0x10000 + if self.version > 1.0: + raise UnsupportedFont('This font has a maxp table with version: %s' + %self.version) + if self.version == 1.0: + self.fields = ('_version', 'num_glyphs', 'max_points', + 'max_contours', 'max_composite_points', + 'max_composite_contours', 'max_zones', + 'max_twilight_points', 'max_storage', 'max_function_defs', + 'max_instruction_defs', 'max_stack_elements', + 'max_size_of_instructions', 'max_component_elements', + 'max_component_depth') + self._fmt = b'>lH' + b'H'*(len(self.fields)-2) + vals = unpack_from(self._fmt, self.raw) for f, val in izip(self.fields, vals): setattr(self, f, val) - @dynamic_property - def version(self): - def fget(self): - return self._version - def fset(self, val): - if val == 0x5000: - self._fmt = b'>LH' - self._fields = ('_version', 'num_glyphs') - elif val == 0x10000: - self.fields = ('_version', 'num_glyphs', 'max_points', - 'max_contours', 'max_composite_points', - 'max_composite_contours', 'max_zones', - 'max_twilight_points', 'max_storage', 'max_function_defs', - 'max_instruction_defs', 'max_stack_elements', - 'max_size_of_instructions', 'max_component_elements', - 'max_component_depth') - self._fmt = b'>LH' + b'H'*(len(self.fields)-2) - self._version = val - return property(fget=fget, fset=fset) - def update(self): - if self._version > 0x10000: - raise UnsupportedFont('maxp table with version > 0x10000 not modifiable') vals = [getattr(self, f) for f in self._fields] self.raw = pack(self._fmt, *vals) From caf8e0ebeddd00bba237d961e86b18e5f9409f43 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 6 Nov 2012 12:21:49 +0530 Subject: [PATCH 093/107] Fix handling of composite glyphs --- src/calibre/utils/fonts/sfnt/glyf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/utils/fonts/sfnt/glyf.py b/src/calibre/utils/fonts/sfnt/glyf.py index 55c2a13767..decf9dc576 100644 --- a/src/calibre/utils/fonts/sfnt/glyf.py +++ b/src/calibre/utils/fonts/sfnt/glyf.py @@ -49,7 +49,7 @@ class CompositeGlyph(SimpleGlyph): self.is_composite = True flags = MORE_COMPONENTS - offset = 0 + offset = 10 while flags & MORE_COMPONENTS: flags, glyph_index = unpack_from(b'>HH', raw, offset) self.glyph_indices.append(glyph_index) From 0817ef2e58d8d25447279ec365403a5d6df92cd7 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 6 Nov 2012 12:26:39 +0530 Subject: [PATCH 094/107] Get rid of the useless sfntly --- COPYRIGHT | 6 - session.vim | 1 - setup/extensions.py | 19 - setup/sfntly.py | 93 -- src/calibre/constants.py | 1 - src/calibre/test_build.py | 6 - src/calibre/utils/fonts/sfntly.cpp | 628 -------- src/calibre/utils/fonts/sfntly.h | 196 --- src/calibre/utils/fonts/subset.py | 208 --- src/sfntly/COPYING.txt | 203 --- src/sfntly/src/sfntly/data/byte_array.cc | 199 --- src/sfntly/src/sfntly/data/byte_array.h | 201 --- src/sfntly/src/sfntly/data/font_data.cc | 82 -- src/sfntly/src/sfntly/data/font_data.h | 135 -- .../src/sfntly/data/font_input_stream.cc | 141 -- .../src/sfntly/data/font_input_stream.h | 97 -- .../src/sfntly/data/font_output_stream.cc | 130 -- .../src/sfntly/data/font_output_stream.h | 79 - .../sfntly/data/growable_memory_byte_array.cc | 82 -- .../sfntly/data/growable_memory_byte_array.h | 66 - .../src/sfntly/data/memory_byte_array.cc | 93 -- .../src/sfntly/data/memory_byte_array.h | 81 -- .../src/sfntly/data/readable_font_data.cc | 336 ----- .../src/sfntly/data/readable_font_data.h | 308 ---- .../src/sfntly/data/writable_font_data.cc | 201 --- .../src/sfntly/data/writable_font_data.h | 211 --- src/sfntly/src/sfntly/font.cc | 568 -------- src/sfntly/src/sfntly/font.h | 352 ----- src/sfntly/src/sfntly/font_factory.cc | 214 --- src/sfntly/src/sfntly/font_factory.h | 140 -- src/sfntly/src/sfntly/math/fixed1616.h | 41 - src/sfntly/src/sfntly/math/font_math.h | 49 - src/sfntly/src/sfntly/port/atomic.h | 71 - src/sfntly/src/sfntly/port/config.h | 28 - src/sfntly/src/sfntly/port/endian.h | 77 - src/sfntly/src/sfntly/port/exception_type.h | 125 -- .../src/sfntly/port/file_input_stream.cc | 169 --- .../src/sfntly/port/file_input_stream.h | 57 - src/sfntly/src/sfntly/port/input_stream.h | 49 - src/sfntly/src/sfntly/port/java_iterator.h | 94 -- src/sfntly/src/sfntly/port/lock.cc | 72 - src/sfntly/src/sfntly/port/lock.h | 76 - .../src/sfntly/port/memory_input_stream.cc | 147 -- .../src/sfntly/port/memory_input_stream.h | 57 - .../src/sfntly/port/memory_output_stream.cc | 72 - .../src/sfntly/port/memory_output_stream.h | 51 - src/sfntly/src/sfntly/port/output_stream.h | 46 - src/sfntly/src/sfntly/port/refcount.h | 277 ---- src/sfntly/src/sfntly/port/type.h | 102 -- .../sfntly/table/bitmap/big_glyph_metrics.cc | 171 --- .../sfntly/table/bitmap/big_glyph_metrics.h | 96 -- .../src/sfntly/table/bitmap/bitmap_glyph.cc | 101 -- .../src/sfntly/table/bitmap/bitmap_glyph.h | 119 -- .../sfntly/table/bitmap/bitmap_glyph_info.cc | 68 - .../sfntly/table/bitmap/bitmap_glyph_info.h | 85 -- .../sfntly/table/bitmap/bitmap_size_table.cc | 604 -------- .../sfntly/table/bitmap/bitmap_size_table.h | 173 --- .../table/bitmap/composite_bitmap_glyph.cc | 109 -- .../table/bitmap/composite_bitmap_glyph.h | 75 - .../src/sfntly/table/bitmap/ebdt_table.cc | 236 --- .../src/sfntly/table/bitmap/ebdt_table.h | 108 -- .../src/sfntly/table/bitmap/eblc_table.cc | 313 ---- .../src/sfntly/table/bitmap/eblc_table.h | 194 --- .../src/sfntly/table/bitmap/ebsc_table.cc | 107 -- .../src/sfntly/table/bitmap/ebsc_table.h | 101 -- .../src/sfntly/table/bitmap/glyph_metrics.cc | 39 - .../src/sfntly/table/bitmap/glyph_metrics.h | 43 - .../sfntly/table/bitmap/index_sub_table.cc | 278 ---- .../src/sfntly/table/bitmap/index_sub_table.h | 178 --- .../table/bitmap/index_sub_table_format1.cc | 299 ---- .../table/bitmap/index_sub_table_format1.h | 116 -- .../table/bitmap/index_sub_table_format2.cc | 272 ---- .../table/bitmap/index_sub_table_format2.h | 106 -- .../table/bitmap/index_sub_table_format3.cc | 295 ---- .../table/bitmap/index_sub_table_format3.h | 113 -- .../table/bitmap/index_sub_table_format4.cc | 381 ----- .../table/bitmap/index_sub_table_format4.h | 135 -- .../table/bitmap/index_sub_table_format5.cc | 344 ----- .../table/bitmap/index_sub_table_format5.h | 118 -- .../table/bitmap/simple_bitmap_glyph.cc | 45 - .../sfntly/table/bitmap/simple_bitmap_glyph.h | 44 - .../table/bitmap/small_glyph_metrics.cc | 126 -- .../sfntly/table/bitmap/small_glyph_metrics.h | 79 - .../sfntly/table/byte_array_table_builder.cc | 70 - .../sfntly/table/byte_array_table_builder.h | 53 - .../src/sfntly/table/core/cmap_table.cc | 1288 ----------------- src/sfntly/src/sfntly/table/core/cmap_table.h | 711 --------- .../sfntly/table/core/font_header_table.cc | 265 ---- .../src/sfntly/table/core/font_header_table.h | 168 --- .../core/horizontal_device_metrics_table.cc | 124 -- .../core/horizontal_device_metrics_table.h | 82 -- .../table/core/horizontal_header_table.cc | 213 --- .../table/core/horizontal_header_table.h | 111 -- .../table/core/horizontal_metrics_table.cc | 138 -- .../table/core/horizontal_metrics_table.h | 87 -- .../table/core/maximum_profile_table.cc | 240 --- .../sfntly/table/core/maximum_profile_table.h | 120 -- .../src/sfntly/table/core/name_table.cc | 721 --------- src/sfntly/src/sfntly/table/core/name_table.h | 744 ---------- src/sfntly/src/sfntly/table/core/os2_table.cc | 608 -------- src/sfntly/src/sfntly/table/core/os2_table.h | 508 ------- .../src/sfntly/table/font_data_table.cc | 193 --- src/sfntly/src/sfntly/table/font_data_table.h | 123 -- .../src/sfntly/table/generic_table_builder.cc | 49 - .../src/sfntly/table/generic_table_builder.h | 42 - src/sfntly/src/sfntly/table/header.cc | 66 - src/sfntly/src/sfntly/table/header.h | 114 -- src/sfntly/src/sfntly/table/subtable.cc | 64 - src/sfntly/src/sfntly/table/subtable.h | 73 - .../sfntly/table/subtable_container_table.h | 48 - src/sfntly/src/sfntly/table/table.cc | 162 --- src/sfntly/src/sfntly/table/table.h | 119 -- .../sfntly/table/table_based_table_builder.cc | 69 - .../sfntly/table/table_based_table_builder.h | 48 - .../src/sfntly/table/truetype/glyph_table.cc | 679 --------- .../src/sfntly/table/truetype/glyph_table.h | 335 ----- .../src/sfntly/table/truetype/loca_table.cc | 264 ---- .../src/sfntly/table/truetype/loca_table.h | 183 --- src/sfntly/src/sfntly/tag.cc | 110 -- src/sfntly/src/sfntly/tag.h | 123 -- .../tools/subsetter/glyph_table_subsetter.cc | 90 -- .../tools/subsetter/glyph_table_subsetter.h | 37 - .../src/sfntly/tools/subsetter/subsetter.cc | 102 -- .../src/sfntly/tools/subsetter/subsetter.h | 72 - .../sfntly/tools/subsetter/table_subsetter.h | 39 - .../tools/subsetter/table_subsetter_impl.cc | 38 - .../tools/subsetter/table_subsetter_impl.h | 37 - 127 files changed, 21938 deletions(-) delete mode 100644 setup/sfntly.py delete mode 100644 src/calibre/utils/fonts/sfntly.cpp delete mode 100644 src/calibre/utils/fonts/sfntly.h delete mode 100644 src/calibre/utils/fonts/subset.py delete mode 100644 src/sfntly/COPYING.txt delete mode 100644 src/sfntly/src/sfntly/data/byte_array.cc delete mode 100644 src/sfntly/src/sfntly/data/byte_array.h delete mode 100644 src/sfntly/src/sfntly/data/font_data.cc delete mode 100644 src/sfntly/src/sfntly/data/font_data.h delete mode 100644 src/sfntly/src/sfntly/data/font_input_stream.cc delete mode 100644 src/sfntly/src/sfntly/data/font_input_stream.h delete mode 100644 src/sfntly/src/sfntly/data/font_output_stream.cc delete mode 100644 src/sfntly/src/sfntly/data/font_output_stream.h delete mode 100644 src/sfntly/src/sfntly/data/growable_memory_byte_array.cc delete mode 100644 src/sfntly/src/sfntly/data/growable_memory_byte_array.h delete mode 100644 src/sfntly/src/sfntly/data/memory_byte_array.cc delete mode 100644 src/sfntly/src/sfntly/data/memory_byte_array.h delete mode 100644 src/sfntly/src/sfntly/data/readable_font_data.cc delete mode 100644 src/sfntly/src/sfntly/data/readable_font_data.h delete mode 100644 src/sfntly/src/sfntly/data/writable_font_data.cc delete mode 100644 src/sfntly/src/sfntly/data/writable_font_data.h delete mode 100644 src/sfntly/src/sfntly/font.cc delete mode 100644 src/sfntly/src/sfntly/font.h delete mode 100644 src/sfntly/src/sfntly/font_factory.cc delete mode 100644 src/sfntly/src/sfntly/font_factory.h delete mode 100644 src/sfntly/src/sfntly/math/fixed1616.h delete mode 100644 src/sfntly/src/sfntly/math/font_math.h delete mode 100644 src/sfntly/src/sfntly/port/atomic.h delete mode 100644 src/sfntly/src/sfntly/port/config.h delete mode 100644 src/sfntly/src/sfntly/port/endian.h delete mode 100644 src/sfntly/src/sfntly/port/exception_type.h delete mode 100644 src/sfntly/src/sfntly/port/file_input_stream.cc delete mode 100644 src/sfntly/src/sfntly/port/file_input_stream.h delete mode 100644 src/sfntly/src/sfntly/port/input_stream.h delete mode 100644 src/sfntly/src/sfntly/port/java_iterator.h delete mode 100644 src/sfntly/src/sfntly/port/lock.cc delete mode 100644 src/sfntly/src/sfntly/port/lock.h delete mode 100755 src/sfntly/src/sfntly/port/memory_input_stream.cc delete mode 100755 src/sfntly/src/sfntly/port/memory_input_stream.h delete mode 100644 src/sfntly/src/sfntly/port/memory_output_stream.cc delete mode 100644 src/sfntly/src/sfntly/port/memory_output_stream.h delete mode 100644 src/sfntly/src/sfntly/port/output_stream.h delete mode 100644 src/sfntly/src/sfntly/port/refcount.h delete mode 100644 src/sfntly/src/sfntly/port/type.h delete mode 100644 src/sfntly/src/sfntly/table/bitmap/big_glyph_metrics.cc delete mode 100644 src/sfntly/src/sfntly/table/bitmap/big_glyph_metrics.h delete mode 100644 src/sfntly/src/sfntly/table/bitmap/bitmap_glyph.cc delete mode 100644 src/sfntly/src/sfntly/table/bitmap/bitmap_glyph.h delete mode 100644 src/sfntly/src/sfntly/table/bitmap/bitmap_glyph_info.cc delete mode 100644 src/sfntly/src/sfntly/table/bitmap/bitmap_glyph_info.h delete mode 100644 src/sfntly/src/sfntly/table/bitmap/bitmap_size_table.cc delete mode 100644 src/sfntly/src/sfntly/table/bitmap/bitmap_size_table.h delete mode 100644 src/sfntly/src/sfntly/table/bitmap/composite_bitmap_glyph.cc delete mode 100644 src/sfntly/src/sfntly/table/bitmap/composite_bitmap_glyph.h delete mode 100644 src/sfntly/src/sfntly/table/bitmap/ebdt_table.cc delete mode 100644 src/sfntly/src/sfntly/table/bitmap/ebdt_table.h delete mode 100644 src/sfntly/src/sfntly/table/bitmap/eblc_table.cc delete mode 100644 src/sfntly/src/sfntly/table/bitmap/eblc_table.h delete mode 100644 src/sfntly/src/sfntly/table/bitmap/ebsc_table.cc delete mode 100644 src/sfntly/src/sfntly/table/bitmap/ebsc_table.h delete mode 100644 src/sfntly/src/sfntly/table/bitmap/glyph_metrics.cc delete mode 100644 src/sfntly/src/sfntly/table/bitmap/glyph_metrics.h delete mode 100644 src/sfntly/src/sfntly/table/bitmap/index_sub_table.cc delete mode 100644 src/sfntly/src/sfntly/table/bitmap/index_sub_table.h delete mode 100644 src/sfntly/src/sfntly/table/bitmap/index_sub_table_format1.cc delete mode 100644 src/sfntly/src/sfntly/table/bitmap/index_sub_table_format1.h delete mode 100644 src/sfntly/src/sfntly/table/bitmap/index_sub_table_format2.cc delete mode 100644 src/sfntly/src/sfntly/table/bitmap/index_sub_table_format2.h delete mode 100644 src/sfntly/src/sfntly/table/bitmap/index_sub_table_format3.cc delete mode 100644 src/sfntly/src/sfntly/table/bitmap/index_sub_table_format3.h delete mode 100644 src/sfntly/src/sfntly/table/bitmap/index_sub_table_format4.cc delete mode 100644 src/sfntly/src/sfntly/table/bitmap/index_sub_table_format4.h delete mode 100644 src/sfntly/src/sfntly/table/bitmap/index_sub_table_format5.cc delete mode 100644 src/sfntly/src/sfntly/table/bitmap/index_sub_table_format5.h delete mode 100644 src/sfntly/src/sfntly/table/bitmap/simple_bitmap_glyph.cc delete mode 100644 src/sfntly/src/sfntly/table/bitmap/simple_bitmap_glyph.h delete mode 100644 src/sfntly/src/sfntly/table/bitmap/small_glyph_metrics.cc delete mode 100644 src/sfntly/src/sfntly/table/bitmap/small_glyph_metrics.h delete mode 100644 src/sfntly/src/sfntly/table/byte_array_table_builder.cc delete mode 100644 src/sfntly/src/sfntly/table/byte_array_table_builder.h delete mode 100644 src/sfntly/src/sfntly/table/core/cmap_table.cc delete mode 100644 src/sfntly/src/sfntly/table/core/cmap_table.h delete mode 100644 src/sfntly/src/sfntly/table/core/font_header_table.cc delete mode 100644 src/sfntly/src/sfntly/table/core/font_header_table.h delete mode 100644 src/sfntly/src/sfntly/table/core/horizontal_device_metrics_table.cc delete mode 100644 src/sfntly/src/sfntly/table/core/horizontal_device_metrics_table.h delete mode 100644 src/sfntly/src/sfntly/table/core/horizontal_header_table.cc delete mode 100644 src/sfntly/src/sfntly/table/core/horizontal_header_table.h delete mode 100644 src/sfntly/src/sfntly/table/core/horizontal_metrics_table.cc delete mode 100644 src/sfntly/src/sfntly/table/core/horizontal_metrics_table.h delete mode 100644 src/sfntly/src/sfntly/table/core/maximum_profile_table.cc delete mode 100644 src/sfntly/src/sfntly/table/core/maximum_profile_table.h delete mode 100644 src/sfntly/src/sfntly/table/core/name_table.cc delete mode 100644 src/sfntly/src/sfntly/table/core/name_table.h delete mode 100644 src/sfntly/src/sfntly/table/core/os2_table.cc delete mode 100644 src/sfntly/src/sfntly/table/core/os2_table.h delete mode 100644 src/sfntly/src/sfntly/table/font_data_table.cc delete mode 100644 src/sfntly/src/sfntly/table/font_data_table.h delete mode 100644 src/sfntly/src/sfntly/table/generic_table_builder.cc delete mode 100644 src/sfntly/src/sfntly/table/generic_table_builder.h delete mode 100644 src/sfntly/src/sfntly/table/header.cc delete mode 100644 src/sfntly/src/sfntly/table/header.h delete mode 100644 src/sfntly/src/sfntly/table/subtable.cc delete mode 100644 src/sfntly/src/sfntly/table/subtable.h delete mode 100644 src/sfntly/src/sfntly/table/subtable_container_table.h delete mode 100644 src/sfntly/src/sfntly/table/table.cc delete mode 100644 src/sfntly/src/sfntly/table/table.h delete mode 100644 src/sfntly/src/sfntly/table/table_based_table_builder.cc delete mode 100644 src/sfntly/src/sfntly/table/table_based_table_builder.h delete mode 100644 src/sfntly/src/sfntly/table/truetype/glyph_table.cc delete mode 100644 src/sfntly/src/sfntly/table/truetype/glyph_table.h delete mode 100644 src/sfntly/src/sfntly/table/truetype/loca_table.cc delete mode 100644 src/sfntly/src/sfntly/table/truetype/loca_table.h delete mode 100644 src/sfntly/src/sfntly/tag.cc delete mode 100644 src/sfntly/src/sfntly/tag.h delete mode 100644 src/sfntly/src/sfntly/tools/subsetter/glyph_table_subsetter.cc delete mode 100644 src/sfntly/src/sfntly/tools/subsetter/glyph_table_subsetter.h delete mode 100644 src/sfntly/src/sfntly/tools/subsetter/subsetter.cc delete mode 100644 src/sfntly/src/sfntly/tools/subsetter/subsetter.h delete mode 100644 src/sfntly/src/sfntly/tools/subsetter/table_subsetter.h delete mode 100644 src/sfntly/src/sfntly/tools/subsetter/table_subsetter_impl.cc delete mode 100644 src/sfntly/src/sfntly/tools/subsetter/table_subsetter_impl.h diff --git a/COPYRIGHT b/COPYRIGHT index 1a2c305ad2..85d70a8aa8 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -47,12 +47,6 @@ License: Apache 2.0 The full text of the Apache 2.0 license is available at: http://www.apache.org/licenses/LICENSE-2.0 -Files: src/sfntly/* -Copyright: Google Inc. -License: Apache 2.0 - The full text of the Apache 2.0 license is available at: - http://www.apache.org/licenses/LICENSE-2.0 - Files: resources/viewer/mathjax/* Copyright: Unknown License: Apache 2.0 diff --git a/session.vim b/session.vim index 71c4313365..079975f8d4 100644 --- a/session.vim +++ b/session.vim @@ -11,7 +11,6 @@ let g:syntastic_cpp_include_dirs = [ \'/usr/include/freetype2', \'/usr/include/fontconfig', \'src/qtcurve/common', 'src/qtcurve', - \'src/sfntly/src', 'src/sfntly/src/sample', \'/usr/include/ImageMagick', \] let g:syntastic_c_include_dirs = g:syntastic_cpp_include_dirs diff --git a/setup/extensions.py b/setup/extensions.py index ebc258d7bd..6e3c7e4836 100644 --- a/setup/extensions.py +++ b/setup/extensions.py @@ -19,7 +19,6 @@ from setup.build_environment import (chmlib_inc_dirs, magick_libs, chmlib_lib_dirs, sqlite_inc_dirs, icu_inc_dirs, icu_lib_dirs, win_ddk_lib_dirs, ft_libs, ft_lib_dirs, ft_inc_dirs, zlib_libs, zlib_lib_dirs, zlib_inc_dirs) -from setup.sfntly import SfntlyBuilderMixin MT isunix = islinux or isosx or isbsd @@ -63,26 +62,8 @@ if isosx: icu_libs = ['icucore'] icu_cflags = ['-DU_DISABLE_RENAMING'] # Needed to use system libicucore.dylib -class SfntlyExtension(Extension, SfntlyBuilderMixin): - - def __init__(self, *args, **kwargs): - Extension.__init__(self, *args, **kwargs) - SfntlyBuilderMixin.__init__(self) - - def preflight(self, *args, **kwargs): - self(*args, **kwargs) - extensions = [ - SfntlyExtension('sfntly', - ['calibre/utils/fonts/sfntly.cpp'], - headers= ['calibre/utils/fonts/sfntly.h'], - libraries=icu_libs, - lib_dirs=icu_lib_dirs, - inc_dirs=icu_inc_dirs, - cflags=icu_cflags - ), - Extension('speedup', ['calibre/utils/speedup.c'], ), diff --git a/setup/sfntly.py b/setup/sfntly.py deleted file mode 100644 index 298d0044f0..0000000000 --- a/setup/sfntly.py +++ /dev/null @@ -1,93 +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 ' -__docformat__ = 'restructuredtext en' - -import shlex, os -from glob import glob - -from setup import iswindows - -class Group(object): - - def __init__(self, name, base, build_base, cflags): - self.name = name - self.cflags = cflags - self.headers = frozenset(glob(os.path.join(base, '*.h'))) - self.src_files = glob(os.path.join(base, '*.cc')) - self.bdir = os.path.abspath(os.path.join(build_base, name)) - if not os.path.exists(self.bdir): - os.makedirs(self.bdir) - self.objects = [os.path.join(self.bdir, - os.path.basename(x).rpartition('.')[0] + ('.obj' if iswindows else - '.o')) for x in self.src_files] - - def __call__(self, compiler, linker, builder, all_headers): - for src, obj in zip(self.src_files, self.objects): - if builder.newer(obj, [src] + list(all_headers)): - sinc = ['/Tp'+src] if iswindows else ['-c', src] - oinc = ['/Fo'+obj] if iswindows else ['-o', obj] - cmd = [compiler] + self.cflags + sinc + oinc - builder.info(' '.join(cmd)) - builder.check_call(cmd) - -class SfntlyBuilderMixin(object): - - def __init__(self): - self.sfntly_cflags = [ - '-DSFNTLY_NO_EXCEPTION', - '-DSFNTLY_EXPERIMENTAL', - ] - if iswindows: - self.sfntly_cflags += [ - '-D_UNICODE', '-DUNICODE', - ] + shlex.split('/W4 /WX /Gm- /Gy /GR-') - self.cflags += ['-DWIN32'] - else: - # Possibly add -fno-inline (slower, but more robust) - self.sfntly_cflags += [ - '-Werror', - '-fno-exceptions', - ] - if len(self.libraries) > 1: - self.libraries = ['icuuc'] - if not iswindows: - self.libraries += ['pthread'] - - def __call__(self, obj_dir, compiler, linker, builder, cflags, ldflags): - self.sfntly_build_dir = os.path.join(obj_dir, 'sfntly') - if '/Ox' in cflags: - cflags.remove('/Ox') - if '-O3' in cflags: - cflags.remove('-O3') - if '/W3' in cflags: - cflags.remove('/W3') - if '-ggdb' not in cflags: - cflags.insert(0, '/O2' if iswindows else '-O2') - - groups = [] - all_headers = set() - all_objects = [] - src_dir = self.absolutize([os.path.join('sfntly', 'src')])[0] - inc_dirs = [src_dir] - self.inc_dirs += inc_dirs - inc_flags = builder.inc_dirs_to_cflags(self.inc_dirs) - for loc in ('', 'port', 'data', 'math', 'table', 'table/bitmap', - 'table/core', 'table/truetype'): - path = os.path.join(src_dir, 'sfntly', *loc.split('/')) - gr = Group(loc, path, self.sfntly_build_dir, cflags+ - inc_flags+self.sfntly_cflags+self.cflags) - groups.append(gr) - all_headers |= gr.headers - all_objects.extend(gr.objects) - - for group in groups: - group(compiler, linker, builder, all_headers) - - self.extra_objs = all_objects - - diff --git a/src/calibre/constants.py b/src/calibre/constants.py index fae9b4c87f..05715882f7 100644 --- a/src/calibre/constants.py +++ b/src/calibre/constants.py @@ -91,7 +91,6 @@ class Plugins(collections.Mapping): 'speedup', 'freetype', 'woff', - 'sfntly', ] if iswindows: plugins.extend(['winutil', 'wpd', 'winfonts']) diff --git a/src/calibre/test_build.py b/src/calibre/test_build.py index c80352229e..f173c46ca0 100644 --- a/src/calibre/test_build.py +++ b/src/calibre/test_build.py @@ -37,11 +37,6 @@ def test_freetype(): test() print ('FreeType OK!') -def test_sfntly(): - from calibre.utils.fonts.subset import test - test() - print ('sfntly OK!') - def test_winutil(): from calibre.devices.scanner import win_pnp_drives matches = win_pnp_drives.scanner() @@ -120,7 +115,6 @@ def test(): test_plugins() test_lxml() test_freetype() - test_sfntly() test_sqlite() test_imaging() test_unrar() diff --git a/src/calibre/utils/fonts/sfntly.cpp b/src/calibre/utils/fonts/sfntly.cpp deleted file mode 100644 index d8a3b37a60..0000000000 --- a/src/calibre/utils/fonts/sfntly.cpp +++ /dev/null @@ -1,628 +0,0 @@ -/* - * sfntly.cpp - * Copyright (C) 2012 Kovid Goyal - * - * Distributed under terms of the GPL3 license. - */ - -#define _UNICODE -#define UNICODE -#define PY_SSIZE_T_CLEAN -#include -#include "sfntly.h" - -#include - -#include -#include - -static PyObject *Error = NULL; -static PyObject *NoGlyphs = NULL; -static PyObject *UnsupportedFont = NULL; - -// Predicates {{{ -CompositePredicate::CompositePredicate(IntegerSet &chars, IntegerList &ranges) : - chars(chars), ranges(ranges) {} - -CompositePredicate::~CompositePredicate() {} - -bool CompositePredicate::operator()(int32_t character) const { - for (size_t i = 0; i < ranges.size()/2; i++) { - if (ranges[2*i] <= character && character <= ranges[2*i+1]) return true; - } - return chars.count(character) > 0; -} - -// }}} - -// Font Info {{{ - -GlyphId::GlyphId(int32_t glyph_id, FontId font_id) : glyph_id_(glyph_id), font_id_(font_id) {} - -GlyphId::~GlyphId() {} - -bool GlyphId::operator==(const GlyphId& other) const { return glyph_id_ == other.glyph_id(); } - -bool GlyphId::operator<(const GlyphId& other) const { return glyph_id_ < other.glyph_id(); } - -int32_t GlyphId::glyph_id() const { return glyph_id_; } - -void GlyphId::set_glyph_id(const int32_t glyph_id) { glyph_id_ = glyph_id; } - -FontId GlyphId::font_id() const { return font_id_; } - -void GlyphId::set_font_id(const FontId font_id) { font_id_ = font_id; } - -FontInfo::FontInfo() : chars_to_glyph_ids_(new CharacterMap), - resolved_glyph_ids_(new GlyphIdSet), fonts_(new FontIdMap) { } - -FontInfo::FontInfo(CharacterMap* chars_to_glyph_ids, - GlyphIdSet* resolved_glyph_ids, - FontIdMap* fonts) { - chars_to_glyph_ids_ = new CharacterMap(chars_to_glyph_ids->begin(), - chars_to_glyph_ids->end()); - resolved_glyph_ids_ = new GlyphIdSet(resolved_glyph_ids->begin(), - resolved_glyph_ids->end()); - fonts_ = new FontIdMap(fonts->begin(), fonts->end()); -} - -FontInfo::~FontInfo() { - delete chars_to_glyph_ids_; - delete resolved_glyph_ids_; - delete fonts_; -} - -FontDataTable* FontInfo::GetTable(FontId font_id, int32_t tag) { - if (!fonts_) - return NULL; - FontIdMap::iterator it = fonts_->find(font_id); - if (it == fonts_->end()) - return NULL; - return it->second->GetTable(tag); -} - -const TableMap* FontInfo::GetTableMap(FontId font_id) { - if (!fonts_) - return NULL; - FontIdMap::iterator it = fonts_->find(font_id); - if (it == fonts_->end()) - return NULL; - return it->second->GetTableMap(); -} - -CharacterMap* FontInfo::chars_to_glyph_ids() const { return chars_to_glyph_ids_; } - -void FontInfo::set_chars_to_glyph_ids(CharacterMap* chars_to_glyph_ids) { *chars_to_glyph_ids_ = *chars_to_glyph_ids; } - -GlyphIdSet* FontInfo::resolved_glyph_ids() const { return resolved_glyph_ids_; } - -void FontInfo::set_resolved_glyph_ids(GlyphIdSet* resolved_glyph_ids) { *resolved_glyph_ids_ = *resolved_glyph_ids; } - -FontIdMap* FontInfo::fonts() const { return fonts_; } - -void FontInfo::set_fonts(FontIdMap* fonts) { *fonts_ = *fonts; } - -FontSourcedInfoBuilder::FontSourcedInfoBuilder(Font* font, FontId font_id) : font_(font), font_id_(font_id), -predicate_(NULL) { Initialize(); } - -FontSourcedInfoBuilder::FontSourcedInfoBuilder(Font* font, - FontId font_id, - CharacterPredicate* predicate) : - font_(font), font_id_(font_id), predicate_(predicate) { Initialize(); } - -FontSourcedInfoBuilder::~FontSourcedInfoBuilder() { } - -CALLER_ATTACH FontInfo* FontSourcedInfoBuilder::GetFontInfo() { - if (!cmap_) { - PyErr_SetString(UnsupportedFont, "This font has no format 4 cmap table (usually symbol or asian fonts), subsetting is not supported"); - return NULL; - } - CharacterMap* chars_to_glyph_ids = new CharacterMap; - bool success = GetCharacterMap(chars_to_glyph_ids); - if (!success) { - delete chars_to_glyph_ids; - if (!PyErr_Occurred()) PyErr_SetString(Error, "Error creating character map.\n"); - return NULL; - } - GlyphIdSet* resolved_glyph_ids = new GlyphIdSet; - success = ResolveCompositeGlyphs(chars_to_glyph_ids, resolved_glyph_ids); - if (!success) { - delete chars_to_glyph_ids; - delete resolved_glyph_ids; - if (!PyErr_Occurred()) PyErr_SetString(Error, "Error resolving composite glyphs.\n"); - return NULL; - } - Ptr font_info = new FontInfo; - font_info->set_chars_to_glyph_ids(chars_to_glyph_ids); - font_info->set_resolved_glyph_ids(resolved_glyph_ids); - FontIdMap* font_id_map = new FontIdMap; - font_id_map->insert(std::make_pair(font_id_, font_)); - font_info->set_fonts(font_id_map); - delete chars_to_glyph_ids; - delete resolved_glyph_ids; - delete font_id_map; - return font_info.Detach(); -} - -bool FontSourcedInfoBuilder::GetCharacterMap(CharacterMap* chars_to_glyph_ids) { - if (!cmap_ || !chars_to_glyph_ids) - return false; - chars_to_glyph_ids->clear(); - CMapTable::CMap::CharacterIterator* character_iterator = cmap_->Iterator(); - if (!character_iterator) - return false; - while (character_iterator->HasNext()) { - int32_t character = character_iterator->Next(); - if (!predicate_ || (*predicate_)(character)) { - chars_to_glyph_ids->insert - (std::make_pair(character, - GlyphId(cmap_->GlyphId(character), font_id_))); - } - } - delete character_iterator; - return true; -} - -bool FontSourcedInfoBuilder::ResolveCompositeGlyphs(CharacterMap* chars_to_glyph_ids, - GlyphIdSet* resolved_glyph_ids) { - if (!chars_to_glyph_ids || !resolved_glyph_ids) - return false; - resolved_glyph_ids->clear(); - resolved_glyph_ids->insert(GlyphId(0, font_id_)); - IntegerSet* unresolved_glyph_ids = new IntegerSet; - // Since composite glyph elements might themselves be composite, we would need - // to recursively resolve the elements too. To avoid the recursion we - // create two sets, |unresolved_glyph_ids| for the unresolved glyphs, - // initially containing all the ids and |resolved_glyph_ids|, initially empty. - // We'll remove glyph ids from |unresolved_glyph_ids| until it is empty and, - // if the glyph is composite, add its elements to the unresolved set. - for (CharacterMap::iterator it = chars_to_glyph_ids->begin(), - e = chars_to_glyph_ids->end(); it != e; ++it) { - unresolved_glyph_ids->insert(it->second.glyph_id()); - } - // As long as there are unresolved glyph ids. - while (!unresolved_glyph_ids->empty()) { - // Get the corresponding glyph. - if (!loca_table_) { - PyErr_SetString(UnsupportedFont, "This font does not have a loca table. Subsetting is not supported for fonts without loca tables (usually OTF fonts with PostScript (CFF) outlines)."); - return false; - } - int32_t glyph_id = *(unresolved_glyph_ids->begin()); - unresolved_glyph_ids->erase(unresolved_glyph_ids->begin()); - if (glyph_id < 0 || glyph_id > loca_table_->num_glyphs()) { - continue; - } - int32_t length = loca_table_->GlyphLength(glyph_id); - if (length == 0) { - continue; - } - int32_t offset = loca_table_->GlyphOffset(glyph_id); - GlyphPtr glyph; - if (!glyph_table_) { - PyErr_SetString(UnsupportedFont, "This font does not have a glyf table. Subsetting is not supported for fonts without glyf tables (usually OTF fonts with PostScript (CFF) outlines)."); - return false; - } - glyph.Attach(glyph_table_->GetGlyph(offset, length)); - if (glyph == NULL) { - continue; - } - // Mark the glyph as resolved. - resolved_glyph_ids->insert(GlyphId(glyph_id, font_id_)); - // If it is composite, add all its components to the unresolved glyph set. - if (glyph->GlyphType() == GlyphType::kComposite) { - Ptr composite_glyph = - down_cast(glyph.p_); - int32_t num_glyphs = composite_glyph->NumGlyphs(); - for (int32_t i = 0; i < num_glyphs; ++i) { - int32_t glyph_id = composite_glyph->GlyphIndex(i); - if (resolved_glyph_ids->find(GlyphId(glyph_id, -1)) - == resolved_glyph_ids->end()) { - unresolved_glyph_ids->insert(glyph_id); - } - } - } - } - delete unresolved_glyph_ids; - return true; -} - -void FontSourcedInfoBuilder::Initialize() { - Ptr cmap_table = down_cast(font_->GetTable(Tag::cmap)); - // We prefer Windows BMP format 4 cmaps. - cmap_.Attach(cmap_table->GetCMap(CMapTable::WINDOWS_BMP)); - // But if none is found, - if (!cmap_) { - return; - } - loca_table_ = down_cast(font_->GetTable(Tag::loca)); - glyph_table_ = down_cast(font_->GetTable(Tag::glyf)); -} - - -// }}} - -// Font Assembler {{{ - -FontAssembler::FontAssembler(FontInfo* font_info, IntegerSet* table_blacklist) : - table_blacklist_(table_blacklist) { - font_info_ = font_info; - Initialize(); - } - -FontAssembler::FontAssembler(FontInfo* font_info) : table_blacklist_(NULL) { - font_info_ = font_info; - Initialize(); -} - -FontAssembler::~FontAssembler() { } - -// Assemble a new font from the font info object. -CALLER_ATTACH Font* FontAssembler::Assemble() { - // Assemble tables we can subset. - if (!AssembleCMapTable() || !AssembleGlyphAndLocaTables()) { - return NULL; - } - // For all other tables, either include them unmodified or don't at all. - const TableMap* common_table_map = - font_info_->GetTableMap(font_info_->fonts()->begin()->first); - for (TableMap::const_iterator it = common_table_map->begin(), - e = common_table_map->end(); it != e; ++it) { - if (table_blacklist_ - && table_blacklist_->find(it->first) != table_blacklist_->end()) { - continue; - } - font_builder_->NewTableBuilder(it->first, it->second->ReadFontData()); - } - return font_builder_->Build(); -} - -IntegerSet* FontAssembler::table_blacklist() const { return table_blacklist_; } - -void FontAssembler::set_table_blacklist(IntegerSet* table_blacklist) { - table_blacklist_ = table_blacklist; -} - -bool FontAssembler::AssembleCMapTable() { - // Creating the new CMapTable and the new format 4 CMap - Ptr cmap_table_builder = - down_cast - (font_builder_->NewTableBuilder(Tag::cmap)); - if (!cmap_table_builder) - return false; - Ptr cmap_builder = - down_cast - (cmap_table_builder->NewCMapBuilder(CMapFormat::kFormat4, - CMapTable::WINDOWS_BMP)); - if (!cmap_builder) - return false; - // Creating the segments and the glyph id array - CharacterMap* chars_to_glyph_ids = font_info_->chars_to_glyph_ids(); - SegmentList* segment_list = new SegmentList; - IntegerList* glyph_id_array = new IntegerList; - int32_t last_chararacter = -2; - int32_t last_offset = 0; - Ptr current_segment; - - // For simplicity, we will have one segment per contiguous range. - // To test the algorithm, we've replaced the original CMap with the CMap - // generated by this code without removing any character. - // Tuffy.ttf: CMap went from 3146 to 3972 bytes (1.7% to 2.17% of file) - // AnonymousPro.ttf: CMap went from 1524 to 1900 bytes (0.96% to 1.2%) - for (CharacterMap::iterator it = chars_to_glyph_ids->begin(), - e = chars_to_glyph_ids->end(); it != e; ++it) { - int32_t character = it->first; - int32_t glyph_id = it->second.glyph_id(); - if (character != last_chararacter + 1) { // new segment - if (current_segment != NULL) { - current_segment->set_end_count(last_chararacter); - segment_list->push_back(current_segment); - } - // start_code = character - // end_code = -1 (unknown for now) - // id_delta = 0 (we don't use id_delta for this representation) - // id_range_offset = last_offset (offset into the glyph_id_array) - current_segment = - new CMapTable::CMapFormat4::Builder:: - Segment(character, -1, 0, last_offset); - } - glyph_id_array->push_back(glyph_id); - last_offset += DataSize::kSHORT; - last_chararacter = character; - } - // The last segment is still open. - if (glyph_id_array->size() < 1) { - PyErr_SetString(NoGlyphs, "No glyphs for the specified characters found"); - return false; - } - current_segment->set_end_count(last_chararacter); - segment_list->push_back(current_segment); - // Updating the id_range_offset for every segment. - for (int32_t i = 0, num_segs = segment_list->size(); i < num_segs; ++i) { - Ptr segment = segment_list->at(i); - segment->set_id_range_offset(segment->id_range_offset() - + (num_segs - i + 1) * DataSize::kSHORT); - } - // Adding the final, required segment. - current_segment = - new CMapTable::CMapFormat4::Builder::Segment(0xffff, 0xffff, 1, 0); - segment_list->push_back(current_segment); - // Writing the segments and glyph id array to the CMap - cmap_builder->set_segments(segment_list); - cmap_builder->set_glyph_id_array(glyph_id_array); - delete segment_list; - delete glyph_id_array; - return true; -} - -bool FontAssembler::AssembleGlyphAndLocaTables() { - Ptr loca_table_builder = - down_cast - (font_builder_->NewTableBuilder(Tag::loca)); - Ptr glyph_table_builder = - down_cast - (font_builder_->NewTableBuilder(Tag::glyf)); - - GlyphIdSet* resolved_glyph_ids = font_info_->resolved_glyph_ids(); - IntegerList loca_list; - // Basic sanity check: all LOCA tables are of the same size - // This is necessary but not sufficient! - int32_t previous_size = -1; - for (FontIdMap::iterator it = font_info_->fonts()->begin(); - it != font_info_->fonts()->end(); ++it) { - Ptr loca_table = - down_cast(font_info_->GetTable(it->first, Tag::loca)); - int32_t current_size = loca_table->header_length(); - if (previous_size != -1 && current_size != previous_size) { - return false; - } - previous_size = current_size; - } - - // Assuming all fonts referenced by the FontInfo are the subsets of the same - // font, their loca tables should all have the same sizes. - // We'll just get the size of the first font's LOCA table for simplicty. - Ptr first_loca_table = - down_cast - (font_info_->GetTable(font_info_->fonts()->begin()->first, Tag::loca)); - int32_t num_loca_glyphs = first_loca_table->num_glyphs(); - loca_list.resize(num_loca_glyphs); - loca_list.push_back(0); - int32_t last_glyph_id = 0; - int32_t last_offset = 0; - GlyphTable::GlyphBuilderList* glyph_builders = - glyph_table_builder->GlyphBuilders(); - - for (GlyphIdSet::iterator it = resolved_glyph_ids->begin(), - e = resolved_glyph_ids->end(); it != e; ++it) { - // Get the glyph for this resolved_glyph_id. - int32_t resolved_glyph_id = it->glyph_id(); - int32_t font_id = it->font_id(); - // Get the LOCA table for the current glyph id. - Ptr loca_table = - down_cast - (font_info_->GetTable(font_id, Tag::loca)); - int32_t length = loca_table->GlyphLength(resolved_glyph_id); - int32_t offset = loca_table->GlyphOffset(resolved_glyph_id); - - // Get the GLYF table for the current glyph id. - Ptr glyph_table = - down_cast - (font_info_->GetTable(font_id, Tag::glyf)); - GlyphPtr glyph; - glyph.Attach(glyph_table->GetGlyph(offset, length)); - - // The data reference by the glyph is copied into a new glyph and - // added to the glyph_builders belonging to the glyph_table_builder. - // When Build gets called, all the glyphs will be built. - Ptr data = glyph->ReadFontData(); - Ptr copy_data; - copy_data.Attach(WritableFontData::CreateWritableFontData(data->Length())); - data->CopyTo(copy_data); - GlyphBuilderPtr glyph_builder; - glyph_builder.Attach(glyph_table_builder->GlyphBuilder(copy_data)); - glyph_builders->push_back(glyph_builder); - - // If there are missing glyphs between the last glyph_id and the - // current resolved_glyph_id, since the LOCA table needs to have the same - // size, the offset is kept the same. - for (int32_t i = last_glyph_id + 1; i <= resolved_glyph_id; ++i) - loca_list[i] = last_offset; - last_offset += length; - loca_list[resolved_glyph_id + 1] = last_offset; - last_glyph_id = resolved_glyph_id + 1; - } - // If there are missing glyph ids, their loca entries must all point - // to the same offset as the last valid glyph id making them all zero length. - for (int32_t i = last_glyph_id + 1; i <= num_loca_glyphs; ++i) - loca_list[i] = last_offset; - loca_table_builder->SetLocaList(&loca_list); - return true; -} - -void FontAssembler::Initialize() { - font_factory_.Attach(FontFactory::GetInstance()); - font_builder_.Attach(font_factory_->NewFontBuilder()); -} - - -// }}} - -// Subsetters {{{ -// Subsets a given font using a character predicate. - -PredicateSubsetter::PredicateSubsetter(Font* font, CharacterPredicate* predicate) : font_(font), predicate_(predicate) {} - -PredicateSubsetter::~PredicateSubsetter() { } - -// Performs subsetting returning the subsetted font. -CALLER_ATTACH Font* PredicateSubsetter::Subset() { - Ptr info_builder = - new FontSourcedInfoBuilder(font_, 0, predicate_); - - Ptr font_info; - font_info.Attach(info_builder->GetFontInfo()); - if (!font_info) { - if (!PyErr_Occurred()) PyErr_SetString(Error, "Could not create font info"); - return NULL; - } - - IntegerSet* table_blacklist = new IntegerSet; - table_blacklist->insert(Tag::DSIG); - Ptr font_assembler = new FontAssembler(font_info, - table_blacklist); - Ptr font_subset; - font_subset.Attach(font_assembler->Assemble()); - delete table_blacklist; - if (!font_subset) { if (!PyErr_Occurred()) PyErr_SetString(Error, "Could not subset font"); } - return font_subset.Detach(); -} - - -// }}} - -static void get_stats(Font *font, PyObject *dict) { - PyObject *t; - const TableMap* tables = font->GetTableMap(); - for (TableMap::const_iterator it = tables->begin(), - e = tables->end(); it != e; ++it) { - t = PyInt_FromLong(it->second->DataLength()); - if (t != NULL) { - PyDict_SetItemString(dict, TagToString(it->first), t); - Py_DECREF(t); - } - } -} - -static PyObject* -do_subset(const char *data, Py_ssize_t sz, Ptr &predicate) { - FontPtr font; - Ptr font_factory; - FontArray fonts; - MemoryInputStream stream; - PyObject *stats, *stats2; - - if (!stream.Attach(reinterpret_cast(data), sz)) - return PyErr_NoMemory(); - font_factory.Attach(FontFactory::GetInstance()); - font_factory->LoadFonts(&stream, &fonts); - if (fonts.empty() || fonts[0] == NULL) { - PyErr_SetString(Error, "Failed to load font from provided data."); - return NULL; - } - - font = fonts[0]; - if (font->num_tables() == 0) { - PyErr_SetString(Error, "Loaded font has 0 tables."); - return NULL; - } - Ptr cmap_table = down_cast(font->GetTable(Tag::cmap)); - if (!cmap_table) { - PyErr_SetString(Error, "Loaded font has no cmap table."); - return NULL; - } - Ptr subsetter = new PredicateSubsetter(font, predicate); - Ptr new_font; - new_font.Attach(subsetter->Subset()); - if (!new_font) return NULL; - - Ptr ff; - ff.Attach(FontFactory::GetInstance()); - MemoryOutputStream output_stream; - ff->SerializeFont(new_font, &output_stream); - - stats = PyDict_New(); stats2 = PyDict_New(); - if (stats == NULL || stats2 == NULL) return PyErr_NoMemory(); - get_stats(font, stats); - get_stats(new_font, stats2); - return Py_BuildValue("s#NN", (char*)output_stream.Get(), output_stream.Size(), stats, stats2); -} - -static PyObject* -subset(PyObject *self, PyObject *args) { - const char *data; - Py_ssize_t sz; - PyObject *individual_chars, *ranges, *t; - int32_t temp; - - if (!PyArg_ParseTuple(args, "s#OO", &data, &sz, &individual_chars, &ranges)) return NULL; - - if (!PyTuple_Check(individual_chars) || !PyTuple_Check(ranges)) { - PyErr_SetString(PyExc_TypeError, "individual_chars and ranges must be tuples"); - return NULL; - } - - if (PyTuple_Size(ranges) < 1 && PyTuple_Size(individual_chars) < 1) { - PyErr_SetString(NoGlyphs, "No characters specified"); - return NULL; - } - - IntegerSet chars; - for (Py_ssize_t i = 0; i < PyTuple_Size(individual_chars); i++) { - temp = (int32_t)PyInt_AsLong(PyTuple_GET_ITEM(individual_chars, i)); - if (temp == -1 && PyErr_Occurred()) return NULL; - chars.insert(temp); - } - - IntegerList cranges; - cranges.resize(2*PyTuple_Size(ranges)); - for (Py_ssize_t i = 0; i < PyTuple_Size(ranges); i++) { - t = PyTuple_GET_ITEM(ranges, i); - if (!PyTuple_Check(t) || PyTuple_Size(t) != 2) { - PyErr_SetString(PyExc_TypeError, "ranges must contain only 2-tuples"); - return NULL; - } - for (Py_ssize_t j = 0; j < 2; j++) { - cranges[2*i+j] = (int32_t)PyInt_AsLong(PyTuple_GET_ITEM(t, j)); - if (cranges[2*i+j] == -1 && PyErr_Occurred()) return NULL; - } - } - - Ptr predicate = new (std::nothrow) CompositePredicate(chars, cranges); - if (predicate == NULL) return PyErr_NoMemory(); - - try { - return do_subset(data, sz, predicate); - } catch (std::exception &e) { - PyErr_SetString(Error, e.what()); - return NULL; - } catch (...) { - PyErr_SetString(Error, "An unknown exception occurred while subsetting"); - return NULL; - } - -} - -static -PyMethodDef methods[] = { - {"subset", (PyCFunction)subset, METH_VARARGS, - "subset(bytestring, individual_chars, ranges) -> Subset the sfnt in bytestring, keeping only characters specified by individual_chars and ranges. Returns the subset font as a bytestring and the sizes of all font tables in the old and new fonts." - }, - - {NULL, NULL, 0, NULL} -}; - -PyMODINIT_FUNC -initsfntly(void) { - PyObject *m; - - m = Py_InitModule3( - "sfntly", methods, - "Wrapper for the Google sfntly library" - ); - if (m == NULL) return; - - Error = PyErr_NewException((char*)"sfntly.Error", NULL, NULL); - if (Error == NULL) return; - PyModule_AddObject(m, "Error", Error); - - NoGlyphs = PyErr_NewException((char*)"sfntly.NoGlyphs", NULL, NULL); - if (NoGlyphs == NULL) return; - PyModule_AddObject(m, "NoGlyphs", NoGlyphs); - - UnsupportedFont = PyErr_NewException((char*)"sfntly.UnsupportedFont", NULL, NULL); - if (UnsupportedFont == NULL) return; - PyModule_AddObject(m, "UnsupportedFont", UnsupportedFont); -} - - - diff --git a/src/calibre/utils/fonts/sfntly.h b/src/calibre/utils/fonts/sfntly.h deleted file mode 100644 index 8b015d3dd3..0000000000 --- a/src/calibre/utils/fonts/sfntly.h +++ /dev/null @@ -1,196 +0,0 @@ -/* - * sfntly.h - * Copyright (C) 2012 Kovid Goyal - * - * Distributed under terms of the GPL3 license. - */ -#pragma once - - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -using namespace sfntly; - -typedef int32_t FontId; -typedef std::map > FontIdMap; - -class CharacterPredicate : virtual public RefCount { - public: - CharacterPredicate() {} - virtual ~CharacterPredicate() {} - virtual bool operator()(int32_t character) const = 0; -}; - -class CompositePredicate : public CharacterPredicate, - public RefCounted { - public: - CompositePredicate(IntegerSet &chars, IntegerList &ranges); - ~CompositePredicate(); - virtual bool operator()(int32_t character) const; - private: - IntegerSet chars; - IntegerList ranges; -}; - - - -// Glyph id pair that contains the loca table glyph id as well as the -// font id that has the glyph table this glyph belongs to. -class GlyphId { - public: - GlyphId(int32_t glyph_id, FontId font_id); - ~GlyphId(); - - bool operator==(const GlyphId& other) const; - bool operator<(const GlyphId& other) const; - - int32_t glyph_id() const; - void set_glyph_id(const int32_t glyph_id); - FontId font_id() const; - void set_font_id(const FontId font_id); - - private: - int32_t glyph_id_; - FontId font_id_; -}; - -typedef std::map CharacterMap; -typedef std::set GlyphIdSet; - - -// Font information used for FontAssembler in the construction of a new font. -// Will make copies of character map, glyph id set and font id map. -class FontInfo : public RefCounted { - public: - // Empty FontInfo object. - FontInfo(); - - // chars_to_glyph_ids maps characters to GlyphIds for CMap construction - // resolved_glyph_ids defines GlyphIds which should be in the final font - // fonts is a map of font ids to fonts to reference any needed table - FontInfo(CharacterMap* chars_to_glyph_ids, - GlyphIdSet* resolved_glyph_ids, - FontIdMap* fonts); - - virtual ~FontInfo(); - - // Gets the table with the specified tag from the font corresponding to - // font_id or NULL if there is no such font/table. - // font_id is the id of the font that contains the table - // tag identifies the table to be obtained - virtual FontDataTable* GetTable(FontId font_id, int32_t tag); - - // Gets the table map of the font whose id is font_id - virtual const TableMap* GetTableMap(FontId font_id); - - CharacterMap* chars_to_glyph_ids() const; - // Takes ownership of the chars_to_glyph_ids CharacterMap. - void set_chars_to_glyph_ids(CharacterMap* chars_to_glyph_ids); - - GlyphIdSet* resolved_glyph_ids() const; - // Takes ownership of the glyph_ids GlyphIdSet. - void set_resolved_glyph_ids(GlyphIdSet* resolved_glyph_ids); - - FontIdMap* fonts() const; - - // Takes ownership of the fonts FontIdMap. - void set_fonts(FontIdMap* fonts); - - private: - CharacterMap* chars_to_glyph_ids_; - GlyphIdSet* resolved_glyph_ids_; - FontIdMap* fonts_; -}; - - -// FontSourcedInfoBuilder is used to create a FontInfo object from a Font -// optionally specifying a CharacterPredicate to filter out some of -// the font's characters. -// It does not take ownership or copy the values its constructor receives. -class FontSourcedInfoBuilder : - public RefCounted { - public: - FontSourcedInfoBuilder(Font* font, FontId font_id); - - FontSourcedInfoBuilder(Font* font, - FontId font_id, - CharacterPredicate* predicate); - - virtual ~FontSourcedInfoBuilder(); - - virtual CALLER_ATTACH FontInfo* GetFontInfo(); - - protected: - bool GetCharacterMap(CharacterMap* chars_to_glyph_ids); - - bool ResolveCompositeGlyphs(CharacterMap* chars_to_glyph_ids, - GlyphIdSet* resolved_glyph_ids); - - void Initialize(); - - private: - Ptr font_; - FontId font_id_; - CharacterPredicate* predicate_; - - Ptr cmap_; - Ptr loca_table_; - Ptr glyph_table_; - }; - - -// Assembles FontInfo into font builders. -// Does not take ownership of data passed to it. -class FontAssembler : public RefCounted { - public: - // font_info is the FontInfo which will be used for the new font - // table_blacklist is used to decide which tables to exclude from the - // final font. - FontAssembler(FontInfo* font_info, IntegerSet* table_blacklist); - - explicit FontAssembler(FontInfo* font_info); - - ~FontAssembler(); - - // Assemble a new font from the font info object. - virtual CALLER_ATTACH Font* Assemble(); - - IntegerSet* table_blacklist() const; - - void set_table_blacklist(IntegerSet* table_blacklist); - - protected: - virtual bool AssembleCMapTable(); - - virtual bool AssembleGlyphAndLocaTables(); - - virtual void Initialize(); - - private: - Ptr font_info_; - Ptr font_factory_; - Ptr font_builder_; - IntegerSet* table_blacklist_; -}; - -class PredicateSubsetter : public RefCounted { - public: - PredicateSubsetter(Font* font, CharacterPredicate* predicate); - virtual ~PredicateSubsetter(); - - // Performs subsetting returning the subsetted font. - virtual CALLER_ATTACH Font* Subset(); - - private: - Ptr font_; - Ptr predicate_; -}; diff --git a/src/calibre/utils/fonts/subset.py b/src/calibre/utils/fonts/subset.py deleted file mode 100644 index 777d72971d..0000000000 --- a/src/calibre/utils/fonts/subset.py +++ /dev/null @@ -1,208 +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 ' -__docformat__ = 'restructuredtext en' - -from future_builtins import map - -class NoGlyphs(ValueError): - 'Raised when the font has no glyphs for the specified characters' - pass - -class UnsupportedFont(ValueError): - 'Raised when the font is not supported for subsetting ' - '(usually an OTF font with PostScript outlines).' - pass - -def load_sfntly(): - from calibre.constants import plugins - sfntly, err = plugins['sfntly'] - if err: - raise RuntimeError('Failed to load sfntly: %s'%err) - return sfntly - -def subset(font_data, individual_chars, ranges=()): - if font_data[:4] not in {b'\x00\x01\x00\x00', b'OTTO', b'true', b'typ1'}: - raise ValueError('Not a supported font file. sfnt_version not recognized: %r'% - font_data[:4]) - individual = tuple(sorted(map(ord, individual_chars))) - cranges = [] - for s, e in ranges: - sc, ec = map(ord, (s, e)) - if ec <= sc: - raise ValueError('The start character %s is after the end' - ' character %s'%(s, e)) - cranges.append((sc, ec)) - sfntly = load_sfntly() - try: - return sfntly.subset(font_data, individual, tuple(cranges)) - except sfntly.NoGlyphs: - raise NoGlyphs('No glyphs were found in this font for the' - ' specified characters. Subsetting is pointless') - except sfntly.UnsupportedFont as e: - raise UnsupportedFont(type('')(e)) - -def option_parser(): - import textwrap - from calibre.utils.config import OptionParser - parser = OptionParser(usage=textwrap.dedent('''\ - %prog [options] input_font_file output_font_file characters_to_keep - - Subset the specified font, keeping only the glyphs for the characters in - characters_to_keep. characters_to_keep is a comma separated list of characters of - the form: a,b,c,A-Z,0-9,xyz - - You can specify ranges in the list of characters, as shown above. - ''')) - parser.add_option('-c', '--codes', default=False, action='store_true', - help='If specified, the list of characters is interpreted as ' - 'numeric unicode codes instead of characters. So to specify the ' - 'characters a,b you would use 97,98') - parser.prog = 'subset-font' - return parser - -def print_stats(old_stats, new_stats): - from calibre import prints - prints('========= Table comparison (original vs. subset) =========') - prints('Table', ' ', '%10s'%'Size', ' ', 'Percent', ' ', '%10s'%'New Size', - ' New Percent') - prints('='*80) - old_total = sum(old_stats.itervalues()) - new_total = sum(new_stats.itervalues()) - tables = sorted(old_stats.iterkeys(), key=lambda x:old_stats[x], - reverse=True) - for table in tables: - osz = old_stats[table] - op = osz/old_total * 100 - nsz = new_stats.get(table, 0) - np = nsz/new_total * 100 - suffix = ' | same size' - if nsz != osz: - suffix = ' | reduced to %.1f %%'%(nsz/osz * 100) - prints('%4s'%table, ' ', '%10s'%osz, ' ', '%5.1f %%'%op, ' ', - '%10s'%nsz, ' ', '%5.1f %%'%np, suffix) - prints('='*80) - -def test_mem(): - load_sfntly() - from calibre.utils.mem import memory - import gc - gc.collect() - start_mem = memory() - raw = P('fonts/liberation/LiberationSerif-Regular.ttf', data=True) - calls = 1000 - for i in xrange(calls): - subset(raw, (), (('a', 'z'),)) - del raw - for i in xrange(3): gc.collect() - print ('Leaked memory per call:', (memory() - start_mem)/calls*1024, 'KB') - -def test(): - raw = P('fonts/liberation/LiberationSerif-Regular.ttf', data=True) - sf, old_stats, new_stats = subset(raw, set(('a', 'b', 'c')), ()) - if len(sf) > 0.3 * len(raw): - raise Exception('Subsetting failed') - -def all(): - from calibre.utils.fonts.scanner import font_scanner - failed = [] - unsupported = [] - total = 0 - for family in font_scanner.find_font_families(): - for font in font_scanner.fonts_for_family(family): - raw = font_scanner.get_font_data(font) - print ('Subsetting', font['full_name'], end='\t') - total += 1 - try: - sf, old_stats, new_stats = subset(raw, set(('a', 'b', 'c')), ()) - except NoGlyphs: - print ('No glyphs!') - continue - except UnsupportedFont as e: - unsupported.append((font['full_name'], font['path'], unicode(e))) - print ('Unsupported!') - continue - except Exception as e: - print ('Failed!') - failed.append((font['full_name'], font['path'], unicode(e))) - else: - print ('Reduced to:', '%.1f'%( - sum(new_stats.itervalues())/sum(old_stats.itervalues()) - * 100), '%') - if unsupported: - print ('\n\nUnsupported:') - for name, path, err in unsupported: - print (name, path, err) - print() - if failed: - print ('\n\nFailures:') - for name, path, err in failed: - print (name, path, err) - print() - - print('Total:', total, 'Unsupported:', len(unsupported), 'Failed:', - len(failed)) - - -def main(args): - import sys, time - from calibre import prints - parser = option_parser() - opts, args = parser.parse_args(args) - if len(args) < 4 or len(args) > 4: - parser.print_help() - raise SystemExit(1) - iff, off, chars = args[1:] - with open(iff, 'rb') as f: - orig = f.read() - - chars = [x.strip() for x in chars.split(',')] - individual, ranges = set(), set() - - def not_single(c): - if len(c) > 1: - prints(c, 'is not a single character', file=sys.stderr) - raise SystemExit(1) - - for c in chars: - if '-' in c: - parts = [x.strip() for x in c.split('-')] - if len(parts) != 2: - prints('Invalid range:', c, file=sys.stderr) - raise SystemExit(1) - if opts.codes: - parts = tuple(map(unichr, map(int, parts))) - map(not_single, parts) - ranges.add(tuple(parts)) - else: - if opts.codes: - c = unichr(int(c)) - not_single(c) - individual.add(c) - st = time.time() - sf, old_stats, new_stats = subset(orig, individual, ranges) - taken = time.time() - st - reduced = (len(sf)/len(orig)) * 100 - def sz(x): - return '%gKB'%(len(x)/1024.) - print_stats(old_stats, new_stats) - prints('Original size:', sz(orig), 'Subset size:', sz(sf), 'Reduced to: %g%%'%(reduced)) - prints('Subsetting took %g seconds'%taken) - with open(off, 'wb') as f: - f.write(sf) - prints('Subset font written to:', off) - -if __name__ == '__main__': - try: - import init_calibre - init_calibre - except ImportError: - pass - import sys - main(sys.argv) - - diff --git a/src/sfntly/COPYING.txt b/src/sfntly/COPYING.txt deleted file mode 100644 index c61423cfed..0000000000 --- a/src/sfntly/COPYING.txt +++ /dev/null @@ -1,203 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2011 Google Inc. All Rights Reserved. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - diff --git a/src/sfntly/src/sfntly/data/byte_array.cc b/src/sfntly/src/sfntly/data/byte_array.cc deleted file mode 100644 index 915a40c035..0000000000 --- a/src/sfntly/src/sfntly/data/byte_array.cc +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/data/byte_array.h" - -#include - -#include "sfntly/port/exception_type.h" - -namespace sfntly { - -const int32_t ByteArray::COPY_BUFFER_SIZE = 8192; - -ByteArray::~ByteArray() {} - -int32_t ByteArray::Length() { return filled_length_; } -int32_t ByteArray::Size() { return storage_length_; } - -int32_t ByteArray::SetFilledLength(int32_t filled_length) { - filled_length_ = std::min(filled_length, storage_length_); - return filled_length_; -} - -int32_t ByteArray::Get(int32_t index) { - return InternalGet(index) & 0xff; -} - -int32_t ByteArray::Get(int32_t index, ByteVector* b) { - assert(b); - return Get(index, &((*b)[0]), 0, b->size()); -} - -int32_t ByteArray::Get(int32_t index, - byte_t* b, - int32_t offset, - int32_t length) { - assert(b); - if (index < 0 || index >= filled_length_) { - return 0; - } - int32_t actual_length = std::min(length, filled_length_ - index); - return InternalGet(index, b, offset, actual_length); -} - -void ByteArray::Put(int32_t index, byte_t b) { - if (index < 0 || index >= Size()) { -#if defined (SFNTLY_NO_EXCEPTION) - return; -#else - throw IndexOutOfBoundException( - "Attempt to write outside the bounds of the data"); -#endif - } - InternalPut(index, b); - filled_length_ = std::max(filled_length_, index + 1); -} - -int32_t ByteArray::Put(int index, ByteVector* b) { - assert(b); - return Put(index, &((*b)[0]), 0, b->size()); -} - -int32_t ByteArray::Put(int32_t index, - byte_t* b, - int32_t offset, - int32_t length) { - assert(b); - if (index < 0 || index >= Size()) { -#if defined (SFNTLY_NO_EXCEPTION) - return 0; -#else - throw IndexOutOfBoundException( - "Attempt to write outside the bounds of the data"); -#endif - } - int32_t actual_length = std::min(length, Size() - index); - int32_t bytes_written = InternalPut(index, b, offset, actual_length); - filled_length_ = std::max(filled_length_, index + bytes_written); - return bytes_written; -} - -int32_t ByteArray::CopyTo(ByteArray* array) { - return CopyTo(array, 0, Length()); -} - -int32_t ByteArray::CopyTo(ByteArray* array, int32_t offset, int32_t length) { - return CopyTo(0, array, offset, length); -} - -int32_t ByteArray::CopyTo(int32_t dst_offset, ByteArray* array, - int32_t src_offset, int32_t length) { - assert(array); - if (array->Size() < dst_offset + length) { // insufficient space - return -1; - } - - ByteVector b(COPY_BUFFER_SIZE); - int32_t bytes_read = 0; - int32_t index = 0; - int32_t remaining_length = length; - int32_t buffer_length = std::min(COPY_BUFFER_SIZE, length); - while ((bytes_read = - Get(index + src_offset, &(b[0]), 0, buffer_length)) > 0) { - int bytes_written = array->Put(index + dst_offset, &(b[0]), 0, bytes_read); - UNREFERENCED_PARAMETER(bytes_written); - index += bytes_read; - remaining_length -= bytes_read; - buffer_length = std::min(b.size(), remaining_length); - } - return index; -} - -int32_t ByteArray::CopyTo(OutputStream* os) { - return CopyTo(os, 0, Length()); -} - -int32_t ByteArray::CopyTo(OutputStream* os, int32_t offset, int32_t length) { - ByteVector b(COPY_BUFFER_SIZE); - int32_t bytes_read = 0; - int32_t index = 0; - int32_t buffer_length = std::min(COPY_BUFFER_SIZE, length); - while ((bytes_read = Get(index + offset, &(b[0]), 0, buffer_length)) > 0) { - os->Write(&b, 0, bytes_read); - index += bytes_read; - buffer_length = std::min(b.size(), length - index); - } - return index; -} - -bool ByteArray::CopyFrom(InputStream* is, int32_t length) { - ByteVector b(COPY_BUFFER_SIZE); - int32_t bytes_read = 0; - int32_t index = 0; - int32_t buffer_length = std::min(COPY_BUFFER_SIZE, length); - while ((bytes_read = is->Read(&b, 0, buffer_length)) > 0) { - if (Put(index, &(b[0]), 0, bytes_read) != bytes_read) { -#if defined (SFNTLY_NO_EXCEPTION) - return 0; -#else - throw IOException("Error writing bytes."); -#endif - } - index += bytes_read; - length -= bytes_read; - buffer_length = std::min(b.size(), length); - } - return true; -} - -bool ByteArray::CopyFrom(InputStream* is) { - ByteVector b(COPY_BUFFER_SIZE); - int32_t bytes_read = 0; - int32_t index = 0; - int32_t buffer_length = COPY_BUFFER_SIZE; - while ((bytes_read = is->Read(&b, 0, buffer_length)) > 0) { - if (Put(index, &b[0], 0, bytes_read) != bytes_read) { -#if defined (SFNTLY_NO_EXCEPTION) - return 0; -#else - throw IOException("Error writing bytes."); -#endif - } - index += bytes_read; - } - return true; -} - -ByteArray::ByteArray(int32_t filled_length, - int32_t storage_length, - bool growable) { - Init(filled_length, storage_length, growable); -} - -ByteArray::ByteArray(int32_t filled_length, int32_t storage_length) { - Init(filled_length, storage_length, false); -} - -void ByteArray::Init(int32_t filled_length, - int32_t storage_length, - bool growable) { - storage_length_ = storage_length; - growable_ = growable; - SetFilledLength(filled_length); -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/data/byte_array.h b/src/sfntly/src/sfntly/data/byte_array.h deleted file mode 100644 index 70dc92f51a..0000000000 --- a/src/sfntly/src/sfntly/data/byte_array.h +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (C) 2011 The sfntly Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_BYTE_ARRAY_H_ -#define SFNTLY_CPP_SRC_SFNTLY_DATA_BYTE_ARRAY_H_ - -#include "sfntly/port/refcount.h" -#include "sfntly/port/type.h" -#include "sfntly/port/input_stream.h" -#include "sfntly/port/output_stream.h" - -namespace sfntly { - -// An abstraction to a contiguous array of bytes. -// C++ port of this class assumes that the data are stored in a linear region -// like std::vector. -class ByteArray : virtual public RefCount { - public: - virtual ~ByteArray(); - - // Gets the current filled and readable length of the array. - int32_t Length(); - - // Gets the maximum size of the array. This is the maximum number of bytes that - // the array can hold and all of it may not be filled with data or even fully - // allocated yet. - int32_t Size(); - - // Determines whether or not this array is growable or of fixed size. - bool growable() { return growable_; } - - int32_t SetFilledLength(int32_t filled_length); - - // Gets the byte from the given index. - // @param index the index into the byte array - // @return the byte or -1 if reading beyond the bounds of the data - virtual int32_t Get(int32_t index); - - // Gets the bytes from the given index and fill the buffer with them. As many - // bytes as will fit into the buffer are read unless that would go past the - // end of the array. - // @param index the index into the byte array - // @param b the buffer to put the bytes read into - // @return the number of bytes read from the buffer - virtual int32_t Get(int32_t index, ByteVector* b); - - // Gets the bytes from the given index and fill the buffer with them starting - // at the offset given. As many bytes as the specified length are read unless - // that would go past the end of the array. - // @param index the index into the byte array - // @param b the buffer to put the bytes read into - // @param offset the location in the buffer to start putting the bytes - // @param length the number of bytes to put into the buffer - // @return the number of bytes read from the buffer - virtual int32_t Get(int32_t index, - byte_t* b, - int32_t offset, - int32_t length); - - // Puts the specified byte into the array at the given index unless that would - // be beyond the length of the array and it isn't growable. - virtual void Put(int32_t index, byte_t b); - - // Puts the specified bytes into the array at the given index. The entire - // buffer is put into the array unless that would extend beyond the length and - // the array isn't growable. - virtual int32_t Put(int32_t index, ByteVector* b); - - // Puts the specified bytes into the array at the given index. All of the bytes - // specified are put into the array unless that would extend beyond the length - // and the array isn't growable. The bytes to be put into the array are those - // in the buffer from the given offset and for the given length. - // @param index the index into the ByteArray - // @param b the bytes to put into the array - // @param offset the offset in the bytes to start copying from - // @param length the number of bytes to copy into the array - // @return the number of bytes actually written - virtual int32_t Put(int32_t index, - byte_t* b, - int32_t offset, - int32_t length); - - // Fully copies this ByteArray to another ByteArray to the extent that the - // destination array has storage for the data copied. - virtual int32_t CopyTo(ByteArray* array); - - // Copies a segment of this ByteArray to another ByteArray. - // @param array the destination - // @param offset the offset in this ByteArray to start copying from - // @param length the maximum length in bytes to copy - // @return the number of bytes copied - virtual int32_t CopyTo(ByteArray* array, int32_t offset, int32_t length); - - // Copies this ByteArray to another ByteArray. - // @param dstOffset the offset in the destination array to start copying to - // @param array the destination - // @param srcOffset the offset in this ByteArray to start copying from - // @param length the maximum length in bytes to copy - // @return the number of bytes copied - virtual int32_t CopyTo(int32_t dst_offset, - ByteArray* array, - int32_t src_offset, - int32_t length); - - // Copies this ByteArray to an OutputStream. - // @param os the destination - // @return the number of bytes copied - virtual int32_t CopyTo(OutputStream* os); - - // Copies this ByteArray to an OutputStream. - // @param os the destination - // @param offset - // @param length - // @return the number of bytes copied - virtual int32_t CopyTo(OutputStream* os, int32_t offset, int32_t length); - - // Copies from the InputStream into this ByteArray. - // @param is the source - // @param length the number of bytes to copy - virtual bool CopyFrom(InputStream* is, int32_t length); - - // Copies everything from the InputStream into this ByteArray. - // @param is the source - virtual bool CopyFrom(InputStream* is); - - protected: - // filledLength the length that is "filled" and readable counting from offset. - // storageLength the maximum storage size of the underlying data. - // growable is the storage growable - storageLength is the max growable size. - ByteArray(int32_t filled_length, int32_t storage_length, bool growable); - ByteArray(int32_t filled_length, int32_t storage_length); - void Init(int32_t filled_length, int32_t storage_length, bool growable); - - // Internal subclass API - - // Stores the byte at the index given. - // @param index the location to store at - // @param b the byte to store - virtual void InternalPut(int32_t index, byte_t b) = 0; - - // Stores the array of bytes at the given index. - // @param index the location to store at - // @param b the bytes to store - // @param offset the offset to start from in the byte array - // @param length the length of the byte array to store from the offset - // @return the number of bytes actually stored - virtual int32_t InternalPut(int32_t index, - byte_t* b, - int32_t offset, - int32_t length) = 0; - - // Gets the byte at the index given. - // @param index the location to get from - // @return the byte stored at the index - virtual byte_t InternalGet(int32_t index) = 0; - - // Gets the bytes at the index given of the given length. - // @param index the location to start getting from - // @param b the array to put the bytes into - // @param offset the offset in the array to put the bytes into - // @param length the length of bytes to read - // @return the number of bytes actually ready - virtual int32_t InternalGet(int32_t index, - byte_t* b, - int32_t offset, - int32_t length) = 0; - - // Close this instance of the ByteArray. - virtual void Close() = 0; - - // C++ port only, raw pointer to the first element of storage. - virtual byte_t* Begin() = 0; - - // Java toString() not ported. - - static const int32_t COPY_BUFFER_SIZE; - - private: - //bool bound_; // unused, comment out - int32_t filled_length_; - int32_t storage_length_; - bool growable_; -}; -typedef Ptr ByteArrayPtr; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_DATA_BYTE_ARRAY_H_ diff --git a/src/sfntly/src/sfntly/data/font_data.cc b/src/sfntly/src/sfntly/data/font_data.cc deleted file mode 100644 index d2b95eac1b..0000000000 --- a/src/sfntly/src/sfntly/data/font_data.cc +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include - -#include "sfntly/data/font_data.h" - -namespace sfntly { - -int32_t FontData::Size() const { - return std::min(array_->Size() - bound_offset_, bound_length_); -} - -bool FontData::Bound(int32_t offset, int32_t length) { - if (offset + length > Size() || offset < 0 || length < 0) - return false; - - bound_offset_ += offset; - bound_length_ = length; - return true; -} - -bool FontData::Bound(int32_t offset) { -if (offset > Size() || offset < 0) - return false; - - bound_offset_ += offset; - return true; -} - -int32_t FontData::Length() const { - return std::min(array_->Length() - bound_offset_, bound_length_); -} - -FontData::FontData(ByteArray* ba) { - Init(ba); -} - -FontData::FontData(FontData* data, int32_t offset, int32_t length) { - Init(data->array_); - Bound(data->bound_offset_ + offset, length); -} - -FontData::FontData(FontData* data, int32_t offset) { - Init(data->array_); - Bound(data->bound_offset_ + offset, - (data->bound_length_ == GROWABLE_SIZE) - ? GROWABLE_SIZE : data->bound_length_ - offset); -} - -FontData::~FontData() {} - -void FontData::Init(ByteArray* ba) { - array_ = ba; - bound_offset_ = 0; - bound_length_ = GROWABLE_SIZE; -} - -int32_t FontData::BoundOffset(int32_t offset) { - return offset + bound_offset_; -} - -int32_t FontData::BoundLength(int32_t offset, int32_t length) { - return std::min(length, bound_length_ - offset); -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/data/font_data.h b/src/sfntly/src/sfntly/data/font_data.h deleted file mode 100644 index d02e8b75db..0000000000 --- a/src/sfntly/src/sfntly/data/font_data.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_DATA_H_ -#define SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_DATA_H_ - -#include - -#include - -#include "sfntly/port/type.h" -#include "sfntly/data/byte_array.h" -#include "sfntly/port/refcount.h" - -namespace sfntly { - -struct DataSize { - enum { - kBYTE = 1, - kCHAR = 1, - kUSHORT = 2, - kSHORT = 2, - kUINT24 = 3, - kULONG = 4, - kLONG = 4, - kFixed = 4, - kFUNIT = 4, - kFWORD = 2, - kUFWORD = 2, - kF2DOT14 = 2, - kLONGDATETIME = 8, - kTag = 4, - kGlyphID = 2, - kOffset = 2 - }; -}; - -class FontData : virtual public RefCount { - public: - // Gets the maximum size of the FontData. This is the maximum number of bytes - // that the font data can hold and all of it may not be filled with data or - // even fully allocated yet. - // @return the maximum size of this font data - virtual int32_t Size() const; - - // Sets limits on the size of the FontData. The FontData is then only - // visible within the bounds set. - // @param offset the start of the new bounds - // @param length the number of bytes in the bounded array - // @return true if the bounding range was successful; false otherwise - virtual bool Bound(int32_t offset, int32_t length); - - // Sets limits on the size of the FontData. This is a offset bound only so if - // the FontData is writable and growable then there is no limit to that growth - // from the bounding operation. - // @param offset the start of the new bounds which must be within the current - // size of the FontData - // @return true if the bounding range was successful; false otherwise - virtual bool Bound(int32_t offset); - - // Makes a slice of this FontData. The returned slice will share the data with - // the original FontData. - // @param offset the start of the slice - // @param length the number of bytes in the slice - // @return a slice of the original FontData - virtual CALLER_ATTACH FontData* Slice(int32_t offset, int32_t length) = 0; - - // Makes a bottom bound only slice of this array. The returned slice will - // share the data with the original FontData. - // @param offset the start of the slice - // @return a slice of the original FontData - virtual CALLER_ATTACH FontData* Slice(int32_t offset) = 0; - - // Gets the length of the data. - virtual int32_t Length() const; - - protected: - // Constructor. - // @param ba the byte array to use for the backing data - explicit FontData(ByteArray* ba); - - // Constructor. - // @param data the data to wrap - // @param offset the offset to start the wrap from - // @param length the length of the data wrapped - FontData(FontData* data, int32_t offset, int32_t length); - - // Constructor. - // @param data the data to wrap - // @param offset the offset to start the wrap from - FontData(FontData* data, int32_t offset); - virtual ~FontData(); - - void Init(ByteArray* ba); - - // Gets the offset in the underlying data taking into account any bounds on - // the data. - // @param offset the offset to get the bound compensated offset for - // @return the bound compensated offset - int32_t BoundOffset(int32_t offset); - - // Gets the length in the underlying data taking into account any bounds on - // the data. - // @param offset the offset that the length is being used at - // @param length the length to get the bound compensated length for - // @return the bound compensated length - int32_t BoundLength(int32_t offset, int32_t length); - - static const int32_t GROWABLE_SIZE = INT_MAX; - - // TODO(arthurhsu): style guide violation: refactor this protected member - ByteArrayPtr array_; - - private: - int32_t bound_offset_; - int32_t bound_length_; -}; -typedef Ptr FontDataPtr; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_DATA_H_ diff --git a/src/sfntly/src/sfntly/data/font_input_stream.cc b/src/sfntly/src/sfntly/data/font_input_stream.cc deleted file mode 100644 index dcf8be35f9..0000000000 --- a/src/sfntly/src/sfntly/data/font_input_stream.cc +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/data/font_input_stream.h" - -#include - -namespace sfntly { - -FontInputStream::FontInputStream(InputStream* is) - : stream_(is), position_(0), length_(0), bounded_(false) { -} - -FontInputStream::FontInputStream(InputStream* is, size_t length) - : stream_(is), position_(0), length_(length), bounded_(true) { -} - -FontInputStream::~FontInputStream() { - // Do not close here, underlying InputStream will close themselves. -} - -int32_t FontInputStream::Available() { - if (stream_) { - return stream_->Available(); - } - return 0; -} - -void FontInputStream::Close() { - if (stream_) { - stream_->Close(); - } -} - -void FontInputStream::Mark(int32_t readlimit) { - if (stream_) { - stream_->Mark(readlimit); - } -} - -bool FontInputStream::MarkSupported() { - if (stream_) { - return stream_->MarkSupported(); - } - return false; -} - -void FontInputStream::Reset() { - if (stream_) { - stream_->Reset(); - } -} - -int32_t FontInputStream::Read() { - if (!stream_ || (bounded_ && position_ >= length_)) { - return -1; - } - int32_t b = stream_->Read(); - if (b >= 0) { - position_++; - } - return b; -} - -int32_t FontInputStream::Read(ByteVector* b, int32_t offset, int32_t length) { - if (!stream_ || offset < 0 || length < 0 || - (bounded_ && position_ >= length_)) { - return -1; - } - int32_t bytes_to_read = - bounded_ ? std::min(length, (int32_t)(length_ - position_)) : - length; - int32_t bytes_read = stream_->Read(b, offset, bytes_to_read); - position_ += bytes_read; - return bytes_read; -} - -int32_t FontInputStream::Read(ByteVector* b) { - return Read(b, 0, b->size()); -} - -int32_t FontInputStream::ReadChar() { - return Read(); -} - -int32_t FontInputStream::ReadUShort() { - return 0xffff & (Read() << 8 | Read()); -} - -int32_t FontInputStream::ReadShort() { - return ((Read() << 8 | Read()) << 16) >> 16; -} - -int32_t FontInputStream::ReadUInt24() { - return 0xffffff & (Read() << 16 | Read() << 8 | Read()); -} - -int64_t FontInputStream::ReadULong() { - return 0xffffffffL & ReadLong(); -} - -int32_t FontInputStream::ReadULongAsInt() { - int64_t ulong = ReadULong(); - return ((int32_t)ulong) & ~0x80000000; -} - -int32_t FontInputStream::ReadLong() { - return Read() << 24 | Read() << 16 | Read() << 8 | Read(); -} - -int32_t FontInputStream::ReadFixed() { - return ReadLong(); -} - -int64_t FontInputStream::ReadDateTimeAsLong() { - return (int64_t)ReadULong() << 32 | ReadULong(); -} - -int64_t FontInputStream::Skip(int64_t n) { - if (stream_) { - int64_t skipped = stream_->Skip(n); - position_ += skipped; - return skipped; - } - return 0; -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/data/font_input_stream.h b/src/sfntly/src/sfntly/data/font_input_stream.h deleted file mode 100644 index 9992b0753f..0000000000 --- a/src/sfntly/src/sfntly/data/font_input_stream.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_INPUT_STREAM_H_ -#define SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_INPUT_STREAM_H_ - -#include "sfntly/port/type.h" -#include "sfntly/port/input_stream.h" - -namespace sfntly { - -// An input stream for reading font data. -// The data types used are as listed: -// BYTE 8-bit unsigned integer. -// CHAR 8-bit signed integer. -// USHORT 16-bit unsigned integer. -// SHORT 16-bit signed integer. -// UINT24 24-bit unsigned integer. -// ULONG 32-bit unsigned integer. -// LONG 32-bit signed integer. -// Fixed 32-bit signed fixed-point number (16.16) -// FUNIT Smallest measurable distance in the em space. -// FWORD 16-bit signed integer (SHORT) that describes a quantity in FUnits. -// UFWORD 16-bit unsigned integer (USHORT) that describes a quantity in -// FUnits. -// F2DOT14 16-bit signed fixed number with the low 14 bits of fraction (2.14) -// LONGDATETIME Date represented in number of seconds since 12:00 midnight, -// January 1, 1904. The value is represented as a signed 64-bit -// integer. - -// Note: Original class inherits from Java's FilterOutputStream, which wraps -// an InputStream within. In C++, we directly do the wrapping without -// defining another layer of abstraction. The wrapped output stream is -// *NOT* reference counted (because it's meaningless to ref-count an I/O -// stream). -class FontInputStream : public InputStream { - public: - // Constructor. - // @param is input stream to wrap - explicit FontInputStream(InputStream* is); - - // Constructor for a bounded font input stream. - // @param is input stream to wrap - // @param length the maximum length of bytes to read - FontInputStream(InputStream* is, size_t length); - - virtual ~FontInputStream(); - - - virtual int32_t Available(); - virtual void Close(); - virtual void Mark(int32_t readlimit); - virtual bool MarkSupported(); - virtual void Reset(); - - virtual int32_t Read(); - virtual int32_t Read(ByteVector* buffer); - virtual int32_t Read(ByteVector* buffer, int32_t offset, int32_t length); - - // Get the current position in the stream in bytes. - // @return the current position in bytes - virtual int64_t position() { return position_; } - - virtual int32_t ReadChar(); - virtual int32_t ReadUShort(); - virtual int32_t ReadShort(); - virtual int32_t ReadUInt24(); - virtual int64_t ReadULong(); - virtual int32_t ReadULongAsInt(); - virtual int32_t ReadLong(); - virtual int32_t ReadFixed(); - virtual int64_t ReadDateTimeAsLong(); - virtual int64_t Skip(int64_t n); // n can be negative. - - private: - InputStream* stream_; - int64_t position_; - int64_t length_; // Bound on length of data to read. - bool bounded_; -}; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_INPUT_STREAM_H_ diff --git a/src/sfntly/src/sfntly/data/font_output_stream.cc b/src/sfntly/src/sfntly/data/font_output_stream.cc deleted file mode 100644 index 3422a22827..0000000000 --- a/src/sfntly/src/sfntly/data/font_output_stream.cc +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/data/font_output_stream.h" - -#include - -namespace sfntly { - -FontOutputStream::FontOutputStream(OutputStream* os) - : stream_(os), - position_(0) { -} - -FontOutputStream::~FontOutputStream() { - // Do not close, underlying stream shall clean up themselves. -} - -void FontOutputStream::Write(byte_t b) { - if (stream_) { - stream_->Write(b); - position_++; - } -} - -void FontOutputStream::Write(ByteVector* b) { - if (b) { - Write(b, 0, b->size()); - position_ += b->size(); - } -} - -void FontOutputStream::Write(ByteVector* b, int32_t off, int32_t len) { - assert(b); - assert(stream_); - if (off < 0 || len < 0 || off + len < 0 || - static_cast(off + len) > b->size()) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IndexOutOfBoundException(); -#else - return; -#endif - } - - stream_->Write(b, off, len); - position_ += len; -} - -void FontOutputStream::Write(byte_t* b, int32_t off, int32_t len) { - assert(b); - assert(stream_); - if (off < 0 || len < 0 || off + len < 0) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IndexOutOfBoundException(); -#else - return; -#endif - } - - stream_->Write(b, off, len); - position_ += len; -} - -void FontOutputStream::WriteChar(byte_t c) { - Write(c); -} - -void FontOutputStream::WriteUShort(int32_t us) { - Write((byte_t)((us >> 8) & 0xff)); - Write((byte_t)(us & 0xff)); -} - -void FontOutputStream::WriteShort(int32_t s) { - WriteUShort(s); -} - -void FontOutputStream::WriteUInt24(int32_t ui) { - Write((byte_t)(ui >> 16) & 0xff); - Write((byte_t)(ui >> 8) & 0xff); - Write((byte_t)ui & 0xff); -} - -void FontOutputStream::WriteULong(int64_t ul) { - Write((byte_t)((ul >> 24) & 0xff)); - Write((byte_t)((ul >> 16) & 0xff)); - Write((byte_t)((ul >> 8) & 0xff)); - Write((byte_t)(ul & 0xff)); -} - -void FontOutputStream::WriteLong(int64_t l) { - WriteULong(l); -} - -void FontOutputStream::WriteFixed(int32_t f) { - WriteULong(f); -} - -void FontOutputStream::WriteDateTime(int64_t date) { - WriteULong((date >> 32) & 0xffffffff); - WriteULong(date & 0xffffffff); -} - -void FontOutputStream::Flush() { - if (stream_) { - stream_->Flush(); - } -} - -void FontOutputStream::Close() { - if (stream_) { - stream_->Flush(); - stream_->Close(); - position_ = 0; - } -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/data/font_output_stream.h b/src/sfntly/src/sfntly/data/font_output_stream.h deleted file mode 100644 index fcd48e8aaa..0000000000 --- a/src/sfntly/src/sfntly/data/font_output_stream.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_OUTPUT_STREAM_H_ -#define SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_OUTPUT_STREAM_H_ - -#include "sfntly/port/type.h" -#include "sfntly/port/output_stream.h" - -namespace sfntly { - -// An output stream for writing font data. -// The data types used are as listed: -// BYTE 8-bit unsigned integer. -// CHAR 8-bit signed integer. -// USHORT 16-bit unsigned integer. -// SHORT 16-bit signed integer. -// UINT24 24-bit unsigned integer. -// ULONG 32-bit unsigned integer. -// LONG 32-bit signed integer. -// Fixed 32-bit signed fixed-point number (16.16) -// FUNIT Smallest measurable distance in the em space. -// FWORD 16-bit signed integer (SHORT) that describes a quantity in FUnits. -// UFWORD 16-bit unsigned integer (USHORT) that describes a quantity in -// FUnits. -// F2DOT14 16-bit signed fixed number with the low 14 bits of fraction (2.14) -// LONGDATETIME Date represented in number of seconds since 12:00 midnight, -// January 1, 1904. The value is represented as a signed 64-bit -// integer. - -// Note: The wrapped output stream is *NOT* reference counted (because it's -// meaningless to ref-count an I/O stream). -class FontOutputStream : public OutputStream { - public: - explicit FontOutputStream(OutputStream* os); - virtual ~FontOutputStream(); - - virtual size_t position() { return position_; } - - virtual void Write(byte_t b); - virtual void Write(ByteVector* b); - virtual void Write(ByteVector* b, int32_t off, int32_t len); - virtual void Write(byte_t* b, int32_t off, int32_t len); - virtual void WriteChar(byte_t c); - virtual void WriteUShort(int32_t us); - virtual void WriteShort(int32_t s); - virtual void WriteUInt24(int32_t ui); - virtual void WriteULong(int64_t ul); - virtual void WriteLong(int64_t l); - virtual void WriteFixed(int32_t l); - virtual void WriteDateTime(int64_t date); - - // Note: C++ port only. - virtual void Flush(); - virtual void Close(); - - private: - // Note: we do not use the variable name out as in Java because it has - // special meaning in VC++ and will be very confusing. - OutputStream* stream_; - size_t position_; -}; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_OUTPUT_STREAM_H_ diff --git a/src/sfntly/src/sfntly/data/growable_memory_byte_array.cc b/src/sfntly/src/sfntly/data/growable_memory_byte_array.cc deleted file mode 100644 index c335614d4d..0000000000 --- a/src/sfntly/src/sfntly/data/growable_memory_byte_array.cc +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/data/growable_memory_byte_array.h" - -#include -#include - -#include - -namespace sfntly { - -GrowableMemoryByteArray::GrowableMemoryByteArray() - : ByteArray(0, INT_MAX, true) { - // Note: We did not set an initial size of array like Java because STL - // implementation will determine the best strategy. -} - -GrowableMemoryByteArray::~GrowableMemoryByteArray() {} - -int32_t GrowableMemoryByteArray::CopyTo(OutputStream* os, - int32_t offset, - int32_t length) { - assert(os); - os->Write(&b_, offset, length); - return length; -} - -void GrowableMemoryByteArray::InternalPut(int32_t index, byte_t b) { - if ((size_t)index >= b_.size()) { - b_.resize((size_t)(index + 1)); - } - b_[index] = b; -} - -int32_t GrowableMemoryByteArray::InternalPut(int32_t index, - byte_t* b, - int32_t offset, - int32_t length) { - if ((size_t)index + length >= b_.size()) { - // Note: We grow one byte more than Java version. VC debuggers shows - // data better this way. - b_.resize((size_t)(index + length + 1)); - } - std::copy(b + offset, b + offset + length, b_.begin() + index); - return length; -} - -byte_t GrowableMemoryByteArray::InternalGet(int32_t index) { - return b_[index]; -} - -int32_t GrowableMemoryByteArray::InternalGet(int32_t index, - byte_t* b, - int32_t offset, - int32_t length) { - memcpy(b + offset, &(b_[0]) + index, length); - return length; -} - -void GrowableMemoryByteArray::Close() { - b_.clear(); -} - -byte_t* GrowableMemoryByteArray::Begin() { - return &(b_[0]); -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/data/growable_memory_byte_array.h b/src/sfntly/src/sfntly/data/growable_memory_byte_array.h deleted file mode 100644 index 8583a0d645..0000000000 --- a/src/sfntly/src/sfntly/data/growable_memory_byte_array.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_GROWABLE_MEMORY_BYTE_ARRAY_H_ -#define SFNTLY_CPP_SRC_SFNTLY_DATA_GROWABLE_MEMORY_BYTE_ARRAY_H_ - -#include "sfntly/data/byte_array.h" - -namespace sfntly { - -// Note: This is not really a port of Java version. Instead, this wraps a -// std::vector inside and let it grow by calling resize(). -class GrowableMemoryByteArray : public ByteArray, - public RefCounted { - public: - GrowableMemoryByteArray(); - virtual ~GrowableMemoryByteArray(); - virtual int32_t CopyTo(OutputStream* os, int32_t offset, int32_t length); - - // Make gcc -Woverloaded-virtual happy. - virtual int32_t CopyTo(ByteArray* array) { return ByteArray::CopyTo(array); } - virtual int32_t CopyTo(ByteArray* array, int32_t offset, int32_t length) { - return ByteArray::CopyTo(array, offset, length); - } - virtual int32_t CopyTo(int32_t dst_offset, - ByteArray* array, - int32_t src_offset, - int32_t length) { - return ByteArray::CopyTo(dst_offset, array, src_offset, length); - } - virtual int32_t CopyTo(OutputStream* os) { return ByteArray::CopyTo(os); } - - protected: - virtual void InternalPut(int32_t index, byte_t b); - virtual int32_t InternalPut(int32_t index, - byte_t* b, - int32_t offset, - int32_t length); - virtual byte_t InternalGet(int32_t index); - virtual int32_t InternalGet(int32_t index, - byte_t* b, - int32_t offset, - int32_t length); - virtual void Close(); - virtual byte_t* Begin(); - - private: - ByteVector b_; -}; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_DATA_GROWABLE_MEMORY_BYTE_ARRAY_H_ diff --git a/src/sfntly/src/sfntly/data/memory_byte_array.cc b/src/sfntly/src/sfntly/data/memory_byte_array.cc deleted file mode 100644 index d6c9c4828d..0000000000 --- a/src/sfntly/src/sfntly/data/memory_byte_array.cc +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/data/memory_byte_array.h" - -#include - -namespace sfntly { - -MemoryByteArray::MemoryByteArray(int32_t length) - : ByteArray(0, length), b_(NULL), allocated_(true) { -} - -MemoryByteArray::MemoryByteArray(byte_t* b, int32_t filled_length) - : ByteArray(filled_length, filled_length), b_(b), allocated_(false) { - assert(b); -} - -MemoryByteArray::~MemoryByteArray() { - Close(); -} - -int32_t MemoryByteArray::CopyTo(OutputStream* os, - int32_t offset, - int32_t length) { - assert(os); - os->Write(b_, offset, length); - return length; -} - -void MemoryByteArray::Init() { - if (allocated_ && b_ == NULL) { - b_ = new byte_t[Size()]; - memset(b_, 0, Size()); - } -} - -void MemoryByteArray::InternalPut(int32_t index, byte_t b) { - Init(); - b_[index] = b; -} - -int32_t MemoryByteArray::InternalPut(int32_t index, - byte_t* b, - int32_t offset, - int32_t length) { - assert(b); - Init(); - memcpy(b_ + index, b + offset, length); - return length; -} - -byte_t MemoryByteArray::InternalGet(int32_t index) { - Init(); - return b_[index]; -} - -int32_t MemoryByteArray::InternalGet(int32_t index, - byte_t* b, - int32_t offset, - int32_t length) { - assert(b); - Init(); - memcpy(b + offset, b_ + index, length); - return length; -} - -void MemoryByteArray::Close() { - if (allocated_ && b_) { - delete[] b_; - } - b_ = NULL; -} - -byte_t* MemoryByteArray::Begin() { - Init(); - return b_; -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/data/memory_byte_array.h b/src/sfntly/src/sfntly/data/memory_byte_array.h deleted file mode 100644 index 838fd1aca5..0000000000 --- a/src/sfntly/src/sfntly/data/memory_byte_array.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_MEMORY_BYTE_ARRAY_H_ -#define SFNTLY_CPP_SRC_SFNTLY_DATA_MEMORY_BYTE_ARRAY_H_ - -#include "sfntly/data/byte_array.h" - -namespace sfntly { - -class MemoryByteArray : public ByteArray, public RefCounted { - public: - // Construct a new MemoryByteArray with a new array of the size given. It is - // assumed that none of the array is filled and readable. - explicit MemoryByteArray(int32_t length); - - // Note: not implemented due to dangerous operations in constructor. - //explicit MemoryByteArray(ByteVector* b); - - // Construct a new MemoryByteArray using byte array. - // @param b the byte array that provides the actual storage - // @param filled_length the index of the last byte in the array has data - // Note: This is different from Java version, it does not take over the - // ownership of b. Caller is responsible for handling the lifetime - // of b. C++ port also assumes filled_length is buffer_length since - // there is not a reliable way to identify the actual size of buffer. - MemoryByteArray(byte_t* b, int32_t filled_length); - - virtual ~MemoryByteArray(); - virtual int32_t CopyTo(OutputStream* os, int32_t offset, int32_t length); - - // Make gcc -Woverloaded-virtual happy. - virtual int32_t CopyTo(ByteArray* array) { return ByteArray::CopyTo(array); } - virtual int32_t CopyTo(ByteArray* array, int32_t offset, int32_t length) { - return ByteArray::CopyTo(array, offset, length); - } - virtual int32_t CopyTo(int32_t dst_offset, - ByteArray* array, - int32_t src_offset, - int32_t length) { - return ByteArray::CopyTo(dst_offset, array, src_offset, length); - } - virtual int32_t CopyTo(OutputStream* os) { return ByteArray::CopyTo(os); } - - protected: - virtual void InternalPut(int32_t index, byte_t b); - virtual int32_t InternalPut(int32_t index, - byte_t* b, - int32_t offset, - int32_t length); - virtual byte_t InternalGet(int32_t index); - virtual int32_t InternalGet(int32_t index, - byte_t* b, - int32_t offset, - int32_t length); - virtual void Close(); - virtual byte_t* Begin(); - - private: - void Init(); // C++ port only, used to allocate memory outside constructor. - - byte_t* b_; - bool allocated_; -}; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_DATA_MEMORY_BYTE_ARRAY_H_ diff --git a/src/sfntly/src/sfntly/data/readable_font_data.cc b/src/sfntly/src/sfntly/data/readable_font_data.cc deleted file mode 100644 index 06d783f2e3..0000000000 --- a/src/sfntly/src/sfntly/data/readable_font_data.cc +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/data/readable_font_data.h" - -#include - -#include "sfntly/data/memory_byte_array.h" -#include "sfntly/data/writable_font_data.h" -#include "sfntly/port/exception_type.h" - -namespace sfntly { - -ReadableFontData::ReadableFontData(ByteArray* array) - : FontData(array), - checksum_set_(false), - checksum_(0) { -} - -ReadableFontData::~ReadableFontData() {} - -// TODO(arthurhsu): re-investigate the memory model of this function. It's -// not too useful without copying, but it's not performance -// savvy to do copying. -CALLER_ATTACH -ReadableFontData* ReadableFontData::CreateReadableFontData(ByteVector* b) { - assert(b); - ByteArrayPtr ba = new MemoryByteArray(b->size()); - ba->Put(0, b); - ReadableFontDataPtr wfd = new ReadableFontData(ba); - return wfd.Detach(); -} - -int64_t ReadableFontData::Checksum() { - AutoLock lock(checksum_lock_); - if (!checksum_set_) { - ComputeChecksum(); - } - return checksum_; -} - -void ReadableFontData::SetCheckSumRanges(const IntegerList& ranges) { - checksum_range_ = ranges; - checksum_set_ = false; // UNIMPLEMENTED: atomicity -} - -int32_t ReadableFontData::ReadUByte(int32_t index) { - int32_t b = array_->Get(BoundOffset(index)); -#if !defined (SFNTLY_NO_EXCEPTION) - if (b < 0) { - throw IndexOutOfBoundException( - "Index attempted to be read from is out of bounds", index); - } -#endif - return b; -} - -int32_t ReadableFontData::ReadByte(int32_t index) { - int32_t b = array_->Get(BoundOffset(index)); -#if !defined (SFNTLY_NO_EXCEPTION) - if (b < 0) { - throw IndexOutOfBoundException( - "Index attempted to be read from is out of bounds", index); - } -#endif - return (b << 24) >> 24; -} - -int32_t ReadableFontData::ReadBytes(int32_t index, - byte_t* b, - int32_t offset, - int32_t length) { - return array_->Get(BoundOffset(index), b, offset, BoundLength(index, length)); -} - -int32_t ReadableFontData::ReadChar(int32_t index) { - return ReadUByte(index); -} - -int32_t ReadableFontData::ReadUShort(int32_t index) { - return 0xffff & (ReadUByte(index) << 8 | ReadUByte(index + 1)); -} - -int32_t ReadableFontData::ReadShort(int32_t index) { - return ((ReadByte(index) << 8 | ReadUByte(index + 1)) << 16) >> 16; -} - -int32_t ReadableFontData::ReadUInt24(int32_t index) { - return 0xffffff & (ReadUByte(index) << 16 | - ReadUByte(index + 1) << 8 | - ReadUByte(index + 2)); -} - -int64_t ReadableFontData::ReadULong(int32_t index) { - return 0xffffffffL & (ReadUByte(index) << 24 | - ReadUByte(index + 1) << 16 | - ReadUByte(index + 2) << 8 | - ReadUByte(index + 3)); -} - -int32_t ReadableFontData::ReadULongAsInt(int32_t index) { - int64_t ulong = ReadULong(index); -#if !defined (SFNTLY_NO_EXCEPTION) - if ((ulong & 0x80000000) == 0x80000000) { - throw ArithmeticException("Long value too large to fit into an integer."); - } -#endif - return static_cast(ulong); -} - -int64_t ReadableFontData::ReadULongLE(int32_t index) { - return 0xffffffffL & (ReadUByte(index) | - ReadUByte(index + 1) << 8 | - ReadUByte(index + 2) << 16 | - ReadUByte(index + 3) << 24); -} - -int32_t ReadableFontData::ReadLong(int32_t index) { - return ReadByte(index) << 24 | - ReadUByte(index + 1) << 16 | - ReadUByte(index + 2) << 8 | - ReadUByte(index + 3); -} - -int32_t ReadableFontData::ReadFixed(int32_t index) { - return ReadLong(index); -} - -int64_t ReadableFontData::ReadDateTimeAsLong(int32_t index) { - return (int64_t)ReadULong(index) << 32 | ReadULong(index + 4); -} - -int32_t ReadableFontData::ReadFWord(int32_t index) { - return ReadShort(index); -} - -int32_t ReadableFontData::ReadFUFWord(int32_t index) { - return ReadUShort(index); -} - -int32_t ReadableFontData::CopyTo(OutputStream* os) { - return array_->CopyTo(os, BoundOffset(0), Length()); -} - -int32_t ReadableFontData::CopyTo(WritableFontData* wfd) { - return array_->CopyTo(wfd->BoundOffset(0), - wfd->array_, - BoundOffset(0), - Length()); -} - -int32_t ReadableFontData::CopyTo(ByteArray* ba) { - return array_->CopyTo(ba, BoundOffset(0), Length()); -} - -int32_t ReadableFontData::SearchUShort(int32_t start_index, - int32_t start_offset, - int32_t end_index, - int32_t end_offset, - int32_t length, - int32_t key) { - int32_t location = 0; - int32_t bottom = 0; - int32_t top = length; - while (top != bottom) { - location = (top + bottom) / 2; - int32_t location_start = ReadUShort(start_index + location * start_offset); - if (key < location_start) { - // location is below current location - top = location; - } else { - // is key below the upper bound? - int32_t location_end = ReadUShort(end_index + location * end_offset); -#if defined (SFNTLY_DEBUG_FONTDATA) - fprintf(stderr, "**start: %d; end: %d\n", location_start, location_end); -#endif - if (key <= location_end) { - return location; - } else { - // location is above the current location - bottom = location + 1; - } - } - } - return -1; -} - -int32_t ReadableFontData::SearchUShort(int32_t start_index, - int32_t start_offset, - int32_t length, - int32_t key) { - int32_t location = 0; - int32_t bottom = 0; - int32_t top = length; - while (top != bottom) { - location = (top + bottom) / 2; - int32_t location_start = ReadUShort(start_index + location * start_offset); - if (key < location_start) { - // location is below current location - top = location; - } else if (key > location_start) { - // location is above current location - bottom = location + 1; - } else { - return location; - } - } - return -1; -} - -int32_t ReadableFontData::SearchULong(int32_t start_index, - int32_t start_offset, - int32_t end_index, - int32_t end_offset, - int32_t length, - int32_t key) { - int32_t location = 0; - int32_t bottom = 0; - int32_t top = length; - while (top != bottom) { - location = (top + bottom) / 2; - int32_t location_start = ReadULongAsInt(start_index - + location * start_offset); - if (key < location_start) { - // location is below current location - top = location; - } else { - // is key below the upper bound? - int32_t location_end = ReadULongAsInt(end_index + location * end_offset); -#if defined (SFNTLY_DEBUG_FONTDATA) - fprintf(stderr, "**start: %d; end: %d\n", location_start, location_end); -#endif - if (key <= location_end) { - return location; - } else { - // location is above the current location - bottom = location + 1; - } - } - } - return -1; -} - -CALLER_ATTACH FontData* ReadableFontData::Slice(int32_t offset, - int32_t length) { - if (offset < 0 || offset + length > Size()) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IndexOutOfBoundsException( - "Attempt to bind data outside of its limits"); -#endif - return NULL; - } - FontDataPtr slice = new ReadableFontData(this, offset, length); - return slice.Detach(); -} - -CALLER_ATTACH FontData* ReadableFontData::Slice(int32_t offset) { - if (offset < 0 || offset > Size()) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IndexOutOfBoundsException( - "Attempt to bind data outside of its limits"); -#endif - return NULL; - } - FontDataPtr slice = new ReadableFontData(this, offset); - return slice.Detach(); -} - -ReadableFontData::ReadableFontData(ReadableFontData* data, int32_t offset) - : FontData(data, offset), - checksum_set_(false), - checksum_(0) { -} - -ReadableFontData::ReadableFontData(ReadableFontData* data, - int32_t offset, - int32_t length) - : FontData(data, offset, length), - checksum_set_(false), - checksum_(0) { -} - -void ReadableFontData::ComputeChecksum() { - // TODO(arthurhsu): IMPLEMENT: synchronization/atomicity - int64_t sum = 0; - if (checksum_range_.empty()) { - sum = ComputeCheckSum(0, Length()); - } else { - for (uint32_t low_bound_index = 0; low_bound_index < checksum_range_.size(); - low_bound_index += 2) { - int32_t low_bound = checksum_range_[low_bound_index]; - int32_t high_bound = (low_bound_index == checksum_range_.size() - 1) ? - Length() : - checksum_range_[low_bound_index + 1]; - sum += ComputeCheckSum(low_bound, high_bound); - } - } - - checksum_ = sum & 0xffffffffL; - checksum_set_ = true; -} - -int64_t ReadableFontData::ComputeCheckSum(int32_t low_bound, - int32_t high_bound) { - int64_t sum = 0; - // Checksum all whole 4-byte chunks. - for (int32_t i = low_bound; i <= high_bound - 4; i += 4) { - sum += ReadULong(i); - } - - // Add last fragment if not 4-byte multiple - int32_t off = high_bound & -4; - if (off < high_bound) { - int32_t b3 = ReadUByte(off); - int32_t b2 = (off + 1 < high_bound) ? ReadUByte(off + 1) : 0; - int32_t b1 = (off + 2 < high_bound) ? ReadUByte(off + 2) : 0; - int32_t b0 = 0; - sum += (b3 << 24) | (b2 << 16) | (b1 << 8) | b0; - } - return sum; -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/data/readable_font_data.h b/src/sfntly/src/sfntly/data/readable_font_data.h deleted file mode 100644 index b43c626041..0000000000 --- a/src/sfntly/src/sfntly/data/readable_font_data.h +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_READABLE_FONT_DATA_H_ -#define SFNTLY_CPP_SRC_SFNTLY_DATA_READABLE_FONT_DATA_H_ - -#include "sfntly/data/font_data.h" -#include "sfntly/port/lock.h" - -namespace sfntly { - -class WritableFontData; -class OutputStream; - -// Writable font data wrapper. Supports reading of data primitives in the -// TrueType / OpenType spec. -// The data types used are as listed: -// BYTE 8-bit unsigned integer. -// CHAR 8-bit signed integer. -// USHORT 16-bit unsigned integer. -// SHORT 16-bit signed integer. -// UINT24 24-bit unsigned integer. -// ULONG 32-bit unsigned integer. -// LONG 32-bit signed integer. -// Fixed 32-bit signed fixed-point number (16.16) -// FUNIT Smallest measurable distance in the em space. -// FWORD 16-bit signed integer (SHORT) that describes a quantity in FUnits. -// UFWORD 16-bit unsigned integer (USHORT) that describes a quantity in -// FUnits. -// F2DOT14 16-bit signed fixed number with the low 14 bits of fraction (2.14) -// LONGDATETIME Date represented in number of seconds since 12:00 midnight, -// January 1, 1904. The value is represented as a signed 64-bit -// integer. - -class ReadableFontData : public FontData, - public RefCounted { - public: - explicit ReadableFontData(ByteArray* array); - virtual ~ReadableFontData(); - - static CALLER_ATTACH ReadableFontData* CreateReadableFontData(ByteVector* b); - - // Gets a computed checksum for the data. This checksum uses the OpenType spec - // calculation. Every ULong value (32 bit unsigned) in the data is summed and - // the resulting value is truncated to 32 bits. If the data length in bytes is - // not an integral multiple of 4 then any remaining bytes are treated as the - // start of a 4 byte sequence whose remaining bytes are zero. - // @return the checksum - int64_t Checksum(); - - // Sets the bounds to use for computing the checksum. These bounds are in - // begin and end pairs. If an odd number is given then the final range is - // assumed to extend to the end of the data. The lengths of each range must be - // a multiple of 4. - // @param ranges the range bounds to use for the checksum - void SetCheckSumRanges(const IntegerList& ranges); - - // Read the UBYTE at the given index. - // @param index index into the font data - // @return the UBYTE; -1 if outside the bounds of the font data - // @throws IndexOutOfBoundsException if index is outside the FontData's range - virtual int32_t ReadUByte(int32_t index); - - // Read the BYTE at the given index. - // @param index index into the font data - // @return the BYTE - // @throws IndexOutOfBoundsException if index is outside the FontData's range - virtual int32_t ReadByte(int32_t index); - - // Read the bytes at the given index into the array. - // @param index index into the font data - // @param b the destination for the bytes read - // @param offset offset in the byte array to place the bytes - // @param length the length of bytes to read - // @return the number of bytes actually read; -1 if the index is outside the - // bounds of the font data - virtual int32_t ReadBytes(int32_t index, - byte_t* b, - int32_t offset, - int32_t length); - - // Read the CHAR at the given index. - // @param index index into the font data - // @return the CHAR - // @throws IndexOutOfBoundsException if index is outside the FontData's range - virtual int32_t ReadChar(int32_t index); - - // Read the USHORT at the given index. - // @param index index into the font data - // @return the USHORT - // @throws IndexOutOfBoundsException if index is outside the FontData's range - virtual int32_t ReadUShort(int32_t index); - - // Read the SHORT at the given index. - // @param index index into the font data - // @return the SHORT - // @throws IndexOutOfBoundsException if index is outside the FontData's range - virtual int32_t ReadShort(int32_t index); - - // Read the UINT24 at the given index. - // @param index index into the font data - // @return the UINT24 - // @throws IndexOutOfBoundsException if index is outside the FontData's range - virtual int32_t ReadUInt24(int32_t index); - - // Read the ULONG at the given index. - // @param index index into the font data - // @return the ULONG - // @throws IndexOutOfBoundsException if index is outside the FontData's range - virtual int64_t ReadULong(int32_t index); - - // Read the ULONG at the given index as int32_t. - // @param index index into the font data - // @return the ULONG - // @throws IndexOutOfBoundsException if index is outside the FontData's range - virtual int32_t ReadULongAsInt(int32_t index); - - // Read the ULONG at the given index, little-endian variant - // @param index index into the font data - // @return the ULONG - // @throws IndexOutOfBoundsException if index is outside the FontData's range - virtual int64_t ReadULongLE(int32_t index); - - // Read the LONG at the given index. - // @param index index into the font data - // @return the LONG - // @throws IndexOutOfBoundsException if index is outside the FontData's range - virtual int32_t ReadLong(int32_t index); - - // Read the Fixed at the given index. - // @param index index into the font data - // @return the Fixed - // @throws IndexOutOfBoundsException if index is outside the FontData's range - virtual int32_t ReadFixed(int32_t index); - - // Read the LONGDATETIME at the given index. - // @param index index into the font data - // @return the LONGDATETIME - // @throws IndexOutOfBoundsException if index is outside the FontData's range - virtual int64_t ReadDateTimeAsLong(int32_t index); - - // Read the FWORD at the given index. - // @param index index into the font data - // @return the FWORD - // @throws IndexOutOfBoundsException if index is outside the FontData's range - virtual int32_t ReadFWord(int32_t index); - - // Read the UFWORD at the given index. - // @param index index into the font data - // @return the UFWORD - // @throws IndexOutOfBoundsException if index is outside the FontData's range - virtual int32_t ReadFUFWord(int32_t index); - - // Note: Not ported because they just throw UnsupportedOperationException() - // in Java. - /* - virtual int32_t ReadFUnit(int32_t index); - virtual int64_t ReadF2Dot14(int32_t index); - */ - - // Copy the FontData to an OutputStream. - // @param os the destination - // @return number of bytes copied - // @throws IOException - virtual int32_t CopyTo(OutputStream* os); - - // Copy the FontData to a WritableFontData. - // @param wfd the destination - // @return number of bytes copied - // @throws IOException - virtual int32_t CopyTo(WritableFontData* wfd); - - // Make gcc -Woverloaded-virtual happy. - virtual int32_t CopyTo(ByteArray* ba); - - // Search for the key value in the range tables provided. - // The search looks through the start-end pairs looking for the key value. It - // is assumed that the start-end pairs are both represented by UShort values, - // ranges do not overlap, and are monotonically increasing. - // @param startIndex the position to read the first start value from - // @param startOffset the offset between subsequent start values - // @param endIndex the position to read the first end value from - // @param endOffset the offset between subsequent end values - // @param length the number of start-end pairs - // @param key the value to search for - // @return the index of the start-end pairs in which the key was found; -1 - // otherwise - int32_t SearchUShort(int32_t start_index, - int32_t start_offset, - int32_t end_index, - int32_t end_offset, - int32_t length, - int32_t key); - - // Search for the key value in the table provided. - // The search looks through the values looking for the key value. It is - // assumed that the are represented by UShort values and are monotonically - // increasing. - // @param startIndex the position to read the first start value from - // @param startOffset the offset between subsequent start values - // @param length the number of start-end pairs - // @param key the value to search for - // @return the index of the start-end pairs in which the key was found; -1 - // otherwise - int32_t SearchUShort(int32_t start_index, - int32_t start_offset, - int32_t length, - int32_t key); - - // Search for the key value in the range tables provided. - // The search looks through the start-end pairs looking for the key value. It - // is assumed that the start-end pairs are both represented by ULong values - // that can be represented within 31 bits, ranges do not overlap, and are - // monotonically increasing. - // @param startIndex the position to read the first start value from - // @param startOffset the offset between subsequent start values - // @param endIndex the position to read the first end value from - // @param endOffset the offset between subsequent end values - // @param length the number of start-end pairs - // @param key the value to search for - // @return the index of the start-end pairs in which the key was found; -1 - // otherwise - int32_t SearchULong(int32_t start_index, - int32_t start_offset, - int32_t end_index, - int32_t end_offset, - int32_t length, - int32_t key); - - - // TODO(arthurhsu): IMPLEMENT - /* - virtual int32_t ReadFUnit(int32_t index); - virtual int64_t ReadF2Dot14(int32_t index); - virtual int64_t ReadLongDateTime(int32_t index); - */ - - // Makes a slice of this FontData. The returned slice will share the data with - // the original FontData. - // @param offset the start of the slice - // @param length the number of bytes in the slice - // @return a slice of the original FontData - // Note: C++ polymorphism requires return type to be consistent - virtual CALLER_ATTACH FontData* Slice(int32_t offset, int32_t length); - - // Makes a bottom bound only slice of this array. The returned slice will - // share the data with the original FontData. - // @param offset the start of the slice - // @return a slice of the original FontData - // Note: C++ polymorphism requires return type to be consistent - virtual CALLER_ATTACH FontData* Slice(int32_t offset); - - // Not Ported: toString() - - protected: - // Constructor. Creates a bounded wrapper of another ReadableFontData from the - // given offset until the end of the original ReadableFontData. - // @param data data to wrap - // @param offset the start of this data's view of the original data - ReadableFontData(ReadableFontData* data, int32_t offset); - - // Constructor. Creates a bounded wrapper of another ReadableFontData from the - // given offset until the end of the original ReadableFontData. - // @param data data to wrap - // @param offset the start of this data's view of the original data - // @param length the length of the other FontData to use - ReadableFontData(ReadableFontData* data, int32_t offset, int32_t length); - - private: - // Compute the checksum for the font data using any ranges set for the - // calculation. - void ComputeChecksum(); - - // Do the actual computation of the checksum for a range using the - // TrueType/OpenType checksum algorithm. The range used is from the low bound - // to the high bound in steps of four bytes. If any of the bytes within that 4 - // byte segment are not readable then it will considered a zero for - // calculation. - // Only called from within a synchronized method so it does not need to be - // synchronized itself. - // @param lowBound first position to start a 4 byte segment on - // @param highBound last possible position to start a 4 byte segment on - // @return the checksum for the total range - int64_t ComputeCheckSum(int32_t low_bound, int32_t high_bound); - - Lock checksum_lock_; - bool checksum_set_; - int64_t checksum_; - IntegerList checksum_range_; -}; -typedef Ptr ReadableFontDataPtr; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_DATA_READABLE_FONT_DATA_H_ diff --git a/src/sfntly/src/sfntly/data/writable_font_data.cc b/src/sfntly/src/sfntly/data/writable_font_data.cc deleted file mode 100644 index 7f6f72f533..0000000000 --- a/src/sfntly/src/sfntly/data/writable_font_data.cc +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/data/writable_font_data.h" - -#include "sfntly/data/memory_byte_array.h" -#include "sfntly/data/growable_memory_byte_array.h" - -namespace sfntly { - -WritableFontData::WritableFontData(ByteArray* ba) : ReadableFontData(ba) { -} - -WritableFontData::~WritableFontData() {} - -// static -CALLER_ATTACH -WritableFontData* WritableFontData::CreateWritableFontData(int32_t length) { - ByteArrayPtr ba; - if (length > 0) { - ba = new MemoryByteArray(length); - ba->SetFilledLength(length); - } else { - ba = new GrowableMemoryByteArray(); - } - WritableFontDataPtr wfd = new WritableFontData(ba); - return wfd.Detach(); -} - -// TODO(arthurhsu): re-investigate the memory model of this function. It's -// not too useful without copying, but it's not performance -// savvy to do copying. -CALLER_ATTACH -WritableFontData* WritableFontData::CreateWritableFontData(ByteVector* b) { - ByteArrayPtr ba = new GrowableMemoryByteArray(); - ba->Put(0, b); - WritableFontDataPtr wfd = new WritableFontData(ba); - return wfd.Detach(); -} - -int32_t WritableFontData::WriteByte(int32_t index, byte_t b) { - array_->Put(BoundOffset(index), b); - return 1; -} - -int32_t WritableFontData::WriteBytes(int32_t index, - byte_t* b, - int32_t offset, - int32_t length) { - return array_->Put(BoundOffset(index), - b, - offset, - BoundLength(index, length)); -} - -int32_t WritableFontData::WriteBytes(int32_t index, ByteVector* b) { - assert(b); - return WriteBytes(index, &((*b)[0]), 0, b->size()); -} - -int32_t WritableFontData::WriteBytesPad(int32_t index, - ByteVector* b, - int32_t offset, - int32_t length, - byte_t pad) { - int32_t written = - array_->Put(BoundOffset(index), - &((*b)[0]), - offset, - BoundLength(index, - std::min(length, b->size() - offset))); - written += WritePadding(written + index, length - written, pad); - return written; -} - -int32_t WritableFontData::WritePadding(int32_t index, int32_t count) { - return WritePadding(index, count, (byte_t)0); -} - -int32_t WritableFontData::WritePadding(int32_t index, int32_t count, - byte_t pad) { - for (int32_t i = 0; i < count; ++i) { - array_->Put(index + i, pad); - } - return count; -} - -int32_t WritableFontData::WriteChar(int32_t index, byte_t c) { - return WriteByte(index, c); -} - -int32_t WritableFontData::WriteUShort(int32_t index, int32_t us) { - WriteByte(index, (byte_t)((us >> 8) & 0xff)); - WriteByte(index + 1, (byte_t)(us & 0xff)); - return 2; -} - -int32_t WritableFontData::WriteUShortLE(int32_t index, int32_t us) { - WriteByte(index, (byte_t)(us & 0xff)); - WriteByte(index + 1, (byte_t)((us >> 8) & 0xff)); - return 2; -} - -int32_t WritableFontData::WriteShort(int32_t index, int32_t s) { - return WriteUShort(index, s); -} - -int32_t WritableFontData::WriteUInt24(int32_t index, int32_t ui) { - WriteByte(index, (byte_t)((ui >> 16) & 0xff)); - WriteByte(index + 1, (byte_t)((ui >> 8) & 0xff)); - WriteByte(index + 2, (byte_t)(ui & 0xff)); - return 3; -} - -int32_t WritableFontData::WriteULong(int32_t index, int64_t ul) { - WriteByte(index, (byte_t)((ul >> 24) & 0xff)); - WriteByte(index + 1, (byte_t)((ul >> 16) & 0xff)); - WriteByte(index + 2, (byte_t)((ul >> 8) & 0xff)); - WriteByte(index + 3, (byte_t)(ul & 0xff)); - return 4; -} - -int32_t WritableFontData::WriteULongLE(int32_t index, int64_t ul) { - WriteByte(index, (byte_t)(ul & 0xff)); - WriteByte(index + 1, (byte_t)((ul >> 8) & 0xff)); - WriteByte(index + 2, (byte_t)((ul >> 16) & 0xff)); - WriteByte(index + 3, (byte_t)((ul >> 24) & 0xff)); - return 4; -} - -int32_t WritableFontData::WriteLong(int32_t index, int64_t l) { - return WriteULong(index, l); -} - -int32_t WritableFontData::WriteFixed(int32_t index, int32_t f) { - return WriteLong(index, f); -} - -int32_t WritableFontData::WriteDateTime(int32_t index, int64_t date) { - WriteULong(index, (date >> 32) & 0xffffffff); - WriteULong(index + 4, date & 0xffffffff); - return 8; -} - -void WritableFontData::CopyFrom(InputStream* is, int32_t length) { - array_->CopyFrom(is, length); -} - -void WritableFontData::CopyFrom(InputStream* is) { - array_->CopyFrom(is); -} - -CALLER_ATTACH FontData* WritableFontData::Slice(int32_t offset, - int32_t length) { - if (offset < 0 || offset + length > Size()) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IndexOutOfBoundsException( - "Attempt to bind data outside of its limits"); -#endif - return NULL; - } - FontDataPtr slice = new WritableFontData(this, offset, length); - return slice.Detach(); -} - -CALLER_ATTACH FontData* WritableFontData::Slice(int32_t offset) { - if (offset > Size()) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IndexOutOfBoundsException( - "Attempt to bind data outside of its limits"); -#endif - return NULL; - } - FontDataPtr slice = new WritableFontData(this, offset); - return slice.Detach(); -} - -WritableFontData::WritableFontData(WritableFontData* data, int32_t offset) - : ReadableFontData(data, offset) { -} - -WritableFontData::WritableFontData(WritableFontData* data, - int32_t offset, - int32_t length) - : ReadableFontData(data, offset, length) { -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/data/writable_font_data.h b/src/sfntly/src/sfntly/data/writable_font_data.h deleted file mode 100644 index d2a049eb55..0000000000 --- a/src/sfntly/src/sfntly/data/writable_font_data.h +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_WRITABLE_FONT_DATA_H_ -#define SFNTLY_CPP_SRC_SFNTLY_DATA_WRITABLE_FONT_DATA_H_ - -#include "sfntly/data/readable_font_data.h" - -namespace sfntly { - -// Writable font data wrapper. Supports writing of data primitives in the -// TrueType / OpenType spec. -class WritableFontData : public ReadableFontData { - public: - explicit WritableFontData(ByteArray* ba); - virtual ~WritableFontData(); - - // Constructs a writable font data object. If the length is specified as - // positive then a fixed size font data object will be created. If the length - // is zero or less then a growable font data object will be created and the - // size will be used as an estimate to help in allocating the original space. - // @param length if length > 0 create a fixed length font data; otherwise - // create a growable font data - // @return a new writable font data - static CALLER_ATTACH WritableFontData* CreateWritableFontData(int32_t length); - - // Constructs a writable font data object. The new font data object will wrap - // the bytes passed in to the factory and it will take make a copy of those - // bytes. - // @param b the byte vector to wrap - // @return a new writable font data - static CALLER_ATTACH WritableFontData* CreateWritableFontData(ByteVector* b); - - // Write a byte at the given index. - // @param index index into the font data - // @param b the byte to write - // @return the number of bytes written - virtual int32_t WriteByte(int32_t index, byte_t b); - - // Write the bytes from the array. - // @param index index into the font data - // @param b the source for the bytes to be written - // @param offset offset in the byte array - // @param length the length of the bytes to be written - // @return the number of bytes actually written; -1 if the index is outside - // the FontData's range - virtual int32_t WriteBytes(int32_t index, - byte_t* b, - int32_t offset, - int32_t length); - - // Write the bytes from the array. - // @param index index into the font data - // @param b the source for the bytes to be written - // @return the number of bytes actually written; -1 if the index is outside - // the FontData's range - virtual int32_t WriteBytes(int32_t index, ByteVector* b); - - // Write the bytes from the array and pad if necessary. - // Write to the length given using the byte array provided and if there are - // not enough bytes in the array then pad to the requested length using the - // pad byte specified. - // @param index index into the font data - // @param b the source for the bytes to be written - // @param offset offset in the byte array - // @param length the length of the bytes to be written - // @param pad the padding byte to be used if necessary - // @return the number of bytes actually written - virtual int32_t WriteBytesPad(int32_t index, - ByteVector* b, - int32_t offset, - int32_t length, - byte_t pad); - - // Writes padding to the FontData. The padding byte written is 0x00. - // @param index index into the font data - // @param count the number of pad bytes to write - // @return the number of pad bytes written - virtual int32_t WritePadding(int32_t index, int32_t count); - - // Writes padding to the FontData. - // @param index index into the font data - // @param count the number of pad bytes to write - // @param pad the byte value to use as padding - // @return the number of pad bytes written - virtual int32_t WritePadding(int32_t index, int32_t count, byte_t pad); - - // Write the CHAR at the given index. - // @param index index into the font data - // @param c the CHAR - // @return the number of bytes actually written - // @throws IndexOutOfBoundsException if index is outside the FontData's range - virtual int32_t WriteChar(int32_t index, byte_t c); - - // Write the USHORT at the given index. - // @param index index into the font data - // @param us the USHORT - // @return the number of bytes actually written - // @throws IndexOutOfBoundsException if index is outside the FontData's range - virtual int32_t WriteUShort(int32_t index, int32_t us); - - // Write the USHORT at the given index in little endian format. - // @param index index into the font data - // @param us the USHORT - // @return the number of bytes actually written - // @throws IndexOutOfBoundsException if index is outside the FontData's range - virtual int32_t WriteUShortLE(int32_t index, int32_t us); - - // Write the SHORT at the given index. - // @param index index into the font data - // @param s the SHORT - // @return the number of bytes actually written - // @throws IndexOutOfBoundsException if index is outside the FontData's range - virtual int32_t WriteShort(int32_t index, int32_t s); - - // Write the UINT24 at the given index. - // @param index index into the font data - // @param ui the UINT24 - // @return the number of bytes actually written - // @throws IndexOutOfBoundsException if index is outside the FontData's range - virtual int32_t WriteUInt24(int32_t index, int32_t ui); - - // Write the ULONG at the given index. - // @param index index into the font data - // @param ul the ULONG - // @return the number of bytes actually written - // @throws IndexOutOfBoundsException if index is outside the FontData's range - virtual int32_t WriteULong(int32_t index, int64_t ul); - - // Write the ULONG at the given index in little endian format. - // @param index index into the font data - // @param ul the ULONG - // @return the number of bytes actually written - // @throws IndexOutOfBoundsException if index is outside the FontData's range - virtual int32_t WriteULongLE(int32_t index, int64_t ul); - - // Write the LONG at the given index. - // @param index index into the font data - // @param l the LONG - // @return the number of bytes actually written - // @throws IndexOutOfBoundsException if index is outside the FontData's range - virtual int32_t WriteLong(int32_t index, int64_t l); - - // Write the Fixed at the given index. - // @param index index into the font data - // @param f the Fixed - // @return the number of bytes actually written - // @throws IndexOutOfBoundsException if index is outside the FontData's range - virtual int32_t WriteFixed(int32_t index, int32_t f); - - // Write the LONGDATETIME at the given index. - // @param index index into the font data - // @param date the LONGDATETIME - // @return the number of bytes actually written - // @throws IndexOutOfBoundsException if index is outside the FontData's range - virtual int32_t WriteDateTime(int32_t index, int64_t date); - - // Copy from the InputStream into this FontData. - // @param is the source - // @param length the number of bytes to copy - // @throws IOException - virtual void CopyFrom(InputStream* is, int32_t length); - - // Copy everything from the InputStream into this FontData. - // @param is the source - // @throws IOException - virtual void CopyFrom(InputStream* is); - - // Makes a slice of this FontData. The returned slice will share the data with - // the original FontData. - // @param offset the start of the slice - // @param length the number of bytes in the slice - // @return a slice of the original FontData - virtual CALLER_ATTACH FontData* Slice(int32_t offset, int32_t length); - - // Makes a bottom bound only slice of this array. The returned slice will - // share the data with the original FontData. - // @param offset the start of the slice - // @return a slice of the original FontData - virtual CALLER_ATTACH FontData* Slice(int32_t offset); - - private: - // Constructor with a lower bound. - // @param data other WritableFontData object to share data with - // @param offset offset from the other WritableFontData's data - WritableFontData(WritableFontData* data, int32_t offset); - - // Constructor with lower bound and a length bound. - // @param data other WritableFontData object to share data with - // @param offset offset from the other WritableFontData's data - // @param length length of other WritableFontData's data to use - WritableFontData(WritableFontData* data, int32_t offset, int32_t length); -}; -typedef Ptr WritableFontDataPtr; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_DATA_WRITABLE_FONT_DATA_H_ diff --git a/src/sfntly/src/sfntly/font.cc b/src/sfntly/src/sfntly/font.cc deleted file mode 100644 index f326bccea2..0000000000 --- a/src/sfntly/src/sfntly/font.cc +++ /dev/null @@ -1,568 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/font.h" - -#include - -#include -#include -#include -#include -#include -#include - -#include "sfntly/data/font_input_stream.h" -#include "sfntly/font_factory.h" -#include "sfntly/math/fixed1616.h" -#include "sfntly/math/font_math.h" -#include "sfntly/port/exception_type.h" -#include "sfntly/table/core/font_header_table.h" -#include "sfntly/table/core/horizontal_device_metrics_table.h" -#include "sfntly/table/core/horizontal_header_table.h" -#include "sfntly/table/core/horizontal_metrics_table.h" -#include "sfntly/table/core/maximum_profile_table.h" -#include "sfntly/table/truetype/loca_table.h" -#include "sfntly/tag.h" - -namespace sfntly { - -const int32_t SFNTVERSION_MAJOR = 1; -const int32_t SFNTVERSION_MINOR = 0; - -/****************************************************************************** - * Font class - ******************************************************************************/ -Font::~Font() {} - -bool Font::HasTable(int32_t tag) { - TableMap::const_iterator result = tables_.find(tag); - TableMap::const_iterator end = tables_.end(); - return (result != end); -} - -// Changed by Kovid: these four methods cannot be inlined, if they are they -// return incorrect values when compiled with -fPIC -int32_t Font::sfnt_version() { return sfnt_version_; } - -ByteVector* Font::digest() { return &digest_; } - -int64_t Font::checksum() { return checksum_; } - -int32_t Font::num_tables() { return (int32_t)tables_.size(); } - - -Table* Font::GetTable(int32_t tag) { - if (!HasTable(tag)) { - return NULL; - } - return tables_[tag]; -} - -const TableMap* Font::GetTableMap() { - return &tables_; -} - -void Font::Serialize(OutputStream* os, IntegerList* table_ordering) { - assert(table_ordering); - IntegerList final_table_ordering; - GenerateTableOrdering(table_ordering, &final_table_ordering); - TableHeaderList table_records; - BuildTableHeadersForSerialization(&final_table_ordering, &table_records); - - FontOutputStream fos(os); - SerializeHeader(&fos, &table_records); - SerializeTables(&fos, &table_records); -} - -Font::Font(int32_t sfnt_version, ByteVector* digest) - : sfnt_version_(sfnt_version) { - // non-trivial assignments that makes debugging hard if placed in - // initialization list - digest_ = *digest; -} - -void Font::BuildTableHeadersForSerialization(IntegerList* table_ordering, - TableHeaderList* table_headers) { - assert(table_headers); - assert(table_ordering); - - IntegerList final_table_ordering; - GenerateTableOrdering(table_ordering, &final_table_ordering); - int32_t table_offset = Offset::kTableRecordBegin + num_tables() * - Offset::kTableRecordSize; - for (IntegerList::iterator tag = final_table_ordering.begin(), - tag_end = final_table_ordering.end(); - tag != tag_end; ++tag) { - if (tables_.find(*tag) == tables_.end()) { - continue; - } - TablePtr table = tables_[*tag]; - if (table != NULL) { - HeaderPtr header = - new Header(*tag, table->CalculatedChecksum(), table_offset, - table->header()->length()); - table_headers->push_back(header); - table_offset += (table->DataLength() + 3) & ~3; - } - } -} - -void Font::SerializeHeader(FontOutputStream* fos, - TableHeaderList* table_headers) { - fos->WriteFixed(sfnt_version_); - fos->WriteUShort(table_headers->size()); - int32_t log2_of_max_power_of_2 = FontMath::Log2(table_headers->size()); - int32_t search_range = 2 << (log2_of_max_power_of_2 - 1 + 4); - fos->WriteUShort(search_range); - fos->WriteUShort(log2_of_max_power_of_2); - fos->WriteUShort((table_headers->size() * 16) - search_range); - - HeaderTagSortedSet sorted_headers; - std::copy(table_headers->begin(), - table_headers->end(), - std::inserter(sorted_headers, sorted_headers.end())); - - for (HeaderTagSortedSet::iterator record = sorted_headers.begin(), - record_end = sorted_headers.end(); - record != record_end; ++record) { - fos->WriteULong((*record)->tag()); - fos->WriteULong((int32_t)((*record)->checksum())); - fos->WriteULong((*record)->offset()); - fos->WriteULong((*record)->length()); - } -} - -void Font::SerializeTables(FontOutputStream* fos, - TableHeaderList* table_headers) { - assert(fos); - assert(table_headers); - for (TableHeaderList::iterator record = table_headers->begin(), - end_of_headers = table_headers->end(); - record != end_of_headers; ++record) { - TablePtr target_table = GetTable((*record)->tag()); - if (target_table == NULL) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IOException("Table out of sync with font header."); -#endif - return; - } - int32_t table_size = target_table->Serialize(fos); - if (table_size != (*record)->length()) { - assert(false); - } - int32_t filler_size = ((table_size + 3) & ~3) - table_size; - for (int32_t i = 0; i < filler_size; ++i) { - fos->Write(static_cast(0)); - } - } -} - -void Font::GenerateTableOrdering(IntegerList* default_table_ordering, - IntegerList* table_ordering) { - assert(default_table_ordering); - assert(table_ordering); - table_ordering->clear(); - if (default_table_ordering->empty()) { - DefaultTableOrdering(default_table_ordering); - } - - typedef std::map Int2Bool; - typedef std::pair Int2BoolEntry; - Int2Bool tables_in_font; - for (TableMap::iterator table = tables_.begin(), table_end = tables_.end(); - table != table_end; ++table) { - tables_in_font.insert(Int2BoolEntry(table->first, false)); - } - for (IntegerList::iterator tag = default_table_ordering->begin(), - tag_end = default_table_ordering->end(); - tag != tag_end; ++tag) { - if (HasTable(*tag)) { - table_ordering->push_back(*tag); - tables_in_font[*tag] = true; - } - } - for (Int2Bool::iterator table = tables_in_font.begin(), - table_end = tables_in_font.end(); - table != table_end; ++table) { - if (table->second == false) - table_ordering->push_back(table->first); - } -} - -void Font::DefaultTableOrdering(IntegerList* default_table_ordering) { - assert(default_table_ordering); - default_table_ordering->clear(); - if (HasTable(Tag::CFF)) { - default_table_ordering->resize(CFF_TABLE_ORDERING_SIZE); - std::copy(CFF_TABLE_ORDERING, CFF_TABLE_ORDERING + CFF_TABLE_ORDERING_SIZE, - default_table_ordering->begin()); - return; - } - default_table_ordering->resize(TRUE_TYPE_TABLE_ORDERING_SIZE); - std::copy(TRUE_TYPE_TABLE_ORDERING, - TRUE_TYPE_TABLE_ORDERING + TRUE_TYPE_TABLE_ORDERING_SIZE, - default_table_ordering->begin()); -} - -/****************************************************************************** - * Font::Builder class - ******************************************************************************/ -Font::Builder::~Builder() {} - -CALLER_ATTACH Font::Builder* Font::Builder::GetOTFBuilder(FontFactory* factory, - InputStream* is) { - FontBuilderPtr builder = new Builder(factory); - builder->LoadFont(is); - return builder.Detach(); -} - -CALLER_ATTACH Font::Builder* Font::Builder::GetOTFBuilder( - FontFactory* factory, - WritableFontData* wfd, - int32_t offset_to_offset_table) { - FontBuilderPtr builder = new Builder(factory); - builder->LoadFont(wfd, offset_to_offset_table); - return builder.Detach(); -} - -CALLER_ATTACH Font::Builder* Font::Builder::GetOTFBuilder( - FontFactory* factory) { - FontBuilderPtr builder = new Builder(factory); - return builder.Detach(); -} - -bool Font::Builder::ReadyToBuild() { - // just read in data with no manipulation - if (table_builders_.empty() && !data_blocks_.empty()) { - return true; - } - - // TODO(stuartg): font level checks - required tables etc? - for (TableBuilderMap::iterator table_builder = table_builders_.begin(), - table_builder_end = table_builders_.end(); - table_builder != table_builder_end; - ++table_builder) { - if (!table_builder->second->ReadyToBuild()) - return false; - } - return true; -} - -CALLER_ATTACH Font* Font::Builder::Build() { - FontPtr font = new Font(sfnt_version_, &digest_); - - if (!table_builders_.empty()) { - // Note: Different from Java. Directly use font->tables_ here to avoid - // STL container copying. - BuildTablesFromBuilders(font, &table_builders_, &font->tables_); - } - - table_builders_.clear(); - data_blocks_.clear(); - return font.Detach(); -} - -void Font::Builder::SetDigest(ByteVector* digest) { - digest_.clear(); - digest_ = *digest; -} - -void Font::Builder::ClearTableBuilders() { - table_builders_.clear(); -} - -bool Font::Builder::HasTableBuilder(int32_t tag) { - return (table_builders_.find(tag) != table_builders_.end()); -} - -Table::Builder* Font::Builder::GetTableBuilder(int32_t tag) { - if (HasTableBuilder(tag)) - return table_builders_[tag]; - return NULL; -} - -Table::Builder* Font::Builder::NewTableBuilder(int32_t tag) { - HeaderPtr header = new Header(tag); - TableBuilderPtr builder; - builder.Attach(Table::Builder::GetBuilder(header, NULL)); - table_builders_.insert(TableBuilderEntry(header->tag(), builder)); - return builder; -} - -Table::Builder* Font::Builder::NewTableBuilder(int32_t tag, - ReadableFontData* src_data) { - assert(src_data); - WritableFontDataPtr data; - data.Attach(WritableFontData::CreateWritableFontData(src_data->Length())); - // TODO(stuarg): take over original data instead? - src_data->CopyTo(data); - - HeaderPtr header = new Header(tag, data->Length()); - TableBuilderPtr builder; - builder.Attach(Table::Builder::GetBuilder(header, data)); - table_builders_.insert(TableBuilderEntry(tag, builder)); - return builder; -} - -void Font::Builder::RemoveTableBuilder(int32_t tag) { - TableBuilderMap::iterator target = table_builders_.find(tag); - if (target != table_builders_.end()) { - table_builders_.erase(target); - } -} - -Font::Builder::Builder(FontFactory* factory) - : factory_(factory), - sfnt_version_(Fixed1616::Fixed(SFNTVERSION_MAJOR, SFNTVERSION_MINOR)) { -} - -void Font::Builder::LoadFont(InputStream* is) { - // Note: we do not throw exception here for is. This is more of an assertion. - assert(is); - FontInputStream font_is(is); - HeaderOffsetSortedSet records; - ReadHeader(&font_is, &records); - LoadTableData(&records, &font_is, &data_blocks_); - BuildAllTableBuilders(&data_blocks_, &table_builders_); - font_is.Close(); -} - -void Font::Builder::LoadFont(WritableFontData* wfd, - int32_t offset_to_offset_table) { - // Note: we do not throw exception here for is. This is more of an assertion. - assert(wfd); - HeaderOffsetSortedSet records; - ReadHeader(wfd, offset_to_offset_table, &records); - LoadTableData(&records, wfd, &data_blocks_); - BuildAllTableBuilders(&data_blocks_, &table_builders_); -} - -int32_t Font::Builder::SfntWrapperSize() { - return Offset::kSfntHeaderSize + - (Offset::kTableRecordSize * table_builders_.size()); -} - -void Font::Builder::BuildAllTableBuilders(DataBlockMap* table_data, - TableBuilderMap* builder_map) { - for (DataBlockMap::iterator record = table_data->begin(), - record_end = table_data->end(); - record != record_end; ++record) { - TableBuilderPtr builder; - builder.Attach(GetTableBuilder(record->first.p_, record->second.p_)); - builder_map->insert(TableBuilderEntry(record->first->tag(), builder)); - } - InterRelateBuilders(&table_builders_); -} - -CALLER_ATTACH -Table::Builder* Font::Builder::GetTableBuilder(Header* header, - WritableFontData* data) { - return Table::Builder::GetBuilder(header, data); -} - -void Font::Builder::BuildTablesFromBuilders(Font* font, - TableBuilderMap* builder_map, - TableMap* table_map) { - UNREFERENCED_PARAMETER(font); - InterRelateBuilders(builder_map); - - // Now build all the tables. - for (TableBuilderMap::iterator builder = builder_map->begin(), - builder_end = builder_map->end(); - builder != builder_end; ++builder) { - TablePtr table; - if (builder->second && builder->second->ReadyToBuild()) { - table.Attach(down_cast(builder->second->Build())); - } - if (table == NULL) { - table_map->clear(); -#if !defined (SFNTLY_NO_EXCEPTION) - std::string builder_string = "Unable to build table - "; - char* table_name = TagToString(builder->first); - builder_string += table_name; - delete[] table_name; - throw RuntimeException(builder_string.c_str()); -#endif - return; - } - table_map->insert(TableMapEntry(table->header()->tag(), table)); - } -} - -static Table::Builder* GetBuilder(TableBuilderMap* builder_map, int32_t tag) { - if (builder_map) { - TableBuilderMap::iterator target = builder_map->find(tag); - if (target != builder_map->end()) { - return target->second.p_; - } - } - - return NULL; -} - -void Font::Builder::InterRelateBuilders(TableBuilderMap* builder_map) { - Table::Builder* raw_head_builder = GetBuilder(builder_map, Tag::head); - FontHeaderTableBuilderPtr header_table_builder; - if (raw_head_builder != NULL) { - header_table_builder = - down_cast(raw_head_builder); - } - - Table::Builder* raw_hhea_builder = GetBuilder(builder_map, Tag::hhea); - HorizontalHeaderTableBuilderPtr horizontal_header_builder; - if (raw_head_builder != NULL) { - horizontal_header_builder = - down_cast(raw_hhea_builder); - } - - Table::Builder* raw_maxp_builder = GetBuilder(builder_map, Tag::maxp); - MaximumProfileTableBuilderPtr max_profile_builder; - if (raw_maxp_builder != NULL) { - max_profile_builder = - down_cast(raw_maxp_builder); - } - - Table::Builder* raw_loca_builder = GetBuilder(builder_map, Tag::loca); - LocaTableBuilderPtr loca_table_builder; - if (raw_loca_builder != NULL) { - loca_table_builder = down_cast(raw_loca_builder); - } - - Table::Builder* raw_hmtx_builder = GetBuilder(builder_map, Tag::hmtx); - HorizontalMetricsTableBuilderPtr horizontal_metrics_builder; - if (raw_hmtx_builder != NULL) { - horizontal_metrics_builder = - down_cast(raw_hmtx_builder); - } - -#if defined (SFNTLY_EXPERIMENTAL) - Table::Builder* raw_hdmx_builder = GetBuilder(builder_map, Tag::hdmx); - HorizontalDeviceMetricsTableBuilderPtr hdmx_table_builder; - if (raw_hdmx_builder != NULL) { - hdmx_table_builder = - down_cast(raw_hdmx_builder); - } -#endif - - // set the inter table data required to build certain tables - if (horizontal_metrics_builder != NULL) { - if (max_profile_builder != NULL) { - horizontal_metrics_builder->SetNumGlyphs( - max_profile_builder->NumGlyphs()); - } - if (horizontal_header_builder != NULL) { - horizontal_metrics_builder->SetNumberOfHMetrics( - horizontal_header_builder->NumberOfHMetrics()); - } - } - - if (loca_table_builder != NULL) { - if (max_profile_builder != NULL) { - loca_table_builder->SetNumGlyphs(max_profile_builder->NumGlyphs()); - } - if (header_table_builder != NULL) { - loca_table_builder->set_format_version( - header_table_builder->IndexToLocFormat()); - } - } - -#if defined (SFNTLY_EXPERIMENTAL) - // Note: In C++, hdmx_table_builder can be NULL in a subsetter. - if (max_profile_builder != NULL && hdmx_table_builder != NULL) { - hdmx_table_builder->SetNumGlyphs(max_profile_builder->NumGlyphs()); - } -#endif -} - -void Font::Builder::ReadHeader(FontInputStream* is, - HeaderOffsetSortedSet* records) { - assert(records); - sfnt_version_ = is->ReadFixed(); - num_tables_ = is->ReadUShort(); - search_range_ = is->ReadUShort(); - entry_selector_ = is->ReadUShort(); - range_shift_ = is->ReadUShort(); - - for (int32_t table_number = 0; table_number < num_tables_; ++table_number) { - // Need to use temporary vars here. C++ evaluates function parameters from - // right to left and thus breaks the order of input stream. - int32_t tag = is->ReadULongAsInt(); - int64_t checksum = is->ReadULong(); - int32_t offset = is->ReadULongAsInt(); - int32_t length = is->ReadULongAsInt(); - HeaderPtr table = new Header(tag, checksum, offset, length); - records->insert(table); - } -} - -void Font::Builder::ReadHeader(ReadableFontData* fd, - int32_t offset, - HeaderOffsetSortedSet* records) { - assert(records); - sfnt_version_ = fd->ReadFixed(offset + Offset::kSfntVersion); - num_tables_ = fd->ReadUShort(offset + Offset::kNumTables); - search_range_ = fd->ReadUShort(offset + Offset::kSearchRange); - entry_selector_ = fd->ReadUShort(offset + Offset::kEntrySelector); - range_shift_ = fd->ReadUShort(offset + Offset::kRangeShift); - - int32_t table_offset = offset + Offset::kTableRecordBegin; - for (int32_t table_number = 0; - table_number < num_tables_; - table_number++, table_offset += Offset::kTableRecordSize) { - int32_t tag = fd->ReadULongAsInt(table_offset + Offset::kTableTag); - int64_t checksum = fd->ReadULong(table_offset + Offset::kTableCheckSum); - int32_t offset = fd->ReadULongAsInt(table_offset + Offset::kTableOffset); - int32_t length = fd->ReadULongAsInt(table_offset + Offset::kTableLength); - HeaderPtr table = new Header(tag, checksum, offset, length); - records->insert(table); - } -} - -void Font::Builder::LoadTableData(HeaderOffsetSortedSet* headers, - FontInputStream* is, - DataBlockMap* table_data) { - assert(table_data); - for (HeaderOffsetSortedSet::iterator table_header = headers->begin(), - table_end = headers->end(); - table_header != table_end; - ++table_header) { - is->Skip((*table_header)->offset() - is->position()); - FontInputStream table_is(is, (*table_header)->length()); - WritableFontDataPtr data; - data.Attach( - WritableFontData::CreateWritableFontData((*table_header)->length())); - data->CopyFrom(&table_is, (*table_header)->length()); - table_data->insert(DataBlockEntry(*table_header, data)); - } -} - -void Font::Builder::LoadTableData(HeaderOffsetSortedSet* headers, - WritableFontData* fd, - DataBlockMap* table_data) { - for (HeaderOffsetSortedSet::iterator table_header = headers->begin(), - table_end = headers->end(); - table_header != table_end; - ++table_header) { - FontDataPtr sliced_data; - sliced_data.Attach( - fd->Slice((*table_header)->offset(), (*table_header)->length())); - WritableFontDataPtr data = down_cast(sliced_data.p_); - table_data->insert(DataBlockEntry(*table_header, data)); - } -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/font.h b/src/sfntly/src/sfntly/font.h deleted file mode 100644 index ef8b97f854..0000000000 --- a/src/sfntly/src/sfntly/font.h +++ /dev/null @@ -1,352 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_FONT_H_ -#define SFNTLY_CPP_SRC_SFNTLY_FONT_H_ - -#include - -#include "sfntly/port/refcount.h" -#include "sfntly/port/type.h" -#include "sfntly/port/endian.h" -#include "sfntly/data/font_input_stream.h" -#include "sfntly/data/font_output_stream.h" -#include "sfntly/data/writable_font_data.h" -#include "sfntly/table/table.h" - -namespace sfntly { - -// Note: following constants are embedded in Font class in Java. They are -// extracted out for easier reference from other classes. Offset is the -// one that is kept within class. -// Platform ids. These are used in a number of places within the font whenever -// the platform needs to be specified. -struct PlatformId { - enum { - kUnknown = -1, - kUnicode = 0, - kMacintosh = 1, - kISO = 2, - kWindows = 3, - kCustom = 4 - }; -}; - -// Unicode encoding ids. These are used in a number of places within the font -// whenever character encodings need to be specified. -struct UnicodeEncodingId { - enum { - kUnknown = -1, - kUnicode1_0 = 0, - kUnicode1_1 = 1, - kISO10646 = 2, - kUnicode2_0_BMP = 3, - kUnicode2_0 = 4, - kUnicodeVariationSequences = 5 - }; -}; - -// Windows encoding ids. These are used in a number of places within the font -// whenever character encodings need to be specified. -struct WindowsEncodingId { - enum { - kUnknown = 0xffffffff, - kSymbol = 0, - kUnicodeUCS2 = 1, - kShiftJIS = 2, - kPRC = 3, - kBig5 = 4, - kWansung = 5, - kJohab = 6, - kUnicodeUCS4 = 10 - }; -}; - -// Macintosh encoding ids. These are used in a number of places within the -// font whenever character encodings need to be specified. -struct MacintoshEncodingId { - // Macintosh Platform Encodings - enum { - kUnknown = -1, - kRoman = 0, - kJapanese = 1, - kChineseTraditional = 2, - kKorean = 3, - kArabic = 4, - kHebrew = 5, - kGreek = 6, - kRussian = 7, - kRSymbol = 8, - kDevanagari = 9, - kGurmukhi = 10, - kGujarati = 11, - kOriya = 12, - kBengali = 13, - kTamil = 14, - kTelugu = 15, - kKannada = 16, - kMalayalam = 17, - kSinhalese = 18, - kBurmese = 19, - kKhmer = 20, - kThai = 21, - kLaotian = 22, - kGeorgian = 23, - kArmenian = 24, - kChineseSimplified = 25, - kTibetan = 26, - kMongolian = 27, - kGeez = 28, - kSlavic = 29, - kVietnamese = 30, - kSindhi = 31, - kUninterpreted = 32 - }; -}; - -class FontFactory; - -// An sfnt container font object. This object is immutable and thread safe. To -// construct one use an instance of Font::Builder. -class Font : public RefCounted { - public: - // A builder for a font object. The builder allows the for the creation of - // immutable Font objects. The builder is a one use non-thread safe object and - // once the Font object has been created it is no longer usable. To create a - // further Font object new builder will be required. - class Builder : public RefCounted { - public: - virtual ~Builder(); - - static CALLER_ATTACH Builder* - GetOTFBuilder(FontFactory* factory, InputStream* is); - static CALLER_ATTACH Builder* - GetOTFBuilder(FontFactory* factory, - WritableFontData* ba, - int32_t offset_to_offset_table); - static CALLER_ATTACH Builder* GetOTFBuilder(FontFactory* factory); - - // Get the font factory that created this font builder. - FontFactory* GetFontFactory() { return factory_; } - - // Is the font ready to build? - bool ReadyToBuild(); - - // Build the Font. After this call this builder will no longer be usable. - CALLER_ATTACH Font* Build(); - - // Set a unique fingerprint for the font object. - void SetDigest(ByteVector* digest); - - // Clear all table builders. - void ClearTableBuilders(); - - // Does this font builder have the specified table builder. - bool HasTableBuilder(int32_t tag); - - // Get the table builder for the given tag. If there is no builder for that - // tag then return a null. - Table::Builder* GetTableBuilder(int32_t tag); - - // Creates a new table builder for the table type given by the table id tag. - // This new table has been added to the font and will replace any existing - // builder for that table. - // @return new empty table of the type specified by tag; if tag is not known - // then a generic OpenTypeTable is returned - virtual Table::Builder* NewTableBuilder(int32_t tag); - - // Creates a new table builder for the table type given by the table id tag. - // It makes a copy of the data provided and uses that copy for the table. - // This new table has been added to the font and will replace any existing - // builder for that table. - virtual Table::Builder* NewTableBuilder(int32_t tag, - ReadableFontData* src_data); - - // Get a map of the table builders in this font builder accessed by table - // tag. - virtual TableBuilderMap* table_builders() { return &table_builders_; } - - // Remove the specified table builder from the font builder. - // Note: different from Java: we don't return object in removeTableBuilder - virtual void RemoveTableBuilder(int32_t tag); - - // Get the number of table builders in the font builder. - virtual int32_t number_of_table_builders() { - return (int32_t)table_builders_.size(); - } - - private: - explicit Builder(FontFactory* factory); - virtual void LoadFont(InputStream* is); - virtual void LoadFont(WritableFontData* wfd, - int32_t offset_to_offset_table); - int32_t SfntWrapperSize(); - void BuildAllTableBuilders(DataBlockMap* table_data, - TableBuilderMap* builder_map); - CALLER_ATTACH Table::Builder* - GetTableBuilder(Header* header, WritableFontData* data); - void BuildTablesFromBuilders(Font* font, - TableBuilderMap* builder_map, - TableMap* tables); - static void InterRelateBuilders(TableBuilderMap* builder_map); - - void ReadHeader(FontInputStream* is, - HeaderOffsetSortedSet* records); - - void ReadHeader(ReadableFontData* fd, - int32_t offset, - HeaderOffsetSortedSet* records); - - void LoadTableData(HeaderOffsetSortedSet* headers, - FontInputStream* is, - DataBlockMap* table_data); - - void LoadTableData(HeaderOffsetSortedSet* headers, - WritableFontData* fd, - DataBlockMap* table_data); - - TableBuilderMap table_builders_; - FontFactory* factory_; // dumb pointer, avoid circular refcounting - int32_t sfnt_version_; - int32_t num_tables_; - int32_t search_range_; - int32_t entry_selector_; - int32_t range_shift_; - DataBlockMap data_blocks_; - ByteVector digest_; - }; - - virtual ~Font(); - - // Gets the sfnt version set in the sfnt wrapper of the font. - int32_t sfnt_version(); - - // Gets a copy of the fonts digest that was created when the font was read. If - // no digest was set at creation time then the return result will be null. - ByteVector* digest(); - - // Get the checksum for this font. - int64_t checksum(); - - // Get the number of tables in this font. - int32_t num_tables(); - - // Whether the font has a particular table. - bool HasTable(int32_t tag); - - // UNIMPLEMENTED: public Iterator iterator - - // Get the table in this font with the specified id. - // @param tag the identifier of the table - // @return the table specified if it exists; null otherwise - // C++ port: rename table() to GetTable() - Table* GetTable(int32_t tag); - - // Get a map of the tables in this font accessed by table tag. - // @return an unmodifiable view of the tables in this font - // Note: renamed tableMap() to GetTableMap() - const TableMap* GetTableMap(); - - // UNIMPLEMENTED: toString() - - // Serialize the font to the output stream. - // @param os the destination for the font serialization - // @param tableOrdering the table ordering to apply - void Serialize(OutputStream* os, IntegerList* table_ordering); - - private: - // Offsets to specific elements in the underlying data. These offsets are - // relative to the start of the table or the start of sub-blocks within the - // table. - struct Offset { - enum { - // Offsets within the main directory - kSfntVersion = 0, - kNumTables = 4, - kSearchRange = 6, - kEntrySelector = 8, - kRangeShift = 10, - kTableRecordBegin = 12, - kSfntHeaderSize = 12, - - // Offsets within a specific table record - kTableTag = 0, - kTableCheckSum = 4, - kTableOffset = 8, - kTableLength = 12, - kTableRecordSize = 16 - }; - }; - - // Note: the two constants are moved to tag.h to avoid VC++ bug. -// static const int32_t CFF_TABLE_ORDERING[]; -// static const int32_t TRUE_TYPE_TABLE_ORDERING[]; - - // Constructor. - // @param sfntVersion the sfnt version - // @param digest the computed digest for the font; null if digest was not - // computed - // Note: Current C++ port does not support SHA digest validation. - Font(int32_t sfnt_version, ByteVector* digest); - - // Build the table headers to be used for serialization. These headers will be - // filled out with the data required for serialization. The headers will be - // sorted in the order specified and only those specified will have headers - // generated. - // @param tableOrdering the tables to generate headers for and the order to - // sort them - // @return a list of table headers ready for serialization - void BuildTableHeadersForSerialization(IntegerList* table_ordering, - TableHeaderList* table_headers); - - // Searialize the headers. - // @param fos the destination stream for the headers - // @param tableHeaders the headers to serialize - // @throws IOException - void SerializeHeader(FontOutputStream* fos, TableHeaderList* table_headers); - - // Serialize the tables. - // @param fos the destination stream for the headers - // @param tableHeaders the headers for the tables to serialize - // @throws IOException - void SerializeTables(FontOutputStream* fos, TableHeaderList* table_headers); - - // Generate the full table ordering to used for serialization. The full - // ordering uses the partial ordering as a seed and then adds all remaining - // tables in the font in an undefined order. - // @param defaultTableOrdering the partial ordering to be used as a seed for - // the full ordering - // @param (out) table_ordering the full ordering for serialization - void GenerateTableOrdering(IntegerList* default_table_ordering, - IntegerList* table_ordering); - - // Get the default table ordering based on the type of the font. - // @param (out) default_table_ordering the default table ordering - void DefaultTableOrdering(IntegerList* default_table_ordering); - - int32_t sfnt_version_; - ByteVector digest_; - int64_t checksum_; - TableMap tables_; -}; -typedef Ptr FontPtr; -typedef std::vector FontArray; -typedef Ptr FontBuilderPtr; -typedef std::vector FontBuilderArray; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_FONT_H_ diff --git a/src/sfntly/src/sfntly/font_factory.cc b/src/sfntly/src/sfntly/font_factory.cc deleted file mode 100644 index c162a77af3..0000000000 --- a/src/sfntly/src/sfntly/font_factory.cc +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/font_factory.h" - -#include - -#include "sfntly/tag.h" - -namespace sfntly { - -FontFactory::~FontFactory() { -} - -CALLER_ATTACH FontFactory* FontFactory::GetInstance() { - FontFactoryPtr instance = new FontFactory(); - return instance.Detach(); -} - -void FontFactory::FingerprintFont(bool fingerprint) { - fingerprint_ = fingerprint; -} - -bool FontFactory::FingerprintFont() { - return fingerprint_; -} - -void FontFactory::LoadFonts(InputStream* is, FontArray* output) { - assert(output); - PushbackInputStream* pbis = down_cast(is); - if (IsCollection(pbis)) { - LoadCollection(pbis, output); - return; - } - FontPtr font; - font.Attach(LoadSingleOTF(pbis)); - if (font) { - output->push_back(font); - } -} - -void FontFactory::LoadFonts(ByteVector* b, FontArray* output) { - WritableFontDataPtr wfd; - wfd.Attach(WritableFontData::CreateWritableFontData(b)); - if (IsCollection(wfd)) { - LoadCollection(wfd, output); - return; - } - FontPtr font; - font.Attach(LoadSingleOTF(wfd)); - if (font) { - output->push_back(font); - } -} - -void FontFactory::LoadFontsForBuilding(InputStream* is, - FontBuilderArray* output) { - PushbackInputStream* pbis = down_cast(is); - if (IsCollection(pbis)) { - LoadCollectionForBuilding(pbis, output); - return; - } - FontBuilderPtr builder; - builder.Attach(LoadSingleOTFForBuilding(pbis)); - if (builder) { - output->push_back(builder); - } -} - -void FontFactory::LoadFontsForBuilding(ByteVector* b, - FontBuilderArray* output) { - WritableFontDataPtr wfd; - wfd.Attach(WritableFontData::CreateWritableFontData(b)); - if (IsCollection(wfd)) { - LoadCollectionForBuilding(wfd, output); - return; - } - FontBuilderPtr builder; - builder.Attach(LoadSingleOTFForBuilding(wfd, 0)); - if (builder) { - output->push_back(builder); - } -} - -void FontFactory::SerializeFont(Font* font, OutputStream* os) { - font->Serialize(os, &table_ordering_); -} - -void FontFactory::SetSerializationTableOrdering( - const IntegerList& table_ordering) { - table_ordering_ = table_ordering; -} - -CALLER_ATTACH Font::Builder* FontFactory::NewFontBuilder() { - return Font::Builder::GetOTFBuilder(this); -} - -CALLER_ATTACH Font* FontFactory::LoadSingleOTF(InputStream* is) { - FontBuilderPtr builder; - builder.Attach(LoadSingleOTFForBuilding(is)); - return builder->Build(); -} - -CALLER_ATTACH Font* FontFactory::LoadSingleOTF(WritableFontData* wfd) { - FontBuilderPtr builder; - builder.Attach(LoadSingleOTFForBuilding(wfd, 0)); - return builder->Build(); -} - -void FontFactory::LoadCollection(InputStream* is, FontArray* output) { - FontBuilderArray ba; - LoadCollectionForBuilding(is, &ba); - output->reserve(ba.size()); - for (FontBuilderArray::iterator builder = ba.begin(), builders_end = ba.end(); - builder != builders_end; ++builder) { - FontPtr font; - font.Attach((*builder)->Build()); - output->push_back(font); - } -} - -void FontFactory::LoadCollection(WritableFontData* wfd, FontArray* output) { - FontBuilderArray builders; - LoadCollectionForBuilding(wfd, &builders); - output->reserve(builders.size()); - for (FontBuilderArray::iterator builder = builders.begin(), - builders_end = builders.end(); - builder != builders_end; ++builder) { - FontPtr font; - font.Attach((*builder)->Build()); - output->push_back(font); - } -} - -CALLER_ATTACH -Font::Builder* FontFactory::LoadSingleOTFForBuilding(InputStream* is) { - // UNIMPLEMENTED: SHA-1 hash checking via Java DigestStream - Font::Builder* builder = Font::Builder::GetOTFBuilder(this, is); - // UNIMPLEMENTED: setDigest - return builder; -} - -CALLER_ATTACH Font::Builder* - FontFactory::LoadSingleOTFForBuilding(WritableFontData* wfd, - int32_t offset_to_offset_table) { - // UNIMPLEMENTED: SHA-1 hash checking via Java DigestStream - Font::Builder* builder = - Font::Builder::GetOTFBuilder(this, wfd, offset_to_offset_table); - // UNIMPLEMENTED: setDigest - return builder; -} - -void FontFactory::LoadCollectionForBuilding(InputStream* is, - FontBuilderArray* builders) { - assert(is); - assert(builders); - WritableFontDataPtr wfd; - wfd.Attach(WritableFontData::CreateWritableFontData(is->Available())); - wfd->CopyFrom(is); - LoadCollectionForBuilding(wfd, builders); -} - -void FontFactory::LoadCollectionForBuilding(WritableFontData* wfd, - FontBuilderArray* builders) { - int32_t ttc_tag = wfd->ReadULongAsInt(Offset::kTTCTag); - UNREFERENCED_PARAMETER(ttc_tag); - int32_t version = wfd->ReadFixed(Offset::kVersion); - UNREFERENCED_PARAMETER(version); - int32_t num_fonts = wfd->ReadULongAsInt(Offset::kNumFonts); - - builders->reserve(num_fonts); - int32_t offset_table_offset = Offset::kOffsetTable; - for (int32_t font_number = 0; - font_number < num_fonts; - font_number++, offset_table_offset += DataSize::kULONG) { - int32_t offset = wfd->ReadULongAsInt(offset_table_offset); - FontBuilderPtr builder; - builder.Attach(LoadSingleOTFForBuilding(wfd, offset)); - builders->push_back(builder); - } -} - -bool FontFactory::IsCollection(PushbackInputStream* pbis) { - ByteVector tag(4); - pbis->Read(&tag); - pbis->Unread(&tag); - return Tag::ttcf == GenerateTag(tag[0], tag[1], tag[2], tag[3]); -} - -bool FontFactory::IsCollection(ReadableFontData* rfd) { - ByteVector tag(4); - rfd->ReadBytes(0, &(tag[0]), 0, tag.size()); - return Tag::ttcf == - GenerateTag(tag[0], tag[1], tag[2], tag[3]); -} - -FontFactory::FontFactory() - : fingerprint_(false) { -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/font_factory.h b/src/sfntly/src/sfntly/font_factory.h deleted file mode 100644 index 63deff4abf..0000000000 --- a/src/sfntly/src/sfntly/font_factory.h +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_FONT_FACTORY_H_ -#define SFNTLY_CPP_SRC_SFNTLY_FONT_FACTORY_H_ - -#include - -#include "sfntly/port/refcount.h" -#include "sfntly/port/type.h" -#include "sfntly/font.h" - -namespace sfntly { - -class FontFactory : public RefCounted { - public: - virtual ~FontFactory(); - - // Factory method for the construction of a font factory. - static CALLER_ATTACH FontFactory* GetInstance(); - - // Toggle whether fonts that are loaded are fingerprinted with a SHA-1 hash. - // If a font is fingerprinted then a SHA-1 hash is generated at load time and - // stored in the font. This is useful for uniquely identifying fonts. By - // default this is turned on. - // @param fingerprint whether fingerprinting should be turned on or off - // TODO(arthurhsu): IMPLEMENT: C++ port currently don't do any SHA-1 - void FingerprintFont(bool fingerprint); - bool FingerprintFont(); - - // Load the font(s) from the input stream. The current settings on the factory - // are used during the loading process. One or more fonts are returned if the - // stream contains valid font data. Some font container formats may have more - // than one font and in this case multiple font objects will be returned. If - // the data in the stream cannot be parsed or is invalid an array of size zero - // will be returned. - void LoadFonts(InputStream* is, FontArray* output); - - // ByteArray font loading - // Load the font(s) from the byte array. The current settings on the factory - // are used during the loading process. One or more fonts are returned if the - // stream contains valid font data. Some font container formats may have more - // than one font and in this case multiple font objects will be returned. If - // the data in the stream cannot be parsed or is invalid an array of size zero - // will be returned. - void LoadFonts(ByteVector* b, FontArray* output); - - // Load the font(s) from the input stream into font builders. The current - // settings on the factory are used during the loading process. One or more - // font builders are returned if the stream contains valid font data. Some - // font container formats may have more than one font and in this case - // multiple font builder objects will be returned. If the data in the stream - // cannot be parsed or is invalid an array of size zero will be returned. - void LoadFontsForBuilding(InputStream* is, FontBuilderArray* output); - - // Load the font(s) from the byte array into font builders. The current - // settings on the factory are used during the loading process. One or more - // font builders are returned if the stream contains valid font data. Some - // font container formats may have more than one font and in this case - // multiple font builder objects will be returned. If the data in the stream - // cannot be parsed or is invalid an array of size zero will be returned. - void LoadFontsForBuilding(ByteVector* b, FontBuilderArray* output); - - // Font serialization - // Serialize the font to the output stream. - // NOTE: in this port we attempted not to implement I/O stream because dealing - // with cross-platform I/O stream itself is big enough as a project. - // Byte buffer it is. - void SerializeFont(Font* font, OutputStream* os); - - // Set the table ordering to be used in serializing a font. The table ordering - // is an ordered list of table ids and tables will be serialized in the order - // given. Any tables whose id is not listed in the ordering will be placed in - // an unspecified order following those listed. - void SetSerializationTableOrdering(const IntegerList& table_ordering); - - // Get an empty font builder for creating a new font from scratch. - CALLER_ATTACH Font::Builder* NewFontBuilder(); - - private: - // Offsets to specific elements in the underlying data. These offsets are - // relative to the start of the table or the start of sub-blocks within the - // table. - struct Offset { - enum { - // Offsets within the main directory. - kTTCTag = 0, - kVersion = 4, - kNumFonts = 8, - kOffsetTable = 12, - - // TTC Version 2.0 extensions. - // Offsets from end of OffsetTable. - kulDsigTag = 0, - kulDsigLength = 4, - kulDsigOffset = 8 - }; - }; - - FontFactory(); - - CALLER_ATTACH Font* LoadSingleOTF(InputStream* is); - CALLER_ATTACH Font* LoadSingleOTF(WritableFontData* wfd); - - void LoadCollection(InputStream* is, FontArray* output); - void LoadCollection(WritableFontData* wfd, FontArray* output); - - CALLER_ATTACH Font::Builder* LoadSingleOTFForBuilding(InputStream* is); - CALLER_ATTACH Font::Builder* - LoadSingleOTFForBuilding(WritableFontData* wfd, - int32_t offset_to_offset_table); - - void LoadCollectionForBuilding(InputStream* is, FontBuilderArray* builders); - void LoadCollectionForBuilding(WritableFontData* ba, - FontBuilderArray* builders); - - static bool IsCollection(PushbackInputStream* pbis); - static bool IsCollection(ReadableFontData* wfd); - - bool fingerprint_; - IntegerList table_ordering_; -}; -typedef Ptr FontFactoryPtr; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_FONT_FACTORY_H_ diff --git a/src/sfntly/src/sfntly/math/fixed1616.h b/src/sfntly/src/sfntly/math/fixed1616.h deleted file mode 100644 index 4abbe18098..0000000000 --- a/src/sfntly/src/sfntly/math/fixed1616.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_MATH_FIXED1616_H_ -#define SFNTLY_CPP_SRC_SFNTLY_MATH_FIXED1616_H_ - -#include "sfntly/port/type.h" - -namespace sfntly { - -class Fixed1616 { - public: - static inline int32_t Integral(int32_t fixed) { - return (fixed >> 16); - } - - static inline int32_t Fractional(int32_t fixed) { - return (fixed & 0xffff); - } - - static inline int32_t Fixed(int32_t integral, int32_t fractional) { - return ((integral & 0xffff) << 16) | (fractional & 0xffff); - } -}; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_MATH_FIXED1616_H_ diff --git a/src/sfntly/src/sfntly/math/font_math.h b/src/sfntly/src/sfntly/math/font_math.h deleted file mode 100644 index f1cd2d2a6f..0000000000 --- a/src/sfntly/src/sfntly/math/font_math.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_MATH_FONT_MATH_H_ -#define SFNTLY_CPP_SRC_SFNTLY_MATH_FONT_MATH_H_ - -#include "sfntly/port/type.h" - -namespace sfntly { - -class FontMath { - public: - static int32_t Log2(int32_t a) { - int r = 0; // r will be lg(a) - while (a != 0) { - a >>= 1; - r++; - } - return r - 1; - } - - // Calculates the amount of padding needed. The values provided need to be in - // the same units. So, if the size is given as the number of bytes then the - // alignment size must also be specified as byte size to align to. - // @param size the size of the data that may need padding - // @param alignmentSize the number of units to align to - // @return the number of units needing to be added for alignment - static int32_t PaddingRequired(int32_t size, int32_t alignment_size) { - int32_t padding = alignment_size - (size % alignment_size); - return padding == alignment_size ? 0 : padding; - } -}; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_MATH_FONT_MATH_H_ diff --git a/src/sfntly/src/sfntly/port/atomic.h b/src/sfntly/src/sfntly/port/atomic.h deleted file mode 100644 index b381a52af7..0000000000 --- a/src/sfntly/src/sfntly/port/atomic.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_ATOMIC_H_ -#define SFNTLY_CPP_SRC_SFNTLY_PORT_ATOMIC_H_ - -#if defined (WIN32) - -#include - -static inline size_t AtomicIncrement(size_t* address) { -#if defined (_WIN64) - return InterlockedIncrement64(reinterpret_cast(address)); -#else - return InterlockedIncrement(reinterpret_cast(address)); -#endif -} - -static inline size_t AtomicDecrement(size_t* address) { -#if defined (_WIN64) - return InterlockedDecrement64(reinterpret_cast(address)); -#else - return InterlockedDecrement(reinterpret_cast(address)); -#endif -} - -#elif defined (__APPLE__) - -#include - -static inline size_t AtomicIncrement(size_t* address) { - return OSAtomicIncrement32Barrier(reinterpret_cast(address)); -} - -static inline size_t AtomicDecrement(size_t* address) { - return OSAtomicDecrement32Barrier(reinterpret_cast(address)); -} - -// Originally we check __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4, however, there are -// issues that clang not carring over this definition. Therefore we boldly -// assume it's gcc or gcc-compatible here. Compilation shall still fail since -// the intrinsics used are GCC-specific. - -#else - -#include - -static inline size_t AtomicIncrement(size_t* address) { - return __sync_add_and_fetch(address, 1); -} - -static inline size_t AtomicDecrement(size_t* address) { - return __sync_sub_and_fetch(address, 1); -} - -#endif // WIN32 - -#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_ATOMIC_H_ diff --git a/src/sfntly/src/sfntly/port/config.h b/src/sfntly/src/sfntly/port/config.h deleted file mode 100644 index 0fcdffe724..0000000000 --- a/src/sfntly/src/sfntly/port/config.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_CONFIG_H_ -#define SFNTLY_CPP_SRC_SFNTLY_PORT_CONFIG_H_ - -#if !defined(SFNTLY_BIG_ENDIAN) && !defined(SFNTLY_LITTLE_ENDIAN) - #if defined (__ppc__) || defined (__ppc64__) - #define SFNTLY_BIG_ENDIAN - #else - #define SFNTLY_LITTLE_ENDIAN - #endif -#endif - -#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_CONFIG_H_ diff --git a/src/sfntly/src/sfntly/port/endian.h b/src/sfntly/src/sfntly/port/endian.h deleted file mode 100644 index db58f0a307..0000000000 --- a/src/sfntly/src/sfntly/port/endian.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_ENDIAN_H_ -#define SFNTLY_CPP_SRC_SFNTLY_PORT_ENDIAN_H_ - -#include "sfntly/port/config.h" -#include "sfntly/port/type.h" - -namespace sfntly { - -static inline uint16_t EndianSwap16(uint16_t value) { - return (uint16_t)((value >> 8) | (value << 8)); -} - -static inline int32_t EndianSwap32(int32_t value) { - return (((value & 0x000000ff) << 24) | - ((value & 0x0000ff00) << 8) | - ((value & 0x00ff0000) >> 8) | - ((value & 0xff000000) >> 24)); -} - -static inline uint64_t EndianSwap64(uint64_t value) { - return (((value & 0x00000000000000ffLL) << 56) | - ((value & 0x000000000000ff00LL) << 40) | - ((value & 0x0000000000ff0000LL) << 24) | - ((value & 0x00000000ff000000LL) << 8) | - ((value & 0x000000ff00000000LL) >> 8) | - ((value & 0x0000ff0000000000LL) >> 24) | - ((value & 0x00ff000000000000LL) >> 40) | - ((value & 0xff00000000000000LL) >> 56)); -} - -#ifdef SFNTLY_LITTLE_ENDIAN - #define ToBE16(n) EndianSwap16(n) - #define ToBE32(n) EndianSwap32(n) - #define ToBE64(n) EndianSwap64(n) - #define ToLE16(n) (n) - #define ToLE32(n) (n) - #define ToLE64(n) (n) - #define FromBE16(n) EndianSwap16(n) - #define FromBE32(n) EndianSwap32(n) - #define FromBE64(n) EndianSwap64(n) - #define FromLE16(n) (n) - #define FromLE32(n) (n) - #define FromLE64(n) (n) -#else // SFNTLY_BIG_ENDIAN - #define ToBE16(n) (n) - #define ToBE32(n) (n) - #define ToBE64(n) (n) - #define ToLE16(n) EndianSwap16(n) - #define ToLE32(n) EndianSwap32(n) - #define ToLE64(n) EndianSwap64(n) - #define FromBE16(n) (n) - #define FromBE32(n) (n) - #define FromBE64(n) (n) - #define FromLE16(n) EndianSwap16(n) - #define FromLE32(n) EndianSwap32(n) - #define FromLE64(n) EndianSwap64(n) -#endif - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_ENDIAN_H_ diff --git a/src/sfntly/src/sfntly/port/exception_type.h b/src/sfntly/src/sfntly/port/exception_type.h deleted file mode 100644 index b96efcb6c5..0000000000 --- a/src/sfntly/src/sfntly/port/exception_type.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// Exceptions used in sfntly - -#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_EXCEPTION_TYPE_H_ -#define SFNTLY_CPP_SRC_SFNTLY_PORT_EXCEPTION_TYPE_H_ - -#if !defined (SFNTLY_NO_EXCEPTION) - -#include -#include -#include - -namespace sfntly { - -class Exception : public std::exception { - public: - Exception() : what_("Unknown exception") {} - explicit Exception(const char* message) throw() { SetMessage(message); } - virtual ~Exception() throw() {} - virtual const char* what() const throw() { return what_.c_str(); } - - protected: - void SetMessage(const char* message) throw() { - try { - what_ = message; - } catch (...) {} - } - - private: - std::string what_; -}; - -class IndexOutOfBoundException : public Exception { - public: - IndexOutOfBoundException() throw() : Exception("Index out of bound") {} - explicit IndexOutOfBoundException(const char* message) throw() - : Exception(message) {} - IndexOutOfBoundException(const char* message, int32_t index) throw() { - try { - std::ostringstream msg; - msg << message; - msg << ":"; - msg << index; - SetMessage(msg.str().c_str()); - } catch (...) {} - } - virtual ~IndexOutOfBoundException() throw() {} -}; - -class IOException : public Exception { - public: - IOException() throw() : Exception("I/O exception") {} - explicit IOException(const char* message) throw() : Exception(message) {} - virtual ~IOException() throw() {} -}; - -class ArithmeticException : public Exception { - public: - ArithmeticException() throw() : Exception("Arithmetic exception") {} - explicit ArithmeticException(const char* message) throw() - : Exception(message) {} - virtual ~ArithmeticException() throw() {} -}; - -class UnsupportedOperationException : public Exception { - public: - UnsupportedOperationException() throw() : - Exception("Operation not supported") {} - explicit UnsupportedOperationException(const char* message) throw() - : Exception(message) {} - virtual ~UnsupportedOperationException() throw() {} -}; - -class RuntimeException : public Exception { - public: - RuntimeException() throw() : Exception("Runtime exception") {} - explicit RuntimeException(const char* message) throw() - : Exception(message) {} - virtual ~RuntimeException() throw() {} -}; - -class NoSuchElementException : public Exception { - public: - NoSuchElementException() throw() : Exception("No such element") {} - explicit NoSuchElementException(const char* message) throw() - : Exception(message) {} - virtual ~NoSuchElementException() throw() {} -}; - -class IllegalArgumentException : public Exception { - public: - IllegalArgumentException() throw() : Exception("Illegal argument") {} - explicit IllegalArgumentException(const char* message) throw() - : Exception(message) {} - virtual ~IllegalArgumentException() throw() {} -}; - -class IllegalStateException : public Exception { - public: - IllegalStateException() throw() : Exception("Illegal state") {} - explicit IllegalStateException(const char* message) throw() - : Exception(message) {} - virtual ~IllegalStateException() throw() {} -}; - -} // namespace sfntly - -#endif // #if !defined (SFNTLY_NO_EXCEPTION) - -#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_EXCEPTION_TYPE_H_ diff --git a/src/sfntly/src/sfntly/port/file_input_stream.cc b/src/sfntly/src/sfntly/port/file_input_stream.cc deleted file mode 100644 index 5bcb434af0..0000000000 --- a/src/sfntly/src/sfntly/port/file_input_stream.cc +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#if defined (WIN32) -#include -#endif - -#include "sfntly/port/file_input_stream.h" -#include "sfntly/port/exception_type.h" - -namespace sfntly { - -FileInputStream::FileInputStream() - : file_(NULL), - position_(0), - length_(0) { -} - -FileInputStream::~FileInputStream() { - Close(); -} - -int32_t FileInputStream::Available() { - return length_ - position_; -} - -void FileInputStream::Close() { - if (file_) { - fclose(file_); - length_ = 0; - position_ = 0; - file_ = NULL; - } -} - -void FileInputStream::Mark(int32_t readlimit) { - // NOP - UNREFERENCED_PARAMETER(readlimit); -} - -bool FileInputStream::MarkSupported() { - return false; -} - -int32_t FileInputStream::Read() { - if (!file_) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IOException("no opened file"); -#endif - return 0; - } - if (feof(file_)) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IOException("eof reached"); -#endif - return 0; - } - byte_t value; - size_t length = fread(&value, 1, 1, file_); - position_ += length; - return value; -} - -int32_t FileInputStream::Read(ByteVector* b) { - return Read(b, 0, b->size()); -} - -int32_t FileInputStream::Read(ByteVector* b, int32_t offset, int32_t length) { - assert(b); - if (!file_) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IOException("no opened file"); -#endif - return 0; - } - if (feof(file_)) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IOException("eof reached"); -#endif - return 0; - } - size_t read_count = std::min(length_ - position_, length); - if (b->size() < (size_t)(offset + read_count)) { - b->resize((size_t)(offset + read_count)); - } - int32_t actual_read = fread(&((*b)[offset]), 1, read_count, file_); - position_ += actual_read; - return actual_read; -} - -void FileInputStream::Reset() { - // NOP -} - -int64_t FileInputStream::Skip(int64_t n) { - if (!file_) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IOException("no opened file"); -#endif - return 0; - } - int64_t skip_count = 0; - if (n < 0) { // move backwards - skip_count = std::max(0 - (int64_t)position_, n); - position_ -= (size_t)(0 - skip_count); - fseek(file_, position_, SEEK_SET); - } else { - skip_count = std::min(length_ - position_, (size_t)n); - position_ += (size_t)skip_count; - fseek(file_, (size_t)skip_count, SEEK_CUR); - } - return skip_count; -} - -void FileInputStream::Unread(ByteVector* b) { - Unread(b, 0, b->size()); -} - -void FileInputStream::Unread(ByteVector* b, int32_t offset, int32_t length) { - assert(b); - assert(b->size() >= size_t(offset + length)); - if (!file_) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IOException("no opened file"); -#endif - return; - } - size_t unread_count = std::min(position_, length); - fseek(file_, position_ - unread_count, SEEK_SET); - position_ -= unread_count; - Read(b, offset, length); - fseek(file_, position_ - unread_count, SEEK_SET); - position_ -= unread_count; -} - -bool FileInputStream::Open(const char* file_path) { - assert(file_path); - if (file_) { - Close(); - } -#if defined (WIN32) - fopen_s(&file_, file_path, "rb"); -#else - file_ = fopen(file_path, "rb"); -#endif - if (file_ == NULL) { - return false; - } - - fseek(file_, 0, SEEK_END); - length_ = ftell(file_); - fseek(file_, 0, SEEK_SET); - return true; -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/port/file_input_stream.h b/src/sfntly/src/sfntly/port/file_input_stream.h deleted file mode 100644 index cbca25f7e4..0000000000 --- a/src/sfntly/src/sfntly/port/file_input_stream.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_FILE_INPUT_STREAM_H_ -#define SFNTLY_CPP_SRC_SFNTLY_PORT_FILE_INPUT_STREAM_H_ - -#include - -#include "sfntly/port/input_stream.h" - -namespace sfntly { - -class FileInputStream : public PushbackInputStream { - public: - FileInputStream(); - virtual ~FileInputStream(); - - // InputStream methods - virtual int32_t Available(); - virtual void Close(); - virtual void Mark(int32_t readlimit); - virtual bool MarkSupported(); - virtual int32_t Read(); - virtual int32_t Read(ByteVector* b); - virtual int32_t Read(ByteVector* b, int32_t offset, int32_t length); - virtual void Reset(); - virtual int64_t Skip(int64_t n); - - // PushbackInputStream methods - virtual void Unread(ByteVector* b); - virtual void Unread(ByteVector* b, int32_t offset, int32_t length); - - // Own methods - virtual bool Open(const char* file_path); - - private: - FILE* file_; - size_t position_; - size_t length_; -}; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_FILE_INPUT_STREAM_H_ diff --git a/src/sfntly/src/sfntly/port/input_stream.h b/src/sfntly/src/sfntly/port/input_stream.h deleted file mode 100644 index 5d24036ea7..0000000000 --- a/src/sfntly/src/sfntly/port/input_stream.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_INPUT_STREAM_H_ -#define SFNTLY_CPP_SRC_SFNTLY_PORT_INPUT_STREAM_H_ - -#include "sfntly/port/type.h" - -namespace sfntly { - -// C++ equivalent to Java's OutputStream class -class InputStream { - public: - // Make gcc -Wnon-virtual-dtor happy. - virtual ~InputStream() {} - - virtual int32_t Available() = 0; - virtual void Close() = 0; - virtual void Mark(int32_t readlimit) = 0; - virtual bool MarkSupported() = 0; - virtual int32_t Read() = 0; - virtual int32_t Read(ByteVector* b) = 0; - virtual int32_t Read(ByteVector* b, int32_t offset, int32_t length) = 0; - virtual void Reset() = 0; - virtual int64_t Skip(int64_t n) = 0; -}; - -class PushbackInputStream : public InputStream { - public: - virtual void Unread(ByteVector* b) = 0; - virtual void Unread(ByteVector* b, int32_t offset, int32_t length) = 0; -}; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_INPUT_STREAM_H_ diff --git a/src/sfntly/src/sfntly/port/java_iterator.h b/src/sfntly/src/sfntly/port/java_iterator.h deleted file mode 100644 index 0a99bca1d0..0000000000 --- a/src/sfntly/src/sfntly/port/java_iterator.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_JAVA_ITERATOR_H_ -#define SFNTLY_CPP_SRC_SFNTLY_PORT_JAVA_ITERATOR_H_ - -#include "sfntly/port/refcount.h" - -// Interface of Java iterator. -// This is a forward read-only iterator that represents java.util.Iterator - -namespace sfntly { - -template -class Iterator : public virtual RefCount { - public: - virtual ~Iterator() {} - virtual ContainerBase* container_base() = 0; - - protected: - Iterator() {} - NO_COPY_AND_ASSIGN(Iterator); -}; - -template -class PODIterator : public Iterator, - public RefCounted< PODIterator > { - public: - explicit PODIterator(Container* container) : container_(container) {} - virtual ~PODIterator() {} - virtual ContainerBase* container_base() { - return static_cast(container_); - } - - virtual bool HasNext() = 0; - virtual ReturnType Next() = 0; - virtual void Remove() { -#if !defined (SFNTLY_NO_EXCEPTION) - // Default to no support. - throw UnsupportedOperationException(); -#endif - } - - protected: - Container* container() { return container_; } - - private: - Container* container_; // Dumb pointer is used to avoid circular ref-counting -}; - -template -class RefIterator : public Iterator, - public RefCounted< RefIterator > { - public: - explicit RefIterator(Container* container) : container_(container) {} - virtual ~RefIterator() {} - virtual ContainerBase* container_base() { - return static_cast(container_); - } - - virtual bool HasNext() = 0; - CALLER_ATTACH virtual ReturnType* Next() = 0; - virtual void Remove() { -#if !defined (SFNTLY_NO_EXCEPTION) - // Default to no support. - throw UnsupportedOperationException(); -#endif - } - - protected: - Container* container() { return container_; } - - private: - Container* container_; // Dumb pointer is used to avoid circular ref-counting -}; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_JAVA_ITERATOR_H_ diff --git a/src/sfntly/src/sfntly/port/lock.cc b/src/sfntly/src/sfntly/port/lock.cc deleted file mode 100644 index 6c0c309a94..0000000000 --- a/src/sfntly/src/sfntly/port/lock.cc +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/port/lock.h" - -namespace sfntly { - -#if defined (WIN32) - -Lock::Lock() { - // The second parameter is the spin count, for short-held locks it avoid the - // contending thread from going to sleep which helps performance greatly. - ::InitializeCriticalSectionAndSpinCount(&os_lock_, 2000); -} - -Lock::~Lock() { - ::DeleteCriticalSection(&os_lock_); -} - -bool Lock::Try() { - if (::TryEnterCriticalSection(&os_lock_) != FALSE) { - return true; - } - return false; -} - -void Lock::Acquire() { - ::EnterCriticalSection(&os_lock_); -} - -void Lock::Unlock() { - ::LeaveCriticalSection(&os_lock_); -} - -#else // We assume it's pthread - -Lock::Lock() { - pthread_mutex_init(&os_lock_, NULL); -} - -Lock::~Lock() { - pthread_mutex_destroy(&os_lock_); -} - -bool Lock::Try() { - return (pthread_mutex_trylock(&os_lock_) == 0); -} - -void Lock::Acquire() { - pthread_mutex_lock(&os_lock_); -} - -void Lock::Unlock() { - pthread_mutex_unlock(&os_lock_); -} - -#endif - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/port/lock.h b/src/sfntly/src/sfntly/port/lock.h deleted file mode 100644 index b2e29bf64f..0000000000 --- a/src/sfntly/src/sfntly/port/lock.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_LOCK_H_ -#define SFNTLY_CPP_SRC_SFNTLY_PORT_LOCK_H_ - -#if defined (WIN32) -#include -#else // Assume pthread. -#include -#include -#endif - -#include "sfntly/port/type.h" - -namespace sfntly { - -#if defined (WIN32) - typedef CRITICAL_SECTION OSLockType; -#else // Assume pthread. - typedef pthread_mutex_t OSLockType; -#endif - -class Lock { - public: - Lock(); - ~Lock(); - - // If the lock is not held, take it and return true. If the lock is already - // held by something else, immediately return false. - bool Try(); - - // Take the lock, blocking until it is available if necessary. - void Acquire(); - - // Release the lock. This must only be called by the lock's holder: after - // a successful call to Try, or a call to Lock. - void Unlock(); - - private: - OSLockType os_lock_; - NO_COPY_AND_ASSIGN(Lock); -}; - -// A helper class that acquires the given Lock while the AutoLock is in scope. -class AutoLock { - public: - explicit AutoLock(Lock& lock) : lock_(lock) { - lock_.Acquire(); - } - - ~AutoLock() { - lock_.Unlock(); - } - - private: - Lock& lock_; - NO_COPY_AND_ASSIGN(AutoLock); -}; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_LOCK_H_ diff --git a/src/sfntly/src/sfntly/port/memory_input_stream.cc b/src/sfntly/src/sfntly/port/memory_input_stream.cc deleted file mode 100755 index 56ee81e5dd..0000000000 --- a/src/sfntly/src/sfntly/port/memory_input_stream.cc +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#if defined (WIN32) -#include -#endif - -#include - -#include "sfntly/port/memory_input_stream.h" -#include "sfntly/port/exception_type.h" - -namespace sfntly { - -MemoryInputStream::MemoryInputStream() - : buffer_(NULL), - position_(0), - length_(0) { -} - -MemoryInputStream::~MemoryInputStream() { - Close(); -} - -int32_t MemoryInputStream::Available() { - return length_ - position_; -} - -void MemoryInputStream::Close() { -} - -void MemoryInputStream::Mark(int32_t readlimit) { - // NOP - UNREFERENCED_PARAMETER(readlimit); -} - -bool MemoryInputStream::MarkSupported() { - return false; -} - -int32_t MemoryInputStream::Read() { - if (!buffer_) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IOException("no memory attached"); -#endif - return 0; - } - if (position_ >= length_) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IOException("eof reached"); -#endif - return 0; - } - byte_t value = buffer_[position_++]; - return value; -} - -int32_t MemoryInputStream::Read(ByteVector* b) { - return Read(b, 0, b->size()); -} - -int32_t MemoryInputStream::Read(ByteVector* b, int32_t offset, int32_t length) { - assert(b); - if (!buffer_) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IOException("no memory attached"); -#endif - return 0; - } - if (position_ >= length_) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IOException("eof reached"); -#endif - return 0; - } - size_t read_count = std::min(length_ - position_, length); - if (b->size() < (size_t)(offset + read_count)) { - b->resize((size_t)(offset + read_count)); - } - memcpy(&((*b)[offset]), buffer_ + position_, read_count); - position_ += read_count; - return read_count; -} - -void MemoryInputStream::Reset() { - // NOP -} - -int64_t MemoryInputStream::Skip(int64_t n) { - if (!buffer_) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IOException("no memory attached"); -#endif - return 0; - } - int64_t skip_count = 0; - if (n < 0) { // move backwards - skip_count = std::max(0 - (int64_t)position_, n); - position_ -= (size_t)(0 - skip_count); - } else { - skip_count = std::min(length_ - position_, (size_t)n); - position_ += (size_t)skip_count; - } - return skip_count; -} - -void MemoryInputStream::Unread(ByteVector* b) { - Unread(b, 0, b->size()); -} - -void MemoryInputStream::Unread(ByteVector* b, int32_t offset, int32_t length) { - assert(b); - assert(b->size() >= size_t(offset + length)); - if (!buffer_) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IOException("no memory attached"); -#endif - return; - } - size_t unread_count = std::min(position_, length); - position_ -= unread_count; - Read(b, offset, length); - position_ -= unread_count; -} - -bool MemoryInputStream::Attach(const byte_t* buffer, size_t length) { - assert(buffer); - assert(length); - buffer_ = buffer; - length_ = length; - return true; -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/port/memory_input_stream.h b/src/sfntly/src/sfntly/port/memory_input_stream.h deleted file mode 100755 index bc861c3f13..0000000000 --- a/src/sfntly/src/sfntly/port/memory_input_stream.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_INPUT_STREAM_H_ -#define SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_INPUT_STREAM_H_ - -#include - -#include "sfntly/port/input_stream.h" - -namespace sfntly { - -class MemoryInputStream : public PushbackInputStream { - public: - MemoryInputStream(); - virtual ~MemoryInputStream(); - - // InputStream methods - virtual int32_t Available(); - virtual void Close(); - virtual void Mark(int32_t readlimit); - virtual bool MarkSupported(); - virtual int32_t Read(); - virtual int32_t Read(ByteVector* b); - virtual int32_t Read(ByteVector* b, int32_t offset, int32_t length); - virtual void Reset(); - virtual int64_t Skip(int64_t n); - - // PushbackInputStream methods - virtual void Unread(ByteVector* b); - virtual void Unread(ByteVector* b, int32_t offset, int32_t length); - - // Own methods - virtual bool Attach(const byte_t* buffer, size_t length); - - private: - const byte_t* buffer_; - size_t position_; - size_t length_; -}; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_INPUT_STREAM_H_ diff --git a/src/sfntly/src/sfntly/port/memory_output_stream.cc b/src/sfntly/src/sfntly/port/memory_output_stream.cc deleted file mode 100644 index f2ff2e302e..0000000000 --- a/src/sfntly/src/sfntly/port/memory_output_stream.cc +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/port/memory_output_stream.h" - -namespace sfntly { - -MemoryOutputStream::MemoryOutputStream() { -} - -MemoryOutputStream::~MemoryOutputStream() { -} - -void MemoryOutputStream::Write(ByteVector* buffer) { - store_.insert(store_.end(), buffer->begin(), buffer->end()); -} - -void MemoryOutputStream::Write(ByteVector* buffer, - int32_t offset, - int32_t length) { - assert(buffer); - if (offset >= 0 && length > 0) { - store_.insert(store_.end(), - buffer->begin() + offset, - buffer->begin() + offset + length); - } else { -#if !defined(SFNTLY_NO_EXCEPTION) - throw IndexOutOfBoundException(); -#endif - } -} - -void MemoryOutputStream::Write(byte_t* buffer, int32_t offset, int32_t length) { - assert(buffer); - if (offset >= 0 && length > 0) { - store_.insert(store_.end(), buffer + offset, buffer + offset + length); - } else { -#if !defined(SFNTLY_NO_EXCEPTION) - throw IndexOutOfBoundException(); -#endif - } -} - -void MemoryOutputStream::Write(byte_t b) { - store_.push_back(b); -} - -byte_t* MemoryOutputStream::Get() { - if (store_.empty()) { - return NULL; - } - return &(store_[0]); -} - -size_t MemoryOutputStream::Size() { - return store_.size(); -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/port/memory_output_stream.h b/src/sfntly/src/sfntly/port/memory_output_stream.h deleted file mode 100644 index d1eda7faf8..0000000000 --- a/src/sfntly/src/sfntly/port/memory_output_stream.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_OUTPUT_STREAM_H_ -#define SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_OUTPUT_STREAM_H_ - -#include -#include - -#include "sfntly/port/type.h" -#include "sfntly/port/output_stream.h" - -namespace sfntly { - -// OutputStream backed by STL vector - -class MemoryOutputStream : public OutputStream { - public: - MemoryOutputStream(); - virtual ~MemoryOutputStream(); - - virtual void Close() {} // no-op - virtual void Flush() {} // no-op - virtual void Write(ByteVector* buffer); - virtual void Write(ByteVector* buffer, int32_t offset, int32_t length); - virtual void Write(byte_t* buffer, int32_t offset, int32_t length); - virtual void Write(byte_t b); - - byte_t* Get(); - size_t Size(); - - private: - std::vector store_; -}; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_OUTPUT_STREAM_H_ diff --git a/src/sfntly/src/sfntly/port/output_stream.h b/src/sfntly/src/sfntly/port/output_stream.h deleted file mode 100644 index 64a602471d..0000000000 --- a/src/sfntly/src/sfntly/port/output_stream.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_OUTPUT_STREAM_H_ -#define SFNTLY_CPP_SRC_SFNTLY_PORT_OUTPUT_STREAM_H_ - -#include "sfntly/port/type.h" - -namespace sfntly { - -// C++ equivalent to Java's OutputStream class -class OutputStream { - public: - // Make gcc -Wnon-virtual-dtor happy. - virtual ~OutputStream() {} - - virtual void Close() = 0; - virtual void Flush() = 0; - virtual void Write(ByteVector* buffer) = 0; - virtual void Write(byte_t b) = 0; - - // Note: C++ port offered both versions of Write() here. The first one is - // better because it does check bounds. The second one is there for - // performance concerns. - virtual void Write(ByteVector* buffer, int32_t offset, int32_t length) = 0; - - // Note: Caller is responsible for the boundary of buffer. - virtual void Write(byte_t* buffer, int32_t offset, int32_t length) = 0; -}; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_OUTPUT_STREAM_H_ diff --git a/src/sfntly/src/sfntly/port/refcount.h b/src/sfntly/src/sfntly/port/refcount.h deleted file mode 100644 index eed51622d7..0000000000 --- a/src/sfntly/src/sfntly/port/refcount.h +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// Object reference count and smart pointer implementation. - -// Smart pointer usage in sfntly: -// -// sfntly carries a smart pointer implementation like COM. Ref-countable object -// type inherits from RefCounted<>, which have AddRef and Release just like -// IUnknown (but no QueryInterface). Use a Ptr<> based smart pointer to hold -// the object so that the object ref count is handled correctly. -// -// class Foo : public RefCounted { -// public: -// static Foo* CreateInstance() { -// Ptr obj = new Foo(); // ref count = 1 -// return obj.Detach(); -// } -// }; -// typedef Ptr FooPtr; // common short-hand notation -// FooPtr obj; -// obj.Attach(Foo::CreatedInstance()); // ref count = 1 -// { -// FooPtr obj2 = obj; // ref count = 2 -// } // ref count = 1, obj2 out of scope -// obj.Release(); // ref count = 0, object destroyed - -// Notes on usage: -// 1. Virtual inherit from RefCount interface in base class if smart pointers -// are going to be defined. -// 2. All RefCounted objects must be instantiated on the heap. Allocating the -// object on stack will cause crash. -// 3. Be careful when you have complex inheritance. For example, -// class A : public RefCounted; -// class B : public A, public RefCounted; -// In this case the smart pointer is pretty dumb and don't count on it to -// nicely destroy your objects as designed. Try refactor your code like -// class I; // the common interface and implementations -// class A : public I, public RefCounted; // A specific implementation -// class B : public I, public RefCounted; // B specific implementation -// 4. Smart pointers here are very bad candidates for function parameters. Use -// dumb pointers in function parameter list. -// 5. When down_cast is performed on a dangling pointer due to bugs in code, -// VC++ will generate SEH which is not handled well in VC++ debugger. One -// can use WinDBG to run it and get the faulting stack. -// 6. Idioms for heap object as return value -// Foo* createFoo() { FooPtr obj = new Foo(); return obj.Detach(); } -// Foo* passthru() { FooPtr obj = createFoo(), return obj; } -// FooPtr end_scope_pointer; -// end_scope_pointer.Attach(passThrough); -// If you are not passing that object back, you are the end of scope. - -#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_REFCOUNT_H_ -#define SFNTLY_CPP_SRC_SFNTLY_PORT_REFCOUNT_H_ - -#if !defined (NDEBUG) - #define ENABLE_OBJECT_COUNTER -// #define REF_COUNT_DEBUGGING -#endif - -#if defined (REF_COUNT_DEBUGGING) - #include - #include -#endif - -#include "sfntly/port/atomic.h" -#include "sfntly/port/type.h" - -// Special tag for functions that requires caller to attach instead of using -// assignment operators. -#define CALLER_ATTACH - -#if defined (REF_COUNT_DEBUGGING) - #define DEBUG_OUTPUT(a) \ - fprintf(stderr, "%s%s:oc=%d,oid=%d,rc=%d\n", a, \ - typeid(this).name(), object_counter_, object_id_, ref_count_) -#else - #define DEBUG_OUTPUT(a) -#endif - -#if defined (_MSC_VER) - // VC 2008/2010 incorrectly gives this warning for pure virtual functions - // in virtual inheritance. The only way to get around it is to disable it. - #pragma warning(disable:4250) -#endif - -namespace sfntly { - -class RefCount { - public: - // Make gcc -Wnon-virtual-dtor happy. - virtual ~RefCount() {} - - virtual size_t AddRef() const = 0; - virtual size_t Release() const = 0; -}; - -template -class NoAddRefRelease : public T { - public: - NoAddRefRelease(); - ~NoAddRefRelease(); - - private: - virtual size_t AddRef() const = 0; - virtual size_t Release() const = 0; -}; - -template -class RefCounted : virtual public RefCount { - public: - RefCounted() : ref_count_(0) { -#if defined (ENABLE_OBJECT_COUNTER) - object_id_ = AtomicIncrement(&next_id_); - AtomicIncrement(&object_counter_); - DEBUG_OUTPUT("C "); -#endif - } - RefCounted(const RefCounted&) : ref_count_(0) {} - virtual ~RefCounted() { -#if defined (ENABLE_OBJECT_COUNTER) - AtomicDecrement(&object_counter_); - DEBUG_OUTPUT("D "); -#endif - } - - RefCounted& operator=(const RefCounted&) { - // Each object maintains own ref count, don't propagate. - return *this; - } - - virtual size_t AddRef() const { - size_t new_count = AtomicIncrement(&ref_count_); - DEBUG_OUTPUT("A "); - return new_count; - } - - virtual size_t Release() const { - size_t new_ref_count = AtomicDecrement(&ref_count_); - DEBUG_OUTPUT("R "); - if (new_ref_count == 0) { - // A C-style is used to cast away const-ness and to derived. - // lint does not like this but this is how it works. - delete (TDerived*)(this); - } - return new_ref_count; - } - - mutable size_t ref_count_; // reference count of current object -#if defined (ENABLE_OBJECT_COUNTER) - static size_t object_counter_; - static size_t next_id_; - mutable size_t object_id_; -#endif -}; - -#if defined (ENABLE_OBJECT_COUNTER) -template size_t RefCounted::object_counter_ = 0; -template size_t RefCounted::next_id_ = 0; -#endif - -// semi-smart pointer for RefCount derived objects, similar to CComPtr -template -class Ptr { - public: - Ptr() : p_(NULL) { - } - - // This constructor shall not be explicit. - // lint does not like this but this is how it works. - Ptr(T* pT) : p_(NULL) { - *this = pT; - } - - Ptr(const Ptr& p) : p_(NULL) { - *this = p; - } - - ~Ptr() { - Release(); - } - - T* operator=(T* pT) { - if (p_ == pT) { - return p_; - } - if (pT) { - RefCount* p = static_cast(pT); - if (p == NULL) { - return NULL; - } - p->AddRef(); // always AddRef() before Release() - } - Release(); - p_ = pT; - return p_; - } - - T* operator=(const Ptr& p) { - if (p_ == p.p_) { - return p_; - } - return operator=(p.p_); - } - - operator T*&() { - return p_; - } - - T& operator*() const { - return *p_; // It can throw! - } - - NoAddRefRelease* operator->() const { - return (NoAddRefRelease*)p_; // It can throw! - } - - bool operator!() const { - return (p_ == NULL); - } - - bool operator<(const Ptr& p) const { - return (p_ < p.p_); - } - - bool operator!=(T* pT) const { - return !operator==(pT); - } - - bool operator==(T* pT) const { - return (p_ == pT); - } - - size_t Release() const { - size_t ref_count = 0; - if (p_) { - RefCount* p = static_cast(p_); - if (p) { - ref_count = p->Release(); - } - p_ = NULL; - } - return ref_count; - } - - void Attach(T* pT) { - if (p_ != pT) { - Release(); - p_ = pT; - } - } - - T* Detach() { - T* pT = p_; - p_ = NULL; - return pT; - } - - mutable T* p_; -}; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_REFCOUNT_H_ diff --git a/src/sfntly/src/sfntly/port/type.h b/src/sfntly/src/sfntly/port/type.h deleted file mode 100644 index 20a5ba8a89..0000000000 --- a/src/sfntly/src/sfntly/port/type.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_TYPE_H_ -#define SFNTLY_CPP_SRC_SFNTLY_PORT_TYPE_H_ - -#include - -#if defined (_MSC_VER) && (_MSC_VER < 1600) - typedef unsigned char uint8_t; - typedef signed char int8_t; - typedef unsigned __int16 uint16_t; - typedef signed __int16 int16_t; - typedef unsigned __int32 uint32_t; - typedef signed __int32 int32_t; - typedef unsigned __int64 uint64_t; - typedef signed __int64 int64_t; - // Definitions to avoid ICU redefinition issue - #define U_HAVE_INT8_T 1 - #define U_HAVE_UINT8_T 1 - #define U_HAVE_INT16_T 1 - #define U_HAVE_UINT16_T 1 - #define U_HAVE_INT32_T 1 - #define U_HAVE_UINT32_T 1 - #define U_HAVE_INT64_T 1 - #define U_HAVE_UINT64_T 1 -#else - #include -#endif - -#include -#include -#include - -namespace sfntly { - -typedef uint8_t byte_t; -typedef uint16_t word_t; -typedef uint32_t dword_t; -typedef uint64_t qword_t; - -typedef std::vector ByteVector; -typedef std::vector IntegerList; -typedef std::set IntegerSet; - -// A macro to disallow the copy constructor and operator= functions. -// This should be used in the private: declarations for a class. -#define NO_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&); \ - void operator=(const TypeName&) - -} // namespace sfntly - -// Make google3 happy since it prohibits RTTI. -template -inline To implicit_cast(From const &f) { - return f; -} - -template // use like this: down_cast(foo); -inline To down_cast(From* f) { // so we only accept pointers - // Ensures that To is a sub-type of From *. This test is here only - // for compile-time type checking, and has no overhead in an - // optimized build at run-time, as it will be optimized away - // completely. -#if defined (_MSC_VER) - #pragma warning(push) - #pragma warning(disable:4127) // disable "conditional expression is constant" -#endif - if (false) { - implicit_cast(0); - } -#if defined (_MSC_VER) - #pragma warning(pop) -#endif - -// The following code is the only place for RTTI. It is done so to allow -// additional type checking when SFNTLY_TYPE_VERIFICATION is defined. -#if defined (SFNTLY_TYPE_VERIFICATION) - assert(f == NULL || dynamic_cast(f) != NULL); -#endif - return static_cast(f); -} - -#if !defined(WIN32) - #define UNREFERENCED_PARAMETER(p) do { (void)p; } while (0) -#endif - -#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_TYPE_H_ diff --git a/src/sfntly/src/sfntly/table/bitmap/big_glyph_metrics.cc b/src/sfntly/src/sfntly/table/bitmap/big_glyph_metrics.cc deleted file mode 100644 index d853212bbe..0000000000 --- a/src/sfntly/src/sfntly/table/bitmap/big_glyph_metrics.cc +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/table/bitmap/big_glyph_metrics.h" - -namespace sfntly { -/****************************************************************************** - * BigGlyphMetrics class - ******************************************************************************/ -BigGlyphMetrics::BigGlyphMetrics(ReadableFontData* data) - : GlyphMetrics(data) { -} - -BigGlyphMetrics::~BigGlyphMetrics() { -} - -int32_t BigGlyphMetrics::Height() { - return data_->ReadByte(Offset::kHeight); -} - -int32_t BigGlyphMetrics::Width() { - return data_->ReadByte(Offset::kWidth); -} - -int32_t BigGlyphMetrics::HoriBearingX() { - return data_->ReadByte(Offset::kHoriBearingX); -} - -int32_t BigGlyphMetrics::HoriBearingY() { - return data_->ReadByte(Offset::kHoriBearingY); -} - -int32_t BigGlyphMetrics::HoriAdvance() { - return data_->ReadByte(Offset::kHoriAdvance); -} - -int32_t BigGlyphMetrics::VertBearingX() { - return data_->ReadByte(Offset::kVertBearingX); -} - -int32_t BigGlyphMetrics::VertBearingY() { - return data_->ReadByte(Offset::kVertBearingY); -} - -int32_t BigGlyphMetrics::VertAdvance() { - return data_->ReadByte(Offset::kVertAdvance); -} - -/****************************************************************************** - * BigGlyphMetrics::Builder class - ******************************************************************************/ -BigGlyphMetrics::Builder::Builder(WritableFontData* data) - : GlyphMetrics::Builder(data) { -} - -BigGlyphMetrics::Builder::Builder(ReadableFontData* data) - : GlyphMetrics::Builder(data) { -} - -BigGlyphMetrics::Builder::~Builder() { -} - -int32_t BigGlyphMetrics::Builder::Height() { - return InternalReadData()->ReadByte(Offset::kHeight); -} - -void BigGlyphMetrics::Builder::SetHeight(byte_t height) { - InternalWriteData()->WriteByte(Offset::kHeight, height); -} - -int32_t BigGlyphMetrics::Builder::Width() { - return InternalReadData()->ReadByte(Offset::kWidth); -} - -void BigGlyphMetrics::Builder::SetWidth(byte_t width) { - InternalWriteData()->WriteByte(Offset::kWidth, width); -} - -int32_t BigGlyphMetrics::Builder::HoriBearingX() { - return InternalReadData()->ReadByte(Offset::kHoriBearingX); -} - -void BigGlyphMetrics::Builder::SetHoriBearingX(byte_t bearing) { - InternalWriteData()->WriteByte(Offset::kHoriBearingX, bearing); -} - -int32_t BigGlyphMetrics::Builder::HoriBearingY() { - return InternalReadData()->ReadByte(Offset::kHoriBearingY); -} - -void BigGlyphMetrics::Builder::SetHoriBearingY(byte_t bearing) { - InternalWriteData()->WriteByte(Offset::kHoriBearingY, bearing); -} - -int32_t BigGlyphMetrics::Builder::HoriAdvance() { - return InternalReadData()->ReadByte(Offset::kHoriAdvance); -} - -void BigGlyphMetrics::Builder::SetHoriAdvance(byte_t advance) { - InternalWriteData()->WriteByte(Offset::kHoriAdvance, advance); -} - -int32_t BigGlyphMetrics::Builder::VertBearingX() { - return InternalReadData()->ReadByte(Offset::kVertBearingX); -} - -void BigGlyphMetrics::Builder::SetVertBearingX(byte_t bearing) { - InternalWriteData()->WriteByte(Offset::kVertBearingX, bearing); -} - -int32_t BigGlyphMetrics::Builder::VertBearingY() { - return InternalReadData()->ReadByte(Offset::kVertBearingY); -} - -void BigGlyphMetrics::Builder::SetVertBearingY(byte_t bearing) { - InternalWriteData()->WriteByte(Offset::kVertBearingY, bearing); -} - -int32_t BigGlyphMetrics::Builder::VertAdvance() { - return InternalReadData()->ReadByte(Offset::kVertAdvance); -} - -void BigGlyphMetrics::Builder::SetVertAdvance(byte_t advance) { - InternalWriteData()->WriteByte(Offset::kVertAdvance, advance); -} - -CALLER_ATTACH FontDataTable* - BigGlyphMetrics::Builder::SubBuildTable(ReadableFontData* data) { - BigGlyphMetricsPtr output = new BigGlyphMetrics(data); - return output.Detach(); -} - -void BigGlyphMetrics::Builder::SubDataSet() { - // NOP. -} - -int32_t BigGlyphMetrics::Builder::SubDataSizeToSerialize() { - return 0; -} - -bool BigGlyphMetrics::Builder::SubReadyToSerialize() { - return false; -} - -int32_t BigGlyphMetrics::Builder::SubSerialize(WritableFontData* new_data) { - return Data()->CopyTo(new_data); -} - -// static -CALLER_ATTACH -BigGlyphMetrics::Builder* BigGlyphMetrics::Builder::CreateBuilder() { - WritableFontDataPtr data; - data.Attach(WritableFontData::CreateWritableFontData(Offset::kMetricsLength)); - BigGlyphMetricsBuilderPtr output = new BigGlyphMetrics::Builder(data); - return output.Detach(); -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/bitmap/big_glyph_metrics.h b/src/sfntly/src/sfntly/table/bitmap/big_glyph_metrics.h deleted file mode 100644 index a91601c211..0000000000 --- a/src/sfntly/src/sfntly/table/bitmap/big_glyph_metrics.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BIG_GLYPH_METRICS_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BIG_GLYPH_METRICS_H_ - -#include "sfntly/table/bitmap/glyph_metrics.h" - -namespace sfntly { - -class BigGlyphMetrics : public GlyphMetrics, - public RefCounted { - public: - struct Offset { - enum { - kMetricsLength = 8, - - kHeight = 0, - kWidth = 1, - kHoriBearingX = 2, - kHoriBearingY = 3, - kHoriAdvance = 4, - kVertBearingX = 5, - kVertBearingY = 6, - kVertAdvance = 7, - }; - }; - - class Builder : public GlyphMetrics::Builder, - public RefCounted { - public: - // Constructor scope altered to public because C++ does not allow base - // class to instantiate derived class with protected constructors. - explicit Builder(WritableFontData* data); - explicit Builder(ReadableFontData* data); - - virtual ~Builder(); - - int32_t Height(); - void SetHeight(byte_t height); - int32_t Width(); - void SetWidth(byte_t width); - int32_t HoriBearingX(); - void SetHoriBearingX(byte_t bearing); - int32_t HoriBearingY(); - void SetHoriBearingY(byte_t bearing); - int32_t HoriAdvance(); - void SetHoriAdvance(byte_t advance); - int32_t VertBearingX(); - void SetVertBearingX(byte_t bearing); - int32_t VertBearingY(); - void SetVertBearingY(byte_t bearing); - int32_t VertAdvance(); - void SetVertAdvance(byte_t advance); - - virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); - virtual void SubDataSet(); - virtual int32_t SubDataSizeToSerialize(); - virtual bool SubReadyToSerialize(); - virtual int32_t SubSerialize(WritableFontData* new_data); - - // Static instantiation function. - static CALLER_ATTACH Builder* CreateBuilder(); - }; - - explicit BigGlyphMetrics(ReadableFontData* data); - virtual ~BigGlyphMetrics(); - - int32_t Height(); - int32_t Width(); - int32_t HoriBearingX(); - int32_t HoriBearingY(); - int32_t HoriAdvance(); - int32_t VertBearingX(); - int32_t VertBearingY(); - int32_t VertAdvance(); -}; -typedef Ptr BigGlyphMetricsPtr; -typedef Ptr BigGlyphMetricsBuilderPtr; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BIG_GLYPH_METRICS_H_ diff --git a/src/sfntly/src/sfntly/table/bitmap/bitmap_glyph.cc b/src/sfntly/src/sfntly/table/bitmap/bitmap_glyph.cc deleted file mode 100644 index 334a0c07fb..0000000000 --- a/src/sfntly/src/sfntly/table/bitmap/bitmap_glyph.cc +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 = the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/table/bitmap/bitmap_glyph.h" -#include "sfntly/table/bitmap/simple_bitmap_glyph.h" -#include "sfntly/table/bitmap/composite_bitmap_glyph.h" - -namespace sfntly { -/****************************************************************************** - * BitmapGlyph class - ******************************************************************************/ -BitmapGlyph::~BitmapGlyph() { -} - -CALLER_ATTACH BitmapGlyph* BitmapGlyph::CreateGlyph(ReadableFontData* data, - int32_t format) { - BitmapGlyphPtr glyph; - BitmapGlyphBuilderPtr builder; - builder.Attach(Builder::CreateGlyphBuilder(data, format)); - if (builder) { - glyph.Attach(down_cast(builder->Build())); - } - return glyph; -} - -BitmapGlyph::BitmapGlyph(ReadableFontData* data, int32_t format) - : SubTable(data), format_(format) { -} - -/****************************************************************************** - * BitmapGlyph::Builder class - ******************************************************************************/ -BitmapGlyph::Builder::~Builder() { -} - -CALLER_ATTACH BitmapGlyph::Builder* -BitmapGlyph::Builder::CreateGlyphBuilder(ReadableFontData* data, - int32_t format) { - BitmapGlyphBuilderPtr builder; - switch (format) { - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - builder = new SimpleBitmapGlyph::Builder(data, format); - break; - case 8: - case 9: - builder = new CompositeBitmapGlyph::Builder(data, format); - break; - } - return builder.Detach(); -} - -BitmapGlyph::Builder::Builder(WritableFontData* data, int32_t format) - : SubTable::Builder(data), format_(format) { -} - -BitmapGlyph::Builder::Builder(ReadableFontData* data, int32_t format) - : SubTable::Builder(data), format_(format) { -} - -CALLER_ATTACH -FontDataTable* BitmapGlyph::Builder::SubBuildTable(ReadableFontData* data) { - UNREFERENCED_PARAMETER(data); - return NULL; -} - -void BitmapGlyph::Builder::SubDataSet() { - // NOP -} - -int32_t BitmapGlyph::Builder::SubDataSizeToSerialize() { - return InternalReadData()->Length(); -} - -bool BitmapGlyph::Builder::SubReadyToSerialize() { - return true; -} - -int32_t BitmapGlyph::Builder::SubSerialize(WritableFontData* new_data) { - return InternalReadData()->CopyTo(new_data); -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/bitmap/bitmap_glyph.h b/src/sfntly/src/sfntly/table/bitmap/bitmap_glyph.h deleted file mode 100644 index 2dd4c3a130..0000000000 --- a/src/sfntly/src/sfntly/table/bitmap/bitmap_glyph.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 = the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_GLYPH_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_GLYPH_H_ - -#include -#include - -#include "sfntly/table/subtable.h" - -namespace sfntly { - -class BitmapGlyph : public SubTable { - public: - struct Offset { - enum { - // header - kVersion = 0, - - kSmallGlyphMetricsLength = 5, - kBigGlyphMetricsLength = 8, - // format 1 - kGlyphFormat1_imageData = kSmallGlyphMetricsLength, - - // format 2 - kGlyphFormat2_imageData = kSmallGlyphMetricsLength, - - // format 3 - - // format 4 - - // format 5 - kGlyphFormat5_imageData = 0, - - // format 6 - kGlyphFormat6_imageData = kBigGlyphMetricsLength, - - // format 7 - kGlyphFormat7_imageData = kBigGlyphMetricsLength, - - // format 8 - kGlyphFormat8_numComponents = kSmallGlyphMetricsLength + 1, - kGlyphFormat8_componentArray = kGlyphFormat8_numComponents + - DataSize::kUSHORT, - - // format 9 - kGlyphFormat9_numComponents = kBigGlyphMetricsLength, - kGlyphFormat9_componentArray = kGlyphFormat9_numComponents + - DataSize::kUSHORT, - - // ebdtComponent - kEbdtComponentLength = DataSize::kUSHORT + 2 * DataSize::kCHAR, - kEbdtComponent_glyphCode = 0, - kEbdtComponent_xOffset = 2, - kEbdtComponent_yOffset = 3, - }; - }; - - // TODO(stuartg): builder is not functional at all - // - need to add subclasses for each type of bitmap glyph - class Builder : public SubTable::Builder { - public: - virtual ~Builder(); - - virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); - virtual void SubDataSet(); - virtual int32_t SubDataSizeToSerialize(); - virtual bool SubReadyToSerialize(); - virtual int32_t SubSerialize(WritableFontData* new_data); - - int32_t format() { return format_; } - - static CALLER_ATTACH Builder* CreateGlyphBuilder(ReadableFontData* data, - int32_t format); - - protected: - Builder(WritableFontData* data, int32_t format); - Builder(ReadableFontData* data, int32_t format); - - private: - int32_t format_; - }; - - virtual ~BitmapGlyph(); - - static CALLER_ATTACH BitmapGlyph* CreateGlyph(ReadableFontData* data, - int32_t format); - int32_t format() { return format_; } - - // UNIMPLEMENTED: toString() - - protected: - BitmapGlyph(ReadableFontData* data, int32_t format); - - private: - int32_t format_; -}; -typedef Ptr BitmapGlyphPtr; -typedef Ptr BitmapGlyphBuilderPtr; -typedef std::map BitmapGlyphBuilderMap; -typedef std::vector BitmapGlyphBuilderList; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_GLYPH_H_ diff --git a/src/sfntly/src/sfntly/table/bitmap/bitmap_glyph_info.cc b/src/sfntly/src/sfntly/table/bitmap/bitmap_glyph_info.cc deleted file mode 100644 index ab9953bc77..0000000000 --- a/src/sfntly/src/sfntly/table/bitmap/bitmap_glyph_info.cc +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/table/bitmap/bitmap_glyph_info.h" - -namespace sfntly { - -BitmapGlyphInfo::BitmapGlyphInfo(int32_t glyph_id, - int32_t block_offset, - int32_t start_offset, - int32_t length, - int32_t format) - : glyph_id_(glyph_id), - relative_(true), - block_offset_(block_offset), - start_offset_(start_offset), - length_(length), - format_(format) { -} - -BitmapGlyphInfo::BitmapGlyphInfo(int32_t glyph_id, - int32_t start_offset, - int32_t length, - int32_t format) - : glyph_id_(glyph_id), - relative_(false), - block_offset_(0), - start_offset_(start_offset), - length_(length), - format_(format) { -} - -bool BitmapGlyphInfo::operator==(const BitmapGlyphInfo& rhs) const { - return (format_ == rhs.format_ && - glyph_id_ == rhs.glyph_id_ && - length_ == rhs.length_ && - offset() == rhs.offset()); -} - -bool BitmapGlyphInfo::operator==(BitmapGlyphInfo* rhs) { - if (rhs == NULL) { - return this == NULL; - } - return (format_ == rhs->format() && - glyph_id_ == rhs->glyph_id() && - length_ == rhs->length() && - offset() == rhs->offset()); -} - -bool StartOffsetComparator::operator()(BitmapGlyphInfo* lhs, - BitmapGlyphInfo* rhs) { - return lhs->start_offset() > rhs->start_offset(); -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/bitmap/bitmap_glyph_info.h b/src/sfntly/src/sfntly/table/bitmap/bitmap_glyph_info.h deleted file mode 100644 index 9921d0d526..0000000000 --- a/src/sfntly/src/sfntly/table/bitmap/bitmap_glyph_info.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_INFO_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_INFO_H_ - -#include -#include - -#include "sfntly/table/subtable.h" - -namespace sfntly { - -// An immutable class holding bitmap glyph information. -class BitmapGlyphInfo : public RefCounted { - public: - // Constructor for a relative located glyph. The glyph's position in the EBDT - // table is a combination of it's block offset and it's own start offset. - // @param glyphId the glyph id - // @param blockOffset the offset of the block to which the glyph belongs - // @param startOffset the offset of the glyph within the block - // @param length the byte length - // @param format the glyph image format - BitmapGlyphInfo(int32_t glyph_id, - int32_t block_offset, - int32_t start_offset, - int32_t length, - int32_t format); - - // Constructor for an absolute located glyph. The glyph's position in the EBDT - // table is only given by it's own start offset. - // @param glyphId the glyph id - // @param startOffset the offset of the glyph within the block - // @param length the byte length - // @param format the glyph image format - BitmapGlyphInfo(int32_t glyph_id, - int32_t start_offset, - int32_t length, - int32_t format); - - int32_t glyph_id() const { return glyph_id_; } - bool relative() const { return relative_; } - int32_t block_offset() const { return block_offset_; } - int32_t offset() const { return block_offset() + start_offset(); } - int32_t start_offset() const { return start_offset_; } - int32_t length() const { return length_; } - int32_t format() const { return format_; } - - // UNIMPLEMENTED: hashCode() - bool operator==(const BitmapGlyphInfo& rhs) const; - bool operator==(BitmapGlyphInfo* rhs); - - private: - int32_t glyph_id_; - bool relative_; - int32_t block_offset_; - int32_t start_offset_; - int32_t length_; - int32_t format_; -}; -typedef Ptr BitmapGlyphInfoPtr; -typedef std::map BitmapGlyphInfoMap; -typedef std::vector BitmapLocaList; - -class StartOffsetComparator { - public: - bool operator()(BitmapGlyphInfo* lhs, BitmapGlyphInfo* rhs); -}; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_INFO_H_ diff --git a/src/sfntly/src/sfntly/table/bitmap/bitmap_size_table.cc b/src/sfntly/src/sfntly/table/bitmap/bitmap_size_table.cc deleted file mode 100644 index 6c7d7315a4..0000000000 --- a/src/sfntly/src/sfntly/table/bitmap/bitmap_size_table.cc +++ /dev/null @@ -1,604 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 = the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/table/bitmap/bitmap_size_table.h" - -#include -#include - -#include "sfntly/math/font_math.h" -#include "sfntly/table/bitmap/eblc_table.h" -#include "sfntly/table/bitmap/index_sub_table_format1.h" -#include "sfntly/table/bitmap/index_sub_table_format2.h" -#include "sfntly/table/bitmap/index_sub_table_format3.h" -#include "sfntly/table/bitmap/index_sub_table_format4.h" -#include "sfntly/table/bitmap/index_sub_table_format5.h" - -namespace sfntly { -/****************************************************************************** - * BitmapSizeTable class - ******************************************************************************/ -BitmapSizeTable::~BitmapSizeTable() { -} - -int32_t BitmapSizeTable::IndexSubTableArrayOffset() { - return data_->ReadULongAsInt( - EblcTable::Offset::kBitmapSizeTable_indexSubTableArrayOffset); -} - -int32_t BitmapSizeTable::IndexTableSize() { - return data_->ReadULongAsInt( - EblcTable::Offset::kBitmapSizeTable_indexTableSize); -} - -int32_t BitmapSizeTable::NumberOfIndexSubTables() { - return NumberOfIndexSubTables(data_, 0); -} - -int32_t BitmapSizeTable::ColorRef() { - return data_->ReadULongAsInt(EblcTable::Offset::kBitmapSizeTable_colorRef); -} - -int32_t BitmapSizeTable::StartGlyphIndex() { - return data_->ReadUShort(EblcTable::Offset::kBitmapSizeTable_startGlyphIndex); -} - -int32_t BitmapSizeTable::EndGlyphIndex() { - return data_->ReadUShort(EblcTable::Offset::kBitmapSizeTable_endGlyphIndex); -} - -int32_t BitmapSizeTable::PpemX() { - return data_->ReadByte(EblcTable::Offset::kBitmapSizeTable_ppemX); -} - -int32_t BitmapSizeTable::PpemY() { - return data_->ReadByte(EblcTable::Offset::kBitmapSizeTable_ppemY); -} - -int32_t BitmapSizeTable::BitDepth() { - return data_->ReadByte(EblcTable::Offset::kBitmapSizeTable_bitDepth); -} - -int32_t BitmapSizeTable::FlagsAsInt() { - return data_->ReadChar(EblcTable::Offset::kBitmapSizeTable_flags); -} - -IndexSubTable* BitmapSizeTable::GetIndexSubTable(int32_t index) { - IndexSubTableList* subtable_list = GetIndexSubTableList(); - if (index >= 0 && (size_t)index < subtable_list->size()) { - return (*subtable_list)[index]; - } - return NULL; -} - -int32_t BitmapSizeTable::GlyphOffset(int32_t glyph_id) { - IndexSubTable* subtable = SearchIndexSubTables(glyph_id); - if (subtable == NULL) { - return -1; - } - return subtable->GlyphOffset(glyph_id); -} - -int32_t BitmapSizeTable::GlyphLength(int32_t glyph_id) { - IndexSubTable* subtable = SearchIndexSubTables(glyph_id); - if (subtable == NULL) { - return -1; - } - return subtable->GlyphLength(glyph_id); -} - -CALLER_ATTACH BitmapGlyphInfo* BitmapSizeTable::GlyphInfo(int32_t glyph_id) { - IndexSubTable* sub_table = SearchIndexSubTables(glyph_id); - if (sub_table == NULL) { - return NULL; - } - return sub_table->GlyphInfo(glyph_id); -} - -int32_t BitmapSizeTable::GlyphFormat(int32_t glyph_id) { - IndexSubTable* subtable = SearchIndexSubTables(glyph_id); - if (subtable == NULL) { - return -1; - } - return subtable->image_format(); -} - -BitmapSizeTable::BitmapSizeTable(ReadableFontData* data, - ReadableFontData* master_data) - : SubTable(data, master_data) { -} - -// static -int32_t BitmapSizeTable::NumberOfIndexSubTables(ReadableFontData* data, - int32_t table_offset) { - return data->ReadULongAsInt(table_offset + - EblcTable::Offset::kBitmapSizeTable_numberOfIndexSubTables); -} - -IndexSubTable* BitmapSizeTable::SearchIndexSubTables(int32_t glyph_id) { - // would be faster to binary search but too many size tables don't have - // sorted subtables -#if (SFNTLY_BITMAPSIZE_USE_BINARY_SEARCH) - return BinarySearchIndexSubTables(glyph_id); -#else - return LinearSearchIndexSubTables(glyph_id); -#endif -} - -IndexSubTable* BitmapSizeTable::LinearSearchIndexSubTables(int32_t glyph_id) { - IndexSubTableList* subtable_list = GetIndexSubTableList(); - for (IndexSubTableList::iterator b = subtable_list->begin(), - e = subtable_list->end(); b != e; b++) { - if ((*b)->first_glyph_index() <= glyph_id && - (*b)->last_glyph_index() >= glyph_id) { - return *b; - } - } - return NULL; -} - -IndexSubTable* BitmapSizeTable::BinarySearchIndexSubTables(int32_t glyph_id) { - IndexSubTableList* subtable_list = GetIndexSubTableList(); - int32_t index = 0; - int32_t bottom = 0; - int32_t top = subtable_list->size(); - while (top != bottom) { - index = (top + bottom) / 2; - IndexSubTable* subtable = (*subtable_list)[index]; - if (glyph_id < subtable->first_glyph_index()) { - // Location beow current location - top = index; - } else { - if (glyph_id <= subtable->last_glyph_index()) { - return subtable; - } else { - bottom = index + 1; - } - } - } - return NULL; -} - -CALLER_ATTACH -IndexSubTable* BitmapSizeTable::CreateIndexSubTable(int32_t index) { - return IndexSubTable::CreateIndexSubTable(master_read_data(), - IndexSubTableArrayOffset(), - index); -} - -IndexSubTableList* BitmapSizeTable::GetIndexSubTableList() { - AutoLock lock(index_subtables_lock_); - if (index_subtables_.empty()) { - for (int32_t i = 0; i < NumberOfIndexSubTables(); ++i) { - IndexSubTablePtr table; - table.Attach(CreateIndexSubTable(i)); - index_subtables_.push_back(table); - } - } - return &index_subtables_; -} - -/****************************************************************************** - * BitmapSizeTable::Builder class - ******************************************************************************/ -BitmapSizeTable::Builder::~Builder() { -} - -CALLER_ATTACH -FontDataTable* BitmapSizeTable::Builder::SubBuildTable(ReadableFontData* data) { - BitmapSizeTablePtr output = new BitmapSizeTable(data, master_read_data()); - return output.Detach(); -} - -void BitmapSizeTable::Builder::SubDataSet() { - Revert(); -} - -int32_t BitmapSizeTable::Builder::SubDataSizeToSerialize() { - IndexSubTableBuilderList* builders = IndexSubTableBuilders(); - if (builders->empty()) { - return 0; - } - int32_t size = EblcTable::Offset::kBitmapSizeTableLength; - bool variable = false; - for (IndexSubTableBuilderList::iterator b = builders->begin(), - e = builders->end(); b != e; b++) { - size += EblcTable::Offset::kIndexSubTableEntryLength; - int32_t sub_table_size = (*b)->SubDataSizeToSerialize(); - int32_t padding = FontMath::PaddingRequired(abs(sub_table_size), - DataSize::kULONG); -#if defined (SFNTLY_DEBUG_BITMAP) - fprintf(stderr, "subtable size=%d\n", sub_table_size); -#endif - variable = (sub_table_size > 0) ? variable : true; - size += abs(sub_table_size) + padding; - } -#if defined (SFNTLY_DEBUG_BITMAP) - fprintf(stderr, "bitmap table size=%d\n", variable ? -size : size); -#endif - return variable ? -size : size; -} - -bool BitmapSizeTable::Builder::SubReadyToSerialize() { - if (IndexSubTableBuilders()->empty()) { - return false; - } - return true; -} - -int32_t BitmapSizeTable::Builder::SubSerialize(WritableFontData* new_data) { - SetNumberOfIndexSubTables(IndexSubTableBuilders()->size()); - int32_t size = InternalReadData()->CopyTo(new_data); - return size; -} - -CALLER_ATTACH BitmapSizeTable::Builder* -BitmapSizeTable::Builder::CreateBuilder(WritableFontData* data, - ReadableFontData* master_data) { - BitmapSizeTableBuilderPtr output = - new BitmapSizeTable::Builder(data, master_data); - return output.Detach(); -} - -CALLER_ATTACH BitmapSizeTable::Builder* -BitmapSizeTable::Builder::CreateBuilder(ReadableFontData* data, - ReadableFontData* master_data) { - BitmapSizeTableBuilderPtr output = - new BitmapSizeTable::Builder(data, master_data); - return output.Detach(); -} - -int32_t BitmapSizeTable::Builder::IndexSubTableArrayOffset() { - return InternalReadData()->ReadULongAsInt( - EblcTable::Offset::kBitmapSizeTable_indexSubTableArrayOffset); -} - -void BitmapSizeTable::Builder::SetIndexSubTableArrayOffset(int32_t offset) { - InternalWriteData()->WriteULong( - EblcTable::Offset::kBitmapSizeTable_indexSubTableArrayOffset, offset); -} - -int32_t BitmapSizeTable::Builder::IndexTableSize() { - return InternalReadData()->ReadULongAsInt( - EblcTable::Offset::kBitmapSizeTable_indexTableSize); -} - -void BitmapSizeTable::Builder::SetIndexTableSize(int32_t size) { - InternalWriteData()->WriteULong( - EblcTable::Offset::kBitmapSizeTable_indexTableSize, size); -} - -int32_t BitmapSizeTable::Builder::NumberOfIndexSubTables() { - return GetIndexSubTableBuilders()->size(); -} - -int32_t BitmapSizeTable::Builder::ColorRef() { - return InternalReadData()->ReadULongAsInt( - EblcTable::Offset::kBitmapSizeTable_colorRef); -} - -int32_t BitmapSizeTable::Builder::StartGlyphIndex() { - return InternalReadData()->ReadUShort( - EblcTable::Offset::kBitmapSizeTable_startGlyphIndex); -} - -int32_t BitmapSizeTable::Builder::EndGlyphIndex() { - return InternalReadData()->ReadUShort( - EblcTable::Offset::kBitmapSizeTable_endGlyphIndex); -} - -int32_t BitmapSizeTable::Builder::PpemX() { - return InternalReadData()->ReadByte( - EblcTable::Offset::kBitmapSizeTable_ppemX); -} - -int32_t BitmapSizeTable::Builder::PpemY() { - return InternalReadData()->ReadByte( - EblcTable::Offset::kBitmapSizeTable_ppemY); -} - -int32_t BitmapSizeTable::Builder::BitDepth() { - return InternalReadData()->ReadByte( - EblcTable::Offset::kBitmapSizeTable_bitDepth); -} - -int32_t BitmapSizeTable::Builder::FlagsAsInt() { - return InternalReadData()->ReadChar( - EblcTable::Offset::kBitmapSizeTable_flags); -} - -IndexSubTable::Builder* BitmapSizeTable::Builder::IndexSubTableBuilder( - int32_t index) { - IndexSubTableBuilderList* sub_table_list = GetIndexSubTableBuilders(); - return sub_table_list->at(index); -} - -CALLER_ATTACH BitmapGlyphInfo* BitmapSizeTable::Builder::GlyphInfo( - int32_t glyph_id) { - IndexSubTable::Builder* sub_table = SearchIndexSubTables(glyph_id); - if (sub_table == NULL) { - return NULL; - } - return sub_table->GlyphInfo(glyph_id); -} - -int32_t BitmapSizeTable::Builder::GlyphOffset(int32_t glyph_id) { - IndexSubTable::Builder* subtable = SearchIndexSubTables(glyph_id); - if (subtable == NULL) { - return -1; - } - return subtable->GlyphOffset(glyph_id); -} - -int32_t BitmapSizeTable::Builder::GlyphLength(int32_t glyph_id) { - IndexSubTable::Builder* subtable = SearchIndexSubTables(glyph_id); - if (subtable == NULL) { - return -1; - } - return subtable->GlyphLength(glyph_id); -} - -int32_t BitmapSizeTable::Builder::GlyphFormat(int32_t glyph_id) { - IndexSubTable::Builder* subtable = SearchIndexSubTables(glyph_id); - if (subtable == NULL) { - return -1; - } - return subtable->image_format(); -} - -IndexSubTableBuilderList* BitmapSizeTable::Builder::IndexSubTableBuilders() { - return GetIndexSubTableBuilders(); -} - -CALLER_ATTACH BitmapSizeTable::Builder::BitmapGlyphInfoIterator* -BitmapSizeTable::Builder::GetIterator() { - Ptr output = - new BitmapSizeTable::Builder::BitmapGlyphInfoIterator(this); - return output.Detach(); -} - -void BitmapSizeTable::Builder::GenerateLocaMap(BitmapGlyphInfoMap* output) { - assert(output); - Ptr it; - it.Attach(GetIterator()); - while (it->HasNext()) { - BitmapGlyphInfoPtr info; - info.Attach(it->Next()); - (*output)[info->glyph_id()] = info; - } -} - -void BitmapSizeTable::Builder::Revert() { - index_sub_tables_.clear(); - set_model_changed(false); -} - -BitmapSizeTable::Builder::Builder(WritableFontData* data, - ReadableFontData* master_data) - : SubTable::Builder(data, master_data) { -} - -BitmapSizeTable::Builder::Builder(ReadableFontData* data, - ReadableFontData* master_data) - : SubTable::Builder(data, master_data) { -} - -void BitmapSizeTable::Builder::SetNumberOfIndexSubTables(int32_t count) { - InternalWriteData()->WriteULong( - EblcTable::Offset::kBitmapSizeTable_numberOfIndexSubTables, count); -} - -IndexSubTable::Builder* BitmapSizeTable::Builder::SearchIndexSubTables( - int32_t glyph_id) { - // would be faster to binary search but too many size tables don't have - // sorted subtables -#if (SFNTLY_BITMAPSIZE_USE_BINARY_SEARCH) - return BinarySearchIndexSubTables(glyph_id); -#else - return LinearSearchIndexSubTables(glyph_id); -#endif -} - -IndexSubTable::Builder* BitmapSizeTable::Builder::LinearSearchIndexSubTables( - int32_t glyph_id) { - IndexSubTableBuilderList* subtable_list = GetIndexSubTableBuilders(); - for (IndexSubTableBuilderList::iterator b = subtable_list->begin(), - e = subtable_list->end(); - b != e; b++) { - if ((*b)->first_glyph_index() <= glyph_id && - (*b)->last_glyph_index() >= glyph_id) { - return *b; - } - } - return NULL; -} - -IndexSubTable::Builder* BitmapSizeTable::Builder::BinarySearchIndexSubTables( - int32_t glyph_id) { - IndexSubTableBuilderList* subtable_list = GetIndexSubTableBuilders(); - int32_t index = 0; - int32_t bottom = 0; - int32_t top = subtable_list->size(); - while (top != bottom) { - index = (top + bottom) / 2; - IndexSubTable::Builder* subtable = subtable_list->at(index); - if (glyph_id < subtable->first_glyph_index()) { - // Location beow current location - top = index; - } else { - if (glyph_id <= subtable->last_glyph_index()) { - return subtable; - } else { - bottom = index + 1; - } - } - } - return NULL; -} - -IndexSubTableBuilderList* BitmapSizeTable::Builder::GetIndexSubTableBuilders() { - if (index_sub_tables_.empty()) { - Initialize(InternalReadData()); - set_model_changed(); - } - return &index_sub_tables_; -} - -void BitmapSizeTable::Builder::Initialize(ReadableFontData* data) { - index_sub_tables_.clear(); - if (data) { - int32_t number_of_index_subtables = - BitmapSizeTable::NumberOfIndexSubTables(data, 0); - index_sub_tables_.resize(number_of_index_subtables); - for (int32_t i = 0; i < number_of_index_subtables; ++i) { - index_sub_tables_[i].Attach(CreateIndexSubTableBuilder(i)); - } - } -} - -CALLER_ATTACH IndexSubTable::Builder* -BitmapSizeTable::Builder::CreateIndexSubTableBuilder(int32_t index) { - return IndexSubTable::Builder::CreateBuilder(master_read_data(), - IndexSubTableArrayOffset(), - index); -} - -/****************************************************************************** - * BitmapSizeTable::Builder::BitmapGlyphInfoIterator class - ******************************************************************************/ -BitmapSizeTable::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator( - BitmapSizeTable::Builder* container) - : RefIterator(container) { - sub_table_iter_ = container->IndexSubTableBuilders()->begin(); - sub_table_glyph_info_iter_.Attach((*sub_table_iter_)->GetIterator()); -} - -bool BitmapSizeTable::Builder::BitmapGlyphInfoIterator::HasNext() { - if (sub_table_glyph_info_iter_ && HasNext(sub_table_glyph_info_iter_)) { - return true; - } - while (++sub_table_iter_ != container()->IndexSubTableBuilders()->end()) { - sub_table_glyph_info_iter_.Attach((*sub_table_iter_)->GetIterator()); - if (HasNext(sub_table_glyph_info_iter_)) { - return true; - } - } - return false; -} - -CALLER_ATTACH -BitmapGlyphInfo* BitmapSizeTable::Builder::BitmapGlyphInfoIterator::Next() { - if (!HasNext()) { - // Note: In C++, we do not throw exception when there's no element. - return NULL; - } - return Next(sub_table_glyph_info_iter_); -} - -bool BitmapSizeTable::Builder::BitmapGlyphInfoIterator::HasNext( - BitmapGlyphInfoIter* iterator_base) { - if (iterator_base) { - switch (iterator_base->container_base()->index_format()) { - case 1: { - IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator* it = - down_cast( - iterator_base); - return it->HasNext(); - } - - case 2: { - IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator* it = - down_cast( - iterator_base); - return it->HasNext(); - } - - case 3: { - IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator* it = - down_cast( - iterator_base); - return it->HasNext(); - } - - case 4: { - IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator* it = - down_cast( - iterator_base); - return it->HasNext(); - } - - case 5: { - IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator* it = - down_cast( - iterator_base); - return it->HasNext(); - } - - default: - break; - } - } - return false; -} - -CALLER_ATTACH -BitmapGlyphInfo* BitmapSizeTable::Builder::BitmapGlyphInfoIterator::Next( - BitmapGlyphInfoIter* iterator_base) { - if (iterator_base) { - switch (iterator_base->container_base()->index_format()) { - case 1: { - IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator* it = - down_cast( - iterator_base); - return it->Next(); - } - - case 2: { - IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator* it = - down_cast( - iterator_base); - return it->Next(); - } - - case 3: { - IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator* it = - down_cast( - iterator_base); - return it->Next(); - } - - case 4: { - IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator* it = - down_cast( - iterator_base); - return it->Next(); - } - - case 5: { - IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator* it = - down_cast( - iterator_base); - return it->Next(); - } - - default: - break; - } - } - return NULL; -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/bitmap/bitmap_size_table.h b/src/sfntly/src/sfntly/table/bitmap/bitmap_size_table.h deleted file mode 100644 index 6733e20304..0000000000 --- a/src/sfntly/src/sfntly/table/bitmap/bitmap_size_table.h +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 = the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_SIZE_TABLE_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_SIZE_TABLE_H_ - -#include "sfntly/port/lock.h" -#include "sfntly/table/bitmap/bitmap_glyph_info.h" -#include "sfntly/table/bitmap/index_sub_table.h" - -namespace sfntly { -// Binary search would be faster but many fonts have index subtables that -// aren't sorted. -// Note: preprocessor define is used to avoid const expression warnings in C++ -// code. -#define SFNTLY_BITMAPSIZE_USE_BINARY_SEARCH 0 - -class BitmapSizeTable : public SubTable, - public RefCounted { - public: - class Builder : public SubTable::Builder, - public RefCounted { - public: - class BitmapGlyphInfoIterator : - public RefIterator { - public: - explicit BitmapGlyphInfoIterator(Builder* container); - virtual ~BitmapGlyphInfoIterator() {} - - virtual bool HasNext(); - CALLER_ATTACH virtual BitmapGlyphInfo* Next(); - - private: - bool HasNext(BitmapGlyphInfoIter* iterator_base); - CALLER_ATTACH BitmapGlyphInfo* Next(BitmapGlyphInfoIter* iterator_base); - - IndexSubTableBuilderList::iterator sub_table_iter_; - BitmapGlyphInfoIterPtr sub_table_glyph_info_iter_; - }; - - virtual ~Builder(); - - virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); - virtual void SubDataSet(); - virtual int32_t SubDataSizeToSerialize(); - virtual bool SubReadyToSerialize(); - virtual int32_t SubSerialize(WritableFontData* new_data); - - static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data, - ReadableFontData* master_data); - static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data, - ReadableFontData* master_data); - // Gets the subtable array offset as set in the original table as read from - // the font file. This value cannot be explicitly set and will be generated - // during table building. - // @return the subtable array offset - int32_t IndexSubTableArrayOffset(); - - // Sets the subtable array offset. This is used only during the building - // process when the objects are being serialized. - // @param offset the offset to the index subtable array - void SetIndexSubTableArrayOffset(int32_t offset); - - // Gets the subtable array size as set in the original table as read from - // the font file. This value cannot be explicitly set and will be generated - // during table building. - // @return the subtable array size - int32_t IndexTableSize(); - - // Sets the subtable size. This is used only during the building process - // when the objects are being serialized. - // @param size the offset to the index subtable array - void SetIndexTableSize(int32_t size); - - int32_t NumberOfIndexSubTables(); - int32_t ColorRef(); - // TODO(stuartg): SBitLineMetrics hori(); - // TODO(stuartg): SBitLineMetrics vert(); - int32_t StartGlyphIndex(); - int32_t EndGlyphIndex(); - int32_t PpemX(); - int32_t PpemY(); - int32_t BitDepth(); - int32_t FlagsAsInt(); - - IndexSubTable::Builder* IndexSubTableBuilder(int32_t index); - CALLER_ATTACH BitmapGlyphInfo* GlyphInfo(int32_t glyph_id); - int32_t GlyphOffset(int32_t glyph_id); - int32_t GlyphLength(int32_t glyph_id); - int32_t GlyphFormat(int32_t glyph_id); - IndexSubTableBuilderList* IndexSubTableBuilders(); - // Note: renamed from iterator(), type is the derived type. - CALLER_ATTACH BitmapGlyphInfoIterator* GetIterator(); - void GenerateLocaMap(BitmapGlyphInfoMap* output); - - protected: - void Revert(); - - private: - Builder(WritableFontData* data, ReadableFontData* master_data); - Builder(ReadableFontData* data, ReadableFontData* master_data); - - void SetNumberOfIndexSubTables(int32_t count); - IndexSubTable::Builder* SearchIndexSubTables(int32_t glyph_id); - IndexSubTable::Builder* LinearSearchIndexSubTables(int32_t glyph_id); - IndexSubTable::Builder* BinarySearchIndexSubTables(int32_t glyph_id); - IndexSubTableBuilderList* GetIndexSubTableBuilders(); - void Initialize(ReadableFontData* data); - CALLER_ATTACH IndexSubTable::Builder* CreateIndexSubTableBuilder( - int32_t index); - - IndexSubTableBuilderList index_sub_tables_; - }; - - virtual ~BitmapSizeTable(); - - int32_t IndexSubTableArrayOffset(); - int32_t IndexTableSize(); - int32_t NumberOfIndexSubTables(); - int32_t ColorRef(); - // TODO(stuartg): SBitLineMetrics hori(); - // TODO(stuartg): SBitLineMetrics vert(); - int32_t StartGlyphIndex(); - int32_t EndGlyphIndex(); - int32_t PpemX(); - int32_t PpemY(); - int32_t BitDepth(); - int32_t FlagsAsInt(); - - // Note: renamed from indexSubTable() - IndexSubTable* GetIndexSubTable(int32_t index); - int32_t GlyphOffset(int32_t glyph_id); - int32_t GlyphLength(int32_t glyph_id); - CALLER_ATTACH BitmapGlyphInfo* GlyphInfo(int32_t glyph_id); - int32_t GlyphFormat(int32_t glyph_id); - - protected: - BitmapSizeTable(ReadableFontData* data, - ReadableFontData* master_data); - - private: - static int32_t NumberOfIndexSubTables(ReadableFontData* data, - int32_t table_offset); - IndexSubTable* SearchIndexSubTables(int32_t glyph_id); - IndexSubTable* LinearSearchIndexSubTables(int32_t glyph_id); - IndexSubTable* BinarySearchIndexSubTables(int32_t glyph_id); - CALLER_ATTACH IndexSubTable* CreateIndexSubTable(int32_t index); - IndexSubTableList* GetIndexSubTableList(); - - Lock index_subtables_lock_; - IndexSubTableList index_subtables_; -}; -typedef Ptr BitmapSizeTablePtr; -typedef std::vector BitmapSizeTableList; -typedef Ptr BitmapSizeTableBuilderPtr; -typedef std::vector BitmapSizeTableBuilderList; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_SIZE_TABLE_H_ diff --git a/src/sfntly/src/sfntly/table/bitmap/composite_bitmap_glyph.cc b/src/sfntly/src/sfntly/table/bitmap/composite_bitmap_glyph.cc deleted file mode 100644 index ae7dc5a731..0000000000 --- a/src/sfntly/src/sfntly/table/bitmap/composite_bitmap_glyph.cc +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 = the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/table/bitmap/composite_bitmap_glyph.h" - -namespace sfntly { -/****************************************************************************** - * CompositeBitmapGlyph class - ******************************************************************************/ -CompositeBitmapGlyph::CompositeBitmapGlyph(ReadableFontData* data, - int32_t format) - : BitmapGlyph(data, format) { - Initialize(format); -} - -CompositeBitmapGlyph::~CompositeBitmapGlyph() { -} - -int32_t CompositeBitmapGlyph::NumComponents() { - return data_->ReadUShort(num_components_offset_); -} - -CompositeBitmapGlyph::Component CompositeBitmapGlyph::GetComponent( - int32_t component_num) const { - int32_t component_offset = component_array_offset_ + - component_num * Offset::kEbdtComponentLength; - return CompositeBitmapGlyph::Component( - data_->ReadUShort(component_offset + Offset::kEbdtComponent_glyphCode), - data_->ReadChar(component_offset + Offset::kEbdtComponent_xOffset), - data_->ReadChar(component_offset + Offset::kEbdtComponent_yOffset)); -} - -void CompositeBitmapGlyph::Initialize(int32_t format) { - if (format == 8) { - num_components_offset_ = Offset::kGlyphFormat8_numComponents; - component_array_offset_ = Offset::kGlyphFormat8_componentArray; - } else if (format == 9) { - num_components_offset_ = Offset::kGlyphFormat9_numComponents; - component_array_offset_ = Offset::kGlyphFormat9_componentArray; - } else { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IllegalStateException("Attempt to create a Composite Bitmap Glyph " - "with a non-composite format."); -#endif - } -} - -/****************************************************************************** - * CompositeBitmapGlyph::Component class - ******************************************************************************/ -CompositeBitmapGlyph::Component::Component(const Component& rhs) - : glyph_code_(rhs.glyph_code_), - x_offset_(rhs.x_offset_), - y_offset_(rhs.y_offset_) { -} - -bool CompositeBitmapGlyph::Component::operator==( - const CompositeBitmapGlyph::Component& rhs) { - return glyph_code_ == rhs.glyph_code_; -} - -CompositeBitmapGlyph::Component& CompositeBitmapGlyph::Component::operator=( - const CompositeBitmapGlyph::Component& rhs) { - glyph_code_ = rhs.glyph_code_; - x_offset_ = rhs.x_offset_; - y_offset_ = rhs.y_offset_; - return *this; -} - -CompositeBitmapGlyph::Component::Component(int32_t glyph_code, - int32_t x_offset, - int32_t y_offset) - : glyph_code_(glyph_code), x_offset_(x_offset), y_offset_(y_offset) { -} - -/****************************************************************************** - * CompositeBitmapGlyph::Builder class - ******************************************************************************/ -CompositeBitmapGlyph::Builder::Builder(ReadableFontData* data, int32_t format) - : BitmapGlyph::Builder(data, format) { -} - -CompositeBitmapGlyph::Builder::Builder(WritableFontData* data, int32_t format) - : BitmapGlyph::Builder(data, format) { -} - -CompositeBitmapGlyph::Builder::~Builder() { -} - -CALLER_ATTACH FontDataTable* -CompositeBitmapGlyph::Builder::SubBuildTable(ReadableFontData* data) { - Ptr glyph = new CompositeBitmapGlyph(data, format()); - return glyph.Detach(); -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/bitmap/composite_bitmap_glyph.h b/src/sfntly/src/sfntly/table/bitmap/composite_bitmap_glyph.h deleted file mode 100644 index 897db7e22a..0000000000 --- a/src/sfntly/src/sfntly/table/bitmap/composite_bitmap_glyph.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 = the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_COMPOSITE_BITMAP_GLYPH_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_COMPOSITE_BITMAP_GLYPH_H_ - -#include "sfntly/table/bitmap/bitmap_glyph.h" - -namespace sfntly { - -class CompositeBitmapGlyph : public BitmapGlyph, - public RefCounted { - public: - class Component { - public: - Component(const Component& rhs); - - int32_t glyph_code() { return glyph_code_; } - int32_t x_offset() { return x_offset_; } - int32_t y_offset() { return y_offset_; } - - // UNIMPLEMENTED: int hashCode() - bool operator==(const Component& rhs); - Component& operator=(const Component& rhs); - - protected: - Component(int32_t glyph_code, int32_t x_offset, int32_t y_offset); - - private: - int32_t glyph_code_; - int32_t x_offset_; - int32_t y_offset_; - - friend class CompositeBitmapGlyph; - }; - - class Builder : public BitmapGlyph::Builder, - public RefCounted { - public: - Builder(WritableFontData* data, int32_t format); - Builder(ReadableFontData* data, int32_t format); - virtual ~Builder(); - - virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); - }; - - CompositeBitmapGlyph(ReadableFontData* data, int32_t format); - virtual ~CompositeBitmapGlyph(); - int32_t NumComponents(); - // Note: returned immutable object over stack. - Component GetComponent(int32_t component_num) const; - - private: - void Initialize(int32_t format); - - int32_t num_components_offset_; - int32_t component_array_offset_; -}; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_COMPOSITE_BITMAP_GLYPH_H_ diff --git a/src/sfntly/src/sfntly/table/bitmap/ebdt_table.cc b/src/sfntly/src/sfntly/table/bitmap/ebdt_table.cc deleted file mode 100644 index eeb1fa06b3..0000000000 --- a/src/sfntly/src/sfntly/table/bitmap/ebdt_table.cc +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/table/bitmap/ebdt_table.h" - -#include - -#include "sfntly/table/bitmap/composite_bitmap_glyph.h" -#include "sfntly/table/bitmap/simple_bitmap_glyph.h" - -namespace sfntly { -/****************************************************************************** - * EbdtTable class - ******************************************************************************/ -EbdtTable::~EbdtTable() { -} - -int32_t EbdtTable::Version() { - return data_->ReadFixed(Offset::kVersion); -} - -CALLER_ATTACH -BitmapGlyph* EbdtTable::Glyph(int32_t offset, int32_t length, int32_t format) { - ReadableFontDataPtr glyph_data; - glyph_data.Attach(down_cast(data_->Slice(offset, length))); - return BitmapGlyph::CreateGlyph(glyph_data, format); -} - -EbdtTable::EbdtTable(Header* header, ReadableFontData* data) - : SubTableContainerTable(header, data) { -} - -/****************************************************************************** - * EbdtTable::Builder class - ******************************************************************************/ -EbdtTable::Builder::Builder(Header* header, WritableFontData* data) - : SubTableContainerTable::Builder(header, data) { -} - -EbdtTable::Builder::Builder(Header* header, ReadableFontData* data) - : SubTableContainerTable::Builder(header, data) { -} - -EbdtTable::Builder::~Builder() { -} - -CALLER_ATTACH FontDataTable* - EbdtTable::Builder::SubBuildTable(ReadableFontData* data) { - FontDataTablePtr table = new EbdtTable(header(), data); - return table.Detach(); -} - -void EbdtTable::Builder::SubDataSet() { - Revert(); -} - -int32_t EbdtTable::Builder::SubDataSizeToSerialize() { - if (glyph_builders_.empty()) { - return 0; - } - bool fixed = true; - int32_t size = Offset::kHeaderLength; - for (BitmapGlyphBuilderList::iterator builder_map = glyph_builders_.begin(), - builder_end = glyph_builders_.end(); - builder_map != builder_end; - builder_map++) { - for (BitmapGlyphBuilderMap::iterator glyph_entry = builder_map->begin(), - glyph_entry_end = builder_map->end(); - glyph_entry != glyph_entry_end; - glyph_entry++) { - int32_t glyph_size = glyph_entry->second->SubDataSizeToSerialize(); - size += abs(glyph_size); - fixed = (glyph_size <= 0) ? false : fixed; - } - } - return (fixed ? 1 : -1) * size; -} - -bool EbdtTable::Builder::SubReadyToSerialize() { - if (glyph_builders_.empty()) { - return false; - } - return true; -} - -int32_t EbdtTable::Builder::SubSerialize(WritableFontData* new_data) { - int32_t size = 0; - size += new_data->WriteFixed(Offset::kVersion, kVersion); - for (BitmapGlyphBuilderList::iterator builder_map = glyph_builders_.begin(), - builder_end = glyph_builders_.end(); - builder_map != builder_end; - builder_map++) { - for (BitmapGlyphBuilderMap::iterator glyph_entry = builder_map->begin(), - glyph_entry_end = builder_map->end(); - glyph_entry != glyph_entry_end; - glyph_entry++) { - WritableFontDataPtr slice; - slice.Attach(down_cast(new_data->Slice(size))); - size += glyph_entry->second->SubSerialize(slice); - } - } - return size; -} - -void EbdtTable::Builder::SetLoca(BitmapLocaList* loca_list) { - assert(loca_list); - Revert(); - glyph_loca_.resize(loca_list->size()); - std::copy(loca_list->begin(), loca_list->end(), glyph_loca_.begin()); -} - -void EbdtTable::Builder::GenerateLocaList(BitmapLocaList* output) { - assert(output); - output->clear(); - - if (glyph_builders_.empty()) { - if (glyph_loca_.empty()) { - return; - } - } - - int start_offset = Offset::kHeaderLength; - for (BitmapGlyphBuilderList::iterator builder_map = glyph_builders_.begin(), - builder_end = glyph_builders_.end(); - builder_map != builder_end; - builder_map++) { - BitmapGlyphInfoMap new_loca_map; - int32_t glyph_offset = 0; - for (BitmapGlyphBuilderMap::iterator glyph_entry = builder_map->begin(), - glyph_end = builder_map->end(); - glyph_entry != glyph_end; - glyph_entry++) { - BitmapGlyphBuilderPtr builder = glyph_entry->second; - int32_t size = builder->SubDataSizeToSerialize(); - BitmapGlyphInfoPtr info = new BitmapGlyphInfo(glyph_entry->first, - start_offset + glyph_offset, size, builder->format()); - new_loca_map[glyph_entry->first] = info; - glyph_offset += size; - } - start_offset += glyph_offset; - output->push_back(new_loca_map); - } -} - -BitmapGlyphBuilderList* EbdtTable::Builder::GlyphBuilders() { - return GetGlyphBuilders(); -} - -void EbdtTable::Builder::SetGlyphBuilders( - BitmapGlyphBuilderList* glyph_builders) { - glyph_builders_.clear(); - std::copy(glyph_builders->begin(), glyph_builders->end(), - glyph_builders_.begin()); - set_model_changed(); -} - -void EbdtTable::Builder::Revert() { - glyph_loca_.clear(); - glyph_builders_.clear(); - set_model_changed(false); -} - -CALLER_ATTACH -EbdtTable::Builder* EbdtTable::Builder::CreateBuilder(Header* header, - WritableFontData* data) { - Ptr builder; - builder = new Builder(header, data); - return builder.Detach(); -} - -CALLER_ATTACH -EbdtTable::Builder* EbdtTable::Builder::CreateBuilder(Header* header, - ReadableFontData* data) { - Ptr builder; - builder = new Builder(header, data); - return builder.Detach(); -} - -BitmapGlyphBuilderList* EbdtTable::Builder::GetGlyphBuilders() { - if (glyph_builders_.empty()) { - if (glyph_loca_.empty()) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IllegalStateException( - "Loca values not set - unable to parse glyph data."); -#endif - return NULL; - } - Initialize(InternalReadData(), &glyph_loca_, &glyph_builders_); - set_model_changed(); - } - return &glyph_builders_; -} - -void EbdtTable::Builder::Initialize(ReadableFontData* data, - BitmapLocaList* loca_list, - BitmapGlyphBuilderList* output) { - assert(loca_list); - assert(output); - - output->clear(); - if (data) { - for (BitmapLocaList::iterator loca_map = loca_list->begin(), - loca_end = loca_list->end(); - loca_map != loca_end; loca_map++) { - BitmapGlyphBuilderMap glyph_builder_map; - for (BitmapGlyphInfoMap::iterator entry = loca_map->begin(), - entry_end = loca_map->end(); - entry != entry_end; entry++) { - BitmapGlyphInfoPtr info = entry->second; - ReadableFontDataPtr slice; - slice.Attach(down_cast(data->Slice( - info->offset(), info->length()))); - BitmapGlyphBuilderPtr glyph_builder; - glyph_builder.Attach(BitmapGlyph::Builder::CreateGlyphBuilder( - slice, info->format())); - glyph_builder_map[entry->first] = glyph_builder; - } - output->push_back(glyph_builder_map); - } - } -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/bitmap/ebdt_table.h b/src/sfntly/src/sfntly/table/bitmap/ebdt_table.h deleted file mode 100644 index d138c14ca5..0000000000 --- a/src/sfntly/src/sfntly/table/bitmap/ebdt_table.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBDT_TABLE_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBDT_TABLE_H_ - -#include "sfntly/table/bitmap/bitmap_glyph.h" -#include "sfntly/table/bitmap/bitmap_glyph_info.h" -#include "sfntly/table/subtable_container_table.h" - -namespace sfntly { - -class EbdtTable : public SubTableContainerTable, - public RefCounted { - public: - struct Offset { - enum { - kVersion = 0, - kHeaderLength = DataSize::kFixed, - }; - }; - - class Builder : public SubTableContainerTable::Builder, - public RefCounted { - public: - // Constructor scope altered to public because C++ does not allow base - // class to instantiate derived class with protected constructors. - Builder(Header* header, WritableFontData* data); - Builder(Header* header, ReadableFontData* data); - virtual ~Builder(); - - virtual int32_t SubSerialize(WritableFontData* new_data); - virtual bool SubReadyToSerialize(); - virtual int32_t SubDataSizeToSerialize(); - virtual void SubDataSet(); - virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); - - void SetLoca(BitmapLocaList* loca_list); - void GenerateLocaList(BitmapLocaList* output); - - // Gets the List of glyph builders for the glyph table builder. These may be - // manipulated in any way by the caller and the changes will be reflected in - // the final glyph table produced. - // If there is no current data for the glyph builder or the glyph builders - // have not been previously set then this will return an empty glyph builder - // List. If there is current data (i.e. data read from an existing font) and - // the loca list has not been set or is null, empty, or invalid, then an - // empty glyph builder List will be returned. - // @return the list of glyph builders - BitmapGlyphBuilderList* GlyphBuilders(); - - // Replace the internal glyph builders with the one provided. The provided - // list and all contained objects belong to this builder. - // This call is only required if the entire set of glyphs in the glyph - // table builder are being replaced. If the glyph builder list provided from - // the {@link EbdtTable.Builder#glyphBuilders()} is being used and modified - // then those changes will already be reflected in the glyph table builder. - // @param glyphBuilders the new glyph builders - void SetGlyphBuilders(BitmapGlyphBuilderList* glyph_builders); - - void Revert(); - - // Create a new builder using the header information and data provided. - // @param header the header information - // @param data the data holding the table - static CALLER_ATTACH Builder* CreateBuilder(Header* header, - WritableFontData* data); - static CALLER_ATTACH Builder* CreateBuilder(Header* header, - ReadableFontData* data); - - private: - BitmapGlyphBuilderList* GetGlyphBuilders(); - static void Initialize(ReadableFontData* data, - BitmapLocaList* loca_list, - BitmapGlyphBuilderList* output); - - static const int32_t kVersion = 0x00020000; // TODO(stuartg): const/enum - BitmapLocaList glyph_loca_; - BitmapGlyphBuilderList glyph_builders_; - }; - - virtual ~EbdtTable(); - int32_t Version(); - CALLER_ATTACH BitmapGlyph* Glyph(int32_t offset, - int32_t length, - int32_t format); - protected: - EbdtTable(Header* header, ReadableFontData* data); -}; -typedef Ptr EbdtTablePtr; -typedef Ptr EbdtTableBuilderPtr; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBDT_TABLE_H_ diff --git a/src/sfntly/src/sfntly/table/bitmap/eblc_table.cc b/src/sfntly/src/sfntly/table/bitmap/eblc_table.cc deleted file mode 100644 index 0ad2764bf6..0000000000 --- a/src/sfntly/src/sfntly/table/bitmap/eblc_table.cc +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/table/bitmap/eblc_table.h" - -#include -#include - -#include "sfntly/math/font_math.h" - -namespace sfntly { -/****************************************************************************** - * EblcTable class - ******************************************************************************/ -int32_t EblcTable::Version() { - return data_->ReadFixed(Offset::kVersion); -} - -int32_t EblcTable::NumSizes() { - return data_->ReadULongAsInt(Offset::kNumSizes); -} - -BitmapSizeTable* EblcTable::GetBitmapSizeTable(int32_t index) { - if (index < 0 || index > NumSizes()) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IndexOutOfBoundException( - "Size table index is outside the range of tables."); -#endif - return NULL; - } - BitmapSizeTableList* bitmap_size_table_list = GetBitmapSizeTableList(); - if (bitmap_size_table_list) { - return (*bitmap_size_table_list)[index]; - } - return NULL; -} - -EblcTable::EblcTable(Header* header, ReadableFontData* data) - : SubTableContainerTable(header, data) { -} - -BitmapSizeTableList* EblcTable::GetBitmapSizeTableList() { - AutoLock lock(bitmap_size_table_lock_); - if (bitmap_size_table_.empty()) { - CreateBitmapSizeTable(data_, NumSizes(), &bitmap_size_table_); - } - return &bitmap_size_table_; -} - -// static -void EblcTable::CreateBitmapSizeTable(ReadableFontData* data, - int32_t num_sizes, - BitmapSizeTableList* output) { - assert(data); - assert(output); - for (int32_t i = 0; i < num_sizes; ++i) { - ReadableFontDataPtr new_data; - new_data.Attach(down_cast( - data->Slice(Offset::kBitmapSizeTableArrayStart + - i * Offset::kBitmapSizeTableLength, - Offset::kBitmapSizeTableLength))); - BitmapSizeTableBuilderPtr size_builder; - size_builder.Attach( - BitmapSizeTable::Builder::CreateBuilder(new_data, data)); - BitmapSizeTablePtr size; - size.Attach(down_cast(size_builder->Build())); - output->push_back(size); - } -} - -/****************************************************************************** - * EblcTable::Builder class - ******************************************************************************/ -EblcTable::Builder::Builder(Header* header, WritableFontData* data) - : SubTableContainerTable::Builder(header, data) { -} - -EblcTable::Builder::Builder(Header* header, ReadableFontData* data) - : SubTableContainerTable::Builder(header, data) { -} - -EblcTable::Builder::~Builder() { -} - -int32_t EblcTable::Builder::SubSerialize(WritableFontData* new_data) { - // header - int32_t size = new_data->WriteFixed(0, kVersion); - size += new_data->WriteULong(size, size_table_builders_.size()); - - // calculate the offsets - // offset to the start of the size table array - int32_t size_table_start_offset = size; - // walking offset in the size table array - int32_t size_table_offset = size_table_start_offset; - // offset to the start of the whole index subtable block - int32_t sub_table_block_start_offset = size_table_offset + - size_table_builders_.size() * Offset::kBitmapSizeTableLength; - // walking offset in the index subtable - // points to the start of the current subtable block - int32_t current_sub_table_block_start_offset = sub_table_block_start_offset; - -#if defined (SFNTLY_DEBUG_BITMAP) - int32_t size_index = 0; -#endif - for (BitmapSizeTableBuilderList::iterator - size_builder = size_table_builders_.begin(), - size_builder_end = size_table_builders_.end(); - size_builder != size_builder_end; size_builder++) { - (*size_builder)->SetIndexSubTableArrayOffset( - current_sub_table_block_start_offset); - IndexSubTableBuilderList* index_sub_table_builder_list = - (*size_builder)->IndexSubTableBuilders(); - - // walking offset within the current subTable array - int32_t index_sub_table_array_offset = current_sub_table_block_start_offset; - // walking offset within the subTable entries - int32_t index_sub_table_offset = index_sub_table_array_offset + - index_sub_table_builder_list->size() * Offset::kIndexSubHeaderLength; - -#if defined (SFNTLY_DEBUG_BITMAP) - fprintf(stderr, "size %d: sizeTable=%x, current subTable Block=%x, ", - size_index, size_table_offset, - current_sub_table_block_start_offset); - fprintf(stderr, "index subTableStart=%x\n", index_sub_table_offset); - size_index++; - int32_t sub_table_index = 0; -#endif - for (IndexSubTableBuilderList::iterator - index_sub_table_builder = index_sub_table_builder_list->begin(), - index_sub_table_builder_end = index_sub_table_builder_list->end(); - index_sub_table_builder != index_sub_table_builder_end; - index_sub_table_builder++) { -#if defined (SFNTLY_DEBUG_BITMAP) - fprintf(stderr, "\tsubTableIndex %d: format=%x, ", sub_table_index, - (*index_sub_table_builder)->index_format()); - fprintf(stderr, "indexSubTableArrayOffset=%x, indexSubTableOffset=%x\n", - index_sub_table_array_offset, index_sub_table_offset); - sub_table_index++; -#endif - // array entry - index_sub_table_array_offset += new_data->WriteUShort( - index_sub_table_array_offset, - (*index_sub_table_builder)->first_glyph_index()); - index_sub_table_array_offset += new_data->WriteUShort( - index_sub_table_array_offset, - (*index_sub_table_builder)->last_glyph_index()); - index_sub_table_array_offset += new_data->WriteULong( - index_sub_table_array_offset, - index_sub_table_offset - current_sub_table_block_start_offset); - - // index sub table - WritableFontDataPtr slice_index_sub_table; - slice_index_sub_table.Attach(down_cast( - new_data->Slice(index_sub_table_offset))); - int32_t current_sub_table_size = - (*index_sub_table_builder)->SubSerialize(slice_index_sub_table); - int32_t padding = FontMath::PaddingRequired(current_sub_table_size, - DataSize::kULONG); -#if defined (SFNTLY_DEBUG_BITMAP) - fprintf(stderr, "\t\tsubTableSize = %x, padding = %x\n", - current_sub_table_size, padding); -#endif - index_sub_table_offset += current_sub_table_size; - index_sub_table_offset += - new_data->WritePadding(index_sub_table_offset, padding); - } - - // serialize size table - (*size_builder)->SetIndexTableSize( - index_sub_table_offset - current_sub_table_block_start_offset); - WritableFontDataPtr slice_size_table; - slice_size_table.Attach(down_cast( - new_data->Slice(size_table_offset))); - size_table_offset += (*size_builder)->SubSerialize(slice_size_table); - - current_sub_table_block_start_offset = index_sub_table_offset; - } - return size + current_sub_table_block_start_offset; -} - -bool EblcTable::Builder::SubReadyToSerialize() { - if (size_table_builders_.empty()) { - return false; - } - for (BitmapSizeTableBuilderList::iterator b = size_table_builders_.begin(), - e = size_table_builders_.end(); - b != e; b++) { - if (!(*b)->SubReadyToSerialize()) { - return false; - } - } - return true; -} - -int32_t EblcTable::Builder::SubDataSizeToSerialize() { - if (size_table_builders_.empty()) { - return 0; - } - int32_t size = Offset::kHeaderLength; - bool variable = false; -#if defined (SFNTLY_DEBUG_BITMAP) - size_t size_index = 0; -#endif - for (BitmapSizeTableBuilderList::iterator b = size_table_builders_.begin(), - e = size_table_builders_.end(); - b != e; b++) { - int32_t size_builder_size = (*b)->SubDataSizeToSerialize(); -#if defined (SFNTLY_DEBUG_BITMAP) - fprintf(stderr, "sizeIndex = %d, sizeBuilderSize=0x%x (%d)\n", - size_index++, size_builder_size, size_builder_size); -#endif - variable = size_builder_size > 0 ? variable : true; - size += abs(size_builder_size); - } -#if defined (SFNTLY_DEBUG_BITMAP) - fprintf(stderr, "eblc size=%d\n", size); -#endif - return variable ? -size : size; -} - -void EblcTable::Builder::SubDataSet() { - Revert(); -} - -BitmapSizeTableBuilderList* EblcTable::Builder::BitmapSizeBuilders() { - return GetSizeList(); -} - -void EblcTable::Builder::Revert() { - size_table_builders_.clear(); - set_model_changed(false); -} - -void EblcTable::Builder::GenerateLocaList(BitmapLocaList* output) { - assert(output); - BitmapSizeTableBuilderList* size_builder_list = GetSizeList(); - output->clear(); -#if defined (SFNTLY_DEBUG_BITMAP) - int32_t size_index = 0; -#endif - for (BitmapSizeTableBuilderList::iterator b = size_builder_list->begin(), - e = size_builder_list->end(); - b != e; b++) { -#if defined (SFNTLY_DEBUG_BITMAP) - fprintf(stderr, "size table = %d\n", size_index++); -#endif - BitmapGlyphInfoMap loca_map; - (*b)->GenerateLocaMap(&loca_map); - output->push_back(loca_map); - } -} - -CALLER_ATTACH -FontDataTable* EblcTable::Builder::SubBuildTable(ReadableFontData* data) { - Ptr new_table = new EblcTable(header(), data); - return new_table.Detach(); -} - -// static -CALLER_ATTACH EblcTable::Builder* - EblcTable::Builder::CreateBuilder(Header* header, WritableFontData* data) { - Ptr new_builder = new EblcTable::Builder(header, data); - return new_builder.Detach(); -} - -// static -CALLER_ATTACH EblcTable::Builder* - EblcTable::Builder::CreateBuilder(Header* header, ReadableFontData* data) { - Ptr new_builder = new EblcTable::Builder(header, data); - return new_builder.Detach(); -} - -BitmapSizeTableBuilderList* EblcTable::Builder::GetSizeList() { - if (size_table_builders_.empty()) { - Initialize(InternalReadData(), &size_table_builders_); - set_model_changed(); - } - return &size_table_builders_; -} - -void EblcTable::Builder::Initialize(ReadableFontData* data, - BitmapSizeTableBuilderList* output) { - assert(output); - if (data) { - int32_t num_sizes = data->ReadULongAsInt(Offset::kNumSizes); - for (int32_t i = 0; i < num_sizes; ++i) { - ReadableFontDataPtr new_data; - new_data.Attach(down_cast( - data->Slice(Offset::kBitmapSizeTableArrayStart + - i * Offset::kBitmapSizeTableLength, - Offset::kBitmapSizeTableLength))); - BitmapSizeTableBuilderPtr size_builder; - size_builder.Attach(BitmapSizeTable::Builder::CreateBuilder( - new_data, data)); - output->push_back(size_builder); - } - } -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/bitmap/eblc_table.h b/src/sfntly/src/sfntly/table/bitmap/eblc_table.h deleted file mode 100644 index b04338a93b..0000000000 --- a/src/sfntly/src/sfntly/table/bitmap/eblc_table.h +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBLC_TABLE_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBLC_TABLE_H_ - -#include "sfntly/port/lock.h" -#include "sfntly/table/bitmap/big_glyph_metrics.h" -#include "sfntly/table/bitmap/bitmap_glyph.h" -#include "sfntly/table/bitmap/bitmap_size_table.h" -#include "sfntly/table/subtable_container_table.h" - -namespace sfntly { - -class EblcTable : public SubTableContainerTable, - public RefCounted { - public: - struct Offset { - enum { - // header - kVersion = 0, - kNumSizes = 4, - kHeaderLength = kNumSizes + DataSize::kULONG, - - // bitmapSizeTable - kBitmapSizeTableArrayStart = kHeaderLength, - kBitmapSizeTableLength = 48, - kBitmapSizeTable_indexSubTableArrayOffset = 0, - kBitmapSizeTable_indexTableSize = 4, - kBitmapSizeTable_numberOfIndexSubTables = 8, - kBitmapSizeTable_colorRef = 12, - kBitmapSizeTable_hori = 16, - kBitmapSizeTable_vert = 28, - kBitmapSizeTable_startGlyphIndex = 40, - kBitmapSizeTable_endGlyphIndex = 42, - kBitmapSizeTable_ppemX = 44, - kBitmapSizeTable_ppemY = 45, - kBitmapSizeTable_bitDepth = 46, - kBitmapSizeTable_flags = 47, - - // sbitLineMetrics - kSbitLineMetricsLength = 12, - kSbitLineMetrics_ascender = 0, - kSbitLineMetrics_descender = 1, - kSbitLineMetrics_widthMax = 2, - kSbitLineMetrics_caretSlopeNumerator = 3, - kSbitLineMetrics_caretSlopeDenominator = 4, - kSbitLineMetrics_caretOffset = 5, - kSbitLineMetrics_minOriginSB = 6, - kSbitLineMetrics_minAdvanceSB = 7, - kSbitLineMetrics_maxBeforeBL = 8, - kSbitLineMetrics_minAfterBL = 9, - kSbitLineMetrics_pad1 = 10, - kSbitLineMetrics_pad2 = 11, - - // indexSubTable - kIndexSubTableEntryLength = 8, - kIndexSubTableEntry_firstGlyphIndex = 0, - kIndexSubTableEntry_lastGlyphIndex = 2, - kIndexSubTableEntry_additionalOffsetToIndexSubTable = 4, - - // indexSubHeader - kIndexSubHeaderLength = 8, - kIndexSubHeader_indexFormat = 0, - kIndexSubHeader_imageFormat = 2, - kIndexSubHeader_imageDataOffset = 4, - - // indexSubTable - all offset relative to the subtable start - - // indexSubTable1 - kIndexSubTable1_offsetArray = kIndexSubHeaderLength, - kIndexSubTable1_builderDataSize = kIndexSubHeaderLength, - - // kIndexSubTable2 - kIndexSubTable2Length = kIndexSubHeaderLength + - DataSize::kULONG + - BitmapGlyph::Offset::kBigGlyphMetricsLength, - kIndexSubTable2_imageSize = kIndexSubHeaderLength, - kIndexSubTable2_bigGlyphMetrics = kIndexSubTable2_imageSize + - DataSize::kULONG, - kIndexSubTable2_builderDataSize = kIndexSubTable2_bigGlyphMetrics + - BigGlyphMetrics::Offset::kMetricsLength, - - // kIndexSubTable3 - kIndexSubTable3_offsetArray = kIndexSubHeaderLength, - kIndexSubTable3_builderDataSize = kIndexSubTable3_offsetArray, - - // kIndexSubTable4 - kIndexSubTable4_numGlyphs = kIndexSubHeaderLength, - kIndexSubTable4_glyphArray = kIndexSubTable4_numGlyphs + - DataSize::kULONG, - kIndexSubTable4_codeOffsetPairLength = 2 * DataSize::kUSHORT, - kIndexSubTable4_codeOffsetPair_glyphCode = 0, - kIndexSubTable4_codeOffsetPair_offset = DataSize::kUSHORT, - kIndexSubTable4_builderDataSize = kIndexSubTable4_glyphArray, - - // kIndexSubTable5 - kIndexSubTable5_imageSize = kIndexSubHeaderLength, - kIndexSubTable5_bigGlyphMetrics = kIndexSubTable5_imageSize + - DataSize::kULONG, - kIndexSubTable5_numGlyphs = kIndexSubTable5_bigGlyphMetrics + - BitmapGlyph::Offset::kBigGlyphMetricsLength, - kIndexSubTable5_glyphArray = kIndexSubTable5_numGlyphs + - DataSize::kULONG, - kIndexSubTable5_builderDataSize = kIndexSubTable5_glyphArray, - - // codeOffsetPair - kCodeOffsetPairLength = 2 * DataSize::kUSHORT, - kCodeOffsetPair_glyphCode = 0, - kCodeOffsetPair_offset = DataSize::kUSHORT, - }; - }; - - class Builder : public SubTableContainerTable::Builder, - public RefCounted { - public: - // Constructor scope altered to public because C++ does not allow base - // class to instantiate derived class with protected constructors. - Builder(Header* header, WritableFontData* data); - Builder(Header* header, ReadableFontData* data); - virtual ~Builder(); - - virtual int32_t SubSerialize(WritableFontData* new_data); - virtual bool SubReadyToSerialize(); - virtual int32_t SubDataSizeToSerialize(); - virtual void SubDataSet(); - virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); - - BitmapSizeTableBuilderList* BitmapSizeBuilders(); - void Revert(); - - // Generates the loca list for the EBDT table. The list is intended to be - // used by the EBDT to allow it to parse the glyph data and generate glyph - // objects. After returning from this method the list belongs to the caller. - // The list entries are in the same order as the size table builders are at - // the time of this call. - // @return the list of loca maps with one for each size table builder - void GenerateLocaList(BitmapLocaList* output); - - // Create a new builder using the header information and data provided. - // @param header the header information - // @param data the data holding the table - static CALLER_ATTACH Builder* CreateBuilder(Header* header, - WritableFontData* data); - static CALLER_ATTACH Builder* CreateBuilder(Header* header, - ReadableFontData* data); - - private: - BitmapSizeTableBuilderList* GetSizeList(); - void Initialize(ReadableFontData* data, BitmapSizeTableBuilderList* output); - - static const int32_t kVersion = 0x00020000; - BitmapSizeTableBuilderList size_table_builders_; - }; - - int32_t Version(); - int32_t NumSizes(); - // UNIMPLEMENTED: toString() - - BitmapSizeTable* GetBitmapSizeTable(int32_t index); - - static const int32_t NOTDEF = -1; - - protected: - EblcTable(Header* header, ReadableFontData* data); - - private: - BitmapSizeTableList* GetBitmapSizeTableList(); - - static void CreateBitmapSizeTable(ReadableFontData* data, - int32_t num_sizes, - BitmapSizeTableList* output); - - Lock bitmap_size_table_lock_; - BitmapSizeTableList bitmap_size_table_; -}; -typedef Ptr EblcTablePtr; -typedef Ptr EblcTableBuilderPtr; -} - -#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBLC_TABLE_H_ diff --git a/src/sfntly/src/sfntly/table/bitmap/ebsc_table.cc b/src/sfntly/src/sfntly/table/bitmap/ebsc_table.cc deleted file mode 100644 index 458c2d49e8..0000000000 --- a/src/sfntly/src/sfntly/table/bitmap/ebsc_table.cc +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/table/bitmap/ebsc_table.h" - -namespace sfntly { -/****************************************************************************** - * EbscTable class - ******************************************************************************/ -EbscTable::~EbscTable() { -} - -int32_t EbscTable::Version() { - return data_->ReadFixed(Offset::kVersion); -} - -int32_t EbscTable::NumSizes() { - return data_->ReadULongAsInt(Offset::kNumSizes); -} - -EbscTable::EbscTable(Header* header, ReadableFontData* data) - : Table(header, data) { -} - -/****************************************************************************** - * EbscTable::BitmapScaleTable class - ******************************************************************************/ -EbscTable::BitmapScaleTable::~BitmapScaleTable() { -} - -EbscTable::BitmapScaleTable::BitmapScaleTable(ReadableFontData* data) - : SubTable(data) { -} - -int32_t EbscTable::BitmapScaleTable::PpemX() { - return data_->ReadByte(Offset::kBitmapScaleTable_ppemX); -} - -int32_t EbscTable::BitmapScaleTable::PpemY() { - return data_->ReadByte(Offset::kBitmapScaleTable_ppemY); -} - -int32_t EbscTable::BitmapScaleTable::SubstitutePpemX() { - return data_->ReadByte(Offset::kBitmapScaleTable_substitutePpemX); -} - -int32_t EbscTable::BitmapScaleTable::SubstitutePpemY() { - return data_->ReadByte(Offset::kBitmapScaleTable_substitutePpemY); -} - -/****************************************************************************** - * EbscTable::Builder class - ******************************************************************************/ -EbscTable::Builder::~Builder() { -} - -CALLER_ATTACH EbscTable::Builder* EbscTable::Builder::CreateBuilder( - Header* header, WritableFontData* data) { - EbscTableBuilderPtr builder = new EbscTable::Builder(header, data); - return builder.Detach(); -} - -EbscTable::Builder::Builder(Header* header, WritableFontData* data) - : Table::Builder(header, data) { -} - -EbscTable::Builder::Builder(Header* header, ReadableFontData* data) - : Table::Builder(header, data) { -} - -CALLER_ATTACH -FontDataTable* EbscTable::Builder::SubBuildTable(ReadableFontData* data) { - EbscTablePtr output = new EbscTable(header(), data); - return output.Detach(); -} - -void EbscTable::Builder::SubDataSet() { - // NOP -} - -int32_t EbscTable::Builder::SubDataSizeToSerialize() { - return 0; -} - -bool EbscTable::Builder::SubReadyToSerialize() { - return false; -} - -int32_t EbscTable::Builder::SubSerialize(WritableFontData* new_data) { - UNREFERENCED_PARAMETER(new_data); - return 0; -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/bitmap/ebsc_table.h b/src/sfntly/src/sfntly/table/bitmap/ebsc_table.h deleted file mode 100644 index b79df380df..0000000000 --- a/src/sfntly/src/sfntly/table/bitmap/ebsc_table.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBSC_TABLE_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBSC_TABLE_H_ - -#include "sfntly/table/bitmap/eblc_table.h" - -namespace sfntly { - -class EbscTable : public Table, - public RefCounted { - public: - struct Offset { - enum { - // header - kVersion = 0, - kNumSizes = DataSize::kFixed, - kHeaderLength = kNumSizes + DataSize::kULONG, - kBitmapScaleTableStart = kHeaderLength, - - // bitmapScaleTable - kBitmapScaleTable_hori = 0, - kBitmapScaleTable_vert = EblcTable::Offset::kSbitLineMetricsLength, - kBitmapScaleTable_ppemX = kBitmapScaleTable_vert + - EblcTable::Offset::kSbitLineMetricsLength, - kBitmapScaleTable_ppemY = kBitmapScaleTable_ppemX + DataSize::kBYTE, - kBitmapScaleTable_substitutePpemX = kBitmapScaleTable_ppemY + - DataSize::kBYTE, - kBitmapScaleTable_substitutePpemY = kBitmapScaleTable_substitutePpemX + - DataSize::kBYTE, - kBitmapScaleTableLength = kBitmapScaleTable_substitutePpemY + - DataSize::kBYTE, - }; - }; - - class BitmapScaleTable : public SubTable, - public RefCounted { - public: - virtual ~BitmapScaleTable(); - int32_t PpemX(); - int32_t PpemY(); - int32_t SubstitutePpemX(); - int32_t SubstitutePpemY(); - - protected: - // Note: caller to do data->Slice(offset, Offset::kBitmapScaleTableLength) - explicit BitmapScaleTable(ReadableFontData* data); - }; - - // TODO(stuartg): currently the builder just builds from initial data - // - need to make fully working but few if any examples to test with - class Builder : public Table::Builder, - public RefCounted { - public: - virtual ~Builder(); - - static CALLER_ATTACH Builder* CreateBuilder(Header* header, - WritableFontData* data); - - protected: - Builder(Header* header, WritableFontData* data); - Builder(Header* header, ReadableFontData* data); - - virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); - virtual void SubDataSet(); - virtual int32_t SubDataSizeToSerialize(); - virtual bool SubReadyToSerialize(); - virtual int32_t SubSerialize(WritableFontData* new_data); - }; - - virtual ~EbscTable(); - - int32_t Version(); - int32_t NumSizes(); - // Note: renamed from bitmapScaleTable - CALLER_ATTACH BitmapScaleTable* GetBitmapScaleTable(int32_t index); - - private: - EbscTable(Header* header, ReadableFontData* data); - friend class Builder; -}; -typedef Ptr EbscTablePtr; -typedef Ptr EbscTableBuilderPtr; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBSC_TABLE_H_ diff --git a/src/sfntly/src/sfntly/table/bitmap/glyph_metrics.cc b/src/sfntly/src/sfntly/table/bitmap/glyph_metrics.cc deleted file mode 100644 index e91eb9921e..0000000000 --- a/src/sfntly/src/sfntly/table/bitmap/glyph_metrics.cc +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/table/bitmap/glyph_metrics.h" - -namespace sfntly { - -GlyphMetrics::~GlyphMetrics() { -} - -GlyphMetrics::GlyphMetrics(ReadableFontData* data) - : SubTable(data) { -} - -GlyphMetrics::Builder::~Builder() { -} - -GlyphMetrics::Builder::Builder(WritableFontData* data) - : SubTable::Builder(data) { -} - -GlyphMetrics::Builder::Builder(ReadableFontData* data) - : SubTable::Builder(data) { -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/bitmap/glyph_metrics.h b/src/sfntly/src/sfntly/table/bitmap/glyph_metrics.h deleted file mode 100644 index 5f16aaa661..0000000000 --- a/src/sfntly/src/sfntly/table/bitmap/glyph_metrics.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_METRICS_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_METRICS_H_ - -#include "sfntly/table/subtable.h" - -namespace sfntly { - -class GlyphMetrics : public SubTable { - public: - virtual ~GlyphMetrics(); - - protected: - class Builder : public SubTable::Builder { - public: - virtual ~Builder(); - - protected: - explicit Builder(WritableFontData* data); - explicit Builder(ReadableFontData* data); - }; - - explicit GlyphMetrics(ReadableFontData* data); -}; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_METRICS_H_ diff --git a/src/sfntly/src/sfntly/table/bitmap/index_sub_table.cc b/src/sfntly/src/sfntly/table/bitmap/index_sub_table.cc deleted file mode 100644 index 5e29784504..0000000000 --- a/src/sfntly/src/sfntly/table/bitmap/index_sub_table.cc +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/table/bitmap/index_sub_table.h" - -#include "sfntly/table/bitmap/eblc_table.h" -#include "sfntly/table/bitmap/index_sub_table_format1.h" -#include "sfntly/table/bitmap/index_sub_table_format2.h" -#include "sfntly/table/bitmap/index_sub_table_format3.h" -#include "sfntly/table/bitmap/index_sub_table_format4.h" -#include "sfntly/table/bitmap/index_sub_table_format5.h" - -namespace sfntly { -/****************************************************************************** - * IndexSubTable class - ******************************************************************************/ -CALLER_ATTACH BitmapGlyphInfo* IndexSubTable::GlyphInfo(int32_t glyph_id) { - int32_t loca = CheckGlyphRange(glyph_id); - if (loca == -1) { - return NULL; - } - if (GlyphStartOffset(glyph_id) == -1) { - return NULL; - } - BitmapGlyphInfoPtr output = new BitmapGlyphInfo(glyph_id, - image_data_offset(), - GlyphStartOffset(glyph_id), - GlyphLength(glyph_id), - image_format()); - return output.Detach(); -} - -int32_t IndexSubTable::GlyphOffset(int32_t glyph_id) { - int32_t glyph_start_offset = GlyphStartOffset(glyph_id); - if (glyph_start_offset == -1) { - return -1; - } - return image_data_offset() + glyph_start_offset; -} - -// static -CALLER_ATTACH IndexSubTable* - IndexSubTable::CreateIndexSubTable(ReadableFontData* data, - int32_t offset_to_index_sub_table_array, - int32_t array_index) { - IndexSubTableBuilderPtr builder; - builder.Attach(IndexSubTable::Builder::CreateBuilder( - data, offset_to_index_sub_table_array, array_index)); - return down_cast(builder->Build()); -} - -IndexSubTable::IndexSubTable(ReadableFontData* data, - int32_t first_glyph_index, - int32_t last_glyph_index) - : SubTable(data), - first_glyph_index_(first_glyph_index), - last_glyph_index_(last_glyph_index) { - index_format_ = - data_->ReadUShort(EblcTable::Offset::kIndexSubHeader_indexFormat); - image_format_ = - data_->ReadUShort(EblcTable::Offset::kIndexSubHeader_imageFormat); - image_data_offset_ = - data_->ReadULongAsInt(EblcTable::Offset::kIndexSubHeader_imageDataOffset); -} - -int32_t IndexSubTable::CheckGlyphRange(int32_t glyph_id) { - return CheckGlyphRange(glyph_id, first_glyph_index(), last_glyph_index()); -} - -// static -int32_t IndexSubTable::CheckGlyphRange(int32_t glyph_id, - int32_t first_glyph_id, - int32_t last_glyph_id) { - if (glyph_id < first_glyph_id || glyph_id > last_glyph_id) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IndexOutOfBoundException("Glyph ID is outside of the allowed range."); -#endif - return -1; - } - return glyph_id - first_glyph_id; -} - -/****************************************************************************** - * IndexSubTable::Builder class - ******************************************************************************/ -IndexSubTable::Builder::~Builder() { -} - -void IndexSubTable::Builder::Revert() { - set_model_changed(false); - Initialize(InternalReadData()); -} - -CALLER_ATTACH BitmapGlyphInfo* IndexSubTable::Builder::GlyphInfo( - int32_t glyph_id) { - BitmapGlyphInfoPtr glyph_info = - new BitmapGlyphInfo(glyph_id, - image_data_offset(), - GlyphStartOffset(glyph_id), - GlyphLength(glyph_id), - image_format()); - return glyph_info.Detach(); -} - -int32_t IndexSubTable::Builder::GlyphOffset(int32_t glyph_id) { - return image_data_offset() + GlyphStartOffset(glyph_id); -} - -// static -CALLER_ATTACH IndexSubTable::Builder* -IndexSubTable::Builder::CreateBuilder(int32_t index_format) { - switch (index_format) { - case Format::FORMAT_1: - return IndexSubTableFormat1::Builder::CreateBuilder(); - case Format::FORMAT_2: - return IndexSubTableFormat2::Builder::CreateBuilder(); - case Format::FORMAT_3: - return IndexSubTableFormat3::Builder::CreateBuilder(); - case Format::FORMAT_4: - return IndexSubTableFormat4::Builder::CreateBuilder(); - case Format::FORMAT_5: - return IndexSubTableFormat5::Builder::CreateBuilder(); - default: -#if !defined (SFNTLY_NO_EXCEPTION) - throw IllegalArgumentException("Invalid index subtable format"); -#endif - return NULL; - } -} - -// static -CALLER_ATTACH IndexSubTable::Builder* -IndexSubTable::Builder::CreateBuilder(ReadableFontData* data, - int32_t offset_to_index_sub_table_array, int32_t array_index) { - int32_t index_sub_table_entry_offset = - offset_to_index_sub_table_array + - array_index * EblcTable::Offset::kIndexSubTableEntryLength; - int32_t first_glyph_index = - data->ReadUShort(index_sub_table_entry_offset + - EblcTable::Offset::kIndexSubTableEntry_firstGlyphIndex); - int32_t last_glyph_index = - data->ReadUShort(index_sub_table_entry_offset + - EblcTable::Offset::kIndexSubTableEntry_lastGlyphIndex); - int32_t additional_offset_to_index_subtable = data->ReadULongAsInt( - index_sub_table_entry_offset + - EblcTable::Offset::kIndexSubTableEntry_additionalOffsetToIndexSubTable); - int32_t index_sub_table_offset = offset_to_index_sub_table_array + - additional_offset_to_index_subtable; - int32_t index_format = data->ReadUShort(index_sub_table_offset); - switch (index_format) { - case 1: - return IndexSubTableFormat1::Builder::CreateBuilder( - data, index_sub_table_offset, first_glyph_index, last_glyph_index); - case 2: - return IndexSubTableFormat2::Builder::CreateBuilder( - data, index_sub_table_offset, first_glyph_index, last_glyph_index); - case 3: - return IndexSubTableFormat3::Builder::CreateBuilder( - data, index_sub_table_offset, first_glyph_index, last_glyph_index); - case 4: - return IndexSubTableFormat4::Builder::CreateBuilder( - data, index_sub_table_offset, first_glyph_index, last_glyph_index); - case 5: - return IndexSubTableFormat5::Builder::CreateBuilder( - data, index_sub_table_offset, first_glyph_index, last_glyph_index); - default: - // Unknown format and unable to process. -#if !defined (SFNTLY_NO_EXCEPTION) - throw IllegalArgumentException("Invalid Index Subtable Format"); -#endif - break; - } - return NULL; -} - -CALLER_ATTACH -FontDataTable* IndexSubTable::Builder::SubBuildTable(ReadableFontData* data) { - UNREFERENCED_PARAMETER(data); - return NULL; -} - -void IndexSubTable::Builder::SubDataSet() { - // NOP -} - -int32_t IndexSubTable::Builder::SubDataSizeToSerialize() { - return 0; -} - -bool IndexSubTable::Builder::SubReadyToSerialize() { - return false; -} - -int32_t IndexSubTable::Builder::SubSerialize(WritableFontData* new_data) { - UNREFERENCED_PARAMETER(new_data); - return 0; -} - -IndexSubTable::Builder::Builder(int32_t data_size, int32_t index_format) - : SubTable::Builder(data_size), - first_glyph_index_(0), - last_glyph_index_(0), - index_format_(index_format), - image_format_(0), - image_data_offset_(0) { -} - -IndexSubTable::Builder::Builder(int32_t index_format, - int32_t image_format, - int32_t image_data_offset, - int32_t data_size) - : SubTable::Builder(data_size), - first_glyph_index_(0), - last_glyph_index_(0), - index_format_(index_format), - image_format_(image_format), - image_data_offset_(image_data_offset) { -} - -IndexSubTable::Builder::Builder(WritableFontData* data, - int32_t first_glyph_index, - int32_t last_glyph_index) - : SubTable::Builder(data), - first_glyph_index_(first_glyph_index), - last_glyph_index_(last_glyph_index) { - Initialize(data); -} - -IndexSubTable::Builder::Builder(ReadableFontData* data, - int32_t first_glyph_index, - int32_t last_glyph_index) - : SubTable::Builder(data), - first_glyph_index_(first_glyph_index), - last_glyph_index_(last_glyph_index) { - Initialize(data); -} - -int32_t IndexSubTable::Builder::CheckGlyphRange(int32_t glyph_id) { - return IndexSubTable::CheckGlyphRange(glyph_id, - first_glyph_index(), - last_glyph_index()); -} - -int32_t IndexSubTable::Builder::SerializeIndexSubHeader( - WritableFontData* data) { - int32_t size = - data->WriteUShort(EblcTable::Offset::kIndexSubHeader_indexFormat, - index_format()); - size += data->WriteUShort(EblcTable::Offset::kIndexSubHeader_imageFormat, - image_format()); - size += data->WriteULong(EblcTable::Offset::kIndexSubHeader_imageDataOffset, - image_data_offset()); - return size; -} - -void IndexSubTable::Builder::Initialize(ReadableFontData* data) { - index_format_ = - data->ReadUShort(EblcTable::Offset::kIndexSubHeader_indexFormat); - image_format_ = - data->ReadUShort(EblcTable::Offset::kIndexSubHeader_imageFormat); - image_data_offset_ = - data->ReadULongAsInt(EblcTable::Offset::kIndexSubHeader_imageDataOffset); -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/bitmap/index_sub_table.h b/src/sfntly/src/sfntly/table/bitmap/index_sub_table.h deleted file mode 100644 index 6d27129ccd..0000000000 --- a/src/sfntly/src/sfntly/table/bitmap/index_sub_table.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_H_ - -#include - -#include "sfntly/port/java_iterator.h" -#include "sfntly/table/subtable.h" -#include "sfntly/table/bitmap/bitmap_glyph_info.h" - -namespace sfntly { - -class IndexSubTable : public SubTable { - public: - struct Format { - enum { - FORMAT_1 = 1, - FORMAT_2 = 2, - FORMAT_3 = 3, - FORMAT_4 = 4, - FORMAT_5 = 5, - }; - }; - - class Builder : public SubTable::Builder { - public: - virtual ~Builder(); - - void Revert(); - - int32_t index_format() { return index_format_; } - int32_t first_glyph_index() { return first_glyph_index_; } - void set_first_glyph_index(int32_t v) { first_glyph_index_ = v; } - int32_t last_glyph_index() { return last_glyph_index_; } - void set_last_glyph_index(int32_t v) { last_glyph_index_ = v; } - int32_t image_format() { return image_format_; } - void set_image_format(int32_t v) { image_format_ = v; } - int32_t image_data_offset() { return image_data_offset_; } - void set_image_data_offset(int32_t v) { image_data_offset_ = v; } - - virtual int32_t NumGlyphs() = 0; - - // Gets the glyph info for the specified glyph id. - // @param glyphId the glyph id to look up - // @return the glyph info - CALLER_ATTACH virtual BitmapGlyphInfo* GlyphInfo(int32_t glyph_id); - - // Gets the full offset of the glyph within the EBDT table. - // @param glyphId the glyph id - // @return the glyph offset - virtual int32_t GlyphOffset(int32_t glyph_id); - - // Gets the offset of the glyph relative to the block for this index - // subtable. - // @param glyphId the glyph id - // @return the glyph offset - virtual int32_t GlyphStartOffset(int32_t glyph_id) = 0; - - // Gets the length of the glyph within the EBDT table. - // @param glyphId the glyph id - // @return the glyph offset - virtual int32_t GlyphLength(int32_t glyph_id) = 0; - - // Note: renamed from java iterator() - CALLER_ATTACH virtual Iterator* - GetIterator() = 0; - - // Static instantiation function. - static CALLER_ATTACH Builder* CreateBuilder(int32_t index_format); - static CALLER_ATTACH Builder* - CreateBuilder(ReadableFontData* data, - int32_t offset_to_index_sub_table_array, - int32_t array_index); - - // The following methods will never be called but they need to be here to - // allow the BitmapSizeTable to see these methods through an abstract - // reference. - virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); - virtual void SubDataSet(); - virtual int32_t SubDataSizeToSerialize(); - virtual bool SubReadyToSerialize(); - virtual int32_t SubSerialize(WritableFontData* new_data); - - protected: - Builder(int32_t data_size, int32_t index_format); - Builder(int32_t index_format, - int32_t image_format, - int32_t image_data_offset, - int32_t data_size); - Builder(WritableFontData* data, - int32_t first_glyph_index, - int32_t last_glyph_index); - Builder(ReadableFontData* data, - int32_t first_glyph_index, - int32_t last_glyph_index); - - // Checks that the glyph id is within the correct range. If it returns the - // offset of the glyph id from the start of the range. - // @param glyphId - // @return the offset of the glyphId from the start of the glyph range - // @throws IndexOutOfBoundsException if the glyph id is not within the - // correct range - int32_t CheckGlyphRange(int32_t glyph_id); - int32_t SerializeIndexSubHeader(WritableFontData* data); - - private: - void Initialize(ReadableFontData* data); - - int32_t first_glyph_index_; - int32_t last_glyph_index_; - int32_t index_format_; - int32_t image_format_; - int32_t image_data_offset_; - }; - - int32_t index_format() { return index_format_; } - int32_t first_glyph_index() { return first_glyph_index_; } - int32_t last_glyph_index() { return last_glyph_index_; } - int32_t image_format() { return image_format_; } - int32_t image_data_offset() { return image_data_offset_; } - - CALLER_ATTACH BitmapGlyphInfo* GlyphInfo(int32_t glyph_id); - virtual int32_t GlyphOffset(int32_t glyph_id); - virtual int32_t GlyphStartOffset(int32_t glyph_id) = 0; - virtual int32_t GlyphLength(int32_t glyph_id) = 0; - virtual int32_t NumGlyphs() = 0; - - static CALLER_ATTACH IndexSubTable* - CreateIndexSubTable(ReadableFontData* data, - int32_t offset_to_index_sub_table_array, - int32_t array_index); - - protected: - // Note: the constructor does not implement offset/length form provided in - // Java to avoid heavy lifting in constructors. Callers to call - // GetDataLength() static method of the derived class to get proper - // length and slice ahead. - IndexSubTable(ReadableFontData* data, - int32_t first_glyph_index, - int32_t last_glyph_index); - - int32_t CheckGlyphRange(int32_t glyph_id); - static int32_t CheckGlyphRange(int32_t glyph_id, - int32_t first_glyph_id, - int32_t last_glyph_id); - - private: - int32_t first_glyph_index_; - int32_t last_glyph_index_; - int32_t index_format_; - int32_t image_format_; - int32_t image_data_offset_; -}; -typedef Ptr IndexSubTablePtr; -typedef std::vector IndexSubTableList; -typedef Ptr IndexSubTableBuilderPtr; -typedef std::vector IndexSubTableBuilderList; -typedef Iterator BitmapGlyphInfoIter; -typedef Ptr BitmapGlyphInfoIterPtr; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_H_ diff --git a/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format1.cc b/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format1.cc deleted file mode 100644 index db73723916..0000000000 --- a/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format1.cc +++ /dev/null @@ -1,299 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/table/bitmap/index_sub_table_format1.h" - -#include "sfntly/table/bitmap/eblc_table.h" - -namespace sfntly { -/****************************************************************************** - * IndexSubTableFormat1 class - ******************************************************************************/ -// static -int32_t IndexSubTableFormat1::GetDataLength(ReadableFontData* data, - int32_t offset, - int32_t first, - int32_t last) { - UNREFERENCED_PARAMETER(data); - UNREFERENCED_PARAMETER(offset); - return (last - first + 1 + 1) * DataSize::kULONG; -} - -IndexSubTableFormat1::~IndexSubTableFormat1() { -} - -int32_t IndexSubTableFormat1::NumGlyphs() { - return last_glyph_index() - first_glyph_index() + 1; -} - -int32_t IndexSubTableFormat1::GlyphStartOffset(int32_t glyph_id) { - int32_t loca = CheckGlyphRange(glyph_id); - if (loca == -1) { - return -1; - } - return Loca(loca); -} - -int32_t IndexSubTableFormat1::GlyphLength(int32_t glyph_id) { - int32_t loca = CheckGlyphRange(glyph_id); - if (loca == -1) { - return -1; - } - return Loca(loca + 1) - Loca(loca); -} - -IndexSubTableFormat1::IndexSubTableFormat1(ReadableFontData* data, - int32_t first_glyph_index, - int32_t last_glyph_index) - : IndexSubTable(data, first_glyph_index, last_glyph_index) { -} - -int32_t IndexSubTableFormat1::Loca(int32_t loca) { - return image_data_offset() + - data_->ReadULongAsInt(EblcTable::Offset::kIndexSubTable1_offsetArray + - loca * DataSize::kULONG); -} - -/****************************************************************************** - * IndexSubTableFormat1::Builder class - ******************************************************************************/ -IndexSubTableFormat1::Builder::~Builder() { -} - -int32_t IndexSubTableFormat1::Builder::NumGlyphs() { - return GetOffsetArray()->size() - 1; -} - -int32_t IndexSubTableFormat1::Builder::GlyphLength(int32_t glyph_id) { - int32_t loca = CheckGlyphRange(glyph_id); - if (loca == -1) { - return 0; - } - IntegerList* offset_array = GetOffsetArray(); - return offset_array->at(loca + 1) - offset_array->at(loca); -} - -int32_t IndexSubTableFormat1::Builder::GlyphStartOffset(int32_t glyph_id) { - int32_t loca = CheckGlyphRange(glyph_id); - if (loca == -1) { - return -1; - } - return GetOffsetArray()->at(loca); -} - -CALLER_ATTACH IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator* - IndexSubTableFormat1::Builder::GetIterator() { - Ptr it = - new IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator(this); - return it.Detach(); -} - -// static -CALLER_ATTACH IndexSubTableFormat1::Builder* -IndexSubTableFormat1::Builder::CreateBuilder() { - IndexSubTableFormat1BuilderPtr output = new IndexSubTableFormat1::Builder(); - return output.Detach(); -} - -// static -CALLER_ATTACH IndexSubTableFormat1::Builder* -IndexSubTableFormat1::Builder::CreateBuilder(ReadableFontData* data, - int32_t index_sub_table_offset, - int32_t first_glyph_index, - int32_t last_glyph_index) { - int32_t length = Builder::DataLength(data, - index_sub_table_offset, - first_glyph_index, - last_glyph_index); - ReadableFontDataPtr new_data; - new_data.Attach(down_cast( - data->Slice(index_sub_table_offset, length))); - IndexSubTableFormat1BuilderPtr output = - new IndexSubTableFormat1::Builder(new_data, - first_glyph_index, - last_glyph_index); - return output.Detach(); -} - - -// static -CALLER_ATTACH IndexSubTableFormat1::Builder* -IndexSubTableFormat1::Builder::CreateBuilder(WritableFontData* data, - int32_t index_sub_table_offset, - int32_t first_glyph_index, - int32_t last_glyph_index) { - int32_t length = Builder::DataLength(data, - index_sub_table_offset, - first_glyph_index, - last_glyph_index); - WritableFontDataPtr new_data; - new_data.Attach(down_cast( - data->Slice(index_sub_table_offset, length))); - IndexSubTableFormat1BuilderPtr output = - new IndexSubTableFormat1::Builder(new_data, - first_glyph_index, - last_glyph_index); - return output.Detach(); -} - -CALLER_ATTACH FontDataTable* IndexSubTableFormat1::Builder::SubBuildTable( - ReadableFontData* data) { - IndexSubTableFormat1Ptr output = new IndexSubTableFormat1( - data, first_glyph_index(), last_glyph_index()); - return output.Detach(); -} - -void IndexSubTableFormat1::Builder::SubDataSet() { - Revert(); -} - -int32_t IndexSubTableFormat1::Builder::SubDataSizeToSerialize() { - if (offset_array_.empty()) { - return InternalReadData()->Length(); - } - return EblcTable::Offset::kIndexSubHeaderLength + - offset_array_.size() * DataSize::kULONG; -} - -bool IndexSubTableFormat1::Builder::SubReadyToSerialize() { - if (!offset_array_.empty()) { - return true; - } - return false; -} - -int32_t IndexSubTableFormat1::Builder::SubSerialize( - WritableFontData* new_data) { - int32_t size = SerializeIndexSubHeader(new_data); - if (!model_changed()) { - if (InternalReadData() == NULL) { - return size; - } - ReadableFontDataPtr source; - WritableFontDataPtr target; - source.Attach(down_cast(InternalReadData()->Slice( - EblcTable::Offset::kIndexSubTable1_offsetArray))); - target.Attach(down_cast(new_data->Slice( - EblcTable::Offset::kIndexSubTable1_offsetArray))); - size += source->CopyTo(target); - } else { - for (IntegerList::iterator b = GetOffsetArray()->begin(), - e = GetOffsetArray()->end(); b != e; b++) { - size += new_data->WriteLong(size, *b); - } - } - return size; -} - -IntegerList* IndexSubTableFormat1::Builder::OffsetArray() { - return GetOffsetArray(); -} - -void IndexSubTableFormat1::Builder::SetOffsetArray( - const IntegerList& offset_array) { - offset_array_.clear(); - offset_array_ = offset_array; - set_model_changed(); -} - -void IndexSubTableFormat1::Builder::Revert() { - offset_array_.clear(); - IndexSubTable::Builder::Revert(); -} - -IndexSubTableFormat1::Builder::Builder() - : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable1_builderDataSize, - IndexSubTable::Format::FORMAT_1) { -} - -IndexSubTableFormat1::Builder::Builder(WritableFontData* data, - int32_t first_glyph_index, - int32_t last_glyph_index) - : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { -} - -IndexSubTableFormat1::Builder::Builder(ReadableFontData* data, - int32_t first_glyph_index, - int32_t last_glyph_index) - : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { -} - -IntegerList* IndexSubTableFormat1::Builder::GetOffsetArray() { - if (offset_array_.empty()) { - Initialize(InternalReadData()); - set_model_changed(); - } - return &offset_array_; -} - -void IndexSubTableFormat1::Builder::Initialize(ReadableFontData* data) { - offset_array_.clear(); - if (data) { - int32_t num_offsets = (last_glyph_index() - first_glyph_index() + 1) + 1; - for (int32_t i = 0; i < num_offsets; ++i) { - offset_array_.push_back(data->ReadULongAsInt( - EblcTable::Offset::kIndexSubTable1_offsetArray + - i * DataSize::kULONG)); - } - } -} - -// static -int32_t IndexSubTableFormat1::Builder::DataLength( - ReadableFontData* data, - int32_t index_sub_table_offset, - int32_t first_glyph_index, - int32_t last_glyph_index) { - UNREFERENCED_PARAMETER(data); - UNREFERENCED_PARAMETER(index_sub_table_offset); - return EblcTable::Offset::kIndexSubHeaderLength + - (last_glyph_index - first_glyph_index + 1 + 1) * DataSize::kULONG; -} - -/****************************************************************************** - * IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator class - ******************************************************************************/ -IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator( - IndexSubTableFormat1::Builder* container) - : RefIterator(container) { - glyph_id_ = container->first_glyph_index(); -} - -bool IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator::HasNext() { - if (glyph_id_ <= container()->last_glyph_index()) { - return true; - } - return false; -} - -CALLER_ATTACH BitmapGlyphInfo* -IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator::Next() { - BitmapGlyphInfoPtr output; - if (!HasNext()) { - // Note: In C++, we do not throw exception when there's no element. - return NULL; - } - output = new BitmapGlyphInfo(glyph_id_, - container()->image_data_offset(), - container()->GlyphStartOffset(glyph_id_), - container()->GlyphLength(glyph_id_), - container()->image_format()); - glyph_id_++; - return output.Detach(); -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format1.h b/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format1.h deleted file mode 100644 index 33171c1561..0000000000 --- a/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format1.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT1_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT1_H_ - -#include "sfntly/port/java_iterator.h" -#include "sfntly/table/bitmap/index_sub_table.h" - -namespace sfntly { -// Format 1 Index Subtable Entry. -class IndexSubTableFormat1 : public IndexSubTable, - public RefCounted { - public: - class Builder : public IndexSubTable::Builder, - public RefCounted { - public: - class BitmapGlyphInfoIterator - : public RefIterator { - public: - explicit BitmapGlyphInfoIterator(Builder* container); - virtual ~BitmapGlyphInfoIterator() {} - - virtual bool HasNext(); - CALLER_ATTACH virtual BitmapGlyphInfo* Next(); - - private: - int32_t glyph_id_; - }; - - virtual ~Builder(); - virtual int32_t NumGlyphs(); - virtual int32_t GlyphLength(int32_t glyph_id); - virtual int32_t GlyphStartOffset(int32_t glyph_id); - CALLER_ATTACH virtual BitmapGlyphInfoIterator* GetIterator(); - - virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); - virtual void SubDataSet(); - virtual int32_t SubDataSizeToSerialize(); - virtual bool SubReadyToSerialize(); - virtual int32_t SubSerialize(WritableFontData* new_data); - - IntegerList* OffsetArray(); - void SetOffsetArray(const IntegerList& offset_array); - CALLER_ATTACH BitmapGlyphInfoIter* Iterator(); - - static CALLER_ATTACH Builder* CreateBuilder(); - static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data, - int32_t index_sub_table_offset, - int32_t first_glyph_index, - int32_t last_glyph_index); - static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data, - int32_t index_sub_table_offset, - int32_t first_glyph_index, - int32_t last_glyph_index); - - protected: - void Revert(); - - private: - Builder(); - Builder(WritableFontData* data, - int32_t first_glyph_index, - int32_t last_glyph_index); - Builder(ReadableFontData* data, - int32_t first_glyph_index, - int32_t last_glyph_index); - IntegerList* GetOffsetArray(); - void Initialize(ReadableFontData* data); - - static int32_t DataLength(ReadableFontData* data, - int32_t index_sub_table_offset, - int32_t first_glyph_index, - int32_t last_glyph_index); - - IntegerList offset_array_; - }; - - virtual ~IndexSubTableFormat1(); - - virtual int32_t NumGlyphs(); - virtual int32_t GlyphStartOffset(int32_t glyph_id); - virtual int32_t GlyphLength(int32_t glyph_id); - - static int32_t GetDataLength(ReadableFontData* data, - int32_t offset, - int32_t first, - int32_t last); - - private: - IndexSubTableFormat1(ReadableFontData* data, - int32_t first_glyph_index, - int32_t last_glyph_index); - int32_t Loca(int32_t loca_index); - - friend class Builder; -}; -typedef Ptr IndexSubTableFormat1Ptr; -typedef Ptr IndexSubTableFormat1BuilderPtr; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT1_H_ diff --git a/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format2.cc b/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format2.cc deleted file mode 100644 index b3bffdad91..0000000000 --- a/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format2.cc +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/table/bitmap/index_sub_table_format2.h" - -#include "sfntly/table/bitmap/eblc_table.h" - -namespace sfntly { -/****************************************************************************** - * IndexSubTableFormat2 class - ******************************************************************************/ -IndexSubTableFormat2::~IndexSubTableFormat2() { -} - -int32_t IndexSubTableFormat2::ImageSize() { - return data_->ReadULongAsInt(EblcTable::Offset::kIndexSubTable2_imageSize); -} - -CALLER_ATTACH BigGlyphMetrics* IndexSubTableFormat2::BigMetrics() { - ReadableFontDataPtr slice; - slice.Attach(down_cast( - data_->Slice(EblcTable::Offset::kIndexSubTable2_bigGlyphMetrics, - BigGlyphMetrics::Offset::kMetricsLength))); - BigGlyphMetricsPtr output = new BigGlyphMetrics(slice); - return output.Detach(); -} - -int32_t IndexSubTableFormat2::NumGlyphs() { - return last_glyph_index() - first_glyph_index() + 1; -} - -int32_t IndexSubTableFormat2::GlyphStartOffset(int32_t glyph_id) { - int32_t loca = CheckGlyphRange(glyph_id); - if (loca == -1) { - return -1; - } - return loca * image_size_; -} - -int32_t IndexSubTableFormat2::GlyphLength(int32_t glyph_id) { - if (CheckGlyphRange(glyph_id) == -1) { - return 0; - } - return image_size_; -} - -IndexSubTableFormat2::IndexSubTableFormat2(ReadableFontData* data, - int32_t first, - int32_t last) - : IndexSubTable(data, first, last) { - image_size_ = - data_->ReadULongAsInt(EblcTable::Offset::kIndexSubTable2_imageSize); -} - -/****************************************************************************** - * IndexSubTableFormat2::Builder class - ******************************************************************************/ -IndexSubTableFormat2::Builder::~Builder() { -} - -int32_t IndexSubTableFormat2::Builder::NumGlyphs() { - return last_glyph_index() - first_glyph_index() + 1; -} - -int32_t IndexSubTableFormat2::Builder::GlyphStartOffset(int32_t glyph_id) { - int32_t loca = CheckGlyphRange(glyph_id); - if (loca == -1) { - return -1; - } - return loca * ImageSize(); -} - -int32_t IndexSubTableFormat2::Builder::GlyphLength(int32_t glyph_id) { - int32_t loca = CheckGlyphRange(glyph_id); - if (loca == -1) { - return 0; - } - return ImageSize(); -} - -CALLER_ATTACH IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator* - IndexSubTableFormat2::Builder::GetIterator() { - Ptr it = - new IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator(this); - return it.Detach(); -} - -int32_t IndexSubTableFormat2::Builder::ImageSize() { - return InternalReadData()->ReadULongAsInt( - EblcTable::Offset::kIndexSubTable2_imageSize); -} - -void IndexSubTableFormat2::Builder::SetImageSize(int32_t image_size) { - InternalWriteData()->WriteULong(EblcTable::Offset::kIndexSubTable2_imageSize, - image_size); -} - -BigGlyphMetrics::Builder* IndexSubTableFormat2::Builder::BigMetrics() { - if (metrics_ == NULL) { - WritableFontDataPtr data; - data.Attach(down_cast(InternalWriteData()->Slice( - EblcTable::Offset::kIndexSubTable2_bigGlyphMetrics, - BigGlyphMetrics::Offset::kMetricsLength))); - metrics_ = new BigGlyphMetrics::Builder(data); - } - return metrics_; -} - -// static -CALLER_ATTACH IndexSubTableFormat2::Builder* -IndexSubTableFormat2::Builder::CreateBuilder() { - IndexSubTableFormat2BuilderPtr output = new IndexSubTableFormat2::Builder(); - return output.Detach(); -} - -// static -CALLER_ATTACH IndexSubTableFormat2::Builder* -IndexSubTableFormat2::Builder::CreateBuilder(ReadableFontData* data, - int32_t index_sub_table_offset, - int32_t first_glyph_index, - int32_t last_glyph_index) { - int32_t length = Builder::DataLength(data, - index_sub_table_offset, - first_glyph_index, - last_glyph_index); - ReadableFontDataPtr new_data; - new_data.Attach(down_cast( - data->Slice(index_sub_table_offset, length))); - IndexSubTableFormat2BuilderPtr output = - new IndexSubTableFormat2::Builder(new_data, - first_glyph_index, - last_glyph_index); - return output.Detach(); -} - -// static -CALLER_ATTACH IndexSubTableFormat2::Builder* -IndexSubTableFormat2::Builder::CreateBuilder(WritableFontData* data, - int32_t index_sub_table_offset, - int32_t first_glyph_index, - int32_t last_glyph_index) { - int32_t length = Builder::DataLength(data, - index_sub_table_offset, - first_glyph_index, - last_glyph_index); - WritableFontDataPtr new_data; - new_data.Attach(down_cast( - data->Slice(index_sub_table_offset, length))); - IndexSubTableFormat2BuilderPtr output = - new IndexSubTableFormat2::Builder(new_data, - first_glyph_index, - last_glyph_index); - return output.Detach(); -} - -CALLER_ATTACH FontDataTable* IndexSubTableFormat2::Builder::SubBuildTable( - ReadableFontData* data) { - IndexSubTableFormat2Ptr output = new IndexSubTableFormat2( - data, first_glyph_index(), last_glyph_index()); - return output.Detach(); -} - -void IndexSubTableFormat2::Builder::SubDataSet() { - Revert(); -} - -int32_t IndexSubTableFormat2::Builder::SubDataSizeToSerialize() { - return EblcTable::Offset::kIndexSubTable2Length; -} - -bool IndexSubTableFormat2::Builder::SubReadyToSerialize() { - return true; -} - -int32_t IndexSubTableFormat2::Builder::SubSerialize( - WritableFontData* new_data) { - int32_t size = SerializeIndexSubHeader(new_data); - if (metrics_ == NULL) { - ReadableFontDataPtr source; - WritableFontDataPtr target; - source.Attach(down_cast( - InternalReadData()->Slice(size))); - target.Attach(down_cast(new_data->Slice(size))); - size += source->CopyTo(target); - } else { - WritableFontDataPtr slice; - size += new_data->WriteLong(EblcTable::Offset::kIndexSubTable2_imageSize, - ImageSize()); - slice.Attach(down_cast(new_data->Slice(size))); - size += metrics_->SubSerialize(slice); - } - return size; -} - -IndexSubTableFormat2::Builder::Builder() - : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable3_builderDataSize, - IndexSubTable::Format::FORMAT_2) { - metrics_.Attach(BigGlyphMetrics::Builder::CreateBuilder()); -} - -IndexSubTableFormat2::Builder::Builder(WritableFontData* data, - int32_t first_glyph_index, - int32_t last_glyph_index) - : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { -} - -IndexSubTableFormat2::Builder::Builder(ReadableFontData* data, - int32_t first_glyph_index, - int32_t last_glyph_index) - : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { -} - -// static -int32_t IndexSubTableFormat2::Builder::DataLength( - ReadableFontData* data, - int32_t index_sub_table_offset, - int32_t first_glyph_index, - int32_t last_glyph_index) { - UNREFERENCED_PARAMETER(data); - UNREFERENCED_PARAMETER(index_sub_table_offset); - UNREFERENCED_PARAMETER(first_glyph_index); - UNREFERENCED_PARAMETER(last_glyph_index); - return EblcTable::Offset::kIndexSubTable2Length; -} - -/****************************************************************************** - * IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator class - ******************************************************************************/ -IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator( - IndexSubTableFormat2::Builder* container) - : RefIterator(container) { - glyph_id_ = container->first_glyph_index(); -} - -bool IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator::HasNext() { - if (glyph_id_ <= container()->last_glyph_index()) { - return true; - } - return false; -} - -CALLER_ATTACH BitmapGlyphInfo* -IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator::Next() { - BitmapGlyphInfoPtr output; - if (!HasNext()) { - // Note: In C++, we do not throw exception when there's no element. - return NULL; - } - output = new BitmapGlyphInfo(glyph_id_, - container()->image_data_offset(), - container()->GlyphStartOffset(glyph_id_), - container()->GlyphLength(glyph_id_), - container()->image_format()); - glyph_id_++; - return output.Detach(); -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format2.h b/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format2.h deleted file mode 100644 index 784e8a39fe..0000000000 --- a/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format2.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT2_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT2_H_ - -#include "sfntly/table/bitmap/index_sub_table.h" -#include "sfntly/table/bitmap/big_glyph_metrics.h" - -namespace sfntly { -// Format 2 Index Subtable Entry. -class IndexSubTableFormat2 : public IndexSubTable, - public RefCounted { - public: - class Builder : public IndexSubTable::Builder, - public RefCounted { - public: - class BitmapGlyphInfoIterator - : public RefIterator { - public: - explicit BitmapGlyphInfoIterator(Builder* container); - virtual ~BitmapGlyphInfoIterator() {} - - virtual bool HasNext(); - CALLER_ATTACH virtual BitmapGlyphInfo* Next(); - - private: - int32_t glyph_id_; - }; - - virtual ~Builder(); - virtual int32_t NumGlyphs(); - virtual int32_t GlyphStartOffset(int32_t glyph_id); - virtual int32_t GlyphLength(int32_t glyph_id); - CALLER_ATTACH virtual BitmapGlyphInfoIterator* GetIterator(); - - virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); - virtual void SubDataSet(); - virtual int32_t SubDataSizeToSerialize(); - virtual bool SubReadyToSerialize(); - virtual int32_t SubSerialize(WritableFontData* new_data); - - int32_t ImageSize(); - void SetImageSize(int32_t image_size); - BigGlyphMetrics::Builder* BigMetrics(); - - static CALLER_ATTACH Builder* CreateBuilder(); - static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data, - int32_t index_sub_table_offset, - int32_t first_glyph_index, - int32_t last_glyph_index); - static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data, - int32_t index_sub_table_offset, - int32_t first_glyph_index, - int32_t last_glyph_index); - private: - Builder(); - Builder(WritableFontData* data, - int32_t first_glyph_index, - int32_t last_glyph_index); - Builder(ReadableFontData* data, - int32_t first_glyph_index, - int32_t last_glyph_index); - - static int32_t DataLength(ReadableFontData* data, - int32_t index_sub_table_offset, - int32_t first_glyph_index, - int32_t last_glyph_index); - - BigGlyphMetricsBuilderPtr metrics_; - }; - - virtual ~IndexSubTableFormat2(); - - int32_t ImageSize(); - CALLER_ATTACH BigGlyphMetrics* BigMetrics(); - - virtual int32_t NumGlyphs(); - virtual int32_t GlyphStartOffset(int32_t glyph_id); - virtual int32_t GlyphLength(int32_t glyph_id); - - private: - IndexSubTableFormat2(ReadableFontData* data, int32_t first, int32_t last); - - int32_t image_size_; - friend class Builder; -}; -typedef Ptr IndexSubTableFormat2Ptr; -typedef Ptr IndexSubTableFormat2BuilderPtr; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT1_H_ diff --git a/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format3.cc b/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format3.cc deleted file mode 100644 index b3e418ff54..0000000000 --- a/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format3.cc +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/table/bitmap/index_sub_table_format3.h" - -#include "sfntly/table/bitmap/eblc_table.h" - -namespace sfntly { -/****************************************************************************** - * IndexSubTableFormat3 class - ******************************************************************************/ -IndexSubTableFormat3::~IndexSubTableFormat3() { -} - -int32_t IndexSubTableFormat3::NumGlyphs() { - return last_glyph_index() - first_glyph_index() + 1; -} - -int32_t IndexSubTableFormat3::GlyphStartOffset(int32_t glyph_id) { - int32_t loca = CheckGlyphRange(glyph_id); - if (loca != -1) { - return Loca(loca); - } - return -1; -} - -int32_t IndexSubTableFormat3::GlyphLength(int32_t glyph_id) { - int32_t loca = CheckGlyphRange(glyph_id); - if (loca != -1) { - return Loca(glyph_id + 1) - Loca(glyph_id); - } - return 0; -} - -// static -int32_t IndexSubTableFormat3::GetDataLength(ReadableFontData* data, - int32_t offset, - int32_t first, - int32_t last) { - UNREFERENCED_PARAMETER(data); - UNREFERENCED_PARAMETER(offset); - return (last - first + 1 + 1) * DataSize::kUSHORT; -} - -IndexSubTableFormat3::IndexSubTableFormat3(ReadableFontData* data, - int32_t first_glyph_index, - int32_t last_glyph_index) - : IndexSubTable(data, first_glyph_index, last_glyph_index) { -} - -int32_t IndexSubTableFormat3::Loca(int32_t loca) { - int32_t read_offset = - data_->ReadUShort(EblcTable::Offset::kIndexSubTable3_offsetArray + - loca * DataSize::kUSHORT); - return read_offset; -} - -/****************************************************************************** - * IndexSubTableFormat3::Builder class - ******************************************************************************/ -IndexSubTableFormat3::Builder::~Builder() { -} - -int32_t IndexSubTableFormat3::Builder::NumGlyphs() { - return GetOffsetArray()->size() - 1; -} - -int32_t IndexSubTableFormat3::Builder::GlyphStartOffset(int32_t glyph_id) { - int32_t loca = CheckGlyphRange(glyph_id); - if (loca == -1) { - return -1; - } - return GetOffsetArray()->at(loca); -} - -int32_t IndexSubTableFormat3::Builder::GlyphLength(int32_t glyph_id) { - int32_t loca = CheckGlyphRange(glyph_id); - if (loca == -1) { - return 0; - } - IntegerList* offset_array = GetOffsetArray(); - return offset_array->at(loca + 1) - offset_array->at(loca); -} - -CALLER_ATTACH IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator* - IndexSubTableFormat3::Builder::GetIterator() { - Ptr it = - new IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator(this); - return it.Detach(); -} - -void IndexSubTableFormat3::Builder::Revert() { - offset_array_.clear(); - IndexSubTable::Builder::Revert(); -} - -void IndexSubTableFormat3::Builder::SetOffsetArray( - const IntegerList& offset_array) { - offset_array_.clear(); - offset_array_ = offset_array; - set_model_changed(); -} - -// static -CALLER_ATTACH IndexSubTableFormat3::Builder* -IndexSubTableFormat3::Builder::CreateBuilder() { - IndexSubTableFormat3BuilderPtr output = new IndexSubTableFormat3::Builder(); - return output.Detach(); -} - -// static -CALLER_ATTACH IndexSubTableFormat3::Builder* -IndexSubTableFormat3::Builder::CreateBuilder(ReadableFontData* data, - int32_t index_sub_table_offset, - int32_t first_glyph_index, - int32_t last_glyph_index) { - int32_t length = Builder::DataLength(data, - index_sub_table_offset, - first_glyph_index, - last_glyph_index); - ReadableFontDataPtr new_data; - new_data.Attach(down_cast( - data->Slice(index_sub_table_offset, length))); - IndexSubTableFormat3BuilderPtr output = - new IndexSubTableFormat3::Builder(new_data, - first_glyph_index, - last_glyph_index); - return output.Detach(); -} - -// static -CALLER_ATTACH IndexSubTableFormat3::Builder* -IndexSubTableFormat3::Builder::CreateBuilder(WritableFontData* data, - int32_t index_sub_table_offset, - int32_t first_glyph_index, - int32_t last_glyph_index) { - int32_t length = Builder::DataLength(data, - index_sub_table_offset, - first_glyph_index, - last_glyph_index); - WritableFontDataPtr new_data; - new_data.Attach(down_cast( - data->Slice(index_sub_table_offset, length))); - IndexSubTableFormat3BuilderPtr output = - new IndexSubTableFormat3::Builder(new_data, - first_glyph_index, - last_glyph_index); - return output.Detach(); -} - -CALLER_ATTACH FontDataTable* IndexSubTableFormat3::Builder::SubBuildTable( - ReadableFontData* data) { - IndexSubTableFormat3Ptr output = new IndexSubTableFormat3( - data, first_glyph_index(), last_glyph_index()); - return output.Detach(); -} - -void IndexSubTableFormat3::Builder::SubDataSet() { - Revert(); -} - -int32_t IndexSubTableFormat3::Builder::SubDataSizeToSerialize() { - if (offset_array_.empty()) { - return InternalReadData()->Length(); - } - return EblcTable::Offset::kIndexSubHeaderLength + - offset_array_.size() * DataSize::kULONG; -} - -bool IndexSubTableFormat3::Builder::SubReadyToSerialize() { - if (!offset_array_.empty()) { - return true; - } - return false; -} - -int32_t IndexSubTableFormat3::Builder::SubSerialize( - WritableFontData* new_data) { - int32_t size = SerializeIndexSubHeader(new_data); - if (!model_changed()) { - if (InternalReadData() == NULL) { - return size; - } - ReadableFontDataPtr source; - WritableFontDataPtr target; - source.Attach(down_cast(InternalReadData()->Slice( - EblcTable::Offset::kIndexSubTable3_offsetArray))); - target.Attach(down_cast(new_data->Slice( - EblcTable::Offset::kIndexSubTable3_offsetArray))); - size += source->CopyTo(target); - } else { - for (IntegerList::iterator b = GetOffsetArray()->begin(), - e = GetOffsetArray()->end(); b != e; b++) { - size += new_data->WriteUShort(size, *b); - } - } - return size; -} - -IndexSubTableFormat3::Builder::Builder() - : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable3_builderDataSize, - IndexSubTable::Format::FORMAT_3) { -} - -IndexSubTableFormat3::Builder::Builder(WritableFontData* data, - int32_t first_glyph_index, - int32_t last_glyph_index) - : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { -} - -IndexSubTableFormat3::Builder::Builder(ReadableFontData* data, - int32_t first_glyph_index, - int32_t last_glyph_index) - : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { -} - -IntegerList* IndexSubTableFormat3::Builder::GetOffsetArray() { - if (offset_array_.empty()) { - Initialize(InternalReadData()); - set_model_changed(); - } - return &offset_array_; -} - -void IndexSubTableFormat3::Builder::Initialize(ReadableFontData* data) { - offset_array_.clear(); - if (data) { - int32_t num_offsets = (last_glyph_index() - first_glyph_index() + 1) + 1; - for (int32_t i = 0; i < num_offsets; ++i) { - offset_array_.push_back(data->ReadUShort( - EblcTable::Offset::kIndexSubTable3_offsetArray + - i * DataSize::kUSHORT)); - } - } -} - -// static -int32_t IndexSubTableFormat3::Builder::DataLength( - ReadableFontData* data, - int32_t index_sub_table_offset, - int32_t first_glyph_index, - int32_t last_glyph_index) { - UNREFERENCED_PARAMETER(data); - UNREFERENCED_PARAMETER(index_sub_table_offset); - return EblcTable::Offset::kIndexSubHeaderLength + - (last_glyph_index - first_glyph_index + 1 + 1) * DataSize::kUSHORT; -} - -/****************************************************************************** - * IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator class - ******************************************************************************/ -IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator( - IndexSubTableFormat3::Builder* container) - : RefIterator(container) { - glyph_id_ = container->first_glyph_index(); -} - -bool IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator::HasNext() { - if (glyph_id_ <= container()->last_glyph_index()) { - return true; - } - return false; -} - -CALLER_ATTACH BitmapGlyphInfo* -IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator::Next() { - BitmapGlyphInfoPtr output; - if (!HasNext()) { - // Note: In C++, we do not throw exception when there's no element. - return NULL; - } - output = new BitmapGlyphInfo(glyph_id_, - container()->image_data_offset(), - container()->GlyphStartOffset(glyph_id_), - container()->GlyphLength(glyph_id_), - container()->image_format()); - glyph_id_++; - return output.Detach(); -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format3.h b/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format3.h deleted file mode 100644 index d71f8573cc..0000000000 --- a/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format3.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT3_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT3_H_ - -#include "sfntly/table/bitmap/index_sub_table.h" - -namespace sfntly { -// Format 3 Index Subtable Entry. -class IndexSubTableFormat3 : public IndexSubTable, - public RefCounted { - public: - class Builder : public IndexSubTable::Builder, - public RefCounted { - public: - class BitmapGlyphInfoIterator - : public RefIterator { - public: - explicit BitmapGlyphInfoIterator(Builder* container); - virtual ~BitmapGlyphInfoIterator() {} - - virtual bool HasNext(); - CALLER_ATTACH virtual BitmapGlyphInfo* Next(); - - private: - int32_t glyph_id_; - }; - - virtual ~Builder(); - virtual int32_t NumGlyphs(); - virtual int32_t GlyphStartOffset(int32_t glyph_id); - virtual int32_t GlyphLength(int32_t glyph_id); - CALLER_ATTACH virtual BitmapGlyphInfoIterator* GetIterator(); - - virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); - virtual void SubDataSet(); - virtual int32_t SubDataSizeToSerialize(); - virtual bool SubReadyToSerialize(); - virtual int32_t SubSerialize(WritableFontData* new_data); - - void SetOffsetArray(const IntegerList& offset_array); - - static CALLER_ATTACH Builder* CreateBuilder(); - static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data, - int32_t index_sub_table_offset, - int32_t first_glyph_index, - int32_t last_glyph_index); - static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data, - int32_t index_sub_table_offset, - int32_t first_glyph_index, - int32_t last_glyph_index); - - protected: - void Revert(); - - private: - Builder(); - Builder(WritableFontData* data, - int32_t first_glyph_index, - int32_t last_glyph_index); - Builder(ReadableFontData* data, - int32_t first_glyph_index, - int32_t last_glyph_index); - IntegerList* GetOffsetArray(); - void Initialize(ReadableFontData* data); - - static int32_t DataLength(ReadableFontData* data, - int32_t index_sub_table_offset, - int32_t first_glyph_index, - int32_t last_glyph_index); - - IntegerList offset_array_; - }; - - virtual ~IndexSubTableFormat3(); - - virtual int32_t NumGlyphs(); - virtual int32_t GlyphStartOffset(int32_t glyph_id); - virtual int32_t GlyphLength(int32_t glyph_id); - - static int32_t GetDataLength(ReadableFontData* data, - int32_t offset, - int32_t first, - int32_t last); - - private: - IndexSubTableFormat3(ReadableFontData* data, - int32_t first_glyph_index, - int32_t last_glyph_index); - int32_t Loca(int32_t loca_index); - - friend class Builder; -}; -typedef Ptr IndexSubTableFormat3Ptr; -typedef Ptr IndexSubTableFormat3BuilderPtr; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT3_H_ diff --git a/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format4.cc b/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format4.cc deleted file mode 100644 index 23f3e47406..0000000000 --- a/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format4.cc +++ /dev/null @@ -1,381 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/table/bitmap/index_sub_table_format4.h" - -#include "sfntly/table/bitmap/eblc_table.h" - -namespace sfntly { -/****************************************************************************** - * IndexSubTableFormat4 class - ******************************************************************************/ -IndexSubTableFormat4::~IndexSubTableFormat4() { -} - -int32_t IndexSubTableFormat4::NumGlyphs() { - return IndexSubTableFormat4::NumGlyphs(data_, 0); -} - -int32_t IndexSubTableFormat4::GlyphStartOffset(int32_t glyph_id) { - int32_t loca = CheckGlyphRange(glyph_id); - if (loca == -1) { - return -1; - } - int32_t pair_index = FindCodeOffsetPair(glyph_id); - if (pair_index < 0) { - return -1; - } - return data_->ReadUShort(EblcTable::Offset::kIndexSubTable4_glyphArray + - pair_index * - EblcTable::Offset::kCodeOffsetPairLength + - EblcTable::Offset::kCodeOffsetPair_offset); -} - -int32_t IndexSubTableFormat4::GlyphLength(int32_t glyph_id) { - int32_t loca = CheckGlyphRange(glyph_id); - if (loca == -1) { - return -1; - } - - int32_t pair_index = FindCodeOffsetPair(glyph_id); - if (pair_index < 0) { - return -1; - } - return data_->ReadUShort( - EblcTable::Offset::kIndexSubTable4_glyphArray + - (pair_index + 1) * EblcTable::Offset::kCodeOffsetPairLength + - EblcTable::Offset::kCodeOffsetPair_offset) - - data_->ReadUShort( - EblcTable::Offset::kIndexSubTable4_glyphArray + - (pair_index) * EblcTable::Offset::kCodeOffsetPairLength + - EblcTable::Offset::kCodeOffsetPair_offset); -} - -IndexSubTableFormat4::IndexSubTableFormat4(ReadableFontData* data, - int32_t first, - int32_t last) - : IndexSubTable(data, first, last) { -} - -int32_t IndexSubTableFormat4::FindCodeOffsetPair(int32_t glyph_id) { - return data_->SearchUShort(EblcTable::Offset::kIndexSubTable4_glyphArray, - EblcTable::Offset::kCodeOffsetPairLength, - NumGlyphs(), - glyph_id); -} - -int32_t IndexSubTableFormat4::NumGlyphs(ReadableFontData* data, - int32_t table_offset) { - int32_t num_glyphs = data->ReadULongAsInt(table_offset + - EblcTable::Offset::kIndexSubTable4_numGlyphs); - return num_glyphs; -} - -/****************************************************************************** - * IndexSubTableFormat4::CodeOffsetPair related class - ******************************************************************************/ -IndexSubTableFormat4::CodeOffsetPair::CodeOffsetPair(int32_t glyph_code, - int32_t offset) - : glyph_code_(glyph_code), offset_(offset) { -} - -IndexSubTableFormat4::CodeOffsetPairBuilder::CodeOffsetPairBuilder() - : CodeOffsetPair(0, 0) { -} - -IndexSubTableFormat4::CodeOffsetPairBuilder::CodeOffsetPairBuilder( - int32_t glyph_code, int32_t offset) - : CodeOffsetPair(glyph_code, offset) { -} - -bool IndexSubTableFormat4::CodeOffsetPairGlyphCodeComparator::operator()( - const CodeOffsetPair& lhs, const CodeOffsetPair& rhs) { - return lhs.glyph_code() < rhs.glyph_code(); -} - -/****************************************************************************** - * IndexSubTableFormat4::Builder class - ******************************************************************************/ -IndexSubTableFormat4::Builder::~Builder() { -} - -int32_t IndexSubTableFormat4::Builder::NumGlyphs() { - return GetOffsetArray()->size() - 1; -} - -int32_t IndexSubTableFormat4::Builder::GlyphLength(int32_t glyph_id) { - int32_t loca = CheckGlyphRange(glyph_id); - if (loca == -1) { - return 0; - } - int32_t pair_index = FindCodeOffsetPair(glyph_id); - if (pair_index == -1) { - return 0; - } - return GetOffsetArray()->at(pair_index + 1).offset() - - GetOffsetArray()->at(pair_index).offset(); -} - -int32_t IndexSubTableFormat4::Builder::GlyphStartOffset(int32_t glyph_id) { - int32_t loca = CheckGlyphRange(glyph_id); - if (loca == -1) { - return -1; - } - int32_t pair_index = FindCodeOffsetPair(glyph_id); - if (pair_index == -1) { - return -1; - } - return GetOffsetArray()->at(pair_index).offset(); -} - -CALLER_ATTACH IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator* - IndexSubTableFormat4::Builder::GetIterator() { - Ptr it = - new IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator(this); - return it.Detach(); -} - -// static -CALLER_ATTACH IndexSubTableFormat4::Builder* -IndexSubTableFormat4::Builder::CreateBuilder() { - IndexSubTableFormat4BuilderPtr output = new IndexSubTableFormat4::Builder(); - return output.Detach(); -} - -// static -CALLER_ATTACH IndexSubTableFormat4::Builder* -IndexSubTableFormat4::Builder::CreateBuilder(ReadableFontData* data, - int32_t index_sub_table_offset, - int32_t first_glyph_index, - int32_t last_glyph_index) { - int32_t length = Builder::DataLength(data, - index_sub_table_offset, - first_glyph_index, - last_glyph_index); - ReadableFontDataPtr new_data; - new_data.Attach(down_cast( - data->Slice(index_sub_table_offset, length))); - IndexSubTableFormat4BuilderPtr output = - new IndexSubTableFormat4::Builder(new_data, - first_glyph_index, - last_glyph_index); - return output.Detach(); -} - -// static -CALLER_ATTACH IndexSubTableFormat4::Builder* -IndexSubTableFormat4::Builder::CreateBuilder(WritableFontData* data, - int32_t index_sub_table_offset, - int32_t first_glyph_index, - int32_t last_glyph_index) { - int32_t length = Builder::DataLength(data, - index_sub_table_offset, - first_glyph_index, - last_glyph_index); - WritableFontDataPtr new_data; - new_data.Attach(down_cast( - data->Slice(index_sub_table_offset, length))); - IndexSubTableFormat4BuilderPtr output = - new IndexSubTableFormat4::Builder(new_data, - first_glyph_index, - last_glyph_index); - return output.Detach(); -} - -CALLER_ATTACH FontDataTable* IndexSubTableFormat4::Builder::SubBuildTable( - ReadableFontData* data) { - IndexSubTableFormat4Ptr output = new IndexSubTableFormat4( - data, first_glyph_index(), last_glyph_index()); - return output.Detach(); -} - -void IndexSubTableFormat4::Builder::SubDataSet() { - Revert(); -} - -int32_t IndexSubTableFormat4::Builder::SubDataSizeToSerialize() { - if (offset_pair_array_.empty()) { - return InternalReadData()->Length(); - } - return EblcTable::Offset::kIndexSubHeaderLength + DataSize::kULONG + - GetOffsetArray()->size() * - EblcTable::Offset::kIndexSubTable4_codeOffsetPairLength; -} - -bool IndexSubTableFormat4::Builder::SubReadyToSerialize() { - if (!offset_pair_array_.empty()) { - return true; - } - return false; -} - -int32_t IndexSubTableFormat4::Builder::SubSerialize( - WritableFontData* new_data) { - int32_t size = SerializeIndexSubHeader(new_data); - if (!model_changed()) { - if (InternalReadData() == NULL) { - return size; - } - ReadableFontDataPtr source; - WritableFontDataPtr target; - source.Attach(down_cast(InternalReadData()->Slice( - EblcTable::Offset::kIndexSubTable4_glyphArray))); - target.Attach(down_cast(new_data->Slice( - EblcTable::Offset::kIndexSubTable4_glyphArray))); - size += source->CopyTo(target); - } else { - size += new_data->WriteLong(size, offset_pair_array_.size() - 1); - for (std::vector::iterator - b = GetOffsetArray()->begin(), e = GetOffsetArray()->end(); - b != e; b++) { - size += new_data->WriteUShort(size, b->glyph_code()); - size += new_data->WriteUShort(size, b->offset()); - } - } - return size; -} - -void IndexSubTableFormat4::Builder::Revert() { - offset_pair_array_.clear(); - IndexSubTable::Builder::Revert(); -} - -void IndexSubTableFormat4::Builder::SetOffsetArray( - const std::vector& pair_array) { - offset_pair_array_.clear(); - offset_pair_array_ = pair_array; - set_model_changed(); -} - -IndexSubTableFormat4::Builder::Builder() - : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable4_builderDataSize, - Format::FORMAT_4) { -} - -IndexSubTableFormat4::Builder::Builder(WritableFontData* data, - int32_t first_glyph_index, - int32_t last_glyph_index) - : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { -} - -IndexSubTableFormat4::Builder::Builder(ReadableFontData* data, - int32_t first_glyph_index, - int32_t last_glyph_index) - : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { -} - -std::vector* -IndexSubTableFormat4::Builder::GetOffsetArray() { - if (offset_pair_array_.empty()) { - Initialize(InternalReadData()); - set_model_changed(); - } - return &offset_pair_array_; -} - -void IndexSubTableFormat4::Builder::Initialize(ReadableFontData* data) { - offset_pair_array_.clear(); - if (data) { - int32_t num_pairs = IndexSubTableFormat4::NumGlyphs(data, 0) + 1; - int32_t offset = EblcTable::Offset::kIndexSubTable4_glyphArray; - for (int32_t i = 0; i < num_pairs; ++i) { - int32_t glyph_code = data->ReadUShort(offset + - EblcTable::Offset::kIndexSubTable4_codeOffsetPair_glyphCode); - int32_t glyph_offset = data->ReadUShort(offset + - EblcTable::Offset::kIndexSubTable4_codeOffsetPair_offset); - offset += EblcTable::Offset::kIndexSubTable4_codeOffsetPairLength; - CodeOffsetPairBuilder pair_builder(glyph_code, glyph_offset); - offset_pair_array_.push_back(pair_builder); - } - } -} - -int32_t IndexSubTableFormat4::Builder::FindCodeOffsetPair(int32_t glyph_id) { - std::vector* pair_list = GetOffsetArray(); - int32_t location = 0; - int32_t bottom = 0; - int32_t top = pair_list->size(); - while (top != bottom) { - location = (top + bottom) / 2; - CodeOffsetPairBuilder* pair = &(pair_list->at(location)); - if (glyph_id < pair->glyph_code()) { - // location is below current location - top = location; - } else if (glyph_id > pair->glyph_code()) { - // location is above current location - bottom = location + 1; - } else { - return location; - } - } - return -1; -} - -// static -int32_t IndexSubTableFormat4::Builder::DataLength( - ReadableFontData* data, - int32_t index_sub_table_offset, - int32_t first_glyph_index, - int32_t last_glyph_index) { - int32_t num_glyphs = IndexSubTableFormat4::NumGlyphs(data, - index_sub_table_offset); - UNREFERENCED_PARAMETER(first_glyph_index); - UNREFERENCED_PARAMETER(last_glyph_index); - return EblcTable::Offset::kIndexSubTable4_glyphArray + - num_glyphs * EblcTable::Offset::kIndexSubTable4_codeOffsetPair_offset; -} - - -/****************************************************************************** - * IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator class - ******************************************************************************/ -IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator( - IndexSubTableFormat4::Builder* container) - : RefIterator(container), - code_offset_pair_index_(0) { -} - -bool IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator::HasNext() { - if (code_offset_pair_index_ < - (int32_t)(container()->GetOffsetArray()->size() - 1)) { - return true; - } - return false; -} - -CALLER_ATTACH BitmapGlyphInfo* -IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator::Next() { - BitmapGlyphInfoPtr output; - if (!HasNext()) { - // Note: In C++, we do not throw exception when there's no element. - return NULL; - } - std::vector* offset_array = - container()->GetOffsetArray(); - int32_t offset = offset_array->at(code_offset_pair_index_).offset(); - int32_t next_offset = offset_array->at(code_offset_pair_index_ + 1).offset(); - int32_t glyph_code = offset_array->at(code_offset_pair_index_).glyph_code(); - output = new BitmapGlyphInfo(glyph_code, - container()->image_data_offset(), - offset, - next_offset - offset, - container()->image_format()); - code_offset_pair_index_++; - return output.Detach(); -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format4.h b/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format4.h deleted file mode 100644 index efd540f178..0000000000 --- a/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format4.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT4_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT4_H_ - -#include "sfntly/table/bitmap/index_sub_table.h" - -namespace sfntly { - -class IndexSubTableFormat4 : public IndexSubTable, - public RefCounted { - public: - class CodeOffsetPair { - public: - int32_t glyph_code() const { return glyph_code_; } - int32_t offset() const { return offset_; } - - protected: - CodeOffsetPair(int32_t glyph_code, int32_t offset); - - // TODO(arthurhsu): C++ style guide prohibits protected members. - int32_t glyph_code_; - int32_t offset_; - }; - - class CodeOffsetPairBuilder : public CodeOffsetPair { - public: - CodeOffsetPairBuilder(); - CodeOffsetPairBuilder(int32_t glyph_code, int32_t offset); - void set_glyph_code(int32_t v) { glyph_code_ = v; } - void set_offset(int32_t v) { offset_ = v; } - }; - - class CodeOffsetPairGlyphCodeComparator { - public: - bool operator()(const CodeOffsetPair& lhs, const CodeOffsetPair& rhs); - }; - - class Builder : public IndexSubTable::Builder, - public RefCounted { - public: - class BitmapGlyphInfoIterator - : public RefIterator { - public: - explicit BitmapGlyphInfoIterator(Builder* container); - virtual ~BitmapGlyphInfoIterator() {} - - virtual bool HasNext(); - CALLER_ATTACH virtual BitmapGlyphInfo* Next(); - - private: - int32_t code_offset_pair_index_; - }; - - virtual ~Builder(); - virtual int32_t NumGlyphs(); - virtual int32_t GlyphLength(int32_t glyph_id); - virtual int32_t GlyphStartOffset(int32_t glyph_id); - CALLER_ATTACH virtual BitmapGlyphInfoIterator* GetIterator(); - - virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); - virtual void SubDataSet(); - virtual int32_t SubDataSizeToSerialize(); - virtual bool SubReadyToSerialize(); - virtual int32_t SubSerialize(WritableFontData* new_data); - - void Revert(); - void SetOffsetArray(const std::vector& pair_array); - - static CALLER_ATTACH Builder* CreateBuilder(); - static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data, - int32_t index_sub_table_offset, - int32_t first_glyph_index, - int32_t last_glyph_index); - static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data, - int32_t index_sub_table_offset, - int32_t first_glyph_index, - int32_t last_glyph_index); - private: - Builder(); - Builder(WritableFontData* data, - int32_t first_glyph_index, - int32_t last_glyph_index); - Builder(ReadableFontData* data, - int32_t first_glyph_index, - int32_t last_glyph_index); - std::vector* GetOffsetArray(); - void Initialize(ReadableFontData* data); - int32_t FindCodeOffsetPair(int32_t glyph_id); - - static int32_t DataLength(ReadableFontData* data, - int32_t index_sub_table_offset, - int32_t first_glyph_index, - int32_t last_glyph_index); - - std::vector offset_pair_array_; - }; - - virtual ~IndexSubTableFormat4(); - - virtual int32_t NumGlyphs(); - virtual int32_t GlyphStartOffset(int32_t glyph_id); - virtual int32_t GlyphLength(int32_t glyph_id); - - private: - IndexSubTableFormat4(ReadableFontData* data, - int32_t first_glyph_index, - int32_t last_glyph_index); - - int32_t FindCodeOffsetPair(int32_t glyph_id); - static int32_t NumGlyphs(ReadableFontData* data, int32_t table_offset); - - friend class Builder; -}; -typedef Ptr IndexSubTableFormat4Ptr; -typedef Ptr IndexSubTableFormat4BuilderPtr; -typedef std::vector - CodeOffsetPairBuilderList; -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT4_H_ diff --git a/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format5.cc b/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format5.cc deleted file mode 100644 index b4ab1b8e9e..0000000000 --- a/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format5.cc +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/table/bitmap/index_sub_table_format5.h" - -#include - -#include "sfntly/table/bitmap/eblc_table.h" - -namespace sfntly { -/****************************************************************************** - * IndexSubTableFormat5 class - ******************************************************************************/ -IndexSubTableFormat5::~IndexSubTableFormat5() { -} - -int32_t IndexSubTableFormat5::NumGlyphs() { - return NumGlyphs(data_, 0); -} - -int32_t IndexSubTableFormat5::GlyphStartOffset(int32_t glyph_id) { - int32_t check = CheckGlyphRange(glyph_id); - if (check == -1) { - return -1; - } - int32_t loca = ReadFontData()->SearchUShort( - EblcTable::Offset::kIndexSubTable5_glyphArray, - DataSize::kUSHORT, - NumGlyphs(), - glyph_id); - if (loca == -1) { - return loca; - } - return loca * ImageSize(); -} - -int32_t IndexSubTableFormat5::GlyphLength(int32_t glyph_id) { - int32_t check = CheckGlyphRange(glyph_id); - if (check == -1) { - return 0; - } - return image_size_; -} - -int32_t IndexSubTableFormat5::ImageSize() { - return data_->ReadULongAsInt(EblcTable::Offset::kIndexSubTable5_imageSize); -} - -CALLER_ATTACH BigGlyphMetrics* IndexSubTableFormat5::BigMetrics() { - ReadableFontDataPtr data; - data.Attach(down_cast(data_->Slice( - EblcTable::Offset::kIndexSubTable5_bigGlyphMetrics, - BigGlyphMetrics::Offset::kMetricsLength))); - BigGlyphMetricsPtr output = new BigGlyphMetrics(data); - return output.Detach(); -} - -IndexSubTableFormat5::IndexSubTableFormat5(ReadableFontData* data, - int32_t first_glyph_index, - int32_t last_glyph_index) - : IndexSubTable(data, first_glyph_index, last_glyph_index) { - image_size_ = data_->ReadULongAsInt( - EblcTable::Offset::kIndexSubTable5_imageSize); -} - -// static -int32_t IndexSubTableFormat5::NumGlyphs(ReadableFontData* data, - int32_t table_offset) { - int32_t num_glyphs = data->ReadULongAsInt(table_offset + - EblcTable::Offset::kIndexSubTable5_numGlyphs); - return num_glyphs; -} - -/****************************************************************************** - * IndexSubTableFormat5::Builder class - ******************************************************************************/ -IndexSubTableFormat5::Builder::~Builder() { -} - -int32_t IndexSubTableFormat5::Builder::NumGlyphs() { - return GetGlyphArray()->size(); -} - -int32_t IndexSubTableFormat5::Builder::GlyphLength(int32_t glyph_id) { - UNREFERENCED_PARAMETER(glyph_id); - return ImageSize(); -} - -int32_t IndexSubTableFormat5::Builder::GlyphStartOffset(int32_t glyph_id) { - int32_t check = CheckGlyphRange(glyph_id); - if (check == -1) { - return -1; - } - IntegerList* glyph_array = GetGlyphArray(); - IntegerList::iterator it = std::find(glyph_array->begin(), - glyph_array->end(), - glyph_id); - if (it == glyph_array->end()) { - return -1; - } - return (it - glyph_array->begin()) * ImageSize(); -} - -CALLER_ATTACH IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator* - IndexSubTableFormat5::Builder::GetIterator() { - Ptr it = - new IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator(this); - return it.Detach(); -} - -// static -CALLER_ATTACH IndexSubTableFormat5::Builder* -IndexSubTableFormat5::Builder::CreateBuilder() { - IndexSubTableFormat5BuilderPtr output = new IndexSubTableFormat5::Builder(); - return output.Detach(); -} - -// static -CALLER_ATTACH IndexSubTableFormat5::Builder* -IndexSubTableFormat5::Builder::CreateBuilder(ReadableFontData* data, - int32_t index_sub_table_offset, - int32_t first_glyph_index, - int32_t last_glyph_index) { - int32_t length = Builder::DataLength(data, - index_sub_table_offset, - first_glyph_index, - last_glyph_index); - ReadableFontDataPtr new_data; - new_data.Attach(down_cast( - data->Slice(index_sub_table_offset, length))); - IndexSubTableFormat5BuilderPtr output = - new IndexSubTableFormat5::Builder(new_data, - first_glyph_index, - last_glyph_index); - return output.Detach(); -} - -// static -CALLER_ATTACH IndexSubTableFormat5::Builder* -IndexSubTableFormat5::Builder::CreateBuilder(WritableFontData* data, - int32_t index_sub_table_offset, - int32_t first_glyph_index, - int32_t last_glyph_index) { - int32_t length = Builder::DataLength(data, - index_sub_table_offset, - first_glyph_index, - last_glyph_index); - WritableFontDataPtr new_data; - new_data.Attach(down_cast( - data->Slice(index_sub_table_offset, length))); - IndexSubTableFormat5BuilderPtr output = - new IndexSubTableFormat5::Builder(new_data, - first_glyph_index, - last_glyph_index); - return output.Detach(); -} - -CALLER_ATTACH FontDataTable* IndexSubTableFormat5::Builder::SubBuildTable( - ReadableFontData* data) { - IndexSubTableFormat5Ptr output = new IndexSubTableFormat5( - data, first_glyph_index(), last_glyph_index()); - return output.Detach(); -} - -void IndexSubTableFormat5::Builder::SubDataSet() { - Revert(); -} - -int32_t IndexSubTableFormat5::Builder::SubDataSizeToSerialize() { - if (glyph_array_.empty()) { - return InternalReadData()->Length(); - } - return EblcTable::Offset::kIndexSubTable5_builderDataSize + - glyph_array_.size() * DataSize::kUSHORT; -} - -bool IndexSubTableFormat5::Builder::SubReadyToSerialize() { - if (!glyph_array_.empty()) { - return true; - } - return false; -} - -int32_t IndexSubTableFormat5::Builder::SubSerialize( - WritableFontData* new_data) { - int32_t size = SerializeIndexSubHeader(new_data); - if (!model_changed()) { - ReadableFontDataPtr source; - WritableFontDataPtr target; - source.Attach(down_cast(InternalReadData()->Slice( - EblcTable::Offset::kIndexSubTable5_imageSize))); - target.Attach(down_cast(new_data->Slice( - EblcTable::Offset::kIndexSubTable5_imageSize))); - size += source->CopyTo(target); - } else { - size += new_data->WriteULong(EblcTable::Offset::kIndexSubTable5_imageSize, - ImageSize()); - WritableFontDataPtr slice; - slice.Attach(down_cast(new_data->Slice(size))); - size += BigMetrics()->SubSerialize(slice); - size += new_data->WriteULong(size, glyph_array_.size()); - for (IntegerList::iterator b = glyph_array_.begin(), e = glyph_array_.end(); - b != e; b++) { - size += new_data->WriteUShort(size, *b); - } - } - return size; -} - -int32_t IndexSubTableFormat5::Builder::ImageSize() { - return InternalReadData()->ReadULongAsInt( - EblcTable::Offset::kIndexSubTable5_imageSize); -} - -void IndexSubTableFormat5::Builder::SetImageSize(int32_t image_size) { - InternalWriteData()->WriteULong( - EblcTable::Offset::kIndexSubTable5_imageSize, image_size); -} - -BigGlyphMetrics::Builder* IndexSubTableFormat5::Builder::BigMetrics() { - if (metrics_ == NULL) { - WritableFontDataPtr data; - data.Attach(down_cast(InternalWriteData()->Slice( - EblcTable::Offset::kIndexSubTable5_bigGlyphMetrics, - BigGlyphMetrics::Offset::kMetricsLength))); - metrics_ = new BigGlyphMetrics::Builder(data); - set_model_changed(); - } - return metrics_; -} - -IntegerList* IndexSubTableFormat5::Builder::GlyphArray() { - return GetGlyphArray(); -} - -void IndexSubTableFormat5::Builder::SetGlyphArray(const IntegerList& v) { - glyph_array_.clear(); - glyph_array_ = v; - set_model_changed(); -} - -void IndexSubTableFormat5::Builder::Revert() { - glyph_array_.clear(); - IndexSubTable::Builder::Revert(); -} - -IndexSubTableFormat5::Builder::Builder() - : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable5_builderDataSize, - IndexSubTable::Format::FORMAT_5) { -} - -IndexSubTableFormat5::Builder::Builder(WritableFontData* data, - int32_t first_glyph_index, - int32_t last_glyph_index) - : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { -} - -IndexSubTableFormat5::Builder::Builder(ReadableFontData* data, - int32_t first_glyph_index, - int32_t last_glyph_index) - : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { -} - -IntegerList* IndexSubTableFormat5::Builder::GetGlyphArray() { - if (glyph_array_.empty()) { - Initialize(InternalReadData()); - set_model_changed(); - } - return &glyph_array_; -} - -void IndexSubTableFormat5::Builder::Initialize(ReadableFontData* data) { - glyph_array_.clear(); - if (data) { - int32_t num_glyphs = IndexSubTableFormat5::NumGlyphs(data, 0); - for (int32_t i = 0; i < num_glyphs; ++i) { - glyph_array_.push_back(data->ReadUShort( - EblcTable::Offset::kIndexSubTable5_glyphArray + - i * DataSize::kUSHORT)); - } - } -} - -// static -int32_t IndexSubTableFormat5::Builder::DataLength( - ReadableFontData* data, - int32_t index_sub_table_offset, - int32_t first_glyph_index, - int32_t last_glyph_index) { - int32_t num_glyphs = IndexSubTableFormat5::NumGlyphs(data, - index_sub_table_offset); - UNREFERENCED_PARAMETER(first_glyph_index); - UNREFERENCED_PARAMETER(last_glyph_index); - return EblcTable::Offset::kIndexSubTable5_glyphArray + - num_glyphs * DataSize::kUSHORT; -} - -/****************************************************************************** - * IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator class - ******************************************************************************/ -IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator( - IndexSubTableFormat5::Builder* container) - : RefIterator(container), - offset_index_(0) { -} - -bool IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator::HasNext() { - if (offset_index_ < (int32_t)(container()->GetGlyphArray()->size())) { - return true; - } - return false; -} - -CALLER_ATTACH BitmapGlyphInfo* -IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator::Next() { - BitmapGlyphInfoPtr output; - if (!HasNext()) { - // Note: In C++, we do not throw exception when there's no element. - return NULL; - } - output = new BitmapGlyphInfo(container()->GetGlyphArray()->at(offset_index_), - container()->image_data_offset(), - offset_index_ * container()->ImageSize(), - container()->ImageSize(), - container()->image_format()); - offset_index_++; - return output.Detach(); -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format5.h b/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format5.h deleted file mode 100644 index a39e88caca..0000000000 --- a/src/sfntly/src/sfntly/table/bitmap/index_sub_table_format5.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT5_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT5_H_ - -#include "sfntly/table/bitmap/big_glyph_metrics.h" -#include "sfntly/table/bitmap/index_sub_table.h" - -namespace sfntly { - -class IndexSubTableFormat5 : public IndexSubTable, - public RefCounted { - public: - class Builder : public IndexSubTable::Builder, - public RefCounted { - public: - class BitmapGlyphInfoIterator - : public RefIterator { - public: - explicit BitmapGlyphInfoIterator(Builder* container); - virtual ~BitmapGlyphInfoIterator() {} - - virtual bool HasNext(); - CALLER_ATTACH virtual BitmapGlyphInfo* Next(); - - private: - int32_t offset_index_; - }; - virtual ~Builder(); - virtual int32_t NumGlyphs(); - virtual int32_t GlyphLength(int32_t glyph_id); - virtual int32_t GlyphStartOffset(int32_t glyph_id); - CALLER_ATTACH virtual BitmapGlyphInfoIterator* GetIterator(); - - virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); - virtual void SubDataSet(); - virtual int32_t SubDataSizeToSerialize(); - virtual bool SubReadyToSerialize(); - virtual int32_t SubSerialize(WritableFontData* new_data); - - int32_t ImageSize(); - void SetImageSize(int32_t image_size); - BigGlyphMetrics::Builder* BigMetrics(); - IntegerList* GlyphArray(); - void SetGlyphArray(const IntegerList& v); - - static CALLER_ATTACH Builder* CreateBuilder(); - static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data, - int32_t index_sub_table_offset, - int32_t first_glyph_index, - int32_t last_glyph_index); - static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data, - int32_t index_sub_table_offset, - int32_t first_glyph_index, - int32_t last_glyph_index); - protected: - void Revert(); - - private: - Builder(); - Builder(WritableFontData* data, - int32_t first_glyph_index, - int32_t last_glyph_index); - Builder(ReadableFontData* data, - int32_t first_glyph_index, - int32_t last_glyph_index); - - IntegerList* GetGlyphArray(); - void Initialize(ReadableFontData* data); - - static int32_t DataLength(ReadableFontData* data, - int32_t index_sub_table_offset, - int32_t first_glyph_index, - int32_t last_glyph_index); - - IntegerList glyph_array_; - BigGlyphMetricsBuilderPtr metrics_; - }; - virtual ~IndexSubTableFormat5(); - - virtual int32_t NumGlyphs(); - virtual int32_t GlyphStartOffset(int32_t glyph_id); - virtual int32_t GlyphLength(int32_t glyph_id); - - int32_t ImageSize(); - CALLER_ATTACH BigGlyphMetrics* BigMetrics(); - - private: - IndexSubTableFormat5(ReadableFontData* data, - int32_t first_glyph_index, - int32_t last_glyph_index); - - static int32_t NumGlyphs(ReadableFontData* dta, int32_t table_offset); - - int32_t image_size_; - - friend class Builder; -}; -typedef Ptr IndexSubTableFormat5Ptr; -typedef Ptr IndexSubTableFormat5BuilderPtr; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT5_H_ diff --git a/src/sfntly/src/sfntly/table/bitmap/simple_bitmap_glyph.cc b/src/sfntly/src/sfntly/table/bitmap/simple_bitmap_glyph.cc deleted file mode 100644 index 87031a142b..0000000000 --- a/src/sfntly/src/sfntly/table/bitmap/simple_bitmap_glyph.cc +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 = the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/table/bitmap/simple_bitmap_glyph.h" - -namespace sfntly { - -SimpleBitmapGlyph::SimpleBitmapGlyph(ReadableFontData* data, int32_t format) - : BitmapGlyph(data, format) { -} - -SimpleBitmapGlyph::~SimpleBitmapGlyph() { -} - -SimpleBitmapGlyph::Builder::Builder(ReadableFontData* data, int32_t format) - : BitmapGlyph::Builder(data, format) { -} - -SimpleBitmapGlyph::Builder::Builder(WritableFontData* data, int32_t format) - : BitmapGlyph::Builder(data, format) { -} - -SimpleBitmapGlyph::Builder::~Builder() { -} - -CALLER_ATTACH FontDataTable* -SimpleBitmapGlyph::Builder::SubBuildTable(ReadableFontData* data) { - Ptr glyph = new SimpleBitmapGlyph(data, format()); - return glyph.Detach(); -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/bitmap/simple_bitmap_glyph.h b/src/sfntly/src/sfntly/table/bitmap/simple_bitmap_glyph.h deleted file mode 100644 index 56ede10538..0000000000 --- a/src/sfntly/src/sfntly/table/bitmap/simple_bitmap_glyph.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 = the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_SIMPLE_BITMAP_GLYPH_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_SIMPLE_BITMAP_GLYPH_H_ - -#include "sfntly/table/bitmap/bitmap_glyph.h" - -namespace sfntly { - -class SimpleBitmapGlyph : public BitmapGlyph, - public RefCounted { - public: - class Builder : public BitmapGlyph::Builder, - public RefCounted { - public: - Builder(WritableFontData* data, int32_t format); - Builder(ReadableFontData* data, int32_t format); - virtual ~Builder(); - - virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); - }; - - SimpleBitmapGlyph(ReadableFontData* data, int32_t format); - virtual ~SimpleBitmapGlyph(); -}; -typedef Ptr SimpleBitmapGlyphPtr; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_SIMPLE_BITMAP_GLYPH_H_ diff --git a/src/sfntly/src/sfntly/table/bitmap/small_glyph_metrics.cc b/src/sfntly/src/sfntly/table/bitmap/small_glyph_metrics.cc deleted file mode 100644 index 0f3c1e91d6..0000000000 --- a/src/sfntly/src/sfntly/table/bitmap/small_glyph_metrics.cc +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/table/bitmap/small_glyph_metrics.h" - -namespace sfntly { -/****************************************************************************** - * SmallGlyphMetrics class - ******************************************************************************/ -SmallGlyphMetrics::SmallGlyphMetrics(ReadableFontData* data) - : GlyphMetrics(data) { -} - -SmallGlyphMetrics::~SmallGlyphMetrics() { -} - -int32_t SmallGlyphMetrics::Height() { - return data_->ReadByte(Offset::kHeight); -} - -int32_t SmallGlyphMetrics::Width() { - return data_->ReadByte(Offset::kWidth); -} - -int32_t SmallGlyphMetrics::BearingX() { - return data_->ReadByte(Offset::kBearingX); -} - -int32_t SmallGlyphMetrics::BearingY() { - return data_->ReadByte(Offset::kBearingY); -} - -int32_t SmallGlyphMetrics::Advance() { - return data_->ReadByte(Offset::kAdvance); -} - -/****************************************************************************** - * SmallGlyphMetrics::Builder class - ******************************************************************************/ -SmallGlyphMetrics::Builder::Builder(WritableFontData* data) - : GlyphMetrics::Builder(data) { -} - -SmallGlyphMetrics::Builder::Builder(ReadableFontData* data) - : GlyphMetrics::Builder(data) { -} - -SmallGlyphMetrics::Builder::~Builder() { -} - -int32_t SmallGlyphMetrics::Builder::Height() { - return InternalReadData()->ReadByte(Offset::kHeight); -} - -void SmallGlyphMetrics::Builder::SetHeight(byte_t height) { - InternalWriteData()->WriteByte(Offset::kHeight, height); -} - -int32_t SmallGlyphMetrics::Builder::Width() { - return InternalReadData()->ReadByte(Offset::kWidth); -} - -void SmallGlyphMetrics::Builder::SetWidth(byte_t width) { - InternalWriteData()->WriteByte(Offset::kWidth, width); -} - -int32_t SmallGlyphMetrics::Builder::BearingX() { - return InternalReadData()->ReadByte(Offset::kBearingX); -} - -void SmallGlyphMetrics::Builder::SetBearingX(byte_t bearing) { - InternalWriteData()->WriteByte(Offset::kBearingX, bearing); -} - -int32_t SmallGlyphMetrics::Builder::BearingY() { - return InternalReadData()->ReadByte(Offset::kBearingY); -} - -void SmallGlyphMetrics::Builder::SetBearingY(byte_t bearing) { - InternalWriteData()->WriteByte(Offset::kBearingY, bearing); -} - -int32_t SmallGlyphMetrics::Builder::Advance() { - return InternalReadData()->ReadByte(Offset::kAdvance); -} - -void SmallGlyphMetrics::Builder::SetAdvance(byte_t advance) { - InternalWriteData()->WriteByte(Offset::kAdvance, advance); -} - -CALLER_ATTACH FontDataTable* - SmallGlyphMetrics::Builder::SubBuildTable(ReadableFontData* data) { - SmallGlyphMetricsPtr output = new SmallGlyphMetrics(data); - return output.Detach(); -} - -void SmallGlyphMetrics::Builder::SubDataSet() { - // NOP. -} - -int32_t SmallGlyphMetrics::Builder::SubDataSizeToSerialize() { - return 0; -} - -bool SmallGlyphMetrics::Builder::SubReadyToSerialize() { - return false; -} - -int32_t SmallGlyphMetrics::Builder::SubSerialize(WritableFontData* new_data) { - return Data()->CopyTo(new_data); -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/bitmap/small_glyph_metrics.h b/src/sfntly/src/sfntly/table/bitmap/small_glyph_metrics.h deleted file mode 100644 index ea13720d8f..0000000000 --- a/src/sfntly/src/sfntly/table/bitmap/small_glyph_metrics.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_SMALL_GLYPH_METRICS_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_SMALL_GLYPH_METRICS_H_ - -#include "sfntly/port/refcount.h" -#include "sfntly/table/bitmap/glyph_metrics.h" - -namespace sfntly { - -class SmallGlyphMetrics : public GlyphMetrics, - public RefCounted { - public: - struct Offset { - enum { - kMetricsLength = 5, - kHeight = 0, - kWidth = 1, - kBearingX = 2, - kBearingY = 3, - kAdvance = 4, - }; - }; - - class Builder : public GlyphMetrics::Builder, - public RefCounted { - public: - // Constructor scope altered to public because C++ does not allow base - // class to instantiate derived class with protected constructors. - explicit Builder(WritableFontData* data); - explicit Builder(ReadableFontData* data); - virtual ~Builder(); - - int32_t Height(); - void SetHeight(byte_t height); - int32_t Width(); - void SetWidth(byte_t width); - int32_t BearingX(); - void SetBearingX(byte_t bearing); - int32_t BearingY(); - void SetBearingY(byte_t bearing); - int32_t Advance(); - void SetAdvance(byte_t advance); - - virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); - virtual void SubDataSet(); - virtual int32_t SubDataSizeToSerialize(); - virtual bool SubReadyToSerialize(); - virtual int32_t SubSerialize(WritableFontData* new_data); - }; - - explicit SmallGlyphMetrics(ReadableFontData* data); - virtual ~SmallGlyphMetrics(); - - int32_t Height(); - int32_t Width(); - int32_t BearingX(); - int32_t BearingY(); - int32_t Advance(); -}; -typedef Ptr SmallGlyphMetricsPtr; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_SMALL_GLYPH_METRICS_H_ diff --git a/src/sfntly/src/sfntly/table/byte_array_table_builder.cc b/src/sfntly/src/sfntly/table/byte_array_table_builder.cc deleted file mode 100644 index 631a05fdd6..0000000000 --- a/src/sfntly/src/sfntly/table/byte_array_table_builder.cc +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/table/byte_array_table_builder.h" - -namespace sfntly { - -ByteArrayTableBuilder::~ByteArrayTableBuilder() {} - -int32_t ByteArrayTableBuilder::ByteValue(int32_t index) { - ReadableFontDataPtr data = InternalReadData(); - if (data == NULL) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IOException("No font data for the table"); -#endif - return -1; - } - return data->ReadByte(index); -} - -void ByteArrayTableBuilder::SetByteValue(int32_t index, byte_t b) { - WritableFontDataPtr data = InternalWriteData(); - if (data == NULL) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IOException("No font data for the table"); -#endif - return; - } - data->WriteByte(index, b); -} - -int32_t ByteArrayTableBuilder::ByteCount() { - ReadableFontDataPtr data = InternalReadData(); - if (data == NULL) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IOException("No font data for the table"); -#endif - return 0; - } - return data->Length(); -} - -ByteArrayTableBuilder::ByteArrayTableBuilder(Header* header, - WritableFontData* data) - : TableBasedTableBuilder(header, data) { -} - -ByteArrayTableBuilder::ByteArrayTableBuilder(Header* header, - ReadableFontData* data) - : TableBasedTableBuilder(header, data) { -} - -ByteArrayTableBuilder::ByteArrayTableBuilder(Header* header) - : TableBasedTableBuilder(header) { -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/byte_array_table_builder.h b/src/sfntly/src/sfntly/table/byte_array_table_builder.h deleted file mode 100644 index 42d27a8df0..0000000000 --- a/src/sfntly/src/sfntly/table/byte_array_table_builder.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BYTE_ARRAY_TABLE_BUILDER_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BYTE_ARRAY_TABLE_BUILDER_H_ - -#include "sfntly/table/table_based_table_builder.h" - -namespace sfntly { - -// An abstract builder base for byte array based tables. -class ByteArrayTableBuilder : public TableBasedTableBuilder { - public: - virtual ~ByteArrayTableBuilder(); - - // Get the byte value at the specified index. The index is relative to the - // start of the table. - // @param index index relative to the start of the table - // @return byte value at the given index - virtual int32_t ByteValue(int32_t index); - - // Set the byte value at the specified index. The index is relative to the - // start of the table. - // @param index index relative to the start of the table - // @param b byte value to set - virtual void SetByteValue(int32_t index, byte_t b); - - // Get the number of bytes set for this table. It may include padding bytes at - // the end. - virtual int32_t ByteCount(); - - protected: - ByteArrayTableBuilder(Header* header, WritableFontData* data); - ByteArrayTableBuilder(Header* header, ReadableFontData* data); - explicit ByteArrayTableBuilder(Header* header); -}; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BYTE_ARRAY_TABLE_BUILDER_H_ diff --git a/src/sfntly/src/sfntly/table/core/cmap_table.cc b/src/sfntly/src/sfntly/table/core/cmap_table.cc deleted file mode 100644 index 0b4f89a2bd..0000000000 --- a/src/sfntly/src/sfntly/table/core/cmap_table.cc +++ /dev/null @@ -1,1288 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// type.h needs to be included first because of building issues on Windows -// Type aliases we delcare are defined in other headers and make the build -// fail otherwise. -#include "sfntly/port/type.h" -#include "sfntly/table/core/cmap_table.h" - -#include -#include - -#include - -#include "sfntly/font.h" -#include "sfntly/math/font_math.h" -#include "sfntly/port/endian.h" -#include "sfntly/port/exception_type.h" -#include "sfntly/table/core/name_table.h" - -namespace sfntly { - -const int32_t CMapTable::NOTDEF = 0; - -CMapTable::CMapId CMapTable::WINDOWS_BMP = { - PlatformId::kWindows, - WindowsEncodingId::kUnicodeUCS2 -}; -CMapTable::CMapId CMapTable::WINDOWS_UCS4 = { - PlatformId::kWindows, - WindowsEncodingId::kUnicodeUCS4 -}; -CMapTable::CMapId CMapTable::MAC_ROMAN = { - PlatformId::kWindows, - MacintoshEncodingId::kRoman -}; - -/****************************************************************************** - * CMapTable class - ******************************************************************************/ -CMapTable::CMapTable(Header* header, ReadableFontData* data) - : SubTableContainerTable(header, data) { -} - -CMapTable::~CMapTable() {} - -CALLER_ATTACH CMapTable::CMap* CMapTable::GetCMap(const int32_t index) { - if (index < 0 || index > NumCMaps()) { -#ifndef SFNTLY_NO_EXCEPTION - throw IndexOutOfBoundException("Requested CMap index is out of bounds."); -#else - return NULL; -#endif - } - int32_t platform_id = PlatformId(index); - int32_t encoding_id = EncodingId(index); - CMapId cmap_id = NewCMapId(platform_id, encoding_id); - int32_t offset_ = Offset(index); - Ptr cmap_builder = - (CMap::Builder::GetBuilder(data_, offset_, cmap_id)); - if (!cmap_builder) { -#ifndef SFNTLY_NO_EXCEPTION - throw NoSuchElementException("Cannot find builder for requested CMap."); -#else - return NULL; -#endif - } - return down_cast(cmap_builder->Build()); -} - -CALLER_ATTACH CMapTable::CMap* CMapTable::GetCMap(const int32_t platform_id, - const int32_t encoding_id) { - return GetCMap(NewCMapId(platform_id, encoding_id)); -} - -CALLER_ATTACH CMapTable::CMap* -CMapTable::GetCMap(const CMapTable::CMapId cmap_id) { - CMapIdFilter id_filter(cmap_id); - CMapIterator cmap_iterator(this, &id_filter); - // There can only be one cmap with a particular CMapId - if (cmap_iterator.HasNext()) { - Ptr cmap; - cmap.Attach(cmap_iterator.Next()); - return cmap.Detach(); - } -#ifndef SFNTLY_NO_EXCEPTION - throw NoSuchElementException(); -#else - return NULL; -#endif -} - -int32_t CMapTable::Version() { - return data_->ReadUShort(Offset::kVersion); -} - -int32_t CMapTable::NumCMaps() { - return data_->ReadUShort(Offset::kNumTables); -} - -CMapTable::CMapId CMapTable::GetCMapId(int32_t index) { - return NewCMapId(PlatformId(index), EncodingId(index)); -} - -int32_t CMapTable::PlatformId(int32_t index) { - return data_->ReadUShort(Offset::kEncodingRecordPlatformId + - OffsetForEncodingRecord(index)); -} - -int32_t CMapTable::EncodingId(int32_t index) { - return data_->ReadUShort(Offset::kEncodingRecordEncodingId + - OffsetForEncodingRecord(index)); -} - -int32_t CMapTable::Offset(int32_t index) { - return data_->ReadULongAsInt(Offset::kEncodingRecordOffset + - OffsetForEncodingRecord(index)); -} - -int32_t CMapTable::OffsetForEncodingRecord(int32_t index) { - return Offset::kEncodingRecordStart + index * Offset::kEncodingRecordSize; -} - -CMapTable::CMapId CMapTable::NewCMapId(int32_t platform_id, - int32_t encoding_id) { - CMapId result; - result.platform_id = platform_id; - result.encoding_id = encoding_id; - return result; -} - -CMapTable::CMapId CMapTable::NewCMapId(const CMapId& obj) { - CMapId result; - result.platform_id = obj.platform_id; - result.encoding_id = obj.encoding_id; - return result; -} - -/****************************************************************************** - * CMapTable::CMapIterator class - ******************************************************************************/ -CMapTable::CMapIterator::CMapIterator(CMapTable* table, - const CMapFilter* filter) - : table_index_(0), filter_(filter), table_(table) { -} - -bool CMapTable::CMapIterator::HasNext() { - if (!filter_) { - if (table_index_ < table_->NumCMaps()) { - return true; - } - return false; - } - - for (; table_index_ < table_->NumCMaps(); ++table_index_) { - if (filter_->accept(table_->GetCMapId(table_index_))) { - return true; - } - } - return false; -} - -CALLER_ATTACH CMapTable::CMap* CMapTable::CMapIterator::Next() { - if (!HasNext()) { -#ifndef SFNTLY_NO_EXCEPTION - throw NoSuchElementException(); -#else - return NULL; -#endif - } - CMapPtr next_cmap; - next_cmap.Attach(table_->GetCMap(table_index_++)); - if (next_cmap == NULL) { -#ifndef SFNTLY_NO_EXCEPTION - throw NoSuchElementException("Error during the creation of the CMap"); -#else - return NULL; -#endif - } - return next_cmap.Detach(); -} - -/****************************************************************************** - * CMapTable::CMapId class - ******************************************************************************/ - -/****************************************************************************** - * CMapTable::CMapIdComparator class - ******************************************************************************/ - -bool CMapTable::CMapIdComparator::operator()(const CMapId& lhs, - const CMapId& rhs) const { - return ((lhs.platform_id << 8 | lhs.encoding_id) > - (rhs.platform_id << 8 | rhs.encoding_id)); -} - -/****************************************************************************** - * CMapTable::CMapIdFilter class - ******************************************************************************/ -CMapTable::CMapIdFilter::CMapIdFilter(const CMapId wanted_id) - : wanted_id_(wanted_id), - comparator_(NULL) { -} - -CMapTable::CMapIdFilter::CMapIdFilter(const CMapId wanted_id, - const CMapIdComparator* comparator) - : wanted_id_(wanted_id), - comparator_(comparator) { -} - -bool CMapTable::CMapIdFilter::accept(const CMapId& cmap_id) const { - if (!comparator_) - return wanted_id_ == cmap_id; - return (*comparator_)(wanted_id_, cmap_id); -} - -/****************************************************************************** - * CMapTable::CMap class - ******************************************************************************/ -CMapTable::CMap::CMap(ReadableFontData* data, int32_t format, - const CMapId& cmap_id) - : SubTable(data), format_(format), cmap_id_(cmap_id) { -} - -CMapTable::CMap::~CMap() { -} - -/****************************************************************************** - * CMapTable::CMap::Builder class - ******************************************************************************/ -CMapTable::CMap::Builder::~Builder() { -} - -CALLER_ATTACH CMapTable::CMap::Builder* - CMapTable::CMap::Builder::GetBuilder(ReadableFontData* data, int32_t offset, - const CMapId& cmap_id) { - // NOT IMPLEMENTED: Java enum value validation - int32_t format = data->ReadUShort(offset); - CMapBuilderPtr builder; - switch (format) { - case CMapFormat::kFormat0: - builder.Attach(CMapFormat0::Builder::NewInstance(data, offset, cmap_id)); - break; - case CMapFormat::kFormat2: -#if defined (SFNTLY_DEBUG_CMAP) - fprintf(stderr, "Requesting Format2 builder, but it's unsupported; " - "returning NULL\n"); -#endif - break; - case CMapFormat::kFormat4: - builder.Attach(CMapFormat4::Builder::NewInstance(data, offset, cmap_id)); - break; - default: -#ifdef SFNTLY_DEBUG_CMAP - fprintf(stderr, "Unknown builder format requested\n"); -#endif - break; - } - return builder.Detach(); -} - -CALLER_ATTACH CMapTable::CMap::Builder* -CMapTable::CMap::Builder::GetBuilder(int32_t format, const CMapId& cmap_id) { - Ptr builder; - switch (format) { - case CMapFormat::kFormat0: - builder.Attach(CMapFormat0::Builder::NewInstance(cmap_id)); - break; - case CMapFormat::kFormat2: -#if defined (SFNTLY_DEBUG_CMAP) - fprintf(stderr, "Requesting Format2 builder, but it's unsupported; " - "returning NULL\n"); -#endif - break; - case CMapFormat::kFormat4: - builder.Attach(CMapFormat4::Builder::NewInstance(cmap_id)); - break; - default: -#ifdef SFNTLY_DEBUG_CMAP - fprintf(stderr, "Unknown builder format requested\n"); -#endif - break; - } - return builder.Detach(); -} - -CMapTable::CMap::Builder::Builder(ReadableFontData* data, - int32_t format, - const CMapId& cmap_id) - : SubTable::Builder(data), - format_(format), - cmap_id_(cmap_id), - language_(0) { -} - -CMapTable::CMap::Builder::Builder(WritableFontData* data, - int32_t format, - const CMapId& cmap_id) - : SubTable::Builder(data), - format_(format), - cmap_id_(cmap_id), - language_(0) { -} - -int32_t CMapTable::CMap::Builder::SubSerialize(WritableFontData* new_data) { - return InternalReadData()->CopyTo(new_data); -} - -bool CMapTable::CMap::Builder::SubReadyToSerialize() { - return true; -} - -int32_t CMapTable::CMap::Builder::SubDataSizeToSerialize() { - ReadableFontDataPtr read_data = InternalReadData(); - if (!read_data) - return 0; - return read_data->Length(); -} - -void CMapTable::CMap::Builder::SubDataSet() { - // NOP -} - -/****************************************************************************** - * CMapTable::CMapFormat0 - ******************************************************************************/ -CMapTable::CMapFormat0::~CMapFormat0() { -} - -int32_t CMapTable::CMapFormat0::Language() { - return 0; -} - -int32_t CMapTable::CMapFormat0::GlyphId(int32_t character) { - if (character < 0 || character > 255) { - return CMapTable::NOTDEF; - } - return data_->ReadUByte(character + Offset::kFormat0GlyphIdArray); -} - -CMapTable::CMapFormat0::CMapFormat0(ReadableFontData* data, - const CMapId& cmap_id) - : CMap(data, CMapFormat::kFormat0, cmap_id) { -} - -CMapTable::CMap::CharacterIterator* CMapTable::CMapFormat0::Iterator() { - return new CMapTable::CMapFormat0::CharacterIterator(0, 0xff); -} - - -/****************************************************************************** - * CMapTable::CMapFormat0::CharacterIterator - ******************************************************************************/ -CMapTable::CMapFormat0::CharacterIterator::CharacterIterator(int32_t start, - int32_t end) - : character_(start), - max_character_(end) { -} - -CMapTable::CMapFormat0::CharacterIterator::~CharacterIterator() {} - -bool CMapTable::CMapFormat0::CharacterIterator::HasNext() { - return character_ < max_character_; -} - -int32_t CMapTable::CMapFormat0::CharacterIterator::Next() { - if (HasNext()) - return character_++; -#ifndef SFNTLY_NO_EXCEPTION - throw NoSuchElementException("No more characters to iterate."); -#endif - return -1; -} - -/****************************************************************************** - * CMapTable::CMapFormat0::Builder - ******************************************************************************/ -// static -CALLER_ATTACH CMapTable::CMapFormat0::Builder* -CMapTable::CMapFormat0::Builder::NewInstance(WritableFontData* data, - int32_t offset, - const CMapId& cmap_id) { - WritableFontDataPtr wdata; - if (data) { - wdata.Attach(down_cast( - data->Slice(offset, - data->ReadUShort(offset + Offset::kFormat0Length)))); - } - return new Builder(wdata, CMapFormat::kFormat0, cmap_id); -} - -// static -CALLER_ATTACH CMapTable::CMapFormat0::Builder* -CMapTable::CMapFormat0::Builder::NewInstance(ReadableFontData* data, - int32_t offset, - const CMapId& cmap_id) { - ReadableFontDataPtr rdata; - if (data) { - rdata.Attach(down_cast( - data->Slice(offset, - data->ReadUShort(offset + Offset::kFormat0Length)))); - } - return new Builder(rdata, CMapFormat::kFormat0, cmap_id); -} - -// static -CALLER_ATTACH CMapTable::CMapFormat0::Builder* -CMapTable::CMapFormat0::Builder::NewInstance(const CMapId& cmap_id) { - return new Builder(cmap_id); -} - -// Always call NewInstance instead of the constructor for creating a new builder -// object! This refactoring avoids memory leaks when slicing the font data. -CMapTable::CMapFormat0::Builder::Builder(WritableFontData* data, int32_t offset, - const CMapId& cmap_id) - : CMapTable::CMap::Builder(data, CMapFormat::kFormat0, cmap_id) { - UNREFERENCED_PARAMETER(offset); -} - -CMapTable::CMapFormat0::Builder::Builder( - ReadableFontData* data, - int32_t offset, - const CMapId& cmap_id) - : CMapTable::CMap::Builder(data, CMapFormat::kFormat0, cmap_id) { - UNREFERENCED_PARAMETER(offset); -} - -CMapTable::CMapFormat0::Builder::Builder(const CMapId& cmap_id) - : CMap::Builder(reinterpret_cast(NULL), - CMapFormat::kFormat0, - cmap_id) { -} - -CMapTable::CMapFormat0::Builder::~Builder() { -} - -CALLER_ATTACH FontDataTable* - CMapTable::CMapFormat0::Builder::SubBuildTable(ReadableFontData* data) { - FontDataTablePtr table = new CMapFormat0(data, cmap_id()); - return table.Detach(); -} - -/****************************************************************************** - * CMapTable::CMapFormat2 - ******************************************************************************/ -CMapTable::CMapFormat2::~CMapFormat2() { -} - -int32_t CMapTable::CMapFormat2::Language() { - return 0; -} - -int32_t CMapTable::CMapFormat2::GlyphId(int32_t character) { - if (character > 0xffff) { - return CMapTable::NOTDEF; - } - - uint32_t c = ToBE32(character); - byte_t high_byte = (c >> 8) & 0xff; - byte_t low_byte = c & 0xff; - int32_t offset = SubHeaderOffset(high_byte); - - if (offset == 0) { - low_byte = high_byte; - high_byte = 0; - } - - int32_t first_code = FirstCode(high_byte); - int32_t entry_count = EntryCount(high_byte); - - if (low_byte < first_code || low_byte >= first_code + entry_count) { - return CMapTable::NOTDEF; - } - - int32_t id_range_offset = IdRangeOffset(high_byte); - - // position of idRangeOffset + value of idRangeOffset + index for low byte - // = firstcode - int32_t p_location = (offset + Offset::kFormat2SubHeader_idRangeOffset) + - id_range_offset + - (low_byte - first_code) * DataSize::kUSHORT; - int p = data_->ReadUShort(p_location); - if (p == 0) { - return CMapTable::NOTDEF; - } - - if (offset == 0) { - return p; - } - int id_delta = IdDelta(high_byte); - return (p + id_delta) % 65536; -} - -int32_t CMapTable::CMapFormat2::BytesConsumed(int32_t character) { - uint32_t c = ToBE32(character); - int32_t high_byte = (c >> 8) & 0xff; - int32_t offset = SubHeaderOffset(high_byte); - return (offset == 0) ? 1 : 2; -} - -CMapTable::CMapFormat2::CMapFormat2(ReadableFontData* data, - const CMapId& cmap_id) - : CMap(data, CMapFormat::kFormat2, cmap_id) { -} - -int32_t CMapTable::CMapFormat2::SubHeaderOffset(int32_t sub_header_index) { - return data_->ReadUShort(Offset::kFormat2SubHeaderKeys + - sub_header_index * DataSize::kUSHORT); -} - -int32_t CMapTable::CMapFormat2::FirstCode(int32_t sub_header_index) { - int32_t sub_header_offset = SubHeaderOffset(sub_header_index); - return data_->ReadUShort(sub_header_offset + - Offset::kFormat2SubHeaderKeys + - Offset::kFormat2SubHeader_firstCode); -} - -int32_t CMapTable::CMapFormat2::EntryCount(int32_t sub_header_index) { - int32_t sub_header_offset = SubHeaderOffset(sub_header_index); - return data_->ReadUShort(sub_header_offset + - Offset::kFormat2SubHeaderKeys + - Offset::kFormat2SubHeader_entryCount); -} - -int32_t CMapTable::CMapFormat2::IdRangeOffset(int32_t sub_header_index) { - int32_t sub_header_offset = SubHeaderOffset(sub_header_index); - return data_->ReadUShort(sub_header_offset + - Offset::kFormat2SubHeaderKeys + - Offset::kFormat2SubHeader_idRangeOffset); -} - -int32_t CMapTable::CMapFormat2::IdDelta(int32_t sub_header_index) { - int32_t sub_header_offset = SubHeaderOffset(sub_header_index); - return data_->ReadUShort(sub_header_offset + - Offset::kFormat2SubHeaderKeys + - Offset::kFormat2SubHeader_idDelta); -} - -CMapTable::CMap::CharacterIterator* CMapTable::CMapFormat2::Iterator() { - // UNIMPLEMENTED - return NULL; -} - -/****************************************************************************** - * CMapTable::CMapFormat2::Builder - ******************************************************************************/ -CMapTable::CMapFormat2::Builder::Builder(WritableFontData* data, - int32_t offset, - const CMapId& cmap_id) - : CMapTable::CMap::Builder(data ? down_cast( - data->Slice(offset, data->ReadUShort( - offset + Offset::kFormat0Length))) - : reinterpret_cast(NULL), - CMapFormat::kFormat2, cmap_id) { - // TODO(arthurhsu): FIXIT: heavy lifting and leak, need fix. -} - -CMapTable::CMapFormat2::Builder::Builder(ReadableFontData* data, - int32_t offset, - const CMapId& cmap_id) - : CMapTable::CMap::Builder(data ? down_cast( - data->Slice(offset, data->ReadUShort( - offset + Offset::kFormat0Length))) - : reinterpret_cast(NULL), - CMapFormat::kFormat2, cmap_id) { - // TODO(arthurhsu): FIXIT: heavy lifting and leak, need fix. -} - -CMapTable::CMapFormat2::Builder::~Builder() { -} - -CALLER_ATTACH FontDataTable* - CMapTable::CMapFormat2::Builder::SubBuildTable(ReadableFontData* data) { - FontDataTablePtr table = new CMapFormat2(data, cmap_id()); - return table.Detach(); -} - -/****************************************************************************** - * CMapTable::CMapFormat4 - ******************************************************************************/ -CMapTable::CMapFormat4::CMapFormat4(ReadableFontData* data, - const CMapId& cmap_id) - : CMap(data, CMapFormat::kFormat4, cmap_id), - seg_count_(SegCount(data)), - start_code_offset_(StartCodeOffset(seg_count_)), - end_code_offset_(Offset::kFormat4EndCount), - id_delta_offset_(IdDeltaOffset(seg_count_)), - glyph_id_array_offset_(GlyphIdArrayOffset(seg_count_)) { -} - -CMapTable::CMapFormat4::~CMapFormat4() { -} - -int32_t CMapTable::CMapFormat4::GlyphId(int32_t character) { - int32_t segment = data_->SearchUShort(StartCodeOffset(seg_count_), - DataSize::kUSHORT, - Offset::kFormat4EndCount, - DataSize::kUSHORT, - seg_count_, - character); - if (segment == -1) { - return CMapTable::NOTDEF; - } - int32_t start_code = StartCode(segment); - return RetrieveGlyphId(segment, start_code, character); -} - -int32_t CMapTable::CMapFormat4::RetrieveGlyphId(int32_t segment, - int32_t start_code, - int32_t character) { - if (character < start_code) { - return CMapTable::NOTDEF; - } - int32_t id_range_offset = IdRangeOffset(segment); - if (id_range_offset == 0) { - return (character + IdDelta(segment)) % 65536; - } - return data_->ReadUShort(id_range_offset + - IdRangeOffsetLocation(segment) + - 2 * (character - start_code)); -} - -int32_t CMapTable::CMapFormat4::seg_count() { - return seg_count_; -} - -int32_t CMapTable::CMapFormat4::Length() { - return Length(data_); -} - -int32_t CMapTable::CMapFormat4::StartCode(int32_t segment) { - if (!IsValidIndex(segment)) { - return -1; - } - return StartCode(data_.p_, seg_count_, segment); -} - -// static -int32_t CMapTable::CMapFormat4::Language(ReadableFontData* data) { - int32_t language = data->ReadUShort(Offset::kFormat4Language); - return language; -} - -// static -int32_t CMapTable::CMapFormat4::Length(ReadableFontData* data) { - int32_t length = data->ReadUShort(Offset::kFormat4Length); - return length; -} - -// static -int32_t CMapTable::CMapFormat4::SegCount(ReadableFontData* data) { - int32_t seg_count = data->ReadUShort(Offset::kFormat4SegCountX2) / 2; - return seg_count; -} - -// static -int32_t CMapTable::CMapFormat4::StartCode(ReadableFontData* data, - int32_t seg_count, - int32_t index) { - int32_t start_code = data->ReadUShort(StartCodeOffset(seg_count) + - index * DataSize::kUSHORT); - return start_code; -} - -// static -int32_t CMapTable::CMapFormat4::StartCodeOffset(int32_t seg_count) { - int32_t start_code_offset = Offset::kFormat4EndCount + - (seg_count + 1) * DataSize::kUSHORT; - return start_code_offset; -} - -// static -int32_t CMapTable::CMapFormat4::EndCode(ReadableFontData* data, - int32_t seg_count, - int32_t index) { - UNREFERENCED_PARAMETER(seg_count); - int32_t end_code = data->ReadUShort(Offset::kFormat4EndCount + - index * DataSize::kUSHORT); - return end_code; -} - -// static -int32_t CMapTable::CMapFormat4::IdDelta(ReadableFontData* data, - int32_t seg_count, - int32_t index) { - int32_t id_delta = data->ReadUShort(IdDeltaOffset(seg_count) + - index * DataSize::kUSHORT); - return id_delta; -} - -// static -int32_t CMapTable::CMapFormat4::IdDeltaOffset(int32_t seg_count) { - int32_t id_delta_offset = - Offset::kFormat4EndCount + (2 * seg_count + 1) * DataSize::kUSHORT; - return id_delta_offset; -} - -// static -int32_t CMapTable::CMapFormat4::IdRangeOffset(ReadableFontData* data, - int32_t seg_count, - int32_t index) { - int32_t id_range_offset = - data->ReadUShort(IdRangeOffsetOffset(seg_count) - + index * DataSize::kUSHORT); - return id_range_offset; -} - -// static -int32_t CMapTable::CMapFormat4::IdRangeOffsetOffset(int32_t seg_count) { - int32_t id_range_offset_offset = - Offset::kFormat4EndCount + (2 * seg_count + 1) * DataSize::kUSHORT + - seg_count * DataSize::kSHORT; - return id_range_offset_offset; -} - -// static -int32_t CMapTable::CMapFormat4::GlyphIdArrayOffset(int32_t seg_count) { - int32_t glyph_id_array_offset = - Offset::kFormat4EndCount + (3 * seg_count + 1) * DataSize::kUSHORT + - seg_count * DataSize::kSHORT; - return glyph_id_array_offset; -} - -int32_t CMapTable::CMapFormat4::EndCode(int32_t segment) { - if (IsValidIndex(segment)) { - return EndCode(data_, seg_count_, segment); - } -#if defined (SFNTLY_NO_EXCEPTION) - return -1; -#else - throw IllegalArgumentException(); -#endif -} - -bool CMapTable::CMapFormat4::IsValidIndex(int32_t segment) { - if (segment < 0 || segment >= seg_count_) { -#if defined (SFNTLY_NO_EXCEPTION) - return false; -#else - throw IllegalArgumentException(); -#endif - } - return true; -} - -int32_t CMapTable::CMapFormat4::IdDelta(int32_t segment) { - if (IsValidIndex(segment)) - return IdDelta(data_, seg_count_, segment); - return -1; -} - -int32_t CMapTable::CMapFormat4::IdRangeOffset(int32_t segment) { - if (IsValidIndex(segment)) - return data_->ReadUShort(IdRangeOffsetLocation(segment)); - return -1; -} - -int32_t CMapTable::CMapFormat4::IdRangeOffsetLocation(int32_t segment) { - if (IsValidIndex(segment)) - return IdRangeOffsetOffset(seg_count_) + segment * DataSize::kUSHORT; - return -1; -} - -int32_t CMapTable::CMapFormat4::GlyphIdArray(int32_t index) { - return data_->ReadUShort(glyph_id_array_offset_ + index * DataSize::kUSHORT); -} - -int32_t CMapTable::CMapFormat4::Language() { - return Language(data_); -} - - -CMapTable::CMap::CharacterIterator* CMapTable::CMapFormat4::Iterator() { - return new CharacterIterator(this); -} - -/****************************************************************************** - * CMapTable::CMapFormat4::CharacterIterator class - ******************************************************************************/ -CMapTable::CMapFormat4::CharacterIterator::CharacterIterator( - CMapFormat4* parent) - : parent_(parent), - segment_index_(0), - first_char_in_segment_(-1), - last_char_in_segment_(-1), - next_char_(-1), - next_char_set_(false) { -} - -bool CMapTable::CMapFormat4::CharacterIterator::HasNext() { - if (next_char_set_) - return true; - while (segment_index_ < parent_->seg_count_) { - if (first_char_in_segment_ < 0) { - first_char_in_segment_ = parent_->StartCode(segment_index_); - last_char_in_segment_ = parent_->EndCode(segment_index_); - next_char_ = first_char_in_segment_; - next_char_set_ = true; - return true; - } - if (next_char_ < last_char_in_segment_) { - next_char_++; - next_char_set_ = true; - return true; - } - segment_index_++; - first_char_in_segment_ = -1; - } - return false; -} - -int32_t CMapTable::CMapFormat4::CharacterIterator::Next() { - if (!next_char_set_) { - if (!HasNext()) { -#if defined (SFNTLY_NO_EXCEPTION) - return -1; -#else - throw NoSuchElementException("No more characters to iterate."); -#endif - } - } - next_char_set_ = false; - return next_char_; -} - -/****************************************************************************** - * CMapTable::CMapFormat4::Builder::Segment class - ******************************************************************************/ -CMapTable::CMapFormat4::Builder::Segment::Segment() {} - -CMapTable::CMapFormat4::Builder::Segment::Segment(Segment* other) - : start_count_(other->start_count_), - end_count_(other->end_count_), - id_delta_(other->id_delta_), - id_range_offset_(other->id_range_offset_) { -} - -CMapTable::CMapFormat4::Builder::Segment::Segment(int32_t start_count, - int32_t end_count, - int32_t id_delta, - int32_t id_range_offset) - : start_count_(start_count), - end_count_(end_count), - id_delta_(id_delta), - id_range_offset_(id_range_offset) { -} - -CMapTable::CMapFormat4::Builder::Segment::~Segment() {} - -int32_t CMapTable::CMapFormat4::Builder::Segment::start_count() { - return start_count_; -} - -void -CMapTable::CMapFormat4::Builder::Segment::set_start_count(int32_t start_count) { - start_count_ = start_count; -} - -int32_t CMapTable::CMapFormat4::Builder::Segment::end_count() { - return end_count_; -} - -void -CMapTable::CMapFormat4::Builder::Segment::set_end_count(int32_t end_count) { - end_count_ = end_count; -} - -int32_t CMapTable::CMapFormat4::Builder::Segment::id_delta() { - return id_delta_; -} - -void -CMapTable::CMapFormat4::Builder::Segment::set_id_delta(int32_t id_delta) { - id_delta_ = id_delta; -} - -int32_t CMapTable::CMapFormat4::Builder::Segment::id_range_offset() { - return id_range_offset_; -} - -void -CMapTable::CMapFormat4::Builder::Segment:: -set_id_range_offset(int32_t id_range_offset) { - id_range_offset_ = id_range_offset; -} - -// static -CALLER_ATTACH SegmentList* -CMapTable::CMapFormat4::Builder::Segment::DeepCopy(SegmentList* original) { - SegmentList* list = new SegmentList; - for (SegmentList::iterator it = original->begin(), - e = original->end(); it != e; ++it) { - list->push_back(*it); - } - return list; -} - -/****************************************************************************** - * CMapTable::CMapFormat4::Builder class - ******************************************************************************/ -CALLER_ATTACH CMapTable::CMapFormat4::Builder* -CMapTable::CMapFormat4::Builder::NewInstance(ReadableFontData* data, - int32_t offset, - const CMapId& cmap_id) { - ReadableFontDataPtr rdata; - if (data) { - rdata.Attach - (down_cast - (data->Slice(offset, - data->ReadUShort(offset + Offset::kFormat4Length)))); - } - return new Builder(rdata, CMapFormat::kFormat4, cmap_id); -} - -CALLER_ATTACH CMapTable::CMapFormat4::Builder* -CMapTable::CMapFormat4::Builder::NewInstance(WritableFontData* data, - int32_t offset, - const CMapId& cmap_id) { - WritableFontDataPtr wdata; - if (data) { - wdata.Attach - (down_cast - (data->Slice(offset, - data->ReadUShort(offset + Offset::kFormat4Length)))); - } - return new Builder(wdata, CMapFormat::kFormat4, cmap_id); -} - -CALLER_ATTACH CMapTable::CMapFormat4::Builder* -CMapTable::CMapFormat4::Builder::NewInstance(const CMapId& cmap_id) { - return new Builder(cmap_id); -} - -CMapTable::CMapFormat4::Builder::Builder(ReadableFontData* data, int32_t offset, - const CMapId& cmap_id) - : CMap::Builder(data, CMapFormat::kFormat4, cmap_id) { - UNREFERENCED_PARAMETER(offset); -} - -CMapTable::CMapFormat4::Builder::Builder(WritableFontData* data, int32_t offset, - const CMapId& cmap_id) - : CMap::Builder(data, CMapFormat::kFormat4, cmap_id) { - UNREFERENCED_PARAMETER(offset); -} - -CMapTable::CMapFormat4::Builder::Builder(SegmentList* segments, - IntegerList* glyph_id_array, - const CMapId& cmap_id) - : CMap::Builder(reinterpret_cast(NULL), - CMapFormat::kFormat4, cmap_id), - segments_(segments->begin(), segments->end()), - glyph_id_array_(glyph_id_array->begin(), glyph_id_array->end()) { - set_model_changed(); -} - -CMapTable::CMapFormat4::Builder::Builder(const CMapId& cmap_id) - : CMap::Builder(reinterpret_cast(NULL), - CMapFormat::kFormat4, cmap_id) { -} - -CMapTable::CMapFormat4::Builder::~Builder() {} - -void CMapTable::CMapFormat4::Builder::Initialize(ReadableFontData* data) { - if (data == NULL || data->Length() == 0) - return; - - // build segments - int32_t seg_count = CMapFormat4::SegCount(data); - for (int32_t index = 0; index < seg_count; ++index) { - Ptr segment = new Segment; - segment->set_start_count(CMapFormat4::StartCode(data, seg_count, index)); -#if defined SFNTLY_DEBUG_CMAP - fprintf(stderr, "Segment %d; start %d\n", index, segment->start_count()); -#endif - segment->set_end_count(CMapFormat4::EndCode(data, seg_count, index)); - segment->set_id_delta(CMapFormat4::IdDelta(data, seg_count, index)); - segment->set_id_range_offset(CMapFormat4::IdRangeOffset(data, - seg_count, - index)); - segments_.push_back(segment); - } - - // build glyph id array - int32_t glyph_id_array_offset = CMapFormat4::GlyphIdArrayOffset(seg_count); - int32_t glyph_id_array_length = - (CMapFormat4::Length(data) - glyph_id_array_offset) - / DataSize::kUSHORT; - fprintf(stderr, "id array size %d\n", glyph_id_array_length); - for (int32_t i = 0; i < glyph_id_array_length; i += DataSize::kUSHORT) { - glyph_id_array_.push_back(data->ReadUShort(glyph_id_array_offset + i)); - } -} - -SegmentList* CMapTable::CMapFormat4::Builder::segments() { - if (segments_.empty()) { - Initialize(InternalReadData()); - set_model_changed(); - } - return &segments_; -} - -void CMapTable::CMapFormat4::Builder::set_segments(SegmentList* segments) { - segments_.assign(segments->begin(), segments->end()); - set_model_changed(); -} - -IntegerList* CMapTable::CMapFormat4::Builder::glyph_id_array() { - if (glyph_id_array_.empty()) { - Initialize(InternalReadData()); - set_model_changed(); - } - return &glyph_id_array_; -} - -void CMapTable::CMapFormat4::Builder:: -set_glyph_id_array(IntegerList* glyph_id_array) { - glyph_id_array_.assign(glyph_id_array->begin(), glyph_id_array->end()); - set_model_changed(); -} - -CALLER_ATTACH FontDataTable* -CMapTable::CMapFormat4::Builder::SubBuildTable(ReadableFontData* data) { - FontDataTablePtr table = new CMapFormat4(data, cmap_id()); - return table.Detach(); -} - -void CMapTable::CMapFormat4::Builder::SubDataSet() { - segments_.clear(); - glyph_id_array_.clear(); - set_model_changed(); -} - -int32_t CMapTable::CMapFormat4::Builder::SubDataSizeToSerialize() { - if (!model_changed()) { - return CMap::Builder::SubDataSizeToSerialize(); - } - int32_t size = Offset::kFormat4FixedSize + segments_.size() - * (3 * DataSize::kUSHORT + DataSize::kSHORT) - + glyph_id_array_.size() * DataSize::kSHORT; - return size; -} - -bool CMapTable::CMapFormat4::Builder::SubReadyToSerialize() { - if (!model_changed()) { - return CMap::Builder::SubReadyToSerialize(); - } - if (!segments()->empty()) { - return true; - } - return false; -} - -int32_t -CMapTable::CMapFormat4::Builder::SubSerialize(WritableFontData* new_data) { - if (!model_changed()) { - return CMap::Builder::SubSerialize(new_data); - } - int32_t index = 0; - index += new_data->WriteUShort(index, CMapFormat::kFormat4); - index += DataSize::kUSHORT; // length - write this at the end - index += new_data->WriteUShort(index, language()); - - int32_t seg_count = segments_.size(); - index += new_data->WriteUShort(index, seg_count * 2); - int32_t log2_seg_count = FontMath::Log2(seg_count); - int32_t search_range = 1 << (log2_seg_count + 1); - index += new_data->WriteUShort(index, search_range); - int32_t entry_selector = log2_seg_count; - index += new_data->WriteUShort(index, entry_selector); - int32_t range_shift = 2 * seg_count - search_range; - index += new_data->WriteUShort(index, range_shift); - - for (int32_t i = 0; i < seg_count; ++i) { - index += new_data->WriteUShort(index, segments_[i]->end_count()); - } - index += new_data->WriteUShort(index, 0); // reserved ushort - for (int32_t i = 0; i < seg_count; ++i) { -#if defined SFNTLY_DEBUG_CMAP - fprintf(stderr, "Segment %d; start %d\n", i, segments_[i]->start_count()); -#endif - index += new_data->WriteUShort(index, segments_[i]->start_count()); - } - for (int32_t i = 0; i < seg_count; ++i) { - index += new_data->WriteShort(index, segments_[i]->id_delta()); - } - for (int32_t i = 0; i < seg_count; ++i) { - index += new_data->WriteUShort(index, segments_[i]->id_range_offset()); - } - -#if defined SFNTLY_DEBUG_CMAP - fprintf(stderr, "Glyph id array size %lu\n", glyph_id_array_.size()); -#endif - for (size_t i = 0; i < glyph_id_array_.size(); ++i) { - index += new_data->WriteUShort(index, glyph_id_array_[i]); - } - - new_data->WriteUShort(Offset::kFormat4Length, index); - return index; -} - -/****************************************************************************** - * CMapTable::Builder class - ******************************************************************************/ -CMapTable::Builder::Builder(Header* header, WritableFontData* data) - : SubTableContainerTable::Builder(header, data), version_(0) { -} - -CMapTable::Builder::Builder(Header* header, ReadableFontData* data) - : SubTableContainerTable::Builder(header, data), version_(0) { -} - -CMapTable::Builder::~Builder() { -} - -int32_t CMapTable::Builder::SubSerialize(WritableFontData* new_data) { - int32_t size = new_data->WriteUShort(CMapTable::Offset::kVersion, - version_); - size += new_data->WriteUShort(CMapTable::Offset::kNumTables, - GetCMapBuilders()->size()); - - int32_t index_offset = size; - size += GetCMapBuilders()->size() * CMapTable::Offset::kEncodingRecordSize; - for (CMapBuilderMap::iterator it = GetCMapBuilders()->begin(), - e = GetCMapBuilders()->end(); it != e; ++it) { - CMapBuilderPtr b = it->second; - // header entry - index_offset += new_data->WriteUShort(index_offset, b->platform_id()); - index_offset += new_data->WriteUShort(index_offset, b->encoding_id()); - index_offset += new_data->WriteULong(index_offset, size); - - // cmap - FontDataPtr slice; - slice.Attach(new_data->Slice(size)); - size += b->SubSerialize(down_cast(slice.p_)); - } - return size; -} - -bool CMapTable::Builder::SubReadyToSerialize() { - if (GetCMapBuilders()->empty()) - return false; - - // check each table - for (CMapBuilderMap::iterator it = GetCMapBuilders()->begin(), - e = GetCMapBuilders()->end(); it != e; ++it) { - if (!it->second->SubReadyToSerialize()) - return false; - } - return true; -} - -int32_t CMapTable::Builder::SubDataSizeToSerialize() { - if (GetCMapBuilders()->empty()) - return 0; - - bool variable = false; - int32_t size = CMapTable::Offset::kEncodingRecordStart + - GetCMapBuilders()->size() * CMapTable::Offset::kEncodingRecordSize; - - // calculate size of each table - for (CMapBuilderMap::iterator it = GetCMapBuilders()->begin(), - e = GetCMapBuilders()->end(); it != e; ++it) { - int32_t cmap_size = it->second->SubDataSizeToSerialize(); - size += abs(cmap_size); - variable |= cmap_size <= 0; - } - return variable ? -size : size; -} - -void CMapTable::Builder::SubDataSet() { - GetCMapBuilders()->clear(); - Table::Builder::set_model_changed(); -} - -CALLER_ATTACH FontDataTable* - CMapTable::Builder::SubBuildTable(ReadableFontData* data) { - FontDataTablePtr table = new CMapTable(header(), data); - return table.Detach(); -} - -CALLER_ATTACH CMapTable::Builder* - CMapTable::Builder::CreateBuilder(Header* header, - WritableFontData* data) { - Ptr builder; - builder = new CMapTable::Builder(header, data); - return builder.Detach(); -} - -// static -CALLER_ATTACH CMapTable::CMap::Builder* - CMapTable::Builder::CMapBuilder(ReadableFontData* data, int32_t index) { - if (index < 0 || index > NumCMaps(data)) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IndexOutOfBoundException( - "CMap table is outside of the bounds of the known tables."); -#endif - return NULL; - } - - int32_t platform_id = data->ReadUShort(Offset::kEncodingRecordPlatformId + - OffsetForEncodingRecord(index)); - int32_t encoding_id = data->ReadUShort(Offset::kEncodingRecordEncodingId + - OffsetForEncodingRecord(index)); - int32_t offset = data->ReadULongAsInt(Offset::kEncodingRecordOffset + - OffsetForEncodingRecord(index)); - return CMap::Builder::GetBuilder(data, offset, - NewCMapId(platform_id, encoding_id)); -} - -// static -int32_t CMapTable::Builder::NumCMaps(ReadableFontData* data) { - if (data == NULL) { - return 0; - } - return data->ReadUShort(Offset::kNumTables); -} - -int32_t CMapTable::Builder::NumCMaps() { - return GetCMapBuilders()->size(); -} - -void CMapTable::Builder::Initialize(ReadableFontData* data) { - int32_t num_cmaps = NumCMaps(data); - for (int32_t i = 0; i < num_cmaps; ++i) { - CMapTable::CMap::Builder* cmap_builder = CMapBuilder(data, i); - if (!cmap_builder) - continue; - cmap_builders_[cmap_builder->cmap_id()] = cmap_builder; - } -} - -CMapTable::CMap::Builder* CMapTable::Builder::NewCMapBuilder( - const CMapId& cmap_id, - ReadableFontData* data) { - Ptr wfd; - wfd.Attach(WritableFontData::CreateWritableFontData(data->Size())); - data->CopyTo(wfd.p_); - CMapTable::CMapBuilderPtr builder; - builder.Attach(CMap::Builder::GetBuilder(wfd.p_, 0, cmap_id)); - CMapBuilderMap* cmap_builders = CMapTable::Builder::GetCMapBuilders(); - cmap_builders->insert(std::make_pair(cmap_id, builder.p_)); - return builder.Detach(); -} - -CMapTable::CMap::Builder* -CMapTable::Builder::NewCMapBuilder(int32_t format, const CMapId& cmap_id) { - Ptr cmap_builder; - cmap_builder.Attach(CMap::Builder::GetBuilder(format, cmap_id)); - CMapBuilderMap* cmap_builders = CMapTable::Builder::GetCMapBuilders(); - cmap_builders->insert(std::make_pair(cmap_id, cmap_builder.p_)); - return cmap_builder.Detach(); -} - -CMapTable::CMap::Builder* -CMapTable::Builder::CMapBuilder(const CMapId& cmap_id) { - CMapBuilderMap* cmap_builders = this->GetCMapBuilders(); - CMapBuilderMap::iterator builder = cmap_builders->find(cmap_id); - if (builder != cmap_builders->end()) - return builder->second; -#ifndef SFNTLY_NO_EXCEPTION - throw NoSuchElementException("No builder found for cmap_id"); -#else - return NULL; -#endif -} - -CMapTable::CMapBuilderMap* CMapTable::Builder::GetCMapBuilders() { - if (cmap_builders_.empty()) { - Initialize(InternalReadData()); - set_model_changed(); - } - return &cmap_builders_; -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/core/cmap_table.h b/src/sfntly/src/sfntly/table/core/cmap_table.h deleted file mode 100644 index 29ce3e4189..0000000000 --- a/src/sfntly/src/sfntly/table/core/cmap_table.h +++ /dev/null @@ -1,711 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_CMAP_TABLE_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_CMAP_TABLE_H_ - -// type.h needs to be included first because of building issues on Windows -// Type aliases we delcare are defined in other headers and make the build -// fail otherwise. -#include "sfntly/port/type.h" -#include -#include - -#include "sfntly/port/refcount.h" -#include "sfntly/table/subtable.h" -#include "sfntly/table/subtable_container_table.h" - -namespace sfntly { - -// CMap subtable formats -struct CMapFormat { - enum { - kFormat0 = 0, - kFormat2 = 2, - kFormat4 = 4, - kFormat6 = 6, - kFormat8 = 8, - kFormat10 = 10, - kFormat12 = 12, - kFormat13 = 13, - kFormat14 = 14 - }; -}; - -// A CMap table -class CMapTable : public SubTableContainerTable, public RefCounted { -public: - // CMapTable::CMapId - struct CMapId { - int32_t platform_id; - int32_t encoding_id; - bool operator==(const CMapId& obj) const { - return platform_id == obj.platform_id && encoding_id == obj.encoding_id; - } - }; - static CMapId WINDOWS_BMP; - static CMapId WINDOWS_UCS4; - static CMapId MAC_ROMAN; - - // CMapTable::CMapIdComparator - class CMapIdComparator { - public: - bool operator()(const CMapId& lhs, const CMapId& rhs) const; - }; - - // A filter on cmap - // CMapTable::CMapFilter - class CMapFilter { - public: - // Test on whether the cmap is acceptable or not - // @param cmap_id the id of the cmap - // @return true if the cmap is acceptable; false otherwise - virtual bool accept(const CMapId& cmap_id) const = 0; - // Make gcc -Wnon-virtual-dtor happy. - virtual ~CMapFilter() {} - }; - - // Filters CMaps by CMapId to implement CMapTable::get() - // wanted_id is the CMap we'd like to find. - // We compare the current CMap to it either by equality (==) or using a - // comparator. - // CMapTable::CMapIdFilter - class CMapIdFilter : public CMapFilter { - public: - explicit CMapIdFilter(const CMapId wanted_id); - CMapIdFilter(const CMapId wanted_id, - const CMapIdComparator* comparator); - ~CMapIdFilter() {} - virtual bool accept(const CMapId& cmap_id) const; - private: - CMapIdFilter& operator=(const CMapIdFilter& that); - const CMapId wanted_id_; - const CMapIdComparator *comparator_; - }; - - // The abstract base class for all cmaps. - // - // CMap equality is based on the equality of the (@link {@link CMapId} that - // defines the CMap. In the cmap table for a font there can only be one cmap - // with a given cmap id (pair of platform and encoding ids) no matter what the - // type of the cmap is. - // - // The cmap offers CharacterIterator to allow iteration over - // characters that are mapped by the cmap. This iteration mostly returns the - // characters mapped by the cmap. It will return all characters mapped by the - // cmap to anything but .notdef but it may return some that are not - // mapped or are mapped to .notdef. Various cmap tables provide ranges and - // such to describe characters for lookup but without going the full way to - // mapping to the glyph id it isn't always possible to tell if a character - // will end up with a valid glyph id. So, some of the characters returned from - // the Iterator may still end up pointing to the .notdef glyph. However, the - // number of such characters should be small in most cases with well designed - // cmaps. - class Builder; - class CMap : public SubTable { - public: - // CMapTable::CMap::Builder - class Builder : public SubTable::Builder { - public: - virtual ~Builder(); - - CALLER_ATTACH static Builder* - GetBuilder(ReadableFontData* data, - int32_t offset, - const CMapId& cmap_id); - CALLER_ATTACH static Builder* - GetBuilder(int32_t format, - const CMapId& cmap_id); - - // Note: yes, an object is returned on stack since it's small enough. - virtual CMapId cmap_id() { return cmap_id_; } - virtual int32_t platform_id() { return cmap_id_.platform_id; } - virtual int32_t encoding_id() { return cmap_id_.encoding_id; } - virtual int32_t format() { return format_; } - virtual int32_t language() { return language_; } - virtual void set_language(int32_t language) { language_ = language; } - - protected: - Builder(ReadableFontData* data, - int32_t format, - const CMapId& cmap_id); - Builder(WritableFontData* data, - int32_t format, - const CMapId& cmap_id); - - virtual int32_t SubSerialize(WritableFontData* new_data); - virtual bool SubReadyToSerialize(); - virtual int32_t SubDataSizeToSerialize(); - virtual void SubDataSet(); - - private: - int32_t format_; - CMapId cmap_id_; - int32_t language_; - - friend class CMapTable::Builder; - }; - // Abstract CMap character iterator - // The fully qualified name is CMapTable::CMap::CharacterIterator - class CharacterIterator { - public: - virtual ~CharacterIterator() {} - virtual bool HasNext() = 0; - // Returns -1 if there are no more characters to iterate through - // and exceptions are turned off - virtual int32_t Next() = 0; - - protected: - // Use the CMap::Iterator method below instead of directly requesting - // a CharacterIterator. - CharacterIterator() {} - }; - - CMap(ReadableFontData* data, int32_t format, const CMapId& cmap_id); - virtual ~CMap(); - - virtual CMap::CharacterIterator* Iterator() = 0; - - virtual int32_t format() { return format_; } - virtual CMapId cmap_id() { return cmap_id_; } - virtual int32_t platform_id() { return cmap_id_.platform_id; } - virtual int32_t encoding_id() { return cmap_id_.encoding_id; } - - // Get the language of the cmap. - // - // Note on the language field in 'cmap' subtables: The language field must - // be set to zero for all cmap subtables whose platform IDs are other than - // Macintosh (platform ID 1). For cmap subtables whose platform IDs are - // Macintosh, set this field to the Macintosh language ID of the cmap - // subtable plus one, or to zero if the cmap subtable is not - // language-specific. For example, a Mac OS Turkish cmap subtable must set - // this field to 18, since the Macintosh language ID for Turkish is 17. A - // Mac OS Roman cmap subtable must set this field to 0, since Mac OS Roman - // is not a language-specific encoding. - // - // @return the language id - virtual int32_t Language() = 0; - - // Gets the glyph id for the character code provided. - // The character code provided must be in the encoding used by the cmap - // table. - virtual int32_t GlyphId(int32_t character) = 0; - - private: - int32_t format_; - CMapId cmap_id_; - }; - typedef Ptr CMapPtr; - typedef Ptr CMapBuilderPtr; - typedef std::map CMapBuilderMap; - - // A cmap format 0 sub table - class CMapFormat0 : public CMap, public RefCounted { - public: - // The fully qualified name is CMapTable::CMapFormat0::Builder - class Builder : public CMap::Builder, - public RefCounted { - public: - CALLER_ATTACH static Builder* NewInstance(ReadableFontData* data, - int32_t offset, - const CMapId& cmap_id); - CALLER_ATTACH static Builder* NewInstance(WritableFontData* data, - int32_t offset, - const CMapId& cmap_id); - CALLER_ATTACH static Builder* NewInstance(const CMapId& cmap_id); - virtual ~Builder(); - - protected: - virtual CALLER_ATTACH FontDataTable* - SubBuildTable(ReadableFontData* data); - - private: - // When creating a new CMapFormat0 Builder, use NewInstance instead of - // the constructors! This avoids a memory leak when slicing the FontData. - Builder(ReadableFontData* data, int32_t offset, const CMapId& cmap_id); - Builder(WritableFontData* data, int32_t offset, const CMapId& cmap_id); - Builder(const CMapId& cmap_id); - }; - - // The fully qualified name is CMapTable::CMapFormat0::CharacterIterator - class CharacterIterator : public CMap::CharacterIterator { - public: - virtual ~CharacterIterator(); - virtual bool HasNext(); - virtual int32_t Next(); - - private: - CharacterIterator(int32_t start, int32_t end); - friend class CMapFormat0; - int32_t character_, max_character_; - }; - - virtual ~CMapFormat0(); - virtual int32_t Language(); - virtual int32_t GlyphId(int32_t character); - CMap::CharacterIterator* Iterator(); - - private: - CMapFormat0(ReadableFontData* data, const CMapId& cmap_id); - }; - - // A cmap format 2 sub table - // The format 2 cmap is used for multi-byte encodings such as SJIS, - // EUC-JP/KR/CN, Big5, etc. - class CMapFormat2 : public CMap, public RefCounted { - public: - // CMapTable::CMapFormat2::Builder - class Builder : public CMap::Builder, - public RefCounted { - public: - Builder(ReadableFontData* data, - int32_t offset, - const CMapId& cmap_id); - Builder(WritableFontData* data, - int32_t offset, - const CMapId& cmap_id); - virtual ~Builder(); - - protected: - virtual CALLER_ATTACH FontDataTable* - SubBuildTable(ReadableFontData* data); - }; - // CMapTable::CMapFormat2::CharacterIterator - class CharacterIterator : public CMap::CharacterIterator { - public: - virtual ~CharacterIterator(); - virtual bool hasNext(); - virtual int32_t next(); - - private: - CharacterIterator(); - }; - - virtual int32_t Language(); - virtual int32_t GlyphId(int32_t character); - - // Returns how many bytes would be consumed by a lookup of this character - // with this cmap. This comes about because the cmap format 2 table is - // designed around multi-byte encodings such as SJIS, EUC-JP, Big5, etc. - // return the number of bytes consumed from this "character" - either 1 or 2 - virtual int32_t BytesConsumed(int32_t character); - - virtual ~CMapFormat2(); - - private: - CMapFormat2(ReadableFontData* data, const CMapId& cmap_id); - - int32_t SubHeaderOffset(int32_t sub_header_index); - int32_t FirstCode(int32_t sub_header_index); - int32_t EntryCount(int32_t sub_header_index); - int32_t IdRangeOffset(int32_t sub_header_index); - int32_t IdDelta(int32_t sub_header_index); - CMap::CharacterIterator* Iterator(); - }; - - // CMapTable::CMapFormat4 - class CMapFormat4 : public CMap, - public RefCounted { - public: - // CMapTable::CMapFormat4::Builder - class Builder : public CMap::Builder, - public RefCounted { - public: - // CMapTable::CMapFormat4::Builder::Segment - class Segment : public RefCounted { - public: - Segment(); - explicit Segment(Segment* other); - Segment(int32_t start_count, - int32_t end_count, - int32_t id_delta, - int32_t id_range_offset); - ~Segment(); - - // @return the startCount - int32_t start_count(); - // @param startCount the startCount to set - void set_start_count(int32_t start_count); - // @return the endCount - int32_t end_count(); - // @param endcount the endCount to set - void set_end_count(int32_t end_count); - // @return the idDelta - int32_t id_delta(); - // @param idDelta the idDelta to set - void set_id_delta(int32_t id_delta); - // @return the idRangeOffset - int32_t id_range_offset(); - // @param idRangeOffset the idRangeOffset to set - void set_id_range_offset(int32_t id_range_offset); - - static CALLER_ATTACH - std::vector >* - DeepCopy(std::vector >* original); - - private: - int32_t start_count_; - int32_t end_count_; - int32_t id_delta_; - int32_t id_range_offset_; - }; - typedef std::vector > SegmentList; - - static CALLER_ATTACH Builder* NewInstance(WritableFontData* data, - int32_t offset, - const CMapId& cmap_id); - static CALLER_ATTACH Builder* NewInstance(ReadableFontData* data, - int32_t offset, - const CMapId& cmap_id); - static CALLER_ATTACH Builder* NewInstance(const CMapId& cmap_id); - virtual ~Builder(); - SegmentList* segments(); - void set_segments(SegmentList* segments); - IntegerList* glyph_id_array(); - void set_glyph_id_array(IntegerList* glyph_id_array); - - protected: - Builder(WritableFontData* data, int32_t offset, const CMapId& cmap_id); - Builder(ReadableFontData* data, int32_t offset, const CMapId& cmap_id); - Builder(SegmentList* segments, IntegerList* glyph_id_array, - const CMapId& cmap_id); - explicit Builder(const CMapId& cmap_id); - - virtual CALLER_ATTACH FontDataTable* SubBuildTable( - ReadableFontData* data); - virtual void SubDataSet(); - virtual int32_t SubDataSizeToSerialize(); - virtual bool SubReadyToSerialize(); - virtual int32_t SubSerialize(WritableFontData* new_data); - - private: - void Initialize(ReadableFontData* data); - - SegmentList segments_; - IntegerList glyph_id_array_; - }; - - CMap::CharacterIterator* Iterator(); - // CMapTable::CMapFormat4::CharacterIterator - class CharacterIterator : public CMap::CharacterIterator { - public: - bool HasNext(); - int32_t Next(); - virtual ~CharacterIterator() {} - - private: - explicit CharacterIterator(CMapFormat4 *parent); - friend CMap::CharacterIterator* CMapFormat4::Iterator(); - - CMapFormat4* parent_; - int32_t segment_index_; - int32_t first_char_in_segment_; - int32_t last_char_in_segment_; - int32_t next_char_; - bool next_char_set_; - }; - - virtual int32_t GlyphId(int32_t character); - - // Lower level glyph code retrieval that requires processing the Format 4 - // segments to use. - // @param segment the cmap segment - // @param startCode the start code for the segment - // @param character the character to be looked up - // @return the glyph id for the character; CMapTable.NOTDEF if not found - int32_t RetrieveGlyphId(int32_t segment, - int32_t start_count, - int32_t character); - virtual int32_t Language(); - - // Get the count of the number of segments in this cmap. - // @return the number of segments - int32_t seg_count(); - int32_t Length(); - // Get the start code for a segment. - // @param segment the segment in the lookup table - // @return the start code for a segment - int32_t StartCode(int32_t segment); - // Get the end code for a segment. - // @param segment the segment in the look up table - // @return the end code for the segment - int32_t EndCode(int32_t segment); - // Get the id delta for a segment - // @param segment the segment in the look up table - // @return the id delta for the segment - int32_t IdDelta(int32_t segment); - // Get the id range offset for a segment - // @param segment the segment in the look up table - // @return the id range offset for the segment - int32_t IdRangeOffset(int32_t segment); - // Get the location of the id range offset for a segment - // @param segment the segment in the look up table - // @return the location of the id range offset for the segment - int32_t IdRangeOffsetLocation(int32_t segment); - // Declared above to allow friending inside CharacterIterator class. - // CMap::CharacterIterator* Iterator(); - virtual ~CMapFormat4(); - - protected: - CMapFormat4(ReadableFontData* data, const CMapId& cmap_id); - - private: - static int32_t Language(ReadableFontData* data); - static int32_t Length(ReadableFontData* data); - static int32_t SegCount(ReadableFontData* data); - static int32_t StartCode(ReadableFontData* data, - int32_t seg_count, - int32_t index); - static int32_t StartCodeOffset(int32_t seg_count); - static int32_t EndCode(ReadableFontData* data, - int32_t seg_count, - int32_t index); - static int32_t IdDelta(ReadableFontData* data, - int32_t seg_count, - int32_t index); - static int32_t IdDeltaOffset(int32_t seg_count); - static int32_t IdRangeOffset(ReadableFontData* data, - int32_t seg_count, - int32_t index); - static int32_t IdRangeOffsetOffset(int32_t seg_count); - static int32_t GlyphIdArrayOffset(int32_t seg_count); - // Refactored void to bool to work without exceptions. - bool IsValidIndex(int32_t segment); - int32_t GlyphIdArray(int32_t index); - - int32_t seg_count_; - int32_t start_code_offset_; - int32_t end_code_offset_; - int32_t id_delta_offset_; - int32_t id_range_offset_offset_; - int32_t glyph_id_array_offset_; - }; - - // CMapTable::Builder - class Builder : public SubTableContainerTable::Builder, - public RefCounted { - public: - // Constructor scope is public because C++ does not allow base class to - // instantiate derived class with protected constructors. - Builder(Header* header, WritableFontData* data); - Builder(Header* header, ReadableFontData* data); - virtual ~Builder(); - - virtual int32_t SubSerialize(WritableFontData* new_data); - virtual bool SubReadyToSerialize(); - virtual int32_t SubDataSizeToSerialize(); - virtual void SubDataSet(); - virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); - - static CALLER_ATTACH Builder* CreateBuilder(Header* header, - WritableFontData* data); - - CMap::Builder* NewCMapBuilder(const CMapId& cmap_id, - ReadableFontData* data); - // Create a new empty CMapBuilder of the type specified in the id. - CMap::Builder* NewCMapBuilder(int32_t format, const CMapId& cmap_id); - CMap::Builder* CMapBuilder(const CMapId& cmap_id); - - int32_t NumCMaps(); - void SetVersion(int32_t version); - - CMapBuilderMap* GetCMapBuilders(); - - protected: - static CALLER_ATTACH CMap::Builder* CMapBuilder(ReadableFontData* data, - int32_t index); - - private: - void Initialize(ReadableFontData* data); - static int32_t NumCMaps(ReadableFontData* data); - - int32_t version_; - CMapBuilderMap cmap_builders_; - }; - typedef Ptr CMapTableBuilderPtr; - - class CMapIterator { - public: - // If filter is NULL, filter through all tables. - CMapIterator(CMapTable* table, const CMapFilter* filter); - bool HasNext(); - CMap* Next(); - - private: - int32_t table_index_; - const CMapFilter* filter_; - CMapTable* table_; - }; - - // Make a CMapId from a platform_id, encoding_id pair - static CMapId NewCMapId(int32_t platform_id, int32_t encoding_id); - // Make a CMapId from another CMapId - static CMapId NewCMapId(const CMapId& obj); - - // Get the CMap with the specified parameters if it exists. - // Returns NULL otherwise. - CALLER_ATTACH CMap* GetCMap(const int32_t index); - CALLER_ATTACH CMap* GetCMap(const int32_t platform_id, - const int32_t encoding_id); - CALLER_ATTACH CMap* GetCMap(const CMapId GetCMap_id); - - // Get the table version. - virtual int32_t Version(); - - // Get the number of cmaps within the CMap table. - virtual int32_t NumCMaps(); - - // Get the cmap id for the cmap with the given index. - // Note: yes, an object is returned on stack since it's small enough. - // This function is renamed from cmapId to GetCMapId(). - virtual CMapId GetCMapId(int32_t index); - - virtual int32_t PlatformId(int32_t index); - virtual int32_t EncodingId(int32_t index); - - // Get the offset in the table data for the cmap table with the given index. - // The offset is from the beginning of the table. - virtual int32_t Offset(int32_t index); - - virtual ~CMapTable(); - - static const int32_t NOTDEF; - - private: - // Offsets to specific elements in the underlying data. These offsets are - // relative to the start of the table or the start of sub-blocks within - // the table. - struct Offset { - enum { - kVersion = 0, - kNumTables = 2, - kEncodingRecordStart = 4, - - // offsets relative to the encoding record - kEncodingRecordPlatformId = 0, - kEncodingRecordEncodingId = 2, - kEncodingRecordOffset = 4, - kEncodingRecordSize = 8, - - kFormat = 0, - - // Format 0: Byte encoding table - kFormat0Format = 0, - kFormat0Length = 2, - kFormat0Language = 4, - kFormat0GlyphIdArray = 6, - - // Format 2: High-byte mapping through table - kFormat2Format = 0, - kFormat2Length = 2, - kFormat2Language = 4, - kFormat2SubHeaderKeys = 6, - kFormat2SubHeaders = 518, - // offset relative to the subHeader structure - kFormat2SubHeader_firstCode = 0, - kFormat2SubHeader_entryCount = 2, - kFormat2SubHeader_idDelta = 4, - kFormat2SubHeader_idRangeOffset = 6, - kFormat2SubHeader_structLength = 8, - - // Format 4: Segment mapping to delta values - kFormat4Format = 0, - kFormat4Length = 2, - kFormat4Language = 4, - kFormat4SegCountX2 = 6, - kFormat4SearchRange = 8, - kFormat4EntrySelector = 10, - kFormat4RangeShift = 12, - kFormat4EndCount = 14, - kFormat4FixedSize = 16, - - // format 6: Trimmed table mapping - kFormat6Format = 0, - kFormat6Length = 2, - kFormat6Language = 4, - kFormat6FirstCode = 6, - kFormat6EntryCount = 8, - kFormat6GlyphIdArray = 10, - - // Format 8: mixed 16-bit and 32-bit coverage - kFormat8Format = 0, - kFormat8Length = 4, - kFormat8Language = 8, - kFormat8Is32 = 12, - kFormat8nGroups204 = 8204, - kFormat8Groups208 = 8208, - // offset relative to the group structure - kFormat8Group_startCharCode = 0, - kFormat8Group_endCharCode = 4, - kFormat8Group_startGlyphId = 8, - kFormat8Group_structLength = 12, - - // Format 10: Trimmed array - kFormat10Format = 0, - kFormat10Length = 4, - kFormat10Language = 8, - kFormat10StartCharCode = 12, - kFormat10NumChars = 16, - kFormat10Glyphs0 = 20, - - // Format 12: Segmented coverage - kFormat12Format = 0, - kFormat12Length = 4, - kFormat12Language = 8, - kFormat12nGroups = 12, - kFormat12Groups = 16, - kFormat12Groups_structLength = 12, - // offsets within the group structure - kFormat12_startCharCode = 0, - kFormat12_endCharCode = 4, - kFormat12_startGlyphId = 8, - - // Format 13: Last Resort Font - kFormat13Format = 0, - kFormat13Length = 4, - kFormat13Language = 8, - kFormat13nGroups = 12, - kFormat13Groups = 16, - kFormat13Groups_structLength = 12, - // offsets within the group structure - kFormat13_startCharCode = 0, - kFormat13_endCharCode = 4, - kFormat13_glyphId = 8, - - // Format 14: Unicode Variation Sequences - kFormat14Format = 0, - kFormat14Length = 2, - - // TODO(stuartg): finish tables - // Default UVS Table - - // Non-default UVS Table - kLast = -1 - }; - }; - - CMapTable(Header* header, ReadableFontData* data); - - // Get the offset in the table data for the encoding record for the cmap with - // the given index. The offset is from the beginning of the table. - static int32_t OffsetForEncodingRecord(int32_t index); -}; -typedef std::vector CMapIdList; -typedef Ptr CMapTablePtr; -typedef std::vector > SegmentList; -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_CMAP_TABLE_H_ diff --git a/src/sfntly/src/sfntly/table/core/font_header_table.cc b/src/sfntly/src/sfntly/table/core/font_header_table.cc deleted file mode 100644 index 60015ca954..0000000000 --- a/src/sfntly/src/sfntly/table/core/font_header_table.cc +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/table/core/font_header_table.h" - -namespace sfntly { -/****************************************************************************** - * FontHeaderTable class - ******************************************************************************/ -FontHeaderTable::~FontHeaderTable() {} - -int32_t FontHeaderTable::TableVersion() { - return data_->ReadFixed(Offset::kTableVersion); -} - -int32_t FontHeaderTable::FontRevision() { - return data_->ReadFixed(Offset::kFontRevision); -} - -int64_t FontHeaderTable::ChecksumAdjustment() { - return data_->ReadULong(Offset::kCheckSumAdjustment); -} - -int64_t FontHeaderTable::MagicNumber() { - return data_->ReadULong(Offset::kMagicNumber); -} - -int32_t FontHeaderTable::FlagsAsInt() { - return data_->ReadUShort(Offset::kFlags); -} - -int32_t FontHeaderTable::UnitsPerEm() { - return data_->ReadUShort(Offset::kUnitsPerEm); -} - -int64_t FontHeaderTable::Created() { - return data_->ReadDateTimeAsLong(Offset::kCreated); -} - -int64_t FontHeaderTable::Modified() { - return data_->ReadDateTimeAsLong(Offset::kModified); -} - -int32_t FontHeaderTable::XMin() { - return data_->ReadUShort(Offset::kXMin); -} - -int32_t FontHeaderTable::YMin() { - return data_->ReadUShort(Offset::kYMin); -} - -int32_t FontHeaderTable::XMax() { - return data_->ReadUShort(Offset::kXMax); -} - -int32_t FontHeaderTable::YMax() { - return data_->ReadUShort(Offset::kYMax); -} - -int32_t FontHeaderTable::MacStyleAsInt() { - return data_->ReadUShort(Offset::kMacStyle); -} - -int32_t FontHeaderTable::LowestRecPPEM() { - return data_->ReadUShort(Offset::kLowestRecPPEM); -} - -int32_t FontHeaderTable::FontDirectionHint() { - return data_->ReadShort(Offset::kFontDirectionHint); -} - -int32_t FontHeaderTable::IndexToLocFormat() { - return data_->ReadShort(Offset::kIndexToLocFormat); -} - -int32_t FontHeaderTable::GlyphDataFormat() { - return data_->ReadShort(Offset::kGlyphDataFormat); -} - -FontHeaderTable::FontHeaderTable(Header* header, ReadableFontData* data) - : Table(header, data) { - IntegerList checksum_ranges; - checksum_ranges.push_back(0); - checksum_ranges.push_back(Offset::kCheckSumAdjustment); - checksum_ranges.push_back(Offset::kMagicNumber); - data_->SetCheckSumRanges(checksum_ranges); -} - -/****************************************************************************** - * FontHeaderTable::Builder class - ******************************************************************************/ -FontHeaderTable::Builder::Builder(Header* header, WritableFontData* data) - : TableBasedTableBuilder(header, data) { -} - -FontHeaderTable::Builder::Builder(Header* header, ReadableFontData* data) - : TableBasedTableBuilder(header, data) { -} - -FontHeaderTable::Builder::~Builder() {} - -CALLER_ATTACH FontDataTable* FontHeaderTable::Builder::SubBuildTable( - ReadableFontData* data) { - FontDataTablePtr table = new FontHeaderTable(header(), data); - return table.Detach(); -} - -int32_t FontHeaderTable::Builder::TableVersion() { - return down_cast(GetTable())->TableVersion(); -} - -void FontHeaderTable::Builder::SetTableVersion(int32_t version) { - InternalWriteData()->WriteFixed(Offset::kTableVersion, version); -} - -int32_t FontHeaderTable::Builder::FontRevision() { - return down_cast(GetTable())->FontRevision(); -} - -void FontHeaderTable::Builder::SetFontRevision(int32_t revision) { - InternalWriteData()->WriteFixed(Offset::kFontRevision, revision); -} - -int64_t FontHeaderTable::Builder::ChecksumAdjustment() { - return down_cast(GetTable())->ChecksumAdjustment(); -} - -void FontHeaderTable::Builder::SetChecksumAdjustment(int64_t adjustment) { - InternalWriteData()->WriteULong(Offset::kCheckSumAdjustment, adjustment); -} - -int64_t FontHeaderTable::Builder::MagicNumber() { - return down_cast(GetTable())->MagicNumber(); -} - -void FontHeaderTable::Builder::SetMagicNumber(int64_t magic_number) { - InternalWriteData()->WriteULong(Offset::kMagicNumber, magic_number); -} - -int32_t FontHeaderTable::Builder::FlagsAsInt() { - return down_cast(GetTable())->FlagsAsInt(); -} - -void FontHeaderTable::Builder::SetFlagsAsInt(int32_t flags) { - InternalWriteData()->WriteUShort(Offset::kFlags, flags); -} - -int32_t FontHeaderTable::Builder::UnitsPerEm() { - return down_cast(GetTable())->UnitsPerEm(); -} - -void FontHeaderTable::Builder::SetUnitsPerEm(int32_t units) { - InternalWriteData()->WriteUShort(Offset::kUnitsPerEm, units); -} - -int64_t FontHeaderTable::Builder::Created() { - return down_cast(GetTable())->Created(); -} - -void FontHeaderTable::Builder::SetCreated(int64_t date) { - InternalWriteData()->WriteDateTime(Offset::kCreated, date); -} - -int64_t FontHeaderTable::Builder::Modified() { - return down_cast(GetTable())->Modified(); -} - -void FontHeaderTable::Builder::SetModified(int64_t date) { - InternalWriteData()->WriteDateTime(Offset::kModified, date); -} - -int32_t FontHeaderTable::Builder::XMin() { - return down_cast(GetTable())->XMin(); -} - -void FontHeaderTable::Builder::SetXMin(int32_t xmin) { - InternalWriteData()->WriteShort(Offset::kXMin, xmin); -} - -int32_t FontHeaderTable::Builder::YMin() { - return down_cast(GetTable())->YMin(); -} - -void FontHeaderTable::Builder::SetYMin(int32_t ymin) { - InternalWriteData()->WriteShort(Offset::kYMin, ymin); -} - -int32_t FontHeaderTable::Builder::XMax() { - return down_cast(GetTable())->XMax(); -} - -void FontHeaderTable::Builder::SetXMax(int32_t xmax) { - InternalWriteData()->WriteShort(Offset::kXMax, xmax); -} - -int32_t FontHeaderTable::Builder::YMax() { - return down_cast(GetTable())->YMax(); -} - -void FontHeaderTable::Builder::SetYMax(int32_t ymax) { - InternalWriteData()->WriteShort(Offset::kYMax, ymax); -} - -int32_t FontHeaderTable::Builder::MacStyleAsInt() { - return down_cast(GetTable())->MacStyleAsInt(); -} - -void FontHeaderTable::Builder::SetMacStyleAsInt(int32_t style) { - InternalWriteData()->WriteUShort(Offset::kMacStyle, style); -} - -int32_t FontHeaderTable::Builder::LowestRecPPEM() { - return down_cast(GetTable())->LowestRecPPEM(); -} - -void FontHeaderTable::Builder::SetLowestRecPPEM(int32_t size) { - InternalWriteData()->WriteUShort(Offset::kLowestRecPPEM, size); -} - -int32_t FontHeaderTable::Builder::FontDirectionHint() { - return down_cast(GetTable())->FontDirectionHint(); -} - -void FontHeaderTable::Builder::SetFontDirectionHint(int32_t hint) { - InternalWriteData()->WriteShort(Offset::kFontDirectionHint, hint); -} - -int32_t FontHeaderTable::Builder::IndexToLocFormat() { - return down_cast(GetTable())->IndexToLocFormat(); -} - -void FontHeaderTable::Builder::SetIndexToLocFormat(int32_t format) { - InternalWriteData()->WriteShort(Offset::kIndexToLocFormat, format); -} - -int32_t FontHeaderTable::Builder::GlyphDataFormat() { - return down_cast(GetTable())->GlyphDataFormat(); -} - -void FontHeaderTable::Builder::SetGlyphDataFormat(int32_t format) { - InternalWriteData()->WriteShort(Offset::kGlyphDataFormat, format); -} - -CALLER_ATTACH FontHeaderTable::Builder* - FontHeaderTable::Builder::CreateBuilder(Header* header, - WritableFontData* data) { - Ptr builder; - builder = new FontHeaderTable::Builder(header, data); - return builder.Detach(); -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/core/font_header_table.h b/src/sfntly/src/sfntly/table/core/font_header_table.h deleted file mode 100644 index 841955b423..0000000000 --- a/src/sfntly/src/sfntly/table/core/font_header_table.h +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_FONT_HEADER_TABLE_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_FONT_HEADER_TABLE_H_ - -#include "sfntly/table/table.h" -#include "sfntly/table/table_based_table_builder.h" - -namespace sfntly { - -struct IndexToLocFormat { - enum { - kShortOffset = 0, - kLongOffset = 1 - }; -}; - -struct FontDirectionHint { - enum { - kFullyMixed = 0, - kOnlyStrongLTR = 1, - kStrongLTRAndNeutral = 2, - kOnlyStrongRTL = -1, - kStrongRTLAndNeutral = -2 - }; -}; - -class FontHeaderTable : public Table, public RefCounted { - public: - class Builder : public TableBasedTableBuilder, public RefCounted { - public: - // Constructor scope altered to public because C++ does not allow base - // class to instantiate derived class with protected constructors. - Builder(Header* header, WritableFontData* data); - Builder(Header* header, ReadableFontData* data); - virtual ~Builder(); - virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); - - virtual int32_t TableVersion(); - virtual void SetTableVersion(int32_t version); - virtual int32_t FontRevision(); - virtual void SetFontRevision(int32_t revision); - virtual int64_t ChecksumAdjustment(); - virtual void SetChecksumAdjustment(int64_t adjustment); - virtual int64_t MagicNumber(); - virtual void SetMagicNumber(int64_t magic_number); - virtual int32_t FlagsAsInt(); - virtual void SetFlagsAsInt(int32_t flags); - // TODO(arthurhsu): IMPLEMENT EnumSet Flags() - // TODO(arthurhsu): IMPLEMENT setFlags(EnumSet flags) - virtual int32_t UnitsPerEm(); - virtual void SetUnitsPerEm(int32_t units); - virtual int64_t Created(); - virtual void SetCreated(int64_t date); - virtual int64_t Modified(); - virtual void SetModified(int64_t date); - virtual int32_t XMin(); - virtual void SetXMin(int32_t xmin); - virtual int32_t YMin(); - virtual void SetYMin(int32_t ymin); - virtual int32_t XMax(); - virtual void SetXMax(int32_t xmax); - virtual int32_t YMax(); - virtual void SetYMax(int32_t ymax); - virtual int32_t MacStyleAsInt(); - virtual void SetMacStyleAsInt(int32_t style); - // TODO(arthurhsu): IMPLEMENT EnumSet macStyle() - // TODO(arthurhsu): IMPLEMENT setMacStyle(EnumSet style) - virtual int32_t LowestRecPPEM(); - virtual void SetLowestRecPPEM(int32_t size); - virtual int32_t FontDirectionHint(); - virtual void SetFontDirectionHint(int32_t hint); - virtual int32_t IndexToLocFormat(); - virtual void SetIndexToLocFormat(int32_t format); - virtual int32_t GlyphDataFormat(); - virtual void SetGlyphDataFormat(int32_t format); - - static CALLER_ATTACH Builder* CreateBuilder(Header* header, - WritableFontData* data); - }; - - virtual ~FontHeaderTable(); - int32_t TableVersion(); - int32_t FontRevision(); - - // Get the checksum adjustment. To compute: set it to 0, sum the entire font - // as ULONG, then store 0xB1B0AFBA - sum. - int64_t ChecksumAdjustment(); - - // Get the magic number. Set to 0x5F0F3CF5. - int64_t MagicNumber(); - - // TODO(arthurhsu): IMPLEMENT: EnumSet - int32_t FlagsAsInt(); - // TODO(arthurhsu): IMPLEMENT: Flags() returning EnumSet - - int32_t UnitsPerEm(); - - // Get the created date. Number of seconds since 12:00 midnight, January 1, - // 1904. 64-bit integer. - int64_t Created(); - // Get the modified date. Number of seconds since 12:00 midnight, January 1, - // 1904. 64-bit integer. - int64_t Modified(); - - // Get the x min. For all glyph bounding boxes. - int32_t XMin(); - // Get the y min. For all glyph bounding boxes. - int32_t YMin(); - // Get the x max. For all glyph bounding boxes. - int32_t XMax(); - // Get the y max. For all glyph bounding boxes. - int32_t YMax(); - - // TODO(arthurhsu): IMPLEMENT: EnumSet - int32_t MacStyleAsInt(); - // TODO(arthurhsu): IMPLEMENT: macStyle() returning EnumSet - - int32_t LowestRecPPEM(); - int32_t FontDirectionHint(); // Note: no AsInt() form, already int - int32_t IndexToLocFormat(); // Note: no AsInt() form, already int - int32_t GlyphDataFormat(); - - private: - struct Offset { - enum { - kTableVersion = 0, - kFontRevision = 4, - kCheckSumAdjustment = 8, - kMagicNumber = 12, - kFlags = 16, - kUnitsPerEm = 18, - kCreated = 20, - kModified = 28, - kXMin = 36, - kYMin = 38, - kXMax = 40, - kYMax = 42, - kMacStyle = 44, - kLowestRecPPEM = 46, - kFontDirectionHint = 48, - kIndexToLocFormat = 50, - kGlyphDataFormat = 52 - }; - }; - - FontHeaderTable(Header* header, ReadableFontData* data); -}; -typedef Ptr FontHeaderTablePtr; -typedef Ptr FontHeaderTableBuilderPtr; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_FONT_HEADER_TABLE_H_ diff --git a/src/sfntly/src/sfntly/table/core/horizontal_device_metrics_table.cc b/src/sfntly/src/sfntly/table/core/horizontal_device_metrics_table.cc deleted file mode 100644 index 50b0cf579d..0000000000 --- a/src/sfntly/src/sfntly/table/core/horizontal_device_metrics_table.cc +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/table/core/horizontal_device_metrics_table.h" - -namespace sfntly { -/****************************************************************************** - * HorizontalDeviceMetricsTable class - ******************************************************************************/ -HorizontalDeviceMetricsTable:: ~HorizontalDeviceMetricsTable() {} - -int32_t HorizontalDeviceMetricsTable::Version() { - return data_->ReadUShort(Offset::kVersion); -} - -int32_t HorizontalDeviceMetricsTable::NumRecords() { - return data_->ReadShort(Offset::kNumRecords); -} - -int32_t HorizontalDeviceMetricsTable::RecordSize() { - return data_->ReadLong(Offset::kSizeDeviceRecord); -} - -int32_t HorizontalDeviceMetricsTable::PixelSize(int32_t record_index) { - if (record_index < 0 || record_index >= NumRecords()) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IndexOutOfBoundsException(); -#endif - return -1; - } - return data_->ReadUByte(Offset::kRecords + record_index * RecordSize() + - Offset::kDeviceRecordPixelSize); -} - -int32_t HorizontalDeviceMetricsTable::MaxWidth(int32_t record_index) { - if (record_index < 0 || record_index >= NumRecords()) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IndexOutOfBoundsException(); -#endif - return -1; - } - return data_->ReadUByte(Offset::kRecords + record_index * RecordSize() + - Offset::kDeviceRecordMaxWidth); -} - -int32_t HorizontalDeviceMetricsTable::Width(int32_t record_index, - int32_t glyph_num) { - if (record_index < 0 || record_index >= NumRecords() || - glyph_num < 0 || glyph_num >= num_glyphs_) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IndexOutOfBoundsException(); -#endif - return -1; - } - return data_->ReadUByte(Offset::kRecords + record_index * RecordSize() + - Offset::kDeviceRecordWidths + glyph_num); -} - -HorizontalDeviceMetricsTable::HorizontalDeviceMetricsTable( - Header* header, - ReadableFontData* data, - int32_t num_glyphs) - : Table(header, data), num_glyphs_(num_glyphs) { -} - -/****************************************************************************** - * HorizontalDeviceMetricsTable::Builder class - ******************************************************************************/ -HorizontalDeviceMetricsTable::Builder::Builder(Header* header, - WritableFontData* data) - : TableBasedTableBuilder(header, data), num_glyphs_(-1) { -} - -HorizontalDeviceMetricsTable::Builder::Builder(Header* header, - ReadableFontData* data) - : TableBasedTableBuilder(header, data), num_glyphs_(-1) { -} - -HorizontalDeviceMetricsTable::Builder::~Builder() {} - -CALLER_ATTACH FontDataTable* -HorizontalDeviceMetricsTable::Builder::SubBuildTable(ReadableFontData* data) { - FontDataTablePtr table = new HorizontalDeviceMetricsTable(header(), data, - num_glyphs_); - return table.Detach(); -} - -void HorizontalDeviceMetricsTable::Builder::SetNumGlyphs(int32_t num_glyphs) { - if (num_glyphs < 0) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IllegalArgumentException("Number of glyphs can't be negative."); -#endif - return; - } - num_glyphs_ = num_glyphs; - HorizontalDeviceMetricsTable* table = - down_cast(GetTable()); - if (table) { - table->num_glyphs_ = num_glyphs; - } -} - -CALLER_ATTACH HorizontalDeviceMetricsTable::Builder* -HorizontalDeviceMetricsTable::Builder::CreateBuilder(Header* header, - WritableFontData* data) { - Ptr builder; - builder = new HorizontalDeviceMetricsTable::Builder(header, data); - return builder.Detach(); -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/core/horizontal_device_metrics_table.h b/src/sfntly/src/sfntly/table/core/horizontal_device_metrics_table.h deleted file mode 100644 index 4a27ba0964..0000000000 --- a/src/sfntly/src/sfntly/table/core/horizontal_device_metrics_table.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_DEVICE_METRICS_TABLE_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_DEVICE_METRICS_TABLE_H_ - -#include "sfntly/table/table.h" -#include "sfntly/table/table_based_table_builder.h" - -namespace sfntly { - -// A Horizontal Device Metrics table - 'hdmx' -class HorizontalDeviceMetricsTable - : public Table, - public RefCounted { - public: - class Builder : public TableBasedTableBuilder, public RefCounted { - public: - // Constructor scope altered to public because C++ does not allow base - // class to instantiate derived class with protected constructors. - Builder(Header* header, WritableFontData* data); - Builder(Header* header, ReadableFontData* data); - virtual ~Builder(); - virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); - - static CALLER_ATTACH Builder* CreateBuilder(Header* header, - WritableFontData* data); - - void SetNumGlyphs(int32_t num_glyphs); - - private: - int32_t num_glyphs_; - }; - - virtual ~HorizontalDeviceMetricsTable(); - - int32_t Version(); - int32_t NumRecords(); - int32_t RecordSize(); - int32_t PixelSize(int32_t record_index); - int32_t MaxWidth(int32_t record_index); - int32_t Width(int32_t record_index, int32_t glyph_num); - - private: - struct Offset { - enum { - kVersion = 0, - kNumRecords = 2, - kSizeDeviceRecord = 4, - kRecords = 8, - - // Offsets within a device record - kDeviceRecordPixelSize = 0, - kDeviceRecordMaxWidth = 1, - kDeviceRecordWidths = 2, - }; - }; - HorizontalDeviceMetricsTable(Header* header, - ReadableFontData* data, - int32_t num_glyphs); - - int32_t num_glyphs_; -}; -typedef Ptr HorizontalDeviceMetricsTablePtr; -typedef Ptr - HorizontalDeviceMetricsTableBuilderPtr; -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_DEVICE_METRICS_TABLE_H_ diff --git a/src/sfntly/src/sfntly/table/core/horizontal_header_table.cc b/src/sfntly/src/sfntly/table/core/horizontal_header_table.cc deleted file mode 100644 index 43c20585d3..0000000000 --- a/src/sfntly/src/sfntly/table/core/horizontal_header_table.cc +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/table/core/horizontal_header_table.h" - -namespace sfntly { -/****************************************************************************** - * HorizontalHeaderTable class - ******************************************************************************/ -HorizontalHeaderTable:: ~HorizontalHeaderTable() {} - -int32_t HorizontalHeaderTable::TableVersion() { - return data_->ReadFixed(Offset::kVersion); -} - -int32_t HorizontalHeaderTable::Ascender() { - return data_->ReadShort(Offset::kAscender); -} - -int32_t HorizontalHeaderTable::Descender() { - return data_->ReadShort(Offset::kDescender); -} - -int32_t HorizontalHeaderTable::LineGap() { - return data_->ReadShort(Offset::kLineGap); -} - -int32_t HorizontalHeaderTable::AdvanceWidthMax() { - return data_->ReadUShort(Offset::kAdvanceWidthMax); -} - -int32_t HorizontalHeaderTable::MinLeftSideBearing() { - return data_->ReadShort(Offset::kMinLeftSideBearing); -} - -int32_t HorizontalHeaderTable::MinRightSideBearing() { - return data_->ReadShort(Offset::kMinRightSideBearing); -} - -int32_t HorizontalHeaderTable::XMaxExtent() { - return data_->ReadShort(Offset::kXMaxExtent); -} - -int32_t HorizontalHeaderTable::CaretSlopeRise() { - return data_->ReadShort(Offset::kCaretSlopeRise); -} - -int32_t HorizontalHeaderTable::CaretSlopeRun() { - return data_->ReadShort(Offset::kCaretSlopeRun); -} - -int32_t HorizontalHeaderTable::CaretOffset() { - return data_->ReadShort(Offset::kCaretOffset); -} - -int32_t HorizontalHeaderTable::MetricDataFormat() { - return data_->ReadShort(Offset::kMetricDataFormat); -} - -int32_t HorizontalHeaderTable::NumberOfHMetrics() { - return data_->ReadUShort(Offset::kNumberOfHMetrics); -} - -HorizontalHeaderTable:: HorizontalHeaderTable(Header* header, - ReadableFontData* data) - : Table(header, data) { -} - -/****************************************************************************** - * HorizontalHeaderTable::Builder class - ******************************************************************************/ -HorizontalHeaderTable::Builder::Builder(Header* header, WritableFontData* data) - : TableBasedTableBuilder(header, data) { -} - -HorizontalHeaderTable::Builder::Builder(Header* header, ReadableFontData* data) - : TableBasedTableBuilder(header, data) { -} - -HorizontalHeaderTable::Builder::~Builder() {} - -CALLER_ATTACH FontDataTable* - HorizontalHeaderTable::Builder::SubBuildTable(ReadableFontData* data) { - FontDataTablePtr table = new HorizontalHeaderTable(header(), data); - return table.Detach(); -} - -CALLER_ATTACH HorizontalHeaderTable::Builder* - HorizontalHeaderTable::Builder::CreateBuilder(Header* header, - WritableFontData* data) { - Ptr builder; - builder = new HorizontalHeaderTable::Builder(header, data); - return builder.Detach(); -} - -int32_t HorizontalHeaderTable::Builder::TableVersion() { - return InternalReadData()->ReadFixed(Offset::kVersion); -} - -void HorizontalHeaderTable::Builder::SetTableVersion(int32_t version) { - InternalWriteData()->WriteFixed(Offset::kVersion, version); -} - -int32_t HorizontalHeaderTable::Builder::Ascender() { - return InternalReadData()->ReadShort(Offset::kAscender); -} - -void HorizontalHeaderTable::Builder::SetAscender(int32_t ascender) { - InternalWriteData()->WriteShort(Offset::kVersion, ascender); -} - -int32_t HorizontalHeaderTable::Builder::Descender() { - return InternalReadData()->ReadShort(Offset::kDescender); -} - -void HorizontalHeaderTable::Builder::SetDescender(int32_t descender) { - InternalWriteData()->WriteShort(Offset::kDescender, descender); -} - -int32_t HorizontalHeaderTable::Builder::LineGap() { - return InternalReadData()->ReadShort(Offset::kLineGap); -} - -void HorizontalHeaderTable::Builder::SetLineGap(int32_t line_gap) { - InternalWriteData()->WriteShort(Offset::kLineGap, line_gap); -} - -int32_t HorizontalHeaderTable::Builder::AdvanceWidthMax() { - return InternalReadData()->ReadUShort(Offset::kAdvanceWidthMax); -} - -void HorizontalHeaderTable::Builder::SetAdvanceWidthMax(int32_t value) { - InternalWriteData()->WriteUShort(Offset::kAdvanceWidthMax, value); -} - -int32_t HorizontalHeaderTable::Builder::MinLeftSideBearing() { - return InternalReadData()->ReadShort(Offset::kMinLeftSideBearing); -} - -void HorizontalHeaderTable::Builder::SetMinLeftSideBearing(int32_t value) { - InternalWriteData()->WriteShort(Offset::kMinLeftSideBearing, value); -} - -int32_t HorizontalHeaderTable::Builder::MinRightSideBearing() { - return InternalReadData()->ReadShort(Offset::kMinRightSideBearing); -} - -void HorizontalHeaderTable::Builder::SetMinRightSideBearing(int32_t value) { - InternalWriteData()->WriteShort(Offset::kMinRightSideBearing, value); -} - -int32_t HorizontalHeaderTable::Builder::XMaxExtent() { - return InternalReadData()->ReadShort(Offset::kXMaxExtent); -} - -void HorizontalHeaderTable::Builder::SetXMaxExtent(int32_t value) { - InternalWriteData()->WriteShort(Offset::kXMaxExtent, value); -} - -int32_t HorizontalHeaderTable::Builder::CaretSlopeRise() { - return InternalReadData()->ReadUShort(Offset::kCaretSlopeRise); -} - -void HorizontalHeaderTable::Builder::SetCaretSlopeRise(int32_t value) { - InternalWriteData()->WriteUShort(Offset::kCaretSlopeRise, value); -} - -int32_t HorizontalHeaderTable::Builder::CaretSlopeRun() { - return InternalReadData()->ReadUShort(Offset::kCaretSlopeRun); -} - -void HorizontalHeaderTable::Builder::SetCaretSlopeRun(int32_t value) { - InternalWriteData()->WriteUShort(Offset::kCaretSlopeRun, value); -} - -int32_t HorizontalHeaderTable::Builder::CaretOffset() { - return InternalReadData()->ReadUShort(Offset::kCaretOffset); -} - -void HorizontalHeaderTable::Builder::SetCaretOffset(int32_t value) { - InternalWriteData()->WriteUShort(Offset::kCaretOffset, value); -} - -int32_t HorizontalHeaderTable::Builder::MetricDataFormat() { - return InternalReadData()->ReadUShort(Offset::kMetricDataFormat); -} - -void HorizontalHeaderTable::Builder::SetMetricDataFormat(int32_t value) { - InternalWriteData()->WriteUShort(Offset::kMetricDataFormat, value); -} - -int32_t HorizontalHeaderTable::Builder::NumberOfHMetrics() { - return InternalReadData()->ReadUShort(Offset::kNumberOfHMetrics); -} - -void HorizontalHeaderTable::Builder::SetNumberOfHMetrics(int32_t value) { - InternalWriteData()->WriteUShort(Offset::kNumberOfHMetrics, value); -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/core/horizontal_header_table.h b/src/sfntly/src/sfntly/table/core/horizontal_header_table.h deleted file mode 100644 index 71f30b4475..0000000000 --- a/src/sfntly/src/sfntly/table/core/horizontal_header_table.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_HEADER_TABLE_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_HEADER_TABLE_H_ - -#include "sfntly/table/table.h" -#include "sfntly/table/table_based_table_builder.h" - -namespace sfntly { - -// A Horizontal Header table - 'hhea'. -class HorizontalHeaderTable : public Table, - public RefCounted { - public: - // Builder for a Horizontal Header table - 'hhea'. - class Builder : public TableBasedTableBuilder, public RefCounted { - public: - // Constructor scope altered to public because C++ does not allow base - // class to instantiate derived class with protected constructors. - Builder(Header* header, WritableFontData* data); - Builder(Header* header, ReadableFontData* data); - virtual ~Builder(); - virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); - - static CALLER_ATTACH Builder* CreateBuilder(Header* header, - WritableFontData* data); - - int32_t TableVersion(); - void SetTableVersion(int32_t version); - int32_t Ascender(); - void SetAscender(int32_t ascender); - int32_t Descender(); - void SetDescender(int32_t descender); - int32_t LineGap(); - void SetLineGap(int32_t line_gap); - int32_t AdvanceWidthMax(); - void SetAdvanceWidthMax(int32_t value); - int32_t MinLeftSideBearing(); - void SetMinLeftSideBearing(int32_t value); - int32_t MinRightSideBearing(); - void SetMinRightSideBearing(int32_t value); - int32_t XMaxExtent(); - void SetXMaxExtent(int32_t value); - int32_t CaretSlopeRise(); - void SetCaretSlopeRise(int32_t value); - int32_t CaretSlopeRun(); - void SetCaretSlopeRun(int32_t value); - int32_t CaretOffset(); - void SetCaretOffset(int32_t value); - int32_t MetricDataFormat(); - void SetMetricDataFormat(int32_t value); - int32_t NumberOfHMetrics(); - void SetNumberOfHMetrics(int32_t value); - }; - - virtual ~HorizontalHeaderTable(); - int32_t TableVersion(); - int32_t Ascender(); - int32_t Descender(); - int32_t LineGap(); - int32_t AdvanceWidthMax(); - int32_t MinLeftSideBearing(); - int32_t MinRightSideBearing(); - int32_t XMaxExtent(); - int32_t CaretSlopeRise(); - int32_t CaretSlopeRun(); - int32_t CaretOffset(); - int32_t MetricDataFormat(); - int32_t NumberOfHMetrics(); - - private: - struct Offset { - enum { - kVersion = 0, - kAscender = 4, - kDescender = 6, - kLineGap = 8, - kAdvanceWidthMax = 10, - kMinLeftSideBearing = 12, - kMinRightSideBearing = 14, - kXMaxExtent = 16, - kCaretSlopeRise = 18, - kCaretSlopeRun = 20, - kCaretOffset = 22, - kMetricDataFormat = 32, - kNumberOfHMetrics = 34, - }; - }; - - HorizontalHeaderTable(Header* header, ReadableFontData* data); -}; -typedef Ptr HorizontalHeaderTablePtr; -typedef Ptr HorizontalHeaderTableBuilderPtr; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_HEADER_TABLE_H_ diff --git a/src/sfntly/src/sfntly/table/core/horizontal_metrics_table.cc b/src/sfntly/src/sfntly/table/core/horizontal_metrics_table.cc deleted file mode 100644 index 156387daaf..0000000000 --- a/src/sfntly/src/sfntly/table/core/horizontal_metrics_table.cc +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/table/core/horizontal_metrics_table.h" -#include "sfntly/port/exception_type.h" - -namespace sfntly { -/****************************************************************************** - * HorizontalMetricsTable class - ******************************************************************************/ -HorizontalMetricsTable::~HorizontalMetricsTable() {} - -int32_t HorizontalMetricsTable::NumberOfHMetrics() { - return num_hmetrics_; -} - -int32_t HorizontalMetricsTable::NumberOfLSBs() { - return num_glyphs_ - num_hmetrics_; -} - -int32_t HorizontalMetricsTable::HMetricAdvanceWidth(int32_t entry) { - if (entry > num_hmetrics_) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IndexOutOfBoundException(); -#endif - return 0; - } - int32_t offset = Offset::kHMetricsStart + (entry * Offset::kHMetricsSize) + - Offset::kHMetricsAdvanceWidth; - return data_->ReadUShort(offset); -} - -int32_t HorizontalMetricsTable::HMetricLSB(int32_t entry) { - if (entry > num_hmetrics_) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IndexOutOfBoundException(); -#endif - return 0; - } - int32_t offset = Offset::kHMetricsStart + (entry * Offset::kHMetricsSize) + - Offset::kHMetricsLeftSideBearing; - return data_->ReadShort(offset); -} - -int32_t HorizontalMetricsTable::LsbTableEntry(int32_t entry) { - if (entry > num_hmetrics_) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IndexOutOfBoundException(); -#endif - return 0; - } - int32_t offset = Offset::kHMetricsStart + (entry * Offset::kHMetricsSize) + - Offset::kLeftSideBearingSize; - return data_->ReadShort(offset); -} - -int32_t HorizontalMetricsTable::AdvanceWidth(int32_t glyph_id) { - if (glyph_id < num_hmetrics_) { - return HMetricAdvanceWidth(glyph_id); - } - return HMetricAdvanceWidth(glyph_id - num_hmetrics_); -} - -int32_t HorizontalMetricsTable::LeftSideBearing(int32_t glyph_id) { - if (glyph_id < num_hmetrics_) { - return HMetricLSB(glyph_id); - } - return LsbTableEntry(glyph_id - num_hmetrics_); -} - -HorizontalMetricsTable::HorizontalMetricsTable(Header* header, - ReadableFontData* data, - int32_t num_hmetrics, - int32_t num_glyphs) - : Table(header, data), - num_hmetrics_(num_hmetrics), - num_glyphs_(num_glyphs) { -} - -/****************************************************************************** - * HorizontalMetricsTable::Builder class - ******************************************************************************/ -HorizontalMetricsTable::Builder::Builder(Header* header, WritableFontData* data) - : TableBasedTableBuilder(header, data), num_hmetrics_(-1), num_glyphs_(-1) { -} - -HorizontalMetricsTable::Builder::Builder(Header* header, ReadableFontData* data) - : TableBasedTableBuilder(header, data), num_hmetrics_(-1), num_glyphs_(-1) { -} - -HorizontalMetricsTable::Builder::~Builder() {} - -CALLER_ATTACH FontDataTable* - HorizontalMetricsTable::Builder::SubBuildTable(ReadableFontData* data) { - FontDataTablePtr table = - new HorizontalMetricsTable(header(), data, num_hmetrics_, num_glyphs_); - return table.Detach(); -} - -CALLER_ATTACH HorizontalMetricsTable::Builder* - HorizontalMetricsTable::Builder::CreateBuilder(Header* header, - WritableFontData* data) { - Ptr builder; - builder = new HorizontalMetricsTable::Builder(header, data); - return builder.Detach(); -} - -void HorizontalMetricsTable::Builder::SetNumberOfHMetrics( - int32_t num_hmetrics) { - assert(num_hmetrics >= 0); - num_hmetrics_ = num_hmetrics; - HorizontalMetricsTable* table = - down_cast(this->GetTable()); - table->num_hmetrics_ = num_hmetrics; -} - -void HorizontalMetricsTable::Builder::SetNumGlyphs(int32_t num_glyphs) { - assert(num_glyphs >= 0); - num_glyphs_ = num_glyphs; - HorizontalMetricsTable* table = - down_cast(this->GetTable()); - table->num_glyphs_ = num_glyphs; -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/core/horizontal_metrics_table.h b/src/sfntly/src/sfntly/table/core/horizontal_metrics_table.h deleted file mode 100644 index 44b51f2d79..0000000000 --- a/src/sfntly/src/sfntly/table/core/horizontal_metrics_table.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_METRICS_TABLE_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_METRICS_TABLE_H_ - -#include "sfntly/table/table.h" -#include "sfntly/table/table_based_table_builder.h" - -namespace sfntly { - -// A Horizontal Metrics table - 'hmtx'. -class HorizontalMetricsTable : public Table, - public RefCounted { - public: - // Builder for a Horizontal Metrics Table - 'hmtx'. - class Builder : public TableBasedTableBuilder, public RefCounted { - public: - // Constructor scope altered to public because C++ does not allow base - // class to instantiate derived class with protected constructors. - Builder(Header* header, WritableFontData* data); - Builder(Header* header, ReadableFontData* data); - virtual ~Builder(); - - virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); - static CALLER_ATTACH Builder* CreateBuilder(Header* header, - WritableFontData* data); - - void SetNumberOfHMetrics(int32_t num_hmetrics); - void SetNumGlyphs(int32_t num_glyphs); - - private: - int32_t num_hmetrics_; - int32_t num_glyphs_; - }; - - virtual ~HorizontalMetricsTable(); - int32_t NumberOfHMetrics(); - int32_t NumberOfLSBs(); - int32_t HMetricAdvanceWidth(int32_t entry); - int32_t HMetricLSB(int32_t entry); - int32_t LsbTableEntry(int32_t entry); - int32_t AdvanceWidth(int32_t glyph_id); - int32_t LeftSideBearing(int32_t glyph_id); - - private: - struct Offset { - enum { - // hMetrics - kHMetricsStart = 0, - kHMetricsSize = 4, - - // Offset within an hMetric - kHMetricsAdvanceWidth = 0, - kHMetricsLeftSideBearing = 2, - - kLeftSideBearingSize = 2 - }; - }; - - HorizontalMetricsTable(Header* header, - ReadableFontData* data, - int32_t num_hmetrics, - int32_t num_glyphs); - - int32_t num_hmetrics_; - int32_t num_glyphs_; -}; -typedef Ptr HorizontalMetricsTablePtr; -typedef Ptr HorizontalMetricsTableBuilderPtr; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_METRICS_TABLE_H_ diff --git a/src/sfntly/src/sfntly/table/core/maximum_profile_table.cc b/src/sfntly/src/sfntly/table/core/maximum_profile_table.cc deleted file mode 100644 index a8ac3bc93a..0000000000 --- a/src/sfntly/src/sfntly/table/core/maximum_profile_table.cc +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/table/core/maximum_profile_table.h" - -namespace sfntly { -/****************************************************************************** - * MaximumProfileTable class - ******************************************************************************/ -MaximumProfileTable::~MaximumProfileTable() {} - -int32_t MaximumProfileTable::TableVersion() { - return data_->ReadFixed(Offset::kVersion); -} - -int32_t MaximumProfileTable::NumGlyphs() { - return data_->ReadUShort(Offset::kNumGlyphs); -} - -int32_t MaximumProfileTable::MaxPoints() { - return data_->ReadUShort(Offset::kMaxPoints); -} - -int32_t MaximumProfileTable::MaxContours() { - return data_->ReadUShort(Offset::kMaxContours); -} - -int32_t MaximumProfileTable::MaxCompositePoints() { - return data_->ReadUShort(Offset::kMaxCompositePoints); -} - -int32_t MaximumProfileTable::MaxCompositeContours() { - return data_->ReadUShort(Offset::kMaxCompositeContours); -} - -int32_t MaximumProfileTable::MaxZones() { - return data_->ReadUShort(Offset::kMaxZones); -} - -int32_t MaximumProfileTable::MaxTwilightPoints() { - return data_->ReadUShort(Offset::kMaxTwilightPoints); -} - -int32_t MaximumProfileTable::MaxStorage() { - return data_->ReadUShort(Offset::kMaxStorage); -} - -int32_t MaximumProfileTable::MaxFunctionDefs() { - return data_->ReadUShort(Offset::kMaxFunctionDefs); -} - -int32_t MaximumProfileTable::MaxStackElements() { - return data_->ReadUShort(Offset::kMaxStackElements); -} - -int32_t MaximumProfileTable::MaxSizeOfInstructions() { - return data_->ReadUShort(Offset::kMaxSizeOfInstructions); -} - -int32_t MaximumProfileTable::MaxComponentElements() { - return data_->ReadUShort(Offset::kMaxComponentElements); -} - -int32_t MaximumProfileTable::MaxComponentDepth() { - return data_->ReadUShort(Offset::kMaxComponentDepth); -} - -MaximumProfileTable::MaximumProfileTable(Header* header, - ReadableFontData* data) - : Table(header, data) { -} - -/****************************************************************************** - * MaximumProfileTable::Builder class - ******************************************************************************/ -MaximumProfileTable::Builder::Builder(Header* header, WritableFontData* data) - : TableBasedTableBuilder(header, data) { -} - -MaximumProfileTable::Builder::Builder(Header* header, ReadableFontData* data) - : TableBasedTableBuilder(header, data) { -} - -MaximumProfileTable::Builder::~Builder() {} - -CALLER_ATTACH FontDataTable* - MaximumProfileTable::Builder::SubBuildTable(ReadableFontData* data) { - FontDataTablePtr table = new MaximumProfileTable(header(), data); - return table.Detach(); -} - -CALLER_ATTACH MaximumProfileTable::Builder* - MaximumProfileTable::Builder::CreateBuilder(Header* header, - WritableFontData* data) { - Ptr builder; - builder = new MaximumProfileTable::Builder(header, data); - return builder.Detach(); -} - -int32_t MaximumProfileTable::Builder::TableVersion() { - return InternalReadData()->ReadUShort(Offset::kVersion); -} - -void MaximumProfileTable::Builder::SetTableVersion(int32_t version) { - InternalWriteData()->WriteUShort(Offset::kVersion, version); -} - -int32_t MaximumProfileTable::Builder::NumGlyphs() { - return InternalReadData()->ReadUShort(Offset::kNumGlyphs); -} - -void MaximumProfileTable::Builder::SetNumGlyphs(int32_t num_glyphs) { - InternalWriteData()->WriteUShort(Offset::kNumGlyphs, num_glyphs); -} - -int32_t MaximumProfileTable::Builder::MaxPoints() { - return InternalReadData()->ReadUShort(Offset::kMaxPoints); -} - -void MaximumProfileTable::Builder::SetMaxPoints(int32_t max_points) { - InternalWriteData()->WriteUShort(Offset::kMaxPoints, max_points); -} - -int32_t MaximumProfileTable::Builder::MaxContours() { - return InternalReadData()->ReadUShort(Offset::kMaxContours); -} - -void MaximumProfileTable::Builder::SetMaxContours(int32_t max_contours) { - InternalWriteData()->WriteUShort(Offset::kMaxContours, max_contours); -} - -int32_t MaximumProfileTable::Builder::MaxCompositePoints() { - return InternalReadData()->ReadUShort(Offset::kMaxCompositePoints); -} - -void MaximumProfileTable::Builder::SetMaxCompositePoints( - int32_t max_composite_points) { - InternalWriteData()->WriteUShort(Offset::kMaxCompositePoints, - max_composite_points); -} - -int32_t MaximumProfileTable::Builder::MaxCompositeContours() { - return InternalReadData()->ReadUShort(Offset::kMaxCompositeContours); -} - -void MaximumProfileTable::Builder::SetMaxCompositeContours( - int32_t max_composite_contours) { - InternalWriteData()->WriteUShort(Offset::kMaxCompositeContours, - max_composite_contours); -} - -int32_t MaximumProfileTable::Builder::MaxZones() { - return InternalReadData()->ReadUShort(Offset::kMaxZones); -} - -void MaximumProfileTable::Builder::SetMaxZones(int32_t max_zones) { - InternalWriteData()->WriteUShort(Offset::kMaxZones, max_zones); -} - -int32_t MaximumProfileTable::Builder::MaxTwilightPoints() { - return InternalReadData()->ReadUShort(Offset::kMaxTwilightPoints); -} - -void MaximumProfileTable::Builder::SetMaxTwilightPoints( - int32_t max_twilight_points) { - InternalWriteData()->WriteUShort(Offset::kMaxTwilightPoints, - max_twilight_points); -} - -int32_t MaximumProfileTable::Builder::MaxStorage() { - return InternalReadData()->ReadUShort(Offset::kMaxStorage); -} - -void MaximumProfileTable::Builder::SetMaxStorage(int32_t max_storage) { - InternalWriteData()->WriteUShort(Offset::kMaxStorage, max_storage); -} - -int32_t MaximumProfileTable::Builder::MaxFunctionDefs() { - return InternalReadData()->ReadUShort(Offset::kMaxFunctionDefs); -} - -void MaximumProfileTable::Builder::SetMaxFunctionDefs( - int32_t max_function_defs) { - InternalWriteData()->WriteUShort(Offset::kMaxFunctionDefs, max_function_defs); -} - -int32_t MaximumProfileTable::Builder::MaxStackElements() { - return InternalReadData()->ReadUShort(Offset::kMaxStackElements); -} - -void MaximumProfileTable::Builder::SetMaxStackElements( - int32_t max_stack_elements) { - InternalWriteData()->WriteUShort(Offset::kMaxStackElements, - max_stack_elements); -} - -int32_t MaximumProfileTable::Builder::MaxSizeOfInstructions() { - return InternalReadData()->ReadUShort(Offset::kMaxSizeOfInstructions); -} - -void MaximumProfileTable::Builder::SetMaxSizeOfInstructions( - int32_t max_size_of_instructions) { - InternalWriteData()->WriteUShort(Offset::kMaxSizeOfInstructions, - max_size_of_instructions); -} - -int32_t MaximumProfileTable::Builder::MaxComponentElements() { - return InternalReadData()->ReadUShort(Offset::kMaxComponentElements); -} - -void MaximumProfileTable::Builder::SetMaxComponentElements( - int32_t max_component_elements) { - InternalWriteData()->WriteUShort(Offset::kMaxComponentElements, - max_component_elements); -} - -int32_t MaximumProfileTable::Builder::MaxComponentDepth() { - return InternalReadData()->ReadUShort(Offset::kMaxComponentDepth); -} - -void MaximumProfileTable::Builder::SetMaxComponentDepth( - int32_t max_component_depth) { - InternalWriteData()->WriteUShort(Offset::kMaxComponentDepth, - max_component_depth); -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/core/maximum_profile_table.h b/src/sfntly/src/sfntly/table/core/maximum_profile_table.h deleted file mode 100644 index e7c5abb3ff..0000000000 --- a/src/sfntly/src/sfntly/table/core/maximum_profile_table.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_MAXIMUM_PROFILE_TABLE_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_MAXIMUM_PROFILE_TABLE_H_ - -#include "sfntly/port/refcount.h" -#include "sfntly/table/table.h" -#include "sfntly/table/table_based_table_builder.h" - -namespace sfntly { - -// A Maximum Profile table - 'maxp'. -class MaximumProfileTable : public Table, - public RefCounted { - public: - // Builder for a Maximum Profile table - 'maxp'. - class Builder : public TableBasedTableBuilder, public RefCounted { - public: - // Constructor scope altered to public because C++ does not allow base - // class to instantiate derived class with protected constructors. - Builder(Header* header, WritableFontData* data); - Builder(Header* header, ReadableFontData* data); - virtual ~Builder(); - - virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); - static CALLER_ATTACH Builder* CreateBuilder(Header* header, - WritableFontData* data); - - int32_t TableVersion(); - void SetTableVersion(int32_t version); - int32_t NumGlyphs(); - void SetNumGlyphs(int32_t num_glyphs); - int32_t MaxPoints(); - void SetMaxPoints(int32_t max_points); - int32_t MaxContours(); - void SetMaxContours(int32_t max_contours); - int32_t MaxCompositePoints(); - void SetMaxCompositePoints(int32_t max_composite_points); - int32_t MaxCompositeContours(); - void SetMaxCompositeContours(int32_t max_composite_contours); - int32_t MaxZones(); - void SetMaxZones(int32_t max_zones); - int32_t MaxTwilightPoints(); - void SetMaxTwilightPoints(int32_t max_twilight_points); - int32_t MaxStorage(); - void SetMaxStorage(int32_t max_storage); - int32_t MaxFunctionDefs(); - void SetMaxFunctionDefs(int32_t max_function_defs); - int32_t MaxStackElements(); - void SetMaxStackElements(int32_t max_stack_elements); - int32_t MaxSizeOfInstructions(); - void SetMaxSizeOfInstructions(int32_t max_size_of_instructions); - int32_t MaxComponentElements(); - void SetMaxComponentElements(int32_t max_component_elements); - int32_t MaxComponentDepth(); - void SetMaxComponentDepth(int32_t max_component_depth); - }; - - virtual ~MaximumProfileTable(); - int32_t TableVersion(); - int32_t NumGlyphs(); - int32_t MaxPoints(); - int32_t MaxContours(); - int32_t MaxCompositePoints(); - int32_t MaxCompositeContours(); - int32_t MaxZones(); - int32_t MaxTwilightPoints(); - int32_t MaxStorage(); - int32_t MaxFunctionDefs(); - int32_t MaxStackElements(); - int32_t MaxSizeOfInstructions(); - int32_t MaxComponentElements(); - int32_t MaxComponentDepth(); - - private: - struct Offset { - enum { - // version 0.5 and 1.0 - kVersion = 0, - kNumGlyphs = 4, - - // version 1.0 - kMaxPoints = 6, - kMaxContours = 8, - kMaxCompositePoints = 10, - kMaxCompositeContours = 12, - kMaxZones = 14, - kMaxTwilightPoints = 16, - kMaxStorage = 18, - kMaxFunctionDefs = 20, - kMaxInstructionDefs = 22, - kMaxStackElements = 24, - kMaxSizeOfInstructions = 26, - kMaxComponentElements = 28, - kMaxComponentDepth = 30, - }; - }; - - MaximumProfileTable(Header* header, ReadableFontData* data); -}; -typedef Ptr MaximumProfileTablePtr; -typedef Ptr MaximumProfileTableBuilderPtr; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_MAXIMUM_PROFILE_TABLE_H_ diff --git a/src/sfntly/src/sfntly/table/core/name_table.cc b/src/sfntly/src/sfntly/table/core/name_table.cc deleted file mode 100644 index 5f6d5a5172..0000000000 --- a/src/sfntly/src/sfntly/table/core/name_table.cc +++ /dev/null @@ -1,721 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/table/core/name_table.h" - -#include -#include - -#include - -#include "sfntly/font.h" -#include "sfntly/port/exception_type.h" - -namespace sfntly { -/****************************************************************************** - * NameTable::NameEntryId class - ******************************************************************************/ -NameTable::NameEntryId::NameEntryId() - : platform_id_(0), - encoding_id_(0), - language_id_(0), - name_id_(0) { -} - -NameTable::NameEntryId::NameEntryId(int32_t platform_id, - int32_t encoding_id, - int32_t language_id, - int32_t name_id) - : platform_id_(platform_id), - encoding_id_(encoding_id), - language_id_(language_id), - name_id_(name_id) { -} - -NameTable::NameEntryId::NameEntryId(const NameTable::NameEntryId& rhs) { - *this = rhs; -} - -const NameTable::NameEntryId& - NameTable::NameEntryId::operator=(const NameTable::NameEntryId& rhs) const { - platform_id_ = rhs.platform_id_; - encoding_id_ = rhs.encoding_id_; - language_id_ = rhs.language_id_; - name_id_ = rhs.name_id_; - return *this; -} - -bool NameTable::NameEntryId::operator==(const NameEntryId& rhs) const { - return platform_id_ == rhs.platform_id_ && - encoding_id_ == rhs.encoding_id_ && - language_id_ == rhs.language_id_ && - name_id_ == rhs.name_id_; -} - -bool NameTable::NameEntryId::operator<(const NameEntryId& rhs) const { - if (platform_id_ != rhs.platform_id_) return platform_id_ < rhs.platform_id_; - if (encoding_id_ != rhs.encoding_id_) return encoding_id_ < rhs.encoding_id_; - if (language_id_ != rhs.language_id_) return language_id_ < rhs.language_id_; - return name_id_ < rhs.name_id_; -} - -/****************************************************************************** - * NameTable::NameEntry class - ******************************************************************************/ -NameTable::NameEntry::NameEntry() { - Init(0, 0, 0, 0, NULL); -} - -NameTable::NameEntry::NameEntry(const NameEntryId& name_entry_id, - const ByteVector& name_bytes) { - Init(name_entry_id.platform_id(), - name_entry_id.encoding_id(), - name_entry_id.language_id(), - name_entry_id.name_id(), - &name_bytes); -} - -NameTable::NameEntry::NameEntry(int32_t platform_id, - int32_t encoding_id, - int32_t language_id, - int32_t name_id, - const ByteVector& name_bytes) { - Init(platform_id, encoding_id, language_id, name_id, &name_bytes); -} - -NameTable::NameEntry::~NameEntry() {} - -ByteVector* NameTable::NameEntry::NameAsBytes() { - return &name_bytes_; -} - -int32_t NameTable::NameEntry::NameBytesLength() { - return name_bytes_.size(); -} - -UChar* NameTable::NameEntry::Name() { - return NameTable::ConvertFromNameBytes(&name_bytes_, - platform_id(), - encoding_id()); -} - -bool NameTable::NameEntry::operator==(const NameEntry& rhs) const { - return (name_entry_id_ == rhs.name_entry_id_ && - name_bytes_ == rhs.name_bytes_); -} - -void NameTable::NameEntry::Init(int32_t platform_id, - int32_t encoding_id, - int32_t language_id, - int32_t name_id, - const ByteVector* name_bytes) { - name_entry_id_ = NameEntryId(platform_id, encoding_id, language_id, name_id); - if (name_bytes) { - name_bytes_ = *name_bytes; - } else { - name_bytes_.clear(); - } -} - -/****************************************************************************** - * NameTable::NameEntryBuilder class - ******************************************************************************/ -NameTable::NameEntryBuilder::NameEntryBuilder() { - Init(0, 0, 0, 0, NULL); -} - -NameTable::NameEntryBuilder::NameEntryBuilder(const NameEntryId& name_entry_id, - const ByteVector& name_bytes) { - Init(name_entry_id.platform_id(), - name_entry_id.encoding_id(), - name_entry_id.language_id(), - name_entry_id.name_id(), - &name_bytes); -} - -NameTable::NameEntryBuilder::NameEntryBuilder( - const NameEntryId& name_entry_id) { - Init(name_entry_id.platform_id(), - name_entry_id.encoding_id(), - name_entry_id.language_id(), - name_entry_id.name_id(), - NULL); -} - -NameTable::NameEntryBuilder::NameEntryBuilder(NameEntry* b) { - Init(b->platform_id(), - b->encoding_id(), - b->language_id(), - b->name_id(), - b->NameAsBytes()); -} - -NameTable::NameEntryBuilder::~NameEntryBuilder() {} - -void NameTable::NameEntryBuilder::SetName(const UChar* name) { - if (name == NULL) { - name_entry_->name_bytes_.clear(); - return; - } - NameTable::ConvertToNameBytes(name, - name_entry_->platform_id(), - name_entry_->encoding_id(), - &name_entry_->name_bytes_); -} - -void NameTable::NameEntryBuilder::SetName(const ByteVector& name_bytes) { - name_entry_->name_bytes_.clear(); - std::copy(name_bytes.begin(), - name_bytes.end(), - name_entry_->name_bytes_.begin()); -} - -void NameTable::NameEntryBuilder::SetName(const ByteVector& name_bytes, - int32_t offset, - int32_t length) { - name_entry_->name_bytes_.clear(); - std::copy(name_bytes.begin() + offset, - name_bytes.begin() + offset + length, - name_entry_->name_bytes_.begin()); -} - -void NameTable::NameEntryBuilder::Init(int32_t platform_id, - int32_t encoding_id, - int32_t language_id, - int32_t name_id, - const ByteVector* name_bytes) { - name_entry_ = new NameEntry(); - name_entry_->Init(platform_id, encoding_id, language_id, name_id, name_bytes); -} - -/****************************************************************************** - * NameTable::NameEntryFilterInPlace class (C++ port only) - ******************************************************************************/ -NameTable::NameEntryFilterInPlace::NameEntryFilterInPlace(int32_t platform_id, - int32_t encoding_id, - int32_t language_id, - int32_t name_id) - : platform_id_(platform_id), - encoding_id_(encoding_id), - language_id_(language_id), - name_id_(name_id) { -} - -bool NameTable::NameEntryFilterInPlace::Accept(int32_t platform_id, - int32_t encoding_id, - int32_t language_id, - int32_t name_id) { - return (platform_id_ == platform_id && - encoding_id_ == encoding_id && - language_id_ == language_id && - name_id_ == name_id); -} - -/****************************************************************************** - * NameTable::NameEntryIterator class - ******************************************************************************/ -NameTable::NameEntryIterator::NameEntryIterator(NameTable* table) - : RefIterator(table), - name_index_(0), - filter_(NULL) { -} - -NameTable::NameEntryIterator::NameEntryIterator(NameTable* table, - NameEntryFilter* filter) - : RefIterator(table), - name_index_(0), - filter_(filter) { -} - -bool NameTable::NameEntryIterator::HasNext() { - if (!filter_) { - if (name_index_ < container()->NameCount()) { - return true; - } - return false; - } - for (; name_index_ < container()->NameCount(); ++name_index_) { - if (filter_->Accept(container()->PlatformId(name_index_), - container()->EncodingId(name_index_), - container()->LanguageId(name_index_), - container()->NameId(name_index_))) { - return true; - } - } - return false; -} - -CALLER_ATTACH NameTable::NameEntry* NameTable::NameEntryIterator::Next() { - if (!HasNext()) - return NULL; - return container()->GetNameEntry(name_index_++); -} - -/****************************************************************************** - * NameTable::Builder class - ******************************************************************************/ -NameTable::Builder::Builder(Header* header, WritableFontData* data) - : SubTableContainerTable::Builder(header, data) { -} - -NameTable::Builder::Builder(Header* header, ReadableFontData* data) - : SubTableContainerTable::Builder(header, data) { -} - -CALLER_ATTACH NameTable::Builder* - NameTable::Builder::CreateBuilder(Header* header, - WritableFontData* data) { - Ptr builder; - builder = new NameTable::Builder(header, data); - return builder.Detach(); -} - -void NameTable::Builder::RevertNames() { - name_entry_map_.clear(); - set_model_changed(false); -} - -int32_t NameTable::Builder::BuilderCount() { - GetNameBuilders(); // Ensure name_entry_map_ is built. - return (int32_t)name_entry_map_.size(); -} - -bool NameTable::Builder::Has(int32_t platform_id, - int32_t encoding_id, - int32_t language_id, - int32_t name_id) { - NameEntryId probe(platform_id, encoding_id, language_id, name_id); - GetNameBuilders(); // Ensure name_entry_map_ is built. - return (name_entry_map_.find(probe) != name_entry_map_.end()); -} - -CALLER_ATTACH NameTable::NameEntryBuilder* - NameTable::Builder::NameBuilder(int32_t platform_id, - int32_t encoding_id, - int32_t language_id, - int32_t name_id) { - NameEntryId probe(platform_id, encoding_id, language_id, name_id); - NameEntryBuilderMap builders; - GetNameBuilders(); // Ensure name_entry_map_ is built. - if (name_entry_map_.find(probe) != name_entry_map_.end()) { - return name_entry_map_[probe]; - } - NameEntryBuilderPtr builder = new NameEntryBuilder(probe); - name_entry_map_[probe] = builder; - return builder.Detach(); -} - -bool NameTable::Builder::Remove(int32_t platform_id, - int32_t encoding_id, - int32_t language_id, - int32_t name_id) { - NameEntryId probe(platform_id, encoding_id, language_id, name_id); - GetNameBuilders(); // Ensure name_entry_map_ is built. - NameEntryBuilderMap::iterator position = name_entry_map_.find(probe); - if (position != name_entry_map_.end()) { - name_entry_map_.erase(position); - return true; - } - return false; -} - -CALLER_ATTACH FontDataTable* - NameTable::Builder::SubBuildTable(ReadableFontData* data) { - FontDataTablePtr table = new NameTable(header(), data); - return table.Detach(); -} - -void NameTable::Builder::SubDataSet() { - name_entry_map_.clear(); - set_model_changed(false); -} - -int32_t NameTable::Builder::SubDataSizeToSerialize() { - if (name_entry_map_.empty()) { - return 0; - } - - int32_t size = NameTable::Offset::kNameRecordStart + - name_entry_map_.size() * NameTable::Offset::kNameRecordSize; - for (NameEntryBuilderMap::iterator b = name_entry_map_.begin(), - end = name_entry_map_.end(); - b != end; ++b) { - NameEntryBuilderPtr p = b->second; - NameEntry* entry = p->name_entry(); - size += entry->NameBytesLength(); - } - return size; -} - -bool NameTable::Builder::SubReadyToSerialize() { - return !name_entry_map_.empty(); -} - -int32_t NameTable::Builder::SubSerialize(WritableFontData* new_data) { - int32_t string_table_start_offset = - NameTable::Offset::kNameRecordStart + - name_entry_map_.size() * NameTable::Offset::kNameRecordSize; - - // Header - new_data->WriteUShort(NameTable::Offset::kFormat, 0); - new_data->WriteUShort(NameTable::Offset::kCount, name_entry_map_.size()); - new_data->WriteUShort(NameTable::Offset::kStringOffset, - string_table_start_offset); - int32_t name_record_offset = NameTable::Offset::kNameRecordStart; - int32_t string_offset = 0; - // Note: we offered operator< in NameEntryId, which will be used by std::less, - // and therefore our map will act like TreeMap in Java to provide - // sorted key set. - for (NameEntryBuilderMap::iterator b = name_entry_map_.begin(), - end = name_entry_map_.end(); - b != end; ++b) { - new_data->WriteUShort( - name_record_offset + NameTable::Offset::kNameRecordPlatformId, - b->first.platform_id()); - new_data->WriteUShort( - name_record_offset + NameTable::Offset::kNameRecordEncodingId, - b->first.encoding_id()); - new_data->WriteUShort( - name_record_offset + NameTable::Offset::kNameRecordLanguageId, - b->first.language_id()); - new_data->WriteUShort( - name_record_offset + NameTable::Offset::kNameRecordNameId, - b->first.name_id()); - NameEntry* builder_entry = b->second->name_entry(); - new_data->WriteUShort( - name_record_offset + NameTable::Offset::kNameRecordStringLength, - builder_entry->NameBytesLength()); - new_data->WriteUShort( - name_record_offset + NameTable::Offset::kNameRecordStringOffset, - string_offset); - name_record_offset += NameTable::Offset::kNameRecordSize; - string_offset += new_data->WriteBytes( - string_offset + string_table_start_offset, - builder_entry->NameAsBytes()); - } - - return string_offset + string_table_start_offset; -} - -void NameTable::Builder::Initialize(ReadableFontData* data) { - if (data) { - NameTablePtr table = new NameTable(header(), data); - Ptr name_iter; - name_iter.Attach(table->Iterator()); - while (name_iter->HasNext()) { - NameEntryPtr name_entry; - name_entry.Attach(name_iter->Next()); - NameEntryBuilderPtr name_entry_builder = new NameEntryBuilder(name_entry); - NameEntry* builder_entry = name_entry_builder->name_entry(); - NameEntryId probe = builder_entry->name_entry_id(); - name_entry_map_[probe] = name_entry_builder; - } - } -} - -NameTable::NameEntryBuilderMap* NameTable::Builder::GetNameBuilders() { - if (name_entry_map_.empty()) { - Initialize(InternalReadData()); - } - set_model_changed(); - return &name_entry_map_; -} - -/****************************************************************************** - * NameTable class - ******************************************************************************/ -NameTable::~NameTable() {} - -int32_t NameTable::Format() { - return data_->ReadUShort(Offset::kFormat); -} - -int32_t NameTable::NameCount() { - return data_->ReadUShort(Offset::kCount); -} - -int32_t NameTable::PlatformId(int32_t index) { - return data_->ReadUShort(Offset::kNameRecordPlatformId + - OffsetForNameRecord(index)); -} - -int32_t NameTable::EncodingId(int32_t index) { - return data_->ReadUShort(Offset::kNameRecordEncodingId + - OffsetForNameRecord(index)); -} - -int32_t NameTable::LanguageId(int32_t index) { - return data_->ReadUShort(Offset::kNameRecordLanguageId + - OffsetForNameRecord(index)); -} - -int32_t NameTable::NameId(int32_t index) { - return data_->ReadUShort(Offset::kNameRecordNameId + - OffsetForNameRecord(index)); -} - -void NameTable::NameAsBytes(int32_t index, ByteVector* b) { - assert(b); - int32_t length = NameLength(index); - b->clear(); - b->resize(length); - data_->ReadBytes(NameOffset(index), &((*b)[0]), 0, length); -} - -void NameTable::NameAsBytes(int32_t platform_id, - int32_t encoding_id, - int32_t language_id, - int32_t name_id, - ByteVector* b) { - assert(b); - NameEntryPtr entry; - entry.Attach(GetNameEntry(platform_id, encoding_id, language_id, name_id)); - if (entry) { - ByteVector* name = entry->NameAsBytes(); - std::copy(name->begin(), name->end(), b->begin()); - } -} - -UChar* NameTable::Name(int32_t index) { - ByteVector b; - NameAsBytes(index, &b); - return ConvertFromNameBytes(&b, PlatformId(index), EncodingId(index)); -} - -UChar* NameTable::Name(int32_t platform_id, - int32_t encoding_id, - int32_t language_id, - int32_t name_id) { - NameEntryPtr entry; - entry.Attach(GetNameEntry(platform_id, encoding_id, language_id, name_id)); - if (entry) { - return entry->Name(); - } - return NULL; -} - -CALLER_ATTACH NameTable::NameEntry* NameTable::GetNameEntry(int32_t index) { - ByteVector b; - NameAsBytes(index, &b); - NameEntryPtr instance = new NameEntry(PlatformId(index), - EncodingId(index), - LanguageId(index), - NameId(index), b); - return instance.Detach(); -} - -CALLER_ATTACH NameTable::NameEntry* NameTable::GetNameEntry(int32_t platform_id, - int32_t encoding_id, - int32_t language_id, - int32_t name_id) { - NameTable::NameEntryFilterInPlace - filter(platform_id, encoding_id, language_id, name_id); - Ptr name_entry_iter; - name_entry_iter.Attach(Iterator(&filter)); - NameEntryPtr result; - if (name_entry_iter->HasNext()) { - result = name_entry_iter->Next(); - } - return result; -} - -CALLER_ATTACH NameTable::NameEntryIterator* NameTable::Iterator() { - Ptr output = new NameTable::NameEntryIterator(this); - return output.Detach(); -} - -CALLER_ATTACH -NameTable::NameEntryIterator* NameTable::Iterator(NameEntryFilter* filter) { - Ptr output = - new NameTable::NameEntryIterator(this, filter); - return output.Detach(); -} - -NameTable::NameTable(Header* header, ReadableFontData* data) - : SubTableContainerTable(header, data) {} - -int32_t NameTable::StringOffset() { - return data_->ReadUShort(Offset::kStringOffset); -} - -int32_t NameTable::OffsetForNameRecord(int32_t index) { - return Offset::kNameRecordStart + index * Offset::kNameRecordSize; -} - -int32_t NameTable::NameLength(int32_t index) { - return data_->ReadUShort(Offset::kNameRecordStringLength + - OffsetForNameRecord(index)); -} - -int32_t NameTable::NameOffset(int32_t index) { - return data_->ReadUShort(Offset::kNameRecordStringOffset + - OffsetForNameRecord(index)) + StringOffset(); -} - -const char* NameTable::GetEncodingName(int32_t platform_id, - int32_t encoding_id) { - switch (platform_id) { - case PlatformId::kUnicode: - return "UTF-16BE"; - case PlatformId::kMacintosh: - switch (encoding_id) { - case MacintoshEncodingId::kRoman: - return "MacRoman"; - case MacintoshEncodingId::kJapanese: - return "Shift-JIS"; - case MacintoshEncodingId::kChineseTraditional: - return "Big5"; - case MacintoshEncodingId::kKorean: - return "EUC-KR"; - case MacintoshEncodingId::kArabic: - return "MacArabic"; - case MacintoshEncodingId::kHebrew: - return "MacHebrew"; - case MacintoshEncodingId::kGreek: - return "MacGreek"; - case MacintoshEncodingId::kRussian: - return "MacCyrillic"; - case MacintoshEncodingId::kRSymbol: - return "MacSymbol"; - case MacintoshEncodingId::kThai: - return "MacThai"; - case MacintoshEncodingId::kChineseSimplified: - return "EUC-CN"; - default: // Note: unknown/unconfirmed cases are not ported. - break; - } - break; - case PlatformId::kISO: - break; - case PlatformId::kWindows: - switch (encoding_id) { - case WindowsEncodingId::kSymbol: - case WindowsEncodingId::kUnicodeUCS2: - return "UTF-16BE"; - case WindowsEncodingId::kShiftJIS: - return "windows-933"; - case WindowsEncodingId::kPRC: - return "windows-936"; - case WindowsEncodingId::kBig5: - return "windows-950"; - case WindowsEncodingId::kWansung: - return "windows-949"; - case WindowsEncodingId::kJohab: - return "ms1361"; - case WindowsEncodingId::kUnicodeUCS4: - return "UCS-4"; - } - break; - case PlatformId::kCustom: - break; - default: - break; - } - return NULL; -} - -UConverter* NameTable::GetCharset(int32_t platform_id, int32_t encoding_id) { - UErrorCode error_code = U_ZERO_ERROR; - UConverter* conv = ucnv_open(GetEncodingName(platform_id, encoding_id), - &error_code); - if (U_SUCCESS(error_code)) { - return conv; - } - - if (conv) { - ucnv_close(conv); - } - return NULL; -} - -void NameTable::ConvertToNameBytes(const UChar* name, - int32_t platform_id, - int32_t encoding_id, - ByteVector* b) { - assert(b); - assert(name); - b->clear(); - UConverter* cs = GetCharset(platform_id, encoding_id); - if (cs == NULL) { - return; - } - - // Preflight to get buffer size. - UErrorCode error_code = U_ZERO_ERROR; - int32_t length = ucnv_fromUChars(cs, NULL, 0, name, -1, &error_code); - b->resize(length + 4); // The longest termination "\0" is 4 bytes. - memset(&((*b)[0]), 0, length + 4); - error_code = U_ZERO_ERROR; - ucnv_fromUChars(cs, - reinterpret_cast(&((*b)[0])), - length + 4, - name, - -1, - &error_code); - if (!U_SUCCESS(error_code)) { - b->clear(); - } - ucnv_close(cs); -} - -UChar* NameTable::ConvertFromNameBytes(ByteVector* name_bytes, - int32_t platform_id, - int32_t encoding_id) { - if (name_bytes == NULL) { - return NULL; - } - UConverter* cs = GetCharset(platform_id, encoding_id); - UErrorCode error_code = U_ZERO_ERROR; - if (cs == NULL) { - char buffer[11] = {0}; -#if defined (WIN32) - _itoa_s(platform_id, buffer, 16); -#else - snprintf(buffer, sizeof(buffer), "%x", platform_id); -#endif - UChar* result = new UChar[12]; - memset(result, 0, sizeof(UChar) * 12); - cs = ucnv_open("utf-8", &error_code); - if (U_SUCCESS(error_code)) { - ucnv_toUChars(cs, result, 12, buffer, 11, &error_code); - ucnv_close(cs); - if (U_SUCCESS(error_code)) { - return result; - } - } - delete[] result; - return NULL; - } - - // No preflight needed here, we will be bigger. - UChar* output_buffer = new UChar[name_bytes->size() + 1]; - memset(output_buffer, 0, sizeof(UChar) * (name_bytes->size() + 1)); - int32_t length = ucnv_toUChars(cs, - output_buffer, - name_bytes->size(), - reinterpret_cast(&((*name_bytes)[0])), - name_bytes->size(), - &error_code); - ucnv_close(cs); - if (length > 0) { - return output_buffer; - } - - delete[] output_buffer; - return NULL; -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/core/name_table.h b/src/sfntly/src/sfntly/table/core/name_table.h deleted file mode 100644 index 01d3b29076..0000000000 --- a/src/sfntly/src/sfntly/table/core/name_table.h +++ /dev/null @@ -1,744 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_NAME_TABLE_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_NAME_TABLE_H_ - -// Must include this before ICU to avoid stdint redefinition issue. -#include "sfntly/port/type.h" - -#include -#include - -#include -#include - -#include "sfntly/port/java_iterator.h" -#include "sfntly/table/subtable_container_table.h" - -namespace sfntly { - -// The following code implements the name table defined in TTF/OTF spec, which -// can be found at http://www.microsoft.com/typography/otspec/name.htm. - -// Name IDs defined in TTF/OTF spec. -struct NameId { - enum { - kUnknown = -1, - kCopyrightNotice = 0, - kFontFamilyName = 1, - kFontSubfamilyName = 2, - kUniqueFontIdentifier = 3, - kFullFontName = 4, - kVersionString = 5, - kPostscriptName = 6, - kTrademark = 7, - kManufacturerName = 8, - kDesigner = 9, - kDescription = 10, - kVendorURL = 11, - kDesignerURL = 12, - kLicenseDescription = 13, - kLicenseInfoURL = 14, - kReserved15 = 15, - kPreferredFamily = 16, - kPreferredSubfamily = 17, - kCompatibleFullName = 18, - kSampleText = 19, - kPostscriptCID = 20, - kWWSFamilyName = 21, - kWWSSubfamilyName = 22 - }; -}; - -// Unicode language IDs used in Name Records. -struct UnicodeLanguageId { - enum { - kUnknown = -1, - kAll = 0 - }; -}; - -// Macintosh Language IDs (platform ID = 1) -struct MacintoshLanguageId { - enum { - kUnknown = -1, - kEnglish = 0, - kFrench = 1, - kGerman = 2, - kItalian = 3, - kDutch = 4, - kSwedish = 5, - kSpanish = 6, - kDanish = 7, - kPortuguese = 8, - kNorwegian = 9, - kHebrew = 10, - kJapanese = 11, - kArabic = 12, - kFinnish = 13, - kGreek = 14, - kIcelandic = 15, - kMaltese = 16, - kTurkish = 17, - kCroatian = 18, - kChinese_Traditional = 19, - kUrdu = 20, - kHindi = 21, - kThai = 22, - kKorean = 23, - kLithuanian = 24, - kPolish = 25, - kHungarian = 26, - kEstonian = 27, - kLatvian = 28, - kSami = 29, - kFaroese = 30, - kFarsiPersian = 31, - kRussian = 32, - kChinese_Simplified = 33, - kFlemish = 34, - kIrishGaelic = 35, - kAlbanian = 36, - kRomanian = 37, - kCzech = 38, - kSlovak = 39, - kSlovenian = 40, - kYiddish = 41, - kSerbian = 42, - kMacedonian = 43, - kBulgarian = 44, - kUkrainian = 45, - kByelorussian = 46, - kUzbek = 47, - kKazakh = 48, - kAzerbaijani_Cyrillic = 49, - kAzerbaijani_Arabic = 50, - kArmenian = 51, - kGeorgian = 52, - kMoldavian = 53, - kKirghiz = 54, - kTajiki = 55, - kTurkmen = 56, - kMongolian_Mongolian = 57, - kMongolian_Cyrillic = 58, - kPashto = 59, - kKurdish = 60, - kKashmiri = 61, - kSindhi = 62, - kTibetan = 63, - kNepali = 64, - kSanskrit = 65, - kMarathi = 66, - kBengali = 67, - kAssamese = 68, - kGujarati = 69, - kPunjabi = 70, - kOriya = 71, - kMalayalam = 72, - kKannada = 73, - kTamil = 74, - kTelugu = 75, - kSinhalese = 76, - kBurmese = 77, - kKhmer = 78, - kLao = 79, - kVietnamese = 80, - kIndonesian = 81, - kTagalong = 82, - kMalay_Roman = 83, - kMalay_Arabic = 84, - kAmharic = 85, - kTigrinya = 86, - kGalla = 87, - kSomali = 88, - kSwahili = 89, - kKinyarwandaRuanda = 90, - kRundi = 91, - kNyanjaChewa = 92, - kMalagasy = 93, - kEsperanto = 94, - kWelsh = 128, - kBasque = 129, - kCatalan = 130, - kLatin = 131, - kQuenchua = 132, - kGuarani = 133, - kAymara = 134, - kTatar = 135, - kUighur = 136, - kDzongkha = 137, - kJavanese_Roman = 138, - kSundanese_Roman = 139, - kGalician = 140, - kAfrikaans = 141, - kBreton = 142, - kInuktitut = 143, - kScottishGaelic = 144, - kManxGaelic = 145, - kIrishGaelic_WithDotAbove = 146, - kTongan = 147, - kGreek_Polytonic = 148, - kGreenlandic = 149, - kAzerbaijani_Roman = 150 - }; -}; - -// Windows Language IDs (platformID = 3) -struct WindowsLanguageId { - enum { - kUnknown = -1, - kAfrikaans_SouthAfrica = 0x0436, - kAlbanian_Albania = 0x041C, - kAlsatian_France = 0x0484, - kAmharic_Ethiopia = 0x045E, - kArabic_Algeria = 0x1401, - kArabic_Bahrain = 0x3C01, - kArabic_Egypt = 0x0C01, - kArabic_Iraq = 0x0801, - kArabic_Jordan = 0x2C01, - kArabic_Kuwait = 0x3401, - kArabic_Lebanon = 0x3001, - kArabic_Libya = 0x1001, - kArabic_Morocco = 0x1801, - kArabic_Oman = 0x2001, - kArabic_Qatar = 0x4001, - kArabic_SaudiArabia = 0x0401, - kArabic_Syria = 0x2801, - kArabic_Tunisia = 0x1C01, - kArabic_UAE = 0x3801, - kArabic_Yemen = 0x2401, - kArmenian_Armenia = 0x042B, - kAssamese_India = 0x044D, - kAzeri_Cyrillic_Azerbaijan = 0x082C, - kAzeri_Latin_Azerbaijan = 0x042C, - kBashkir_Russia = 0x046D, - kBasque_Basque = 0x042D, - kBelarusian_Belarus = 0x0423, - kBengali_Bangladesh = 0x0845, - kBengali_India = 0x0445, - kBosnian_Cyrillic_BosniaAndHerzegovina = 0x201A, - kBosnian_Latin_BosniaAndHerzegovina = 0x141A, - kBreton_France = 0x047E, - kBulgarian_Bulgaria = 0x0402, - kCatalan_Catalan = 0x0403, - kChinese_HongKongSAR = 0x0C04, - kChinese_MacaoSAR = 0x1404, - kChinese_PeoplesRepublicOfChina = 0x0804, - kChinese_Singapore = 0x1004, - kChinese_Taiwan = 0x0404, - kCorsican_France = 0x0483, - kCroatian_Croatia = 0x041A, - kCroatian_Latin_BosniaAndHerzegovina = 0x101A, - kCzech_CzechRepublic = 0x0405, - kDanish_Denmark = 0x0406, - kDari_Afghanistan = 0x048C, - kDivehi_Maldives = 0x0465, - kDutch_Belgium = 0x0813, - kDutch_Netherlands = 0x0413, - kEnglish_Australia = 0x0C09, - kEnglish_Belize = 0x2809, - kEnglish_Canada = 0x1009, - kEnglish_Caribbean = 0x2409, - kEnglish_India = 0x4009, - kEnglish_Ireland = 0x1809, - kEnglish_Jamaica = 0x2009, - kEnglish_Malaysia = 0x4409, - kEnglish_NewZealand = 0x1409, - kEnglish_RepublicOfThePhilippines = 0x3409, - kEnglish_Singapore = 0x4809, - kEnglish_SouthAfrica = 0x1C09, - kEnglish_TrinidadAndTobago = 0x2C09, - kEnglish_UnitedKingdom = 0x0809, - kEnglish_UnitedStates = 0x0409, - kEnglish_Zimbabwe = 0x3009, - kEstonian_Estonia = 0x0425, - kFaroese_FaroeIslands = 0x0438, - kFilipino_Philippines = 0x0464, - kFinnish_Finland = 0x040B, - kFrench_Belgium = 0x080C, - kFrench_Canada = 0x0C0C, - kFrench_France = 0x040C, - kFrench_Luxembourg = 0x140c, - kFrench_PrincipalityOfMonoco = 0x180C, - kFrench_Switzerland = 0x100C, - kFrisian_Netherlands = 0x0462, - kGalician_Galician = 0x0456, - kGeorgian_Georgia = 0x0437, - kGerman_Austria = 0x0C07, - kGerman_Germany = 0x0407, - kGerman_Liechtenstein = 0x1407, - kGerman_Luxembourg = 0x1007, - kGerman_Switzerland = 0x0807, - kGreek_Greece = 0x0408, - kGreenlandic_Greenland = 0x046F, - kGujarati_India = 0x0447, - kHausa_Latin_Nigeria = 0x0468, - kHebrew_Israel = 0x040D, - kHindi_India = 0x0439, - kHungarian_Hungary = 0x040E, - kIcelandic_Iceland = 0x040F, - kIgbo_Nigeria = 0x0470, - kIndonesian_Indonesia = 0x0421, - kInuktitut_Canada = 0x045D, - kInuktitut_Latin_Canada = 0x085D, - kIrish_Ireland = 0x083C, - kisiXhosa_SouthAfrica = 0x0434, - kisiZulu_SouthAfrica = 0x0435, - kItalian_Italy = 0x0410, - kItalian_Switzerland = 0x0810, - kJapanese_Japan = 0x0411, - kKannada_India = 0x044B, - kKazakh_Kazakhstan = 0x043F, - kKhmer_Cambodia = 0x0453, - kKiche_Guatemala = 0x0486, - kKinyarwanda_Rwanda = 0x0487, - kKiswahili_Kenya = 0x0441, - kKonkani_India = 0x0457, - kKorean_Korea = 0x0412, - kKyrgyz_Kyrgyzstan = 0x0440, - kLao_LaoPDR = 0x0454, - kLatvian_Latvia = 0x0426, - kLithuanian_Lithuania = 0x0427, - kLowerSorbian_Germany = 0x082E, - kLuxembourgish_Luxembourg = 0x046E, - kMacedonian_FYROM_FormerYugoslavRepublicOfMacedonia = 0x042F, - kMalay_BruneiDarussalam = 0x083E, - kMalay_Malaysia = 0x043E, - kMalayalam_India = 0x044C, - kMaltese_Malta = 0x043A, - kMaori_NewZealand = 0x0481, - kMapudungun_Chile = 0x047A, - kMarathi_India = 0x044E, - kMohawk_Mohawk = 0x047C, - kMongolian_Cyrillic_Mongolia = 0x0450, - kMongolian_Traditional_PeoplesRepublicOfChina = 0x0850, - kNepali_Nepal = 0x0461, - kNorwegian_Bokmal_Norway = 0x0414, - kNorwegian_Nynorsk_Norway = 0x0814, - kOccitan_France = 0x0482, - kOriya_India = 0x0448, - kPashto_Afghanistan = 0x0463, - kPolish_Poland = 0x0415, - kPortuguese_Brazil = 0x0416, - kPortuguese_Portugal = 0x0816, - kPunjabi_India = 0x0446, - kQuechua_Bolivia = 0x046B, - kQuechua_Ecuador = 0x086B, - kQuechua_Peru = 0x0C6B, - kRomanian_Romania = 0x0418, - kRomansh_Switzerland = 0x0417, - kRussian_Russia = 0x0419, - kSami_Inari_Finland = 0x243B, - kSami_Lule_Norway = 0x103B, - kSami_Lule_Sweden = 0x143B, - kSami_Northern_Finland = 0x0C3B, - kSami_Northern_Norway = 0x043B, - kSami_Northern_Sweden = 0x083B, - kSami_Skolt_Finland = 0x203B, - kSami_Southern_Norway = 0x183B, - kSami_Southern_Sweden = 0x1C3B, - kSanskrit_India = 0x044F, - kSerbian_Cyrillic_BosniaAndHerzegovina = 0x1C1A, - kSerbian_Cyrillic_Serbia = 0x0C1A, - kSerbian_Latin_BosniaAndHerzegovina = 0x181A, - kSerbian_Latin_Serbia = 0x081A, - kSesothoSaLeboa_SouthAfrica = 0x046C, - kSetswana_SouthAfrica = 0x0432, - kSinhala_SriLanka = 0x045B, - kSlovak_Slovakia = 0x041B, - kSlovenian_Slovenia = 0x0424, - kSpanish_Argentina = 0x2C0A, - kSpanish_Bolivia = 0x400A, - kSpanish_Chile = 0x340A, - kSpanish_Colombia = 0x240A, - kSpanish_CostaRica = 0x140A, - kSpanish_DominicanRepublic = 0x1C0A, - kSpanish_Ecuador = 0x300A, - kSpanish_ElSalvador = 0x440A, - kSpanish_Guatemala = 0x100A, - kSpanish_Honduras = 0x480A, - kSpanish_Mexico = 0x080A, - kSpanish_Nicaragua = 0x4C0A, - kSpanish_Panama = 0x180A, - kSpanish_Paraguay = 0x3C0A, - kSpanish_Peru = 0x280A, - kSpanish_PuertoRico = 0x500A, - kSpanish_ModernSort_Spain = 0x0C0A, - kSpanish_TraditionalSort_Spain = 0x040A, - kSpanish_UnitedStates = 0x540A, - kSpanish_Uruguay = 0x380A, - kSpanish_Venezuela = 0x200A, - kSweden_Finland = 0x081D, - kSwedish_Sweden = 0x041D, - kSyriac_Syria = 0x045A, - kTajik_Cyrillic_Tajikistan = 0x0428, - kTamazight_Latin_Algeria = 0x085F, - kTamil_India = 0x0449, - kTatar_Russia = 0x0444, - kTelugu_India = 0x044A, - kThai_Thailand = 0x041E, - kTibetan_PRC = 0x0451, - kTurkish_Turkey = 0x041F, - kTurkmen_Turkmenistan = 0x0442, - kUighur_PRC = 0x0480, - kUkrainian_Ukraine = 0x0422, - kUpperSorbian_Germany = 0x042E, - kUrdu_IslamicRepublicOfPakistan = 0x0420, - kUzbek_Cyrillic_Uzbekistan = 0x0843, - kUzbek_Latin_Uzbekistan = 0x0443, - kVietnamese_Vietnam = 0x042A, - kWelsh_UnitedKingdom = 0x0452, - kWolof_Senegal = 0x0448, - kYakut_Russia = 0x0485, - kYi_PRC = 0x0478, - kYoruba_Nigeria = 0x046A - }; -}; - -class NameTable : public SubTableContainerTable, public RefCounted { - public: - // Unique identifier for a given name record. - class NameEntryId { - public: - NameEntryId(); // C++ port only, must provide default constructor. - NameEntryId(int32_t platform_id, int32_t encoding_id, int32_t language_id, - int32_t name_id); - NameEntryId(const NameEntryId&); - // Make gcc -Wnon-virtual-dtor happy. - virtual ~NameEntryId() {} - - int32_t platform_id() const { return platform_id_; } - int32_t encoding_id() const { return encoding_id_; } - int32_t language_id() const { return language_id_; } - int32_t name_id() const { return name_id_; } - - const NameEntryId& operator=(const NameEntryId& rhs) const; - bool operator==(const NameEntryId& rhs) const; - bool operator<(const NameEntryId& rhs) const; - - // UNIMPLEMENTED: int hashCode() - // String toString() - - private: - mutable int32_t platform_id_; - mutable int32_t encoding_id_; - mutable int32_t language_id_; - mutable int32_t name_id_; - }; - - class NameEntryBuilder; - - // Class to represent a name entry in the name table. - class NameEntry : public RefCounted { - public: - NameEntry(); - NameEntry(const NameEntryId& name_entry_id, const ByteVector& name_bytes); - NameEntry(int32_t platform_id, - int32_t encoding_id, - int32_t language_id, - int32_t name_id, - const ByteVector& name_bytes); - virtual ~NameEntry(); - - NameEntryId& name_entry_id() { return name_entry_id_; } - int32_t platform_id() const { return name_entry_id_.platform_id(); } - int32_t encoding_id() const { return name_entry_id_.encoding_id(); } - int32_t language_id() const { return name_entry_id_.language_id(); } - int32_t name_id() const { return name_entry_id_.name_id(); } - - // Get the bytes for name. Returned pointer is the address of private - // member of this class, do not attempt to delete. - ByteVector* NameAsBytes(); - - // C++ port only: get the length of NameAsBytes. - int32_t NameBytesLength(); - - // Returns the name in Unicode as UChar array. - // Note: ICU UChar* convention requires caller to delete[] it. - UChar* Name(); - bool operator==(const NameEntry& rhs) const; - - // UNIMPLEMENTED: String toString() - // int hashCode() - - private: - void Init(int32_t platform_id, int32_t encoding_id, int32_t language_id, - int32_t name_id, const ByteVector* name_bytes); - - NameEntryId name_entry_id_; - int32_t length_; - ByteVector name_bytes_; - - friend class NameEntryBuilder; - }; - - // Builder of a name entry. - // C++ port: original Java hierarchy inherits from NameEntry. In C++ port, we - // opted not doing so to avoid ref count issues and nasty protected members. - class NameEntryBuilder : public RefCounted { - public: - NameEntryBuilder(); - NameEntryBuilder(const NameEntryId& name_entry_id, - const ByteVector& name_bytes); - explicit NameEntryBuilder(const NameEntryId& name_entry_id); - explicit NameEntryBuilder(NameEntry* entry); - virtual ~NameEntryBuilder(); - - virtual void SetName(const UChar* name); - virtual void SetName(const ByteVector& name_bytes); - virtual void SetName(const ByteVector& name_bytes, - int32_t offset, - int32_t length); - - // C++ port only. CALLER_ATTACH is not added because the lifetime shall be - // controlled by this class, therefore the caller shall not increase the ref - // count. - NameEntry* name_entry() { return name_entry_; } - - private: - void Init(int32_t platform_id, int32_t encoding_id, int32_t language_id, - int32_t name_id, const ByteVector* name_bytes); - - Ptr name_entry_; - }; - typedef std::map > NameEntryBuilderMap; - - // An interface for a filter to use with the name entry iterator. This allows - // name entries to be iterated and only those acceptable to the filter will be - // returned. - class NameEntryFilter { - public: - virtual bool Accept(int32_t platform_id, - int32_t encoding_id, - int32_t language_id, - int32_t name_id) = 0; - // Make gcc -Wnon-virtual-dtor happy. - virtual ~NameEntryFilter() {} - }; - - // C++ port only: an in-place filter to mimic Java Iterator's filtering. - class NameEntryFilterInPlace : public NameEntryFilter { - public: - NameEntryFilterInPlace(int32_t platform_id, - int32_t encoding_id, - int32_t language_id, - int32_t name_id); - // Make gcc -Wnon-virtual-dtor happy. - virtual ~NameEntryFilterInPlace() {} - - virtual bool Accept(int32_t platform_id, - int32_t encoding_id, - int32_t language_id, - int32_t name_id); - - private: - int32_t platform_id_; - int32_t encoding_id_; - int32_t language_id_; - int32_t name_id_; - }; - - class NameEntryIterator : public RefIterator { - public: - // If filter is NULL, filter through all tables. - explicit NameEntryIterator(NameTable* table); - NameEntryIterator(NameTable* table, NameEntryFilter* filter); - virtual ~NameEntryIterator() {} - - virtual bool HasNext(); - virtual CALLER_ATTACH NameEntry* Next(); - - private: - int32_t name_index_; - NameEntryFilter* filter_; - }; - - // The builder to construct name table for outputting. - class Builder : public SubTableContainerTable::Builder, - public RefCounted { - public: - // Constructor scope altered to public because C++ does not allow base - // class to instantiate derived class with protected constructors. - Builder(Header* header, WritableFontData* data); - Builder(Header* header, ReadableFontData* data); - - static CALLER_ATTACH Builder* CreateBuilder(Header* header, - WritableFontData* data); - - // Revert the name builders for the name table to the last version that came - // from data. - void RevertNames(); - - // Number of name entry builders contained. - int32_t BuilderCount(); - - // Note: For C++ port, clear() is not implemented. The clear() function - // implies completely remove name entry builders, which is easy in - // Java but will take a lot of efforts in C++ to release the builders - // nicely and correctly. - // TODO(arthurhsu): IMPLEMENT - // Clear the name builders for the name table. - // void clear(); - - // Check the existance of a name entry builder by key. - bool Has(int32_t platform_id, int32_t encoding_id, int32_t language_id, - int32_t name_id); - - // Get name entry builder by key. - CALLER_ATTACH NameEntryBuilder* NameBuilder(int32_t platform_id, - int32_t encoding_id, int32_t language_id, int32_t name_id); - - // Remove name entry builder by key. - bool Remove(int32_t platform_id, int32_t encoding_id, int32_t language_id, - int32_t name_id); - - // FontDataTable::Builder API implementation - virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); - virtual void SubDataSet(); - virtual int32_t SubDataSizeToSerialize(); - virtual bool SubReadyToSerialize(); - virtual int32_t SubSerialize(WritableFontData* new_data); - - private: - void Initialize(ReadableFontData* data); - NameEntryBuilderMap* GetNameBuilders(); - - // Note: callers should use the getter funtion provided above to ensure that - // this is lazily initialized instead of accessing directly. - NameEntryBuilderMap name_entry_map_; - }; - - /**************************************************************************** - * public methods of NameTable class - ****************************************************************************/ - virtual ~NameTable(); - - // Get the format used in the name table. - virtual int32_t Format(); - - // Get the number of names in the name table. - virtual int32_t NameCount(); - - // Get the platform id for the given name record. - virtual int32_t PlatformId(int32_t index); - - // Get the encoding id for the given name record. - // see MacintoshEncodingId, WindowsEncodingId, UnicodeEncodingId - virtual int32_t EncodingId(int32_t index); - - // Get the language id for the given name record. - virtual int32_t LanguageId(int32_t index); - - // Get the name id for given name record. - virtual int32_t NameId(int32_t index); - - // Get the name as bytes for the specified name. If there is no entry for the - // requested name, then empty vector is returned. - virtual void NameAsBytes(int32_t index, ByteVector* b); - virtual void NameAsBytes(int32_t platform_id, int32_t encoding_id, - int32_t language_id, int32_t name_id, - ByteVector* b); - - // Get the name as a UChar* for the given name record. If there is no - // encoding conversion available for the name record then a best attempt - // UChar* will be returned. - // Note: ICU UChar* convention requires caller to delete[] it. - virtual UChar* Name(int32_t index); - - // Get the name as a UChar* for the specified name. If there is no entry for - // the requested name then NULL is returned. If there is no encoding - // conversion available for the name then a best attempt UChar* will be - // returned. - // Note: ICU UChar* convention requires caller to delete[] it. - virtual UChar* Name(int32_t platform_id, int32_t encoding_id, - int32_t language_id, int32_t name_id); - - // Note: These functions are renamed in C++ port. Their original Java name is - // nameEntry(). - virtual CALLER_ATTACH NameEntry* GetNameEntry(int32_t index); - virtual CALLER_ATTACH NameEntry* GetNameEntry(int32_t platform_id, - int32_t encoding_id, int32_t language_id, int32_t name_id); - - // Note: Not implemented in C++ port due to complexity and low usage. - // virtual void names(std::set*); - - // Get the iterator to iterate through all name entries. - virtual CALLER_ATTACH NameEntryIterator* Iterator(); - virtual CALLER_ATTACH NameEntryIterator* Iterator(NameEntryFilter* filter); - - private: - struct Offset { - enum { - kFormat = 0, - kCount = 2, - kStringOffset = 4, - kNameRecordStart = 6, - - // Format 1 - offset from the end of the name records - kLangTagCount = 0, - kLangTagRecord = 2, - - kNameRecordSize = 12, - // Name Records - kNameRecordPlatformId = 0, - kNameRecordEncodingId = 2, - kNameRecordLanguageId = 4, - kNameRecordNameId = 6, - kNameRecordStringLength = 8, - kNameRecordStringOffset = 10 - }; - }; - - // The table shall be constructed using Builder, no direct instantiation. - NameTable(Header* header, ReadableFontData* data); - - // Get the offset to the string data in the name table. - int32_t StringOffset(); - - // Get the offset for the given name record. - int32_t OffsetForNameRecord(int32_t index); - - // Get the length of the string data for the given name record. - int32_t NameLength(int32_t index); - - // Get the offset of the string data for the given name record. - int32_t NameOffset(int32_t index); - - // Note: string literals are returned. Caller shall not attempt to manipulate - // the returned pointer. - static const char* GetEncodingName(int32_t platform_id, int32_t encoding_id); - - // Note: ICU UConverter* convention requires caller to ucnv_close() it. - static UConverter* GetCharset(int32_t platform_id, int32_t encoding_id); - - // Note: Output will be stored in ByteVector* b. Original data in b will be - // erased and replaced with converted name bytes. - static void ConvertToNameBytes(const UChar* name, int32_t platform_id, - int32_t encoding_id, ByteVector* b); - - // Note: ICU UChar* convention requires caller to delete[] it. - static UChar* ConvertFromNameBytes(ByteVector* name_bytes, - int32_t platform_id, int32_t encoding_id); -}; // class NameTable -typedef Ptr NameTablePtr; -typedef Ptr NameEntryPtr; -typedef Ptr NameTableBuilderPtr; -typedef Ptr NameEntryBuilderPtr; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_NAME_TABLE_H_ diff --git a/src/sfntly/src/sfntly/table/core/os2_table.cc b/src/sfntly/src/sfntly/table/core/os2_table.cc deleted file mode 100644 index 7ca9d9a4fd..0000000000 --- a/src/sfntly/src/sfntly/table/core/os2_table.cc +++ /dev/null @@ -1,608 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/table/core/os2_table.h" - -namespace sfntly { -/****************************************************************************** - * Constants - ******************************************************************************/ -const int64_t CodePageRange::kLatin1_1252 = (int64_t)1 << 0; -const int64_t CodePageRange::kLatin2_1250 = (int64_t)1 << (int64_t)1; -const int64_t CodePageRange::kCyrillic_1251 = (int64_t)1 << 2; -const int64_t CodePageRange::kGreek_1253 = (int64_t)1 << 3; -const int64_t CodePageRange::kTurkish_1254 = (int64_t)1 << 4; -const int64_t CodePageRange::kHebrew_1255 = (int64_t)1 << 5; -const int64_t CodePageRange::kArabic_1256 = (int64_t)1 << 6; -const int64_t CodePageRange::kWindowsBaltic_1257 = (int64_t)1 << 7; -const int64_t CodePageRange::kVietnamese_1258 = (int64_t)1 << 8; -const int64_t CodePageRange::kAlternateANSI9 = (int64_t)1 << 9; -const int64_t CodePageRange::kAlternateANSI10 = (int64_t)1 << 10; -const int64_t CodePageRange::kAlternateANSI11 = (int64_t)1 << 11; -const int64_t CodePageRange::kAlternateANSI12 = (int64_t)1 << 12; -const int64_t CodePageRange::kAlternateANSI13 = (int64_t)1 << 13; -const int64_t CodePageRange::kAlternateANSI14 = (int64_t)1 << 14; -const int64_t CodePageRange::kAlternateANSI15 = (int64_t)1 << 15; -const int64_t CodePageRange::kThai_874 = (int64_t)1 << 16; -const int64_t CodePageRange::kJapanJIS_932 = (int64_t)1 << 17; -const int64_t CodePageRange::kChineseSimplified_936 = (int64_t)1 << 18; -const int64_t CodePageRange::kKoreanWansung_949 = (int64_t)1 << 19; -const int64_t CodePageRange::kChineseTraditional_950 = (int64_t)1 << 20; -const int64_t CodePageRange::kKoreanJohab_1361 = (int64_t)1 << 21; -const int64_t CodePageRange::kAlternateANSI22 = (int64_t)1 << 22; -const int64_t CodePageRange::kAlternateANSI23 = (int64_t)1 << 23; -const int64_t CodePageRange::kAlternateANSI24 = (int64_t)1 << 24; -const int64_t CodePageRange::kAlternateANSI25 = (int64_t)1 << 25; -const int64_t CodePageRange::kAlternateANSI26 = (int64_t)1 << 26; -const int64_t CodePageRange::kAlternateANSI27 = (int64_t)1 << 27; -const int64_t CodePageRange::kAlternateANSI28 = (int64_t)1 << 28; -const int64_t CodePageRange::kMacintoshCharacterSet = (int64_t)1 << 29; -const int64_t CodePageRange::kOEMCharacterSet = (int64_t)1 << 30; -const int64_t CodePageRange::kSymbolCharacterSet = (int64_t)1 << 31; -const int64_t CodePageRange::kReservedForOEM32 = (int64_t)1 << 32; -const int64_t CodePageRange::kReservedForOEM33 = (int64_t)1 << 33; -const int64_t CodePageRange::kReservedForOEM34 = (int64_t)1 << 34; -const int64_t CodePageRange::kReservedForOEM35 = (int64_t)1 << 35; -const int64_t CodePageRange::kReservedForOEM36 = (int64_t)1 << 36; -const int64_t CodePageRange::kReservedForOEM37 = (int64_t)1 << 37; -const int64_t CodePageRange::kReservedForOEM38 = (int64_t)1 << 38; -const int64_t CodePageRange::kReservedForOEM39 = (int64_t)1 << 39; -const int64_t CodePageRange::kReservedForOEM40 = (int64_t)1 << 40; -const int64_t CodePageRange::kReservedForOEM41 = (int64_t)1 << 41; -const int64_t CodePageRange::kReservedForOEM42 = (int64_t)1 << 42; -const int64_t CodePageRange::kReservedForOEM43 = (int64_t)1 << 43; -const int64_t CodePageRange::kReservedForOEM44 = (int64_t)1 << 44; -const int64_t CodePageRange::kReservedForOEM45 = (int64_t)1 << 45; -const int64_t CodePageRange::kReservedForOEM46 = (int64_t)1 << 46; -const int64_t CodePageRange::kReservedForOEM47 = (int64_t)1 << 47; -const int64_t CodePageRange::kIBMGreek_869 = (int64_t)1 << 48; -const int64_t CodePageRange::kMSDOSRussion_866 = (int64_t)1 << 49; -const int64_t CodePageRange::kMSDOSNordic_865 = (int64_t)1 << 50; -const int64_t CodePageRange::kArabic_864 = (int64_t)1 << 51; -const int64_t CodePageRange::kMSDOSCanadianFrench_863 = (int64_t)1 << 52; -const int64_t CodePageRange::kHebrew_862 = (int64_t)1 << 53; -const int64_t CodePageRange::kMSDOSIcelandic_861 = (int64_t)1 << 54; -const int64_t CodePageRange::kMSDOSPortugese_860 = (int64_t)1 << 55; -const int64_t CodePageRange::kIBMTurkish_857 = (int64_t)1 << 56; -const int64_t CodePageRange::kIBMCyrillic_855 = (int64_t)1 << 57; -const int64_t CodePageRange::kLatin2_852 = (int64_t)1 << 58; -const int64_t CodePageRange::kMSDOSBaltic_775 = (int64_t)1 << 59; -const int64_t CodePageRange::kGreek_737 = (int64_t)1 << 60; -const int64_t CodePageRange::kArabic_708 = (int64_t)1 << 61; -const int64_t CodePageRange::kLatin1_850 = (int64_t)1 << 62; -const int64_t CodePageRange::kUS_437 = (int64_t)1 << 63; - -/****************************************************************************** - * struct UnicodeRange - ******************************************************************************/ -int32_t UnicodeRange::range(int32_t bit) { - if (bit < 0 || bit > kLast) { - return -1; - } - return bit; -} - -/****************************************************************************** - * class OS2Table - ******************************************************************************/ -OS2Table::~OS2Table() {} - -int32_t OS2Table::TableVersion() { - return data_->ReadUShort(Offset::kVersion); -} - -int32_t OS2Table::XAvgCharWidth() { - return data_->ReadShort(Offset::kXAvgCharWidth); -} - -int32_t OS2Table::UsWeightClass() { - return data_->ReadUShort(Offset::kUsWeightClass); -} - -int32_t OS2Table::UsWidthClass() { - return data_->ReadUShort(Offset::kUsWidthClass); -} - -int32_t OS2Table::FsType() { - return data_->ReadUShort(Offset::kFsType); -} - -int32_t OS2Table::YSubscriptXSize() { - return data_->ReadShort(Offset::kYSubscriptXSize); -} - -int32_t OS2Table::YSubscriptYSize() { - return data_->ReadShort(Offset::kYSubscriptYSize); -} - -int32_t OS2Table::YSubscriptXOffset() { - return data_->ReadShort(Offset::kYSubscriptXOffset); -} - -int32_t OS2Table::YSubscriptYOffset() { - return data_->ReadShort(Offset::kYSubscriptYOffset); -} - -int32_t OS2Table::YSuperscriptXSize() { - return data_->ReadShort(Offset::kYSuperscriptXSize); -} - -int32_t OS2Table::YSuperscriptYSize() { - return data_->ReadShort(Offset::kYSuperscriptYSize); -} - -int32_t OS2Table::YSuperscriptXOffset() { - return data_->ReadShort(Offset::kYSuperscriptXOffset); -} - -int32_t OS2Table::YSuperscriptYOffset() { - return data_->ReadShort(Offset::kYSuperscriptYOffset); -} - -int32_t OS2Table::YStrikeoutSize() { - return data_->ReadShort(Offset::kYStrikeoutSize); -} - -int32_t OS2Table::YStrikeoutPosition() { - return data_->ReadShort(Offset::kYStrikeoutPosition); -} - -int32_t OS2Table::SFamilyClass() { - return data_->ReadShort(Offset::kSFamilyClass); -} - -void OS2Table::Panose(ByteVector* value) { - assert(value); - value->clear(); - value->resize(10); - data_->ReadBytes(Offset::kPanose, &((*value)[0]), 0, 10); -} - -int64_t OS2Table::UlUnicodeRange1() { - return data_->ReadULong(Offset::kUlUnicodeRange1); -} - -int64_t OS2Table::UlUnicodeRange2() { - return data_->ReadULong(Offset::kUlUnicodeRange2); -} - -int64_t OS2Table::UlUnicodeRange3() { - return data_->ReadULong(Offset::kUlUnicodeRange3); -} - -int64_t OS2Table::UlUnicodeRange4() { - return data_->ReadULong(Offset::kUlUnicodeRange4); -} - -void OS2Table::AchVendId(ByteVector* b) { - assert(b); - b->clear(); - b->resize(4); - data_->ReadBytes(Offset::kAchVendId, &((*b)[0]), 0, 4); -} - -int32_t OS2Table::FsSelection() { - return data_->ReadUShort(Offset::kFsSelection); -} - -int32_t OS2Table::UsFirstCharIndex() { - return data_->ReadUShort(Offset::kUsFirstCharIndex); -} - -int32_t OS2Table::UsLastCharIndex() { - return data_->ReadUShort(Offset::kUsLastCharIndex); -} - -int32_t OS2Table::STypoAscender() { - return data_->ReadShort(Offset::kSTypoAscender); -} - -int32_t OS2Table::STypoDescender() { - return data_->ReadShort(Offset::kSTypoDescender); -} - -int32_t OS2Table::STypoLineGap() { - return data_->ReadShort(Offset::kSTypoLineGap); -} - -int32_t OS2Table::UsWinAscent() { - return data_->ReadUShort(Offset::kUsWinAscent); -} - -int32_t OS2Table::UsWinDescent() { - return data_->ReadUShort(Offset::kUsWinDescent); -} - -int64_t OS2Table::UlCodePageRange1() { - return data_->ReadULong(Offset::kUlCodePageRange1); -} - -int64_t OS2Table::UlCodePageRange2() { - return data_->ReadULong(Offset::kUlCodePageRange2); -} - -int32_t OS2Table::SxHeight() { - return data_->ReadShort(Offset::kSxHeight); -} - -int32_t OS2Table::SCapHeight() { - return data_->ReadShort(Offset::kSCapHeight); -} - -int32_t OS2Table::UsDefaultChar() { - return data_->ReadUShort(Offset::kUsDefaultChar); -} - -int32_t OS2Table::UsBreakChar() { - return data_->ReadUShort(Offset::kUsBreakChar); -} - -int32_t OS2Table::UsMaxContext() { - return data_->ReadUShort(Offset::kUsMaxContext); -} - -OS2Table::OS2Table(Header* header, ReadableFontData* data) - : Table(header, data) { -} - -/****************************************************************************** - * class OS2Table::Builder - ******************************************************************************/ -OS2Table::Builder::Builder(Header* header, WritableFontData* data) - : TableBasedTableBuilder(header, data) { -} - -OS2Table::Builder::Builder(Header* header, ReadableFontData* data) - : TableBasedTableBuilder(header, data) { -} - -OS2Table::Builder::~Builder() {} - -CALLER_ATTACH FontDataTable* OS2Table::Builder::SubBuildTable( - ReadableFontData* data) { - FontDataTablePtr table = new OS2Table(header(), data); - return table.Detach(); -} - -CALLER_ATTACH OS2Table::Builder* - OS2Table::Builder::CreateBuilder(Header* header, - WritableFontData* data) { - Ptr builder; - builder = new OS2Table::Builder(header, data); - return builder.Detach(); -} - -int32_t OS2Table::Builder::TableVersion() { - return InternalReadData()->ReadUShort(Offset::kVersion); -} - -void OS2Table::Builder::SetTableVersion(int32_t version) { - InternalWriteData()->WriteUShort(Offset::kVersion, version); -} - -int32_t OS2Table::Builder::XAvgCharWidth() { - return InternalReadData()->ReadShort(Offset::kXAvgCharWidth); -} - -void OS2Table::Builder::SetXAvgCharWidth(int32_t width) { - InternalWriteData()->WriteShort(Offset::kXAvgCharWidth, width); -} - -int32_t OS2Table::Builder::UsWeightClass() { - return InternalReadData()->ReadUShort(Offset::kUsWeightClass); -} - -void OS2Table::Builder::SetUsWeightClass(int32_t weight) { - InternalWriteData()->WriteUShort(Offset::kUsWeightClass, weight); -} - -int32_t OS2Table::Builder::UsWidthClass() { - return InternalReadData()->ReadUShort(Offset::kUsWidthClass); -} - -void OS2Table::Builder::SetUsWidthClass(int32_t width) { - InternalWriteData()->WriteUShort(Offset::kUsWidthClass, width); -} - -int32_t OS2Table::Builder::FsType() { - return InternalReadData()->ReadUShort(Offset::kFsType); -} - -void OS2Table::Builder::SetFsType(int32_t fs_type) { - InternalWriteData()->WriteUShort(Offset::kFsType, fs_type); -} - -int32_t OS2Table::Builder::YSubscriptXSize() { - return InternalReadData()->ReadShort(Offset::kYSubscriptXSize); -} - -void OS2Table::Builder::SetYSubscriptXSize(int32_t size) { - InternalWriteData()->WriteShort(Offset::kYSubscriptXSize, size); -} - -int32_t OS2Table::Builder::YSubscriptYSize() { - return InternalReadData()->ReadShort(Offset::kYSubscriptYSize); -} - -void OS2Table::Builder::SetYSubscriptYSize(int32_t size) { - InternalWriteData()->WriteShort(Offset::kYSubscriptYSize, size); -} - -int32_t OS2Table::Builder::YSubscriptXOffset() { - return InternalReadData()->ReadShort(Offset::kYSubscriptXOffset); -} - -void OS2Table::Builder::SetYSubscriptXOffset(int32_t offset) { - InternalWriteData()->WriteShort(Offset::kYSubscriptXOffset, offset); -} - -int32_t OS2Table::Builder::YSubscriptYOffset() { - return InternalReadData()->ReadShort(Offset::kYSubscriptYOffset); -} - -void OS2Table::Builder::SetYSubscriptYOffset(int32_t offset) { - InternalWriteData()->WriteShort(Offset::kYSubscriptYOffset, offset); -} - -int32_t OS2Table::Builder::YSuperscriptXSize() { - return InternalReadData()->ReadShort(Offset::kYSuperscriptXSize); -} - -void OS2Table::Builder::SetYSuperscriptXSize(int32_t size) { - InternalWriteData()->WriteShort(Offset::kYSuperscriptXSize, size); -} - -int32_t OS2Table::Builder::YSuperscriptYSize() { - return InternalReadData()->ReadShort(Offset::kYSuperscriptYSize); -} - -void OS2Table::Builder::SetYSuperscriptYSize(int32_t size) { - InternalWriteData()->WriteShort(Offset::kYSuperscriptYSize, size); -} - -int32_t OS2Table::Builder::YSuperscriptXOffset() { - return InternalReadData()->ReadShort(Offset::kYSuperscriptXOffset); -} - -void OS2Table::Builder::SetYSuperscriptXOffset(int32_t offset) { - InternalWriteData()->WriteShort(Offset::kYSuperscriptXOffset, offset); -} - -int32_t OS2Table::Builder::YSuperscriptYOffset() { - return InternalReadData()->ReadShort(Offset::kYSuperscriptYOffset); -} - -void OS2Table::Builder::SetYSuperscriptYOffset(int32_t offset) { - InternalWriteData()->WriteShort(Offset::kYSuperscriptYOffset, offset); -} - -int32_t OS2Table::Builder::YStrikeoutSize() { - return InternalReadData()->ReadShort(Offset::kYStrikeoutSize); -} - -void OS2Table::Builder::SetYStrikeoutSize(int32_t size) { - InternalWriteData()->WriteShort(Offset::kYStrikeoutSize, size); -} - -int32_t OS2Table::Builder::YStrikeoutPosition() { - return InternalReadData()->ReadShort(Offset::kYStrikeoutPosition); -} - -void OS2Table::Builder::SetYStrikeoutPosition(int32_t position) { - InternalWriteData()->WriteShort(Offset::kYStrikeoutPosition, position); -} - -int32_t OS2Table::Builder::SFamilyClass() { - return InternalReadData()->ReadShort(Offset::kSFamilyClass); -} - -void OS2Table::Builder::SetSFamilyClass(int32_t family) { - InternalWriteData()->WriteShort(Offset::kSFamilyClass, family); -} - -void OS2Table::Builder::Panose(ByteVector* value) { - assert(value); - value->clear(); - value->resize(Offset::kPanoseLength); - InternalReadData()->ReadBytes(Offset::kPanose, - &((*value)[0]), - 0, - Offset::kPanoseLength); -} - -void OS2Table::Builder::SetPanose(ByteVector* panose) { - assert(panose); - if (panose->size() != Offset::kPanoseLength) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IllegalArgumentException("Panose bytes must be exactly 10 in length"); -#endif - return; - } - InternalWriteData()->WriteBytes(Offset::kPanose, panose); -} - -int64_t OS2Table::Builder::UlUnicodeRange1() { - return InternalReadData()->ReadULong(Offset::kUlUnicodeRange1); -} - -void OS2Table::Builder::SetUlUnicodeRange1(int64_t range) { - InternalWriteData()->WriteULong(Offset::kUlUnicodeRange1, range); -} - -int64_t OS2Table::Builder::UlUnicodeRange2() { - return InternalReadData()->ReadULong(Offset::kUlUnicodeRange2); -} - -void OS2Table::Builder::SetUlUnicodeRange2(int64_t range) { - InternalWriteData()->WriteULong(Offset::kUlUnicodeRange2, range); -} - -int64_t OS2Table::Builder::UlUnicodeRange3() { - return InternalReadData()->ReadULong(Offset::kUlUnicodeRange3); -} - -void OS2Table::Builder::SetUlUnicodeRange3(int64_t range) { - InternalWriteData()->WriteULong(Offset::kUlUnicodeRange3, range); -} - -int64_t OS2Table::Builder::UlUnicodeRange4() { - return InternalReadData()->ReadULong(Offset::kUlUnicodeRange4); -} - -void OS2Table::Builder::SetUlUnicodeRange4(int64_t range) { - InternalWriteData()->WriteULong(Offset::kUlUnicodeRange4, range); -} - -void OS2Table::Builder::AchVendId(ByteVector* b) { - assert(b); - b->clear(); - b->resize(4); - InternalReadData()->ReadBytes(Offset::kAchVendId, &((*b)[0]), 0, 4); -} - -void OS2Table::Builder::SetAchVendId(ByteVector* b) { - assert(b); - assert(b->size()); - InternalWriteData()->WriteBytesPad(Offset::kAchVendId, - b, - 0, - std::min( - (size_t)Offset::kAchVendIdLength, - b->size()), - static_cast(' ')); -} - -int32_t OS2Table::Builder::FsSelection() { - return InternalReadData()->ReadUShort(Offset::kFsSelection); -} - -void OS2Table::Builder::SetFsSelection(int32_t fs_selection) { - InternalWriteData()->WriteUShort(Offset::kFsSelection, fs_selection); -} - -int32_t OS2Table::Builder::UsFirstCharIndex() { - return InternalReadData()->ReadUShort(Offset::kUsFirstCharIndex); -} - -void OS2Table::Builder::SetUsFirstCharIndex(int32_t first_index) { - InternalWriteData()->WriteUShort(Offset::kUsFirstCharIndex, first_index); -} - -int32_t OS2Table::Builder::UsLastCharIndex() { - return InternalReadData()->ReadUShort(Offset::kUsLastCharIndex); -} - -void OS2Table::Builder::SetUsLastCharIndex(int32_t last_index) { - InternalWriteData()->WriteUShort(Offset::kUsLastCharIndex, last_index); -} - -int32_t OS2Table::Builder::STypoAscender() { - return InternalReadData()->ReadShort(Offset::kSTypoAscender); -} - -void OS2Table::Builder::SetSTypoAscender(int32_t ascender) { - InternalWriteData()->WriteShort(Offset::kSTypoAscender, ascender); -} - -int32_t OS2Table::Builder::STypoDescender() { - return InternalReadData()->ReadShort(Offset::kSTypoDescender); -} - -void OS2Table::Builder::SetSTypoDescender(int32_t descender) { - InternalWriteData()->WriteShort(Offset::kSTypoDescender, descender); -} - -int32_t OS2Table::Builder::STypoLineGap() { - return InternalReadData()->ReadShort(Offset::kSTypoLineGap); -} - -void OS2Table::Builder::SetSTypoLineGap(int32_t line_gap) { - InternalWriteData()->WriteShort(Offset::kSTypoLineGap, line_gap); -} - -int32_t OS2Table::Builder::UsWinAscent() { - return InternalReadData()->ReadUShort(Offset::kUsWinAscent); -} - -void OS2Table::Builder::SetUsWinAscent(int32_t ascent) { - InternalWriteData()->WriteUShort(Offset::kUsWinAscent, ascent); -} - -int32_t OS2Table::Builder::UsWinDescent() { - return InternalReadData()->ReadUShort(Offset::kUsWinDescent); -} - -void OS2Table::Builder::SetUsWinDescent(int32_t descent) { - InternalWriteData()->WriteUShort(Offset::kUsWinDescent, descent); -} - -int64_t OS2Table::Builder::UlCodePageRange1() { - return InternalReadData()->ReadULong(Offset::kUlCodePageRange1); -} - -void OS2Table::Builder::SetUlCodePageRange1(int64_t range) { - InternalWriteData()->WriteULong(Offset::kUlCodePageRange1, range); -} - -int64_t OS2Table::Builder::UlCodePageRange2() { - return InternalReadData()->ReadULong(Offset::kUlCodePageRange2); -} - -void OS2Table::Builder::SetUlCodePageRange2(int64_t range) { - InternalWriteData()->WriteULong(Offset::kUlCodePageRange2, range); -} - -int32_t OS2Table::Builder::SxHeight() { - return InternalReadData()->ReadShort(Offset::kSxHeight); -} - -void OS2Table::Builder::SetSxHeight(int32_t height) { - InternalWriteData()->WriteShort(Offset::kSxHeight, height); -} - -int32_t OS2Table::Builder::SCapHeight() { - return InternalReadData()->ReadShort(Offset::kSCapHeight); -} - -void OS2Table::Builder::SetSCapHeight(int32_t height) { - InternalWriteData()->WriteShort(Offset::kSCapHeight, height); -} - -int32_t OS2Table::Builder::UsDefaultChar() { - return InternalReadData()->ReadUShort(Offset::kUsDefaultChar); -} - -void OS2Table::Builder::SetUsDefaultChar(int32_t default_char) { - InternalWriteData()->WriteUShort(Offset::kUsDefaultChar, default_char); -} - -int32_t OS2Table::Builder::UsBreakChar() { - return InternalReadData()->ReadUShort(Offset::kUsBreakChar); -} - -void OS2Table::Builder::SetUsBreakChar(int32_t break_char) { - InternalWriteData()->WriteUShort(Offset::kUsBreakChar, break_char); -} - -int32_t OS2Table::Builder::UsMaxContext() { - return InternalReadData()->ReadUShort(Offset::kUsMaxContext); -} - -void OS2Table::Builder::SetUsMaxContext(int32_t max_context) { - InternalWriteData()->WriteUShort(Offset::kUsMaxContext, max_context); -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/core/os2_table.h b/src/sfntly/src/sfntly/table/core/os2_table.h deleted file mode 100644 index 00d26d2a3b..0000000000 --- a/src/sfntly/src/sfntly/table/core/os2_table.h +++ /dev/null @@ -1,508 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_OS2_TABLE_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_OS2_TABLE_H_ - -#include "sfntly/port/refcount.h" -#include "sfntly/table/table.h" -#include "sfntly/table/table_based_table_builder.h" - -namespace sfntly { - -struct WeightClass { - enum { - kThin = 100, - kExtraLight = 200, - kUltraLight = 200, - kLight = 300, - kNormal = 400, - kRegular = 400, - kMedium = 500, - kSemiBold = 600, - kDemiBold = 600, - kBold = 700, - kExtraBold = 800, - kUltraBold = 800, - kBlack = 900, - kHeavy = 900 - }; -}; - -struct WidthClass { - enum { - kUltraCondensed = 1, - kExtraCondensed = 2, - kCondensed = 3, - kSemiCondensed = 4, - kMedium = 5, - kNormal = 5, - kSemiExpanded = 6, - kExpanded = 7, - kExtraExpanded = 8, - kUltraExpanded = 9 - }; -}; - -// Flags to indicate the embedding licensing rights for a font. -struct EmbeddingFlags { - enum { - kReserved0 = 1 << 0, - kRestrictedLicenseEmbedding = 1 << 1, - kPreviewAndPrintEmbedding = 1 << 2, - kEditableEmbedding = 1 << 3, - kReserved4 = 1 << 4, - kReserved5 = 1 << 5, - kReserved6 = 1 << 6, - kReserved7 = 1 << 7, - kNoSubsetting = 1 << 8, - kBitmapEmbeddingOnly = 1 << 9, - kReserved10 = 1 << 10, - kReserved11 = 1 << 11, - kReserved12 = 1 << 12, - kReserved13 = 1 << 13, - kReserved14 = 1 << 14, - kReserved15 = 1 << 15 - }; -}; - -struct UnicodeRange { - enum { - // Do NOT reorder. This enum relies on the ordering of the data matching the - // ordinal numbers of the properties. - kBasicLatin, - kLatin1Supplement, - kLatinExtendedA, - kLatinExtendedB, - kIPAExtensions, - kSpacingModifierLetters, - kCombiningDiacriticalMarks, - kGreekAndCoptic, - kCoptic, - kCyrillic, - kArmenian, - kHebrew, - kVai, - kArabic, - kNKo, - kDevanagari, - kBengali, - kGurmukhi, - kGujarati, - kOriya, - kTamil, - kTelugu, - kKannada, - kMalayalam, - kThai, - kLao, - kGeorgian, - kBalinese, - kHangulJamo, - kLatinExtendedAdditional, - kGreekExtended, - kGeneralPunctuation, - kSuperscriptsAndSubscripts, - kCurrencySymbols, - kNumberForms, - kArrows, - kMathematicalOperators, - kMiscTechnical, - kControlPictures, - kOCR, - kEnclosedAlphanumerics, - kBoxDrawing, - kBlockElements, - kGeometricShapes, - kMiscSymbols, - kDingbats, - kCJKSymbolsAndPunctuation, - kHiragana, - kKatakana, - kBopomofo, - kHangulCompatibilityJamo, - kPhagspa, - kEnclosedCJKLettersAndMonths, - kCJKCompatibility, - kHangulSyllables, - kNonPlane0, - kPhoenician, - kCJKUnifiedIdeographs, - kPrivateUseAreaPlane0, - kCJKStrokes, - kAlphabeticPresentationForms, - kArabicPresentationFormsA, - kCombiningHalfMarks, - kVerticalForms, - kSmallFormVariants, - kArabicPresentationFormsB, - kHalfwidthAndFullwidthForms, - kSpecials, - kTibetan, - kSyriac, - kThaana, - kSinhala, - kMyanmar, - kEthiopic, - kCherokee, - kUnifiedCanadianAboriginalSyllabics, - kOgham, - kRunic, - kKhmer, - kMongolian, - kBraillePatterns, - kYiSyllables, - kTagalog, - kOldItalic, - kGothic, - kDeseret, - kMusicalSymbols, - kMathematicalAlphanumericSymbols, - kPrivateUsePlane15And16, - kVariationSelectors, - kTags, - kLimbu, - kTaiLe, - kNewTaiLue, - kBuginese, - kGlagolitic, - kTifnagh, - kYijingHexagramSymbols, - kSylotiNagari, - kLinearB, - kAncientGreekNumbers, - kUgaritic, - kOldPersian, - kShavian, - kOsmanya, - kCypriotSyllabary, - kKharoshthi, - kTaiXuanJingSymbols, - kCuneiform, - kCountingRodNumerals, - kSudanese, - kLepcha, - kOlChiki, - kSaurashtra, - kKayahLi, - kRejang, - kCharm, - kAncientSymbols, - kPhaistosDisc, - kCarian, - kDominoTiles, - kReserved123, - kReserved124, - kReserved125, - kReserved126, - kReserved127, - kLast = kReserved127 - }; - - int32_t range(int32_t bit); - // UNIMPLEMENTED: EnumSet asSet(long range1, long range2, - // long range3, long range4) - // long[] asArray(EnumSet rangeSet) -}; - -struct FsSelection { - enum { - kITALIC = 1 << 0, - kUNDERSCORE = 1 << 1, - kNEGATIVE = 1 << 2, - kOUTLINED = 1 << 3, - kSTRIKEOUT = 1 << 4, - kBOLD = 1 << 5, - kREGULAR = 1 << 6, - kUSE_TYPO_METRICS = 1 << 7, - kWWS = 1 << 8, - kOBLIQUE = 1 << 9 - }; - // UNIMPLEMENTED: EnumSet asSet(long range1, long range2, - // long range3, long range4) - // long[] asArray(EnumSet rangeSet) -}; - -// C++ port only: C++ does not support 64-bit enums until C++0x. For better -// portability, we need to use static const int64_t instead. -struct CodePageRange { - static const int64_t kLatin1_1252; - static const int64_t kLatin2_1250; - static const int64_t kCyrillic_1251; - static const int64_t kGreek_1253; - static const int64_t kTurkish_1254; - static const int64_t kHebrew_1255; - static const int64_t kArabic_1256; - static const int64_t kWindowsBaltic_1257; - static const int64_t kVietnamese_1258; - static const int64_t kAlternateANSI9; - static const int64_t kAlternateANSI10; - static const int64_t kAlternateANSI11; - static const int64_t kAlternateANSI12; - static const int64_t kAlternateANSI13; - static const int64_t kAlternateANSI14; - static const int64_t kAlternateANSI15; - static const int64_t kThai_874; - static const int64_t kJapanJIS_932; - static const int64_t kChineseSimplified_936; - static const int64_t kKoreanWansung_949; - static const int64_t kChineseTraditional_950; - static const int64_t kKoreanJohab_1361; - static const int64_t kAlternateANSI22; - static const int64_t kAlternateANSI23; - static const int64_t kAlternateANSI24; - static const int64_t kAlternateANSI25; - static const int64_t kAlternateANSI26; - static const int64_t kAlternateANSI27; - static const int64_t kAlternateANSI28; - static const int64_t kMacintoshCharacterSet; - static const int64_t kOEMCharacterSet; - static const int64_t kSymbolCharacterSet; - static const int64_t kReservedForOEM32; - static const int64_t kReservedForOEM33; - static const int64_t kReservedForOEM34; - static const int64_t kReservedForOEM35; - static const int64_t kReservedForOEM36; - static const int64_t kReservedForOEM37; - static const int64_t kReservedForOEM38; - static const int64_t kReservedForOEM39; - static const int64_t kReservedForOEM40; - static const int64_t kReservedForOEM41; - static const int64_t kReservedForOEM42; - static const int64_t kReservedForOEM43; - static const int64_t kReservedForOEM44; - static const int64_t kReservedForOEM45; - static const int64_t kReservedForOEM46; - static const int64_t kReservedForOEM47; - static const int64_t kIBMGreek_869; - static const int64_t kMSDOSRussion_866; - static const int64_t kMSDOSNordic_865; - static const int64_t kArabic_864; - static const int64_t kMSDOSCanadianFrench_863; - static const int64_t kHebrew_862; - static const int64_t kMSDOSIcelandic_861; - static const int64_t kMSDOSPortugese_860; - static const int64_t kIBMTurkish_857; - static const int64_t kIBMCyrillic_855; - static const int64_t kLatin2_852; - static const int64_t kMSDOSBaltic_775; - static const int64_t kGreek_737; - static const int64_t kArabic_708; - static const int64_t kLatin1_850; - static const int64_t kUS_437; - - // UNIMPLEMENTED: EnumSet asSet(long range1, long range2, - // long range3, long range4) - // long[] asArray(EnumSet rangeSet) -}; - -// An OS/2 table - 'OS/2'. -class OS2Table : public Table, public RefCounted { - public: - // A builder for the OS/2 table = 'OS/2'. - class Builder : public TableBasedTableBuilder, public RefCounted { - public: - Builder(Header* header, WritableFontData* data); - Builder(Header* header, ReadableFontData* data); - virtual ~Builder(); - virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); - - static CALLER_ATTACH Builder* CreateBuilder(Header* header, - WritableFontData* data); - - int32_t TableVersion(); - void SetTableVersion(int32_t version); - int32_t XAvgCharWidth(); - void SetXAvgCharWidth(int32_t width); - int32_t UsWeightClass(); - void SetUsWeightClass(int32_t weight); - int32_t UsWidthClass(); - void SetUsWidthClass(int32_t width); - // UNIMPLEMENTED: EnumSet fsType() - // void setFsType(EnumSeT flagSet) - int32_t FsType(); - void SetFsType(int32_t fs_type); - int32_t YSubscriptXSize(); - void SetYSubscriptXSize(int32_t size); - int32_t YSubscriptYSize(); - void SetYSubscriptYSize(int32_t size); - int32_t YSubscriptXOffset(); - void SetYSubscriptXOffset(int32_t offset); - int32_t YSubscriptYOffset(); - void SetYSubscriptYOffset(int32_t offset); - int32_t YSuperscriptXSize(); - void SetYSuperscriptXSize(int32_t size); - int32_t YSuperscriptYSize(); - void SetYSuperscriptYSize(int32_t size); - int32_t YSuperscriptXOffset(); - void SetYSuperscriptXOffset(int32_t offset); - int32_t YSuperscriptYOffset(); - void SetYSuperscriptYOffset(int32_t offset); - int32_t YStrikeoutSize(); - void SetYStrikeoutSize(int32_t size); - int32_t YStrikeoutPosition(); - void SetYStrikeoutPosition(int32_t position); - int32_t SFamilyClass(); - void SetSFamilyClass(int32_t family); - void Panose(ByteVector* value); - void SetPanose(ByteVector* panose); - int64_t UlUnicodeRange1(); - void SetUlUnicodeRange1(int64_t range); - int64_t UlUnicodeRange2(); - void SetUlUnicodeRange2(int64_t range); - int64_t UlUnicodeRange3(); - void SetUlUnicodeRange3(int64_t range); - int64_t UlUnicodeRange4(); - void SetUlUnicodeRange4(int64_t range); - // UNIMPLEMENTED: EnumSet UlUnicodeRange() - // setUlUnicodeRange(EnumSet rangeSet) - void AchVendId(ByteVector* b); - // This field is 4 bytes in length and only the first 4 bytes of the byte - // array will be written. If the byte array is less than 4 bytes it will be - // padded out with space characters (0x20). - // @param b ach Vendor Id - void SetAchVendId(ByteVector* b); - // UNIMPLEMENTED: public EnumSet fsSelection() - int32_t FsSelection(); - void SetFsSelection(int32_t fs_selection); - int32_t UsFirstCharIndex(); - void SetUsFirstCharIndex(int32_t first_index); - int32_t UsLastCharIndex(); - void SetUsLastCharIndex(int32_t last_index); - int32_t STypoAscender(); - void SetSTypoAscender(int32_t ascender); - int32_t STypoDescender(); - void SetSTypoDescender(int32_t descender); - int32_t STypoLineGap(); - void SetSTypoLineGap(int32_t line_gap); - int32_t UsWinAscent(); - void SetUsWinAscent(int32_t ascent); - int32_t UsWinDescent(); - void SetUsWinDescent(int32_t descent); - int64_t UlCodePageRange1(); - void SetUlCodePageRange1(int64_t range); - int64_t UlCodePageRange2(); - void SetUlCodePageRange2(int64_t range); - // UNIMPLEMENTED: EnumSet ulCodePageRange() - // void setUlCodePageRange(EnumSet rangeSet) - int32_t SxHeight(); - void SetSxHeight(int32_t height); - int32_t SCapHeight(); - void SetSCapHeight(int32_t height); - int32_t UsDefaultChar(); - void SetUsDefaultChar(int32_t default_char); - int32_t UsBreakChar(); - void SetUsBreakChar(int32_t break_char); - int32_t UsMaxContext(); - void SetUsMaxContext(int32_t max_context); - }; - - ~OS2Table(); - - int32_t TableVersion(); - int32_t XAvgCharWidth(); - int32_t UsWeightClass(); - int32_t UsWidthClass(); - // UNIMPLEMENTED: public EnumSet fsType() - int32_t FsType(); - int32_t YSubscriptXSize(); - int32_t YSubscriptYSize(); - int32_t YSubscriptXOffset(); - int32_t YSubscriptYOffset(); - int32_t YSuperscriptXSize(); - int32_t YSuperscriptYSize(); - int32_t YSuperscriptXOffset(); - int32_t YSuperscriptYOffset(); - int32_t YStrikeoutSize(); - int32_t YStrikeoutPosition(); - int32_t SFamilyClass(); - void Panose(ByteVector* value); - int64_t UlUnicodeRange1(); - int64_t UlUnicodeRange2(); - int64_t UlUnicodeRange3(); - int64_t UlUnicodeRange4(); - // UNIMPLEMENTED: public EnumSet UlUnicodeRange() - void AchVendId(ByteVector* b); - // UNIMPLEMENTED: public EnumSet fsSelection() - int32_t FsSelection(); - int32_t UsFirstCharIndex(); - int32_t UsLastCharIndex(); - int32_t STypoAscender(); - int32_t STypoDescender(); - int32_t STypoLineGap(); - int32_t UsWinAscent(); - int32_t UsWinDescent(); - int64_t UlCodePageRange1(); - int64_t UlCodePageRange2(); - // UNIMPLEMENTED: public EnumSet ulCodePageRange() - int32_t SxHeight(); - int32_t SCapHeight(); - int32_t UsDefaultChar(); - int32_t UsBreakChar(); - int32_t UsMaxContext(); - - private: - struct Offset { - enum { - kVersion = 0, - kXAvgCharWidth = 2, - kUsWeightClass = 4, - kUsWidthClass = 6, - kFsType = 8, - kYSubscriptXSize = 10, - kYSubscriptYSize = 12, - kYSubscriptXOffset = 14, - kYSubscriptYOffset = 16, - kYSuperscriptXSize = 18, - kYSuperscriptYSize = 20, - kYSuperscriptXOffset = 22, - kYSuperscriptYOffset = 24, - kYStrikeoutSize = 26, - kYStrikeoutPosition = 28, - kSFamilyClass = 30, - kPanose = 32, - kPanoseLength = 10, // Length of panose bytes. - kUlUnicodeRange1 = 42, - kUlUnicodeRange2 = 46, - kUlUnicodeRange3 = 50, - kUlUnicodeRange4 = 54, - kAchVendId = 58, - kAchVendIdLength = 4, // Length of ach vend id bytes. - kFsSelection = 62, - kUsFirstCharIndex = 64, - kUsLastCharIndex = 66, - kSTypoAscender = 68, - kSTypoDescender = 70, - kSTypoLineGap = 72, - kUsWinAscent = 74, - kUsWinDescent = 76, - kUlCodePageRange1 = 78, - kUlCodePageRange2 = 82, - kSxHeight = 86, - kSCapHeight = 88, - kUsDefaultChar = 90, - kUsBreakChar = 92, - kUsMaxContext = 94 - }; - }; - - OS2Table(Header* header, ReadableFontData* data); -}; -typedef Ptr OS2TablePtr; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_OS2_TABLE_H_ diff --git a/src/sfntly/src/sfntly/table/font_data_table.cc b/src/sfntly/src/sfntly/table/font_data_table.cc deleted file mode 100644 index 0e27f7a771..0000000000 --- a/src/sfntly/src/sfntly/table/font_data_table.cc +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/table/font_data_table.h" - -#include "sfntly/data/font_output_stream.h" - -namespace sfntly { - -/****************************************************************************** - * FontDataTable class - ******************************************************************************/ - -FontDataTable::FontDataTable(ReadableFontData* data) { - data_ = data; -} - -FontDataTable::~FontDataTable() {} - -ReadableFontData* FontDataTable::ReadFontData() { - return data_; -} - -int32_t FontDataTable::DataLength() { - return data_->Length(); -} - -int32_t FontDataTable::Serialize(OutputStream* os) { - return data_->CopyTo(os); -} - -int32_t FontDataTable::Serialize(WritableFontData* data) { - return data_->CopyTo(data); -} - -/****************************************************************************** - * FontDataTable::Builder class - ******************************************************************************/ -CALLER_ATTACH WritableFontData* FontDataTable::Builder::Data() { - WritableFontDataPtr new_data; - if (model_changed_) { - if (!SubReadyToSerialize()) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IOException("Table not ready to build."); -#endif - return NULL; - } - int32_t size = SubDataSizeToSerialize(); - new_data.Attach(WritableFontData::CreateWritableFontData(size)); - SubSerialize(new_data); - } else { - ReadableFontDataPtr data = InternalReadData(); - new_data.Attach(WritableFontData::CreateWritableFontData( - data != NULL ? data->Length() : 0)); - if (data != NULL) { - data->CopyTo(new_data); - } - } - return new_data.Detach(); -} - -void FontDataTable::Builder::SetData(ReadableFontData* data) { - InternalSetData(data, true); -} - - -CALLER_ATTACH FontDataTable* FontDataTable::Builder::Build() { - FontDataTablePtr table; // NULL default table - ReadableFontDataPtr data = InternalReadData(); - if (model_changed_) { - // Let subclass serialize from model. - if (!SubReadyToSerialize()) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IOException("Table not ready to build."); -#endif - return NULL; - } - int32_t size = SubDataSizeToSerialize(); - WritableFontDataPtr new_data; - new_data.Attach(WritableFontData::CreateWritableFontData(size)); - SubSerialize(new_data); - data = new_data; - } - - if (data != NULL) { - table = SubBuildTable(data); - NotifyPostTableBuild(table); - } - - r_data_.Release(); - w_data_.Release(); - return table; -} - -bool FontDataTable::Builder::ReadyToBuild() { - return true; -} - -ReadableFontData* FontDataTable::Builder::InternalReadData() { - return (r_data_ != NULL) ? r_data_.p_ : - static_cast(w_data_.p_); -} - -WritableFontData* FontDataTable::Builder::InternalWriteData() { - if (w_data_ == NULL) { - WritableFontDataPtr new_data; - new_data.Attach(WritableFontData::CreateWritableFontData( - r_data_ == NULL ? 0 : r_data_->Length())); -#if !defined (SFNTLY_NO_EXCEPTION) - try { -#endif - if (r_data_) { - r_data_->CopyTo(new_data); - } -#if !defined (SFNTLY_NO_EXCEPTION) - } catch (IOException& e) { - // TODO(stuartg): fix when IOExceptions are cleaned up - } -#endif - InternalSetData(new_data, false); - } - return w_data_.p_; -} - -FontDataTable::Builder::Builder() - : model_changed_(false), - contained_model_changed_(false), - data_changed_(false) { -} - -FontDataTable::Builder::Builder(int32_t data_size) - : model_changed_(false), - contained_model_changed_(false), - data_changed_(false) { - w_data_.Attach(WritableFontData::CreateWritableFontData(data_size)); -} - -FontDataTable::Builder::Builder(WritableFontData* data) - : model_changed_(false), - contained_model_changed_(false), - data_changed_(false) { - w_data_ = data; -} - -FontDataTable::Builder::Builder(ReadableFontData* data) - : model_changed_(false), - contained_model_changed_(false), - data_changed_(false) { - r_data_ = data; -} - -FontDataTable::Builder::~Builder() { -} - -void FontDataTable::Builder::NotifyPostTableBuild(FontDataTable* table) { - // Default: NOP. - UNREFERENCED_PARAMETER(table); -} - -void FontDataTable::Builder::InternalSetData(WritableFontData* data, - bool data_changed) { - w_data_ = data; - r_data_ = NULL; - if (data_changed) { - data_changed_ = true; - SubDataSet(); - } -} - -void FontDataTable::Builder::InternalSetData(ReadableFontData* data, - bool data_changed) { - w_data_ = NULL; - r_data_ = data; - if (data_changed) { - data_changed_ = true; - SubDataSet(); - } -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/font_data_table.h b/src/sfntly/src/sfntly/table/font_data_table.h deleted file mode 100644 index 5e437e2f34..0000000000 --- a/src/sfntly/src/sfntly/table/font_data_table.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_FONT_DATA_TABLE_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TABLE_FONT_DATA_TABLE_H_ - -#include "sfntly/data/readable_font_data.h" -#include "sfntly/data/writable_font_data.h" -#include "sfntly/port/refcount.h" - -namespace sfntly { - -// An abstract base for any table that contains a FontData. This is the root of -// the table class hierarchy. -class FontDataTable : virtual public RefCount { - public: - // Note: original version is abstract Builder - // C++ template is not designed that way so plain class is chosen. - class Builder : virtual public RefCount { - public: - // Get a snapshot copy of the internal data of the builder. - // This causes any internal data structures to be serialized to a new data - // object. This data object belongs to the caller and must be properly - // disposed of. No changes are made to the builder and any changes to the - // data directly do not affect the internal state. To do that a subsequent - // call must be made to {@link #SetData(WritableFontData)}. - // @return a copy of the internal data of the builder - CALLER_ATTACH WritableFontData* Data(); - virtual void SetData(ReadableFontData* data); - - // Note: changed from protected to avoid accessibility error in C++ - virtual CALLER_ATTACH FontDataTable* Build(); - virtual bool ReadyToBuild(); - - ReadableFontData* InternalReadData(); - WritableFontData* InternalWriteData(); - - bool data_changed() { return data_changed_; } - bool model_changed() { - return current_model_changed() || contained_model_changed(); - } - bool current_model_changed() { return model_changed_; } - bool contained_model_changed() { return contained_model_changed_; } - - bool set_model_changed() { return set_model_changed(true); } - bool set_model_changed(bool changed) { - bool old = model_changed_; - model_changed_ = changed; - return old; - } - - protected: - explicit Builder(); - - // Construct a FontDataTable.Builder with a WritableFontData backing store - // of size given. A positive size will create a fixed size backing store and - // a 0 or less size is an estimate for a growable backing store with the - // estimate being the absolute of the size. - // @param dataSize if positive then a fixed size; if 0 or less then an - // estimate for a growable size - Builder(int32_t data_size); - Builder(WritableFontData* data); - Builder(ReadableFontData* data); - virtual ~Builder(); - - // subclass API - virtual void NotifyPostTableBuild(FontDataTable* table); - virtual int32_t SubSerialize(WritableFontData* new_data) = 0; - virtual bool SubReadyToSerialize() = 0; - virtual int32_t SubDataSizeToSerialize() = 0; - virtual void SubDataSet() = 0; - virtual CALLER_ATTACH FontDataTable* - SubBuildTable(ReadableFontData* data) = 0; - - private: - void InternalSetData(WritableFontData* data, bool data_changed); - void InternalSetData(ReadableFontData* data, bool data_changed); - - WritableFontDataPtr w_data_; - ReadableFontDataPtr r_data_; - bool model_changed_; - bool contained_model_changed_; // may expand to list of submodel states - bool data_changed_; - }; - - explicit FontDataTable(ReadableFontData* data); - virtual ~FontDataTable(); - - // Get the readable font data for this table. - ReadableFontData* ReadFontData(); - - // Get the length of the data for this table in bytes. This is the full - // allocated length of the data underlying the table and may or may not - // include any padding. - virtual int32_t DataLength(); - - virtual int32_t Serialize(OutputStream* os); - - protected: - virtual int32_t Serialize(WritableFontData* data); - - // TODO(arthurhsu): style guide violation: protected member, need refactoring - ReadableFontDataPtr data_; -}; -typedef Ptr FontDataTablePtr; -typedef Ptr FontDataTableBuilderPtr; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_FONT_DATA_TABLE_H_ diff --git a/src/sfntly/src/sfntly/table/generic_table_builder.cc b/src/sfntly/src/sfntly/table/generic_table_builder.cc deleted file mode 100644 index 78e679772c..0000000000 --- a/src/sfntly/src/sfntly/table/generic_table_builder.cc +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/table/generic_table_builder.h" - -namespace sfntly { - -GenericTableBuilder::~GenericTableBuilder() {} - -CALLER_ATTACH -FontDataTable* GenericTableBuilder::SubBuildTable(ReadableFontData* data) { - // Note: In C++ port, we use GenericTable, the ref-counted version of Table - UNREFERENCED_PARAMETER(data); - Ptr table = new GenericTable(header(), InternalReadData()); - return table.Detach(); -} - -// static -CALLER_ATTACH GenericTableBuilder* - GenericTableBuilder::CreateBuilder(Header* header, WritableFontData* data) { - Ptr builder = - new GenericTableBuilder(header, data); - return builder.Detach(); -} - -GenericTableBuilder::GenericTableBuilder(Header* header, - WritableFontData* data) - : TableBasedTableBuilder(header, data) { -} - -GenericTableBuilder::GenericTableBuilder(Header* header, - ReadableFontData* data) - : TableBasedTableBuilder(header, data) { -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/generic_table_builder.h b/src/sfntly/src/sfntly/table/generic_table_builder.h deleted file mode 100644 index a100ea072c..0000000000 --- a/src/sfntly/src/sfntly/table/generic_table_builder.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_GENERIC_TABLE_BUILDER_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TABLE_GENERIC_TABLE_BUILDER_H_ - -#include "sfntly/table/table_based_table_builder.h" - -namespace sfntly { - -// A table builder to do the minimal table building for an unknown table type. -class GenericTableBuilder : public TableBasedTableBuilder, - public RefCounted { - public: - virtual ~GenericTableBuilder(); - - virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); - - static CALLER_ATTACH GenericTableBuilder* - CreateBuilder(Header* header, WritableFontData* data); - - private: - GenericTableBuilder(Header* header, WritableFontData* data); - GenericTableBuilder(Header* header, ReadableFontData* data); -}; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BYTE_ARRAY_TABLE_BUILDER_H_ diff --git a/src/sfntly/src/sfntly/table/header.cc b/src/sfntly/src/sfntly/table/header.cc deleted file mode 100644 index 672ace5749..0000000000 --- a/src/sfntly/src/sfntly/table/header.cc +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/table/header.h" - -namespace sfntly { - -/****************************************************************************** - * Header class - ******************************************************************************/ -Header::Header(int32_t tag) - : tag_(tag), - offset_(0), - offset_valid_(false), - length_(0), - length_valid_(false), - checksum_(0), - checksum_valid_(false) { -} - -Header::Header(int32_t tag, int32_t length) - : tag_(tag), - offset_(0), - offset_valid_(false), - length_(length), - length_valid_(true), - checksum_(0), - checksum_valid_(false) { -} - -Header::Header(int32_t tag, int64_t checksum, int32_t offset, int32_t length) - : tag_(tag), - offset_(offset), - offset_valid_(true), - length_(length), - length_valid_(true), - checksum_(checksum), - checksum_valid_(true) { -} - -Header::~Header() {} - -bool HeaderComparatorByOffset::operator() (const HeaderPtr lhs, - const HeaderPtr rhs) { - return lhs->offset_ > rhs->offset_; -} - -bool HeaderComparatorByTag::operator() (const HeaderPtr lhs, - const HeaderPtr rhs) { - return lhs->tag_ > rhs->tag_; -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/header.h b/src/sfntly/src/sfntly/table/header.h deleted file mode 100644 index 280e556c47..0000000000 --- a/src/sfntly/src/sfntly/table/header.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_HEADER_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TABLE_HEADER_H_ - -#include "sfntly/port/refcount.h" - -namespace sfntly { - -class Header : public RefCounted
{ - public: - // Make a partial header with only the basic info for an empty new table. - explicit Header(int32_t tag); - - // Make a partial header with only the basic info for a new table. - Header(int32_t tag, int32_t length); - - // Make a full header as read from an existing font. - Header(int32_t tag, int64_t checksum, int32_t offset, int32_t length); - virtual ~Header(); - - // Get the table tag. - int32_t tag() { return tag_; } - - // Get the table offset. The offset is from the start of the font file. This - // offset value is what was read from the font file during construction of the - // font. It may not be meaningful if the font was maninpulated through the - // builders. - int32_t offset() { return offset_; } - - // Is the offset in the header valid. The offset will not be valid if the - // table was constructed during building and has no physical location in a - // font file. - bool offset_valid() { return offset_valid_; } - - // Get the length of the table as recorded in the table record header. During - // building the header length will reflect the length that was initially read - // from the font file. This may not be consistent with the current state of - // the data. - int32_t length() { return length_; } - - // Is the length in the header valid. The length will not be valid if the - // table was constructed during building and has no physical location in a - // font file until the table is built from the builder. - bool length_valid() { return length_valid_; } - - // Get the checksum for the table as recorded in the table record header. - int64_t checksum() { return checksum_; } - - // Is the checksum valid. The checksum will not be valid if the table was - // constructed during building and has no physical location in a font file. - // Note that this does *NOT* check the validity of the checksum against - // the calculated checksum for the table data. - bool checksum_valid() { return checksum_valid_; } - - // UNIMPLEMENTED: boolean equals(Object obj) - // int hashCode() - // string toString() - - private: - int32_t tag_; - int32_t offset_; - bool offset_valid_; - int32_t length_; - bool length_valid_; - int64_t checksum_; - bool checksum_valid_; - - friend class HeaderComparatorByOffset; - friend class HeaderComparatorByTag; -}; -typedef Ptr
HeaderPtr; - -class HeaderComparator { - public: - virtual ~HeaderComparator() {} - virtual bool operator()(const HeaderPtr h1, - const HeaderPtr h2) = 0; -}; - -class HeaderComparatorByOffset : public HeaderComparator { - public: - virtual ~HeaderComparatorByOffset() {} - virtual bool operator()(const HeaderPtr h1, - const HeaderPtr h2); -}; - -class HeaderComparatorByTag : public HeaderComparator { - public: - virtual ~HeaderComparatorByTag() {} - virtual bool operator()(const HeaderPtr h1, - const HeaderPtr h2); -}; - -typedef std::set HeaderOffsetSortedSet; -typedef std::set HeaderTagSortedSet; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_HEADER_H_ diff --git a/src/sfntly/src/sfntly/table/subtable.cc b/src/sfntly/src/sfntly/table/subtable.cc deleted file mode 100644 index e5b906fd37..0000000000 --- a/src/sfntly/src/sfntly/table/subtable.cc +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/table/subtable.h" - -namespace sfntly { -/****************************************************************************** - * SubTable class - ******************************************************************************/ -SubTable::~SubTable() {} - -SubTable::SubTable(ReadableFontData* data, ReadableFontData* master_data) - : FontDataTable(data), padding_(0) { - master_data_ = master_data; -} - -SubTable::SubTable(ReadableFontData* data) - : FontDataTable(data), padding_(0) { -} - -/****************************************************************************** - * SubTable::Builder class - ******************************************************************************/ -SubTable::Builder::~Builder() { -} - -SubTable::Builder::Builder(int32_t data_size) - : FontDataTable::Builder(data_size) { -} - -SubTable::Builder::Builder(WritableFontData* data, - ReadableFontData* master_data) - : FontDataTable::Builder(data) { - master_data_ = master_data; -} - -SubTable::Builder::Builder(ReadableFontData* data, - ReadableFontData* master_data) - : FontDataTable::Builder(data) { - master_data_ = master_data; -} - -SubTable::Builder::Builder(WritableFontData* data) - : FontDataTable::Builder(data) { -} - -SubTable::Builder::Builder(ReadableFontData* data) - : FontDataTable::Builder(data) { -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/subtable.h b/src/sfntly/src/sfntly/table/subtable.h deleted file mode 100644 index fa6f4c6bcd..0000000000 --- a/src/sfntly/src/sfntly/table/subtable.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_SUBTABLE_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TABLE_SUBTABLE_H_ - -#include "sfntly/table/font_data_table.h" - -namespace sfntly { - -// An abstract base class for subtables. Subtables are smaller tables nested -// within other tables and don't have an entry in the main font index. Examples -// of these are the CMap subtables within CMap table (cmap) or a glyph within -// the glyph table (glyf). -class SubTable : public FontDataTable { - public: - class Builder : public FontDataTable::Builder { - public: - virtual ~Builder(); - - protected: - // @param data the data for the subtable being built - // @param master_data the data for the full table - Builder(int32_t data_size); - Builder(WritableFontData* data, ReadableFontData* master_data); - Builder(ReadableFontData* data, ReadableFontData* master_data); - explicit Builder(WritableFontData* data); - explicit Builder(ReadableFontData* data); - - ReadableFontData* master_read_data() { return master_data_; } - - private: - ReadableFontDataPtr master_data_; - }; - - virtual ~SubTable(); - virtual int32_t Padding() { return padding_; } - - // Sets the amount of padding that is part of the data being used by this - // subtable. - void set_padding(int32_t padding) { padding_ = padding; } - - protected: - SubTable(ReadableFontData* data, ReadableFontData* master_data); - - // Note: constructor refactored in C++ to avoid heavy lifting. - // caller need to do data->Slice(offset, length) beforehand. - explicit SubTable(ReadableFontData* data); - - ReadableFontData* master_read_data() { return master_data_; } - - private: - // The data for the whole table in which this subtable is contained. - ReadableFontDataPtr master_data_; - int32_t padding_; -}; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_SUBTABLE_H_ diff --git a/src/sfntly/src/sfntly/table/subtable_container_table.h b/src/sfntly/src/sfntly/table/subtable_container_table.h deleted file mode 100644 index 0f099debb4..0000000000 --- a/src/sfntly/src/sfntly/table/subtable_container_table.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef TYPOGRAPHY_FONT_SFNTLY_SRC_SFNTLY_TABLE_SUBTABLE_CONTAINER_TABLE_H_ -#define TYPOGRAPHY_FONT_SFNTLY_SRC_SFNTLY_TABLE_SUBTABLE_CONTAINER_TABLE_H_ - -#include "sfntly/table/table.h" - -namespace sfntly { - -class SubTableContainerTable : public Table { - public: - class Builder : public Table::Builder { - public: - Builder(Header* header, WritableFontData* data) - : Table::Builder(header, data) { - } - - Builder(Header* header, ReadableFontData* data) - : Table::Builder(header, data) { - } - - virtual ~Builder() {} - }; - - SubTableContainerTable(Header* header, ReadableFontData* data) - : Table(header, data) { - } - - virtual ~SubTableContainerTable() {} -}; - -} // namespace sfntly - -#endif // TYPOGRAPHY_FONT_SFNTLY_SRC_SFNTLY_TABLE_SUBTABLE_CONTAINER_TABLE_H_ diff --git a/src/sfntly/src/sfntly/table/table.cc b/src/sfntly/src/sfntly/table/table.cc deleted file mode 100644 index cf574b838b..0000000000 --- a/src/sfntly/src/sfntly/table/table.cc +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// type.h needs to be included first because of building issues on Windows -// Type aliases we delcare are defined in other headers and make the build -// fail otherwise. -#include "sfntly/port/type.h" -#include "sfntly/table/table.h" - -#include "sfntly/font.h" -#include "sfntly/tag.h" -#include "sfntly/table/bitmap/ebdt_table.h" -#include "sfntly/table/bitmap/eblc_table.h" -#include "sfntly/table/bitmap/ebsc_table.h" -#include "sfntly/table/core/cmap_table.h" -#include "sfntly/table/core/font_header_table.h" -#include "sfntly/table/core/horizontal_device_metrics_table.h" -#include "sfntly/table/core/horizontal_header_table.h" -#include "sfntly/table/core/horizontal_metrics_table.h" -#include "sfntly/table/core/maximum_profile_table.h" -#include "sfntly/table/core/name_table.h" -#include "sfntly/table/core/os2_table.h" -#include "sfntly/table/generic_table_builder.h" -#include "sfntly/table/table_based_table_builder.h" -#include "sfntly/table/truetype/glyph_table.h" -#include "sfntly/table/truetype/loca_table.h" - -namespace sfntly { - -/****************************************************************************** - * Table class - ******************************************************************************/ -Table::~Table() {} - -int64_t Table::CalculatedChecksum() { - return data_->Checksum(); -} - -void Table::SetFont(Font* font) { - font_ = font; -} - -Table::Table(Header* header, ReadableFontData* data) - : FontDataTable(data) { - header_ = header; -} - -/****************************************************************************** - * Table::Builder class - ******************************************************************************/ -Table::Builder::~Builder() { - header_.Release(); -} - -void Table::Builder::NotifyPostTableBuild(FontDataTable* table) { - if (model_changed() || data_changed()) { - Table* derived_table = down_cast(table); - derived_table->header_ = new Header(header()->tag(), - derived_table->DataLength()); - } -} - -CALLER_ATTACH -Table::Builder* Table::Builder::GetBuilder(Header* header, - WritableFontData* table_data) { - int32_t tag = header->tag(); - Table::Builder* builder_raw = NULL; - - // Note: Tables are commented out when they are not used/ported. - // TODO(arthurhsu): IMPLEMENT: finish tables that are not ported. - if (tag == Tag::head) { - builder_raw = static_cast( - FontHeaderTable::Builder::CreateBuilder(header, table_data)); -#if defined (SFNTLY_EXPERIMENTAL) - } else if (tag == Tag::cmap) { - builder_raw = static_cast( - CMapTable::Builder::CreateBuilder(header, table_data)); -#endif // SFNTLY_EXPERIMENTAL - } else if (tag == Tag::hhea) { - builder_raw = static_cast( - HorizontalHeaderTable::Builder::CreateBuilder(header, table_data)); - } else if (tag == Tag::hmtx) { - builder_raw = static_cast( - HorizontalMetricsTable::Builder::CreateBuilder(header, table_data)); - } else if (tag == Tag::maxp) { - builder_raw = static_cast( - MaximumProfileTable::Builder::CreateBuilder(header, table_data)); - } else if (tag == Tag::name) { - builder_raw = static_cast( - NameTable::Builder::CreateBuilder(header, table_data)); - } else if (tag == Tag::OS_2) { - builder_raw = static_cast( - OS2Table::Builder::CreateBuilder(header, table_data)); - }/* else if (tag == Tag::PostScript) { - builder_raw = static_cast( - PostScriptTable::Builder::CreateBuilder(header, table_data)); - } else if (tag == Tag::cvt) { - builder_raw = static_cast( - ControlValueTable::Builder::CreateBuilder(header, table_data)); - }*/ else if (tag == Tag::glyf) { - builder_raw = static_cast( - GlyphTable::Builder::CreateBuilder(header, table_data)); - } else if (tag == Tag::loca) { - builder_raw = static_cast( - LocaTable::Builder::CreateBuilder(header, table_data)); - } else if (tag == Tag::EBDT || tag == Tag::bdat) { - builder_raw = static_cast( - EbdtTable::Builder::CreateBuilder(header, table_data)); - } else if (tag == Tag::EBLC || tag == Tag::bloc) { - builder_raw = static_cast( - EblcTable::Builder::CreateBuilder(header, table_data)); - } else if (tag == Tag::EBSC) { - builder_raw = static_cast( - EbscTable::Builder::CreateBuilder(header, table_data)); - } /* else if (tag == Tag::prep) { - builder_raw = static_cast( - ControlProgramTable::Builder::CreateBuilder(header, table_data)); - }*/ else if (tag == Tag::bhed) { - builder_raw = static_cast( - FontHeaderTable::Builder::CreateBuilder(header, table_data)); -#if defined (SFNTLY_EXPERIMENTAL) - } else if (tag == Tag::hdmx) { - builder_raw = static_cast( - HorizontalDeviceMetricsTable::Builder::CreateBuilder(header, - table_data)); -#endif // SFNTLY_EXPERIMENTAL - } else { - builder_raw = static_cast( - GenericTableBuilder::CreateBuilder(header, table_data)); - } - - return builder_raw; -} - -Table::Builder::Builder(Header* header, WritableFontData* data) - : FontDataTable::Builder(data) { - header_ = header; -} - -Table::Builder::Builder(Header* header, ReadableFontData* data) - : FontDataTable::Builder(data) { - header_ = header; -} - -Table::Builder::Builder(Header* header) { - header_ = header; -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/table.h b/src/sfntly/src/sfntly/table/table.h deleted file mode 100644 index 6ebc22df8a..0000000000 --- a/src/sfntly/src/sfntly/table/table.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_TABLE_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TABLE_TABLE_H_ - -#include -#include -#include -#include - -#include "sfntly/port/type.h" -#include "sfntly/table/font_data_table.h" -#include "sfntly/table/header.h" - -namespace sfntly { -class Font; - -// A concrete implementation of a root level table in the font. This is the base -// class used for all specific table implementations and is used as the generic -// table for all tables which have no specific implementations. -class Table : public FontDataTable { - public: - // Note: original version is Builder - // C++ template is not designed that way so plain old inheritance is - // chosen. - class Builder : public FontDataTable::Builder { - public: - virtual ~Builder(); - virtual Header* header() { return header_; } - virtual void NotifyPostTableBuild(FontDataTable* table); - - // Get a builder for the table type specified by the data in the header. - // @param header the header for the table - // @param tableData the data to be used to build the table from - // @return builder for the table specified - static CALLER_ATTACH Builder* GetBuilder(Header* header, - WritableFontData* table_data); - - // UNIMPLEMENTED: toString() - - protected: - Builder(Header* header, WritableFontData* data); - Builder(Header* header, ReadableFontData* data); - Builder(Header* header); - - private: - Ptr
header_; - }; - - // Note: GenericTableBuilder moved to table_based_table_builder.h to avoid - // circular inclusion. - - virtual ~Table(); - - // Get the calculated checksum for the data in the table. - virtual int64_t CalculatedChecksum(); - - // Get the header for the table. - virtual Header* header() { return header_; } - - // Get the tag for the table from the record header. - virtual int32_t header_tag() { return header_->tag(); } - - // Get the offset for the table from the record header. - virtual int32_t header_offset() { return header_->offset(); } - - // Get the length of the table from the record header. - virtual int32_t header_length() { return header_->length(); } - - // Get the checksum for the table from the record header. - virtual int64_t header_checksum() { return header_->checksum(); } - - // UNIMPLEMENTED: toString() - - virtual void SetFont(Font* font); - - protected: - Table(Header* header, ReadableFontData* data); - - private: - Ptr
header_; - Ptr font_; -}; - -// C++ port only -class GenericTable : public Table, public RefCounted { - public: - GenericTable(Header* header, ReadableFontData* data) : Table(header, data) {} - virtual ~GenericTable() {} -}; - -typedef Ptr
TablePtr; -typedef std::vector TableHeaderList; -typedef Ptr TableBuilderPtr; -typedef std::map TableMap; -typedef std::pair TableMapEntry; - -typedef std::map DataBlockMap; -typedef std::pair DataBlockEntry; -typedef std::map TableBuilderMap; -typedef std::pair TableBuilderEntry; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_TABLE_H_ diff --git a/src/sfntly/src/sfntly/table/table_based_table_builder.cc b/src/sfntly/src/sfntly/table/table_based_table_builder.cc deleted file mode 100644 index b505704638..0000000000 --- a/src/sfntly/src/sfntly/table/table_based_table_builder.cc +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/table/table_based_table_builder.h" - -namespace sfntly { - -/****************************************************************************** - * TableBasedTableBuilder class - ******************************************************************************/ -TableBasedTableBuilder::~TableBasedTableBuilder() {} - -int32_t TableBasedTableBuilder::SubSerialize(WritableFontData* data) { - UNREFERENCED_PARAMETER(data); - return 0; -} - -bool TableBasedTableBuilder::SubReadyToSerialize() { - return false; -} - -int32_t TableBasedTableBuilder::SubDataSizeToSerialize() { - return 0; -} - -void TableBasedTableBuilder::SubDataSet() { - table_ = NULL; -} - -CALLER_ATTACH FontDataTable* TableBasedTableBuilder::Build() { - FontDataTablePtr table = static_cast(GetTable()); - return table.Detach(); -} - -TableBasedTableBuilder::TableBasedTableBuilder(Header* header, - WritableFontData* data) - : Table::Builder(header, data) { -} - -TableBasedTableBuilder::TableBasedTableBuilder(Header* header, - ReadableFontData* data) - : Table::Builder(header, data) { -} - -TableBasedTableBuilder::TableBasedTableBuilder(Header* header) - : Table::Builder(header) { -} - -Table* TableBasedTableBuilder::GetTable() { - if (table_ == NULL) { - table_.Attach(down_cast(SubBuildTable(InternalReadData()))); - } - return table_; -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/table_based_table_builder.h b/src/sfntly/src/sfntly/table/table_based_table_builder.h deleted file mode 100644 index d88eefd11e..0000000000 --- a/src/sfntly/src/sfntly/table/table_based_table_builder.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_TABLE_BASED_TABLE_BUILDER_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TABLE_TABLE_BASED_TABLE_BUILDER_H_ - -#include "sfntly/table/table.h" - -namespace sfntly { - -class TableBasedTableBuilder : public Table::Builder { - public: - virtual ~TableBasedTableBuilder(); - - virtual int32_t SubSerialize(WritableFontData* new_data); - virtual bool SubReadyToSerialize(); - virtual int32_t SubDataSizeToSerialize(); - virtual void SubDataSet(); - virtual CALLER_ATTACH FontDataTable* Build(); - - protected: - TableBasedTableBuilder(Header* header, WritableFontData* data); - TableBasedTableBuilder(Header* header, ReadableFontData* data); - explicit TableBasedTableBuilder(Header* header); - - // C++ port: renamed table() to GetTable() - virtual Table* GetTable(); - - // TODO(arthurhsu): style guide violation: protected member, need refactor - TablePtr table_; -}; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_TABLE_BASED_TABLE_BUILDER_H_ diff --git a/src/sfntly/src/sfntly/table/truetype/glyph_table.cc b/src/sfntly/src/sfntly/table/truetype/glyph_table.cc deleted file mode 100644 index f38fac5c5c..0000000000 --- a/src/sfntly/src/sfntly/table/truetype/glyph_table.cc +++ /dev/null @@ -1,679 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/table/truetype/glyph_table.h" - -#include - -#include "sfntly/port/exception_type.h" - -namespace sfntly { -/****************************************************************************** - * Constants - ******************************************************************************/ -const int32_t GlyphTable::SimpleGlyph::kFLAG_ONCURVE = 1; -const int32_t GlyphTable::SimpleGlyph::kFLAG_XSHORT = 1 << 1; -const int32_t GlyphTable::SimpleGlyph::kFLAG_YSHORT = 1 << 2; -const int32_t GlyphTable::SimpleGlyph::kFLAG_REPEAT = 1 << 3; -const int32_t GlyphTable::SimpleGlyph::kFLAG_XREPEATSIGN = 1 << 4; -const int32_t GlyphTable::SimpleGlyph::kFLAG_YREPEATSIGN = 1 << 5; - -const int32_t GlyphTable::CompositeGlyph::kFLAG_ARG_1_AND_2_ARE_WORDS = 1 << 0; -const int32_t GlyphTable::CompositeGlyph::kFLAG_ARGS_ARE_XY_VALUES = 1 << 1; -const int32_t GlyphTable::CompositeGlyph::kFLAG_ROUND_XY_TO_GRID = 1 << 2; -const int32_t GlyphTable::CompositeGlyph::kFLAG_WE_HAVE_A_SCALE = 1 << 3; -const int32_t GlyphTable::CompositeGlyph::kFLAG_RESERVED = 1 << 4; -const int32_t GlyphTable::CompositeGlyph::kFLAG_MORE_COMPONENTS = 1 << 5; -const int32_t GlyphTable::CompositeGlyph::kFLAG_WE_HAVE_AN_X_AND_Y_SCALE = 1 << 6; -const int32_t GlyphTable::CompositeGlyph::kFLAG_WE_HAVE_A_TWO_BY_TWO = 1 << 7; -const int32_t GlyphTable::CompositeGlyph::kFLAG_WE_HAVE_INSTRUCTIONS = 1 << 8; -const int32_t GlyphTable::CompositeGlyph::kFLAG_USE_MY_METRICS = 1 << 9; -const int32_t GlyphTable::CompositeGlyph::kFLAG_OVERLAP_COMPOUND = 1 << 10; -const int32_t GlyphTable::CompositeGlyph::kFLAG_SCALED_COMPONENT_OFFSET = 1 << 11; -const int32_t GlyphTable::CompositeGlyph::kFLAG_UNSCALED_COMPONENT_OFFSET = 1 << 12; - -/****************************************************************************** - * GlyphTable class - ******************************************************************************/ -GlyphTable::~GlyphTable() { -} - -GlyphTable::Glyph* GlyphTable::GetGlyph(int32_t offset, int32_t length) { - return GlyphTable::Glyph::GetGlyph(this, this->data_, offset, length); -} - -GlyphTable::GlyphTable(Header* header, ReadableFontData* data) - : SubTableContainerTable(header, data) { -} - -/****************************************************************************** - * GlyphTable::Builder class - ******************************************************************************/ -GlyphTable::Builder::Builder(Header* header, ReadableFontData* data) - : SubTableContainerTable::Builder(header, data) { -} - -GlyphTable::Builder::~Builder() { -} - -void GlyphTable::Builder::SetLoca(const IntegerList& loca) { - loca_ = loca; - set_model_changed(false); - glyph_builders_.clear(); -} - -void GlyphTable::Builder::GenerateLocaList(IntegerList* locas) { - assert(locas); - GlyphBuilderList* glyph_builders = GetGlyphBuilders(); - locas->push_back(0); - if (glyph_builders->size() == 0) { - locas->push_back(0); - } else { - int32_t total = 0; - for (GlyphBuilderList::iterator b = glyph_builders->begin(), - b_end = glyph_builders->end(); - b != b_end; ++b) { - int32_t size = (*b)->SubDataSizeToSerialize(); - locas->push_back(total + size); - total += size; - } - } -} - -CALLER_ATTACH GlyphTable::Builder* - GlyphTable::Builder::CreateBuilder(Header* header, WritableFontData* data) { - Ptr builder; - builder = new GlyphTable::Builder(header, data); - return builder.Detach(); -} - -GlyphTable::GlyphBuilderList* GlyphTable::Builder::GlyphBuilders() { - return GetGlyphBuilders(); -} - -void GlyphTable::Builder::SetGlyphBuilders(GlyphBuilderList* glyph_builders) { - glyph_builders_ = *glyph_builders; - set_model_changed(); -} - -CALLER_ATTACH GlyphTable::Glyph::Builder* - GlyphTable::Builder::GlyphBuilder(ReadableFontData* data) { - return Glyph::Builder::GetBuilder(this, data); -} - -CALLER_ATTACH FontDataTable* - GlyphTable::Builder::SubBuildTable(ReadableFontData* data) { - FontDataTablePtr table = new GlyphTable(header(), data); - return table.Detach(); -} - -void GlyphTable::Builder::SubDataSet() { - glyph_builders_.clear(); - set_model_changed(false); -} - -int32_t GlyphTable::Builder::SubDataSizeToSerialize() { - if (glyph_builders_.empty()) - return 0; - - bool variable = false; - int32_t size = 0; - - // Calculate size of each table. - for (GlyphBuilderList::iterator b = glyph_builders_.begin(), - end = glyph_builders_.end(); b != end; ++b) { - int32_t glyph_size = (*b)->SubDataSizeToSerialize(); - size += abs(glyph_size); - variable |= glyph_size <= 0; - } - return variable ? -size : size; -} - -bool GlyphTable::Builder::SubReadyToSerialize() { - return !glyph_builders_.empty(); -} - -int32_t GlyphTable::Builder::SubSerialize(WritableFontData* new_data) { - int32_t size = 0; - for (GlyphBuilderList::iterator b = glyph_builders_.begin(), - end = glyph_builders_.end(); b != end; ++b) { - FontDataPtr data; - data.Attach(new_data->Slice(size)); - size += (*b)->SubSerialize(down_cast(data.p_)); - } - return size; -} - -void GlyphTable::Builder::Initialize(ReadableFontData* data, - const IntegerList& loca) { - if (data != NULL) { - if (loca_.empty()) { - return; - } - int32_t loca_value; - int32_t last_loca_value = loca[0]; - for (size_t i = 1; i < loca.size(); ++i) { - loca_value = loca[i]; - GlyphBuilderPtr builder; - builder.Attach( - Glyph::Builder::GetBuilder(this, - data, - last_loca_value /*offset*/, - loca_value - last_loca_value /*length*/)); - glyph_builders_.push_back(builder); - last_loca_value = loca_value; - } - } -} - -GlyphTable::GlyphBuilderList* GlyphTable::Builder::GetGlyphBuilders() { - if (glyph_builders_.empty()) { - if (InternalReadData() && !loca_.empty()) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IllegalStateException( - "Loca values not set - unable to parse glyph data."); -#endif - return NULL; - } - Initialize(InternalReadData(), loca_); - set_model_changed(); - } - return &glyph_builders_; -} - -void GlyphTable::Builder::Revert() { - glyph_builders_.clear(); - set_model_changed(false); -} - -/****************************************************************************** - * GlyphTable::Glyph class - ******************************************************************************/ -GlyphTable::Glyph::~Glyph() {} - -CALLER_ATTACH GlyphTable::Glyph* - GlyphTable::Glyph::GetGlyph(GlyphTable* table, - ReadableFontData* data, - int32_t offset, - int32_t length) { - UNREFERENCED_PARAMETER(table); - int32_t type = GlyphType(data, offset, length); - GlyphPtr glyph; - - ReadableFontDataPtr sliced_data; - sliced_data.Attach(down_cast(data->Slice(offset, length))); - if (type == GlyphType::kSimple) { - glyph = new SimpleGlyph(sliced_data); - } else { - glyph = new CompositeGlyph(sliced_data); - } - return glyph.Detach(); -} - -int32_t GlyphTable::Glyph::Padding() { - Initialize(); - return SubTable::Padding(); -} - -int32_t GlyphTable::Glyph::GlyphType() { - return glyph_type_; -} - -int32_t GlyphTable::Glyph::NumberOfContours() { - return number_of_contours_; -} - -int32_t GlyphTable::Glyph::XMin() { - return data_->ReadShort(Offset::kXMin); -} - -int32_t GlyphTable::Glyph::XMax() { - return data_->ReadShort(Offset::kXMax); -} - -int32_t GlyphTable::Glyph::YMin() { - return data_->ReadShort(Offset::kYMin); -} - -int32_t GlyphTable::Glyph::YMax() { - return data_->ReadShort(Offset::kYMax); -} - -GlyphTable::Glyph::Glyph(ReadableFontData* data, int32_t glyph_type) - : SubTable(data), - glyph_type_(glyph_type) { - if (data_->Length() == 0) { - number_of_contours_ = 0; - } else { - // -1 if composite - number_of_contours_ = data_->ReadShort(Offset::kNumberOfContours); - } -} - -int32_t GlyphTable::Glyph::GlyphType(ReadableFontData* data, - int32_t offset, - int32_t length) { - if (length == 0) { - return GlyphType::kSimple; - } - int32_t number_of_contours = data->ReadShort(offset); - if (number_of_contours >= 0) { - return GlyphType::kSimple; - } - return GlyphType::kComposite; -} - -/****************************************************************************** - * GlyphTable::Glyph::Builder class - ******************************************************************************/ -GlyphTable::Glyph::Builder::~Builder() { -} - -GlyphTable::Glyph::Builder::Builder(WritableFontData* data) - : SubTable::Builder(data) { -} - -GlyphTable::Glyph::Builder::Builder(ReadableFontData* data) - : SubTable::Builder(data) { -} - -CALLER_ATTACH GlyphTable::Glyph::Builder* - GlyphTable::Glyph::Builder::GetBuilder( - GlyphTable::Builder* table_builder, - ReadableFontData* data) { - return GetBuilder(table_builder, data, 0, data->Length()); -} - -CALLER_ATTACH GlyphTable::Glyph::Builder* - GlyphTable::Glyph::Builder::GetBuilder( - GlyphTable::Builder* table_builder, - ReadableFontData* data, - int32_t offset, - int32_t length) { - UNREFERENCED_PARAMETER(table_builder); - int32_t type = Glyph::GlyphType(data, offset, length); - GlyphBuilderPtr builder; - ReadableFontDataPtr sliced_data; - sliced_data.Attach(down_cast(data->Slice(offset, length))); - if (type == GlyphType::kSimple) { - builder = new SimpleGlyph::SimpleGlyphBuilder(sliced_data); - } else { - builder = new CompositeGlyph::CompositeGlyphBuilder(sliced_data); - } - return builder.Detach(); -} - -void GlyphTable::Glyph::Builder::SubDataSet() { - // NOP -} - -int32_t GlyphTable::Glyph::Builder::SubDataSizeToSerialize() { - return InternalReadData()->Length(); -} - -bool GlyphTable::Glyph::Builder::SubReadyToSerialize() { - return true; -} - -int32_t GlyphTable::Glyph::Builder::SubSerialize(WritableFontData* new_data) { - return InternalReadData()->CopyTo(new_data); -} - -/****************************************************************************** - * GlyphTable::SimpleGlyph - ******************************************************************************/ -GlyphTable::SimpleGlyph::SimpleGlyph(ReadableFontData* data) - : GlyphTable::Glyph(data, GlyphType::kSimple), initialized_(false) { -} - -GlyphTable::SimpleGlyph::~SimpleGlyph() { -} - -int32_t GlyphTable::SimpleGlyph::InstructionSize() { - Initialize(); - return instruction_size_; -} - -CALLER_ATTACH ReadableFontData* GlyphTable::SimpleGlyph::Instructions() { - Initialize(); - return down_cast( - data_->Slice(instructions_offset_, InstructionSize())); -} - -int32_t GlyphTable::SimpleGlyph::NumberOfPoints(int32_t contour) { - Initialize(); - if (contour >= NumberOfContours()) { - return 0; - } - return contour_index_[contour + 1] - contour_index_[contour]; -} - -int32_t GlyphTable::SimpleGlyph::XCoordinate(int32_t contour, int32_t point) { - Initialize(); - return x_coordinates_[contour_index_[contour] + point]; -} - -int32_t GlyphTable::SimpleGlyph::YCoordinate(int32_t contour, int32_t point) { - Initialize(); - return y_coordinates_[contour_index_[contour] + point]; -} - -bool GlyphTable::SimpleGlyph::OnCurve(int32_t contour, int32_t point) { - Initialize(); - return on_curve_[contour_index_[contour] + point]; -} - -void GlyphTable::SimpleGlyph::Initialize() { - AutoLock lock(initialization_lock_); - if (initialized_) { - return; - } - - if (ReadFontData()->Length() == 0) { - instruction_size_ = 0; - number_of_points_ = 0; - instructions_offset_ = 0; - flags_offset_ = 0; - x_coordinates_offset_ = 0; - y_coordinates_offset_ = 0; - return; - } - - instruction_size_ = data_->ReadUShort(Offset::kSimpleEndPtsOfCountours + - NumberOfContours() * DataSize::kUSHORT); - instructions_offset_ = Offset::kSimpleEndPtsOfCountours + - (NumberOfContours() + 1) * DataSize::kUSHORT; - flags_offset_ = instructions_offset_ + instruction_size_ * DataSize::kBYTE; - number_of_points_ = ContourEndPoint(NumberOfContours() - 1) + 1; - x_coordinates_.resize(number_of_points_); - y_coordinates_.resize(number_of_points_); - on_curve_.resize(number_of_points_); - ParseData(false); - x_coordinates_offset_ = flags_offset_ + flag_byte_count_ * DataSize::kBYTE; - y_coordinates_offset_ = x_coordinates_offset_ + x_byte_count_ * - DataSize::kBYTE; - contour_index_.resize(NumberOfContours() + 1); - contour_index_[0] = 0; - for (uint32_t contour = 0; contour < contour_index_.size() - 1; ++contour) { - contour_index_[contour + 1] = ContourEndPoint(contour) + 1; - } - ParseData(true); - int32_t non_padded_data_length = - 5 * DataSize::kSHORT + - (NumberOfContours() * DataSize::kUSHORT) + - DataSize::kUSHORT + - (instruction_size_ * DataSize::kBYTE) + - (flag_byte_count_ * DataSize::kBYTE) + - (x_byte_count_ * DataSize::kBYTE) + - (y_byte_count_ * DataSize::kBYTE); - set_padding(DataLength() - non_padded_data_length); - initialized_ = true; -} - -void GlyphTable::SimpleGlyph::ParseData(bool fill_arrays) { - int32_t flag = 0; - int32_t flag_repeat = 0; - int32_t flag_index = 0; - int32_t x_byte_index = 0; - int32_t y_byte_index = 0; - - for (int32_t point_index = 0; point_index < number_of_points_; - ++point_index) { - // get the flag for the current point - if (flag_repeat == 0) { - flag = FlagAsInt(flag_index++); - if ((flag & kFLAG_REPEAT) == kFLAG_REPEAT) { - flag_repeat = FlagAsInt(flag_index++); - } - } else { - flag_repeat--; - } - - // on the curve? - if (fill_arrays) { - on_curve_[point_index] = ((flag & kFLAG_ONCURVE) == kFLAG_ONCURVE); - } - // get the x coordinate - if ((flag & kFLAG_XSHORT) == kFLAG_XSHORT) { - // single byte x coord value - if (fill_arrays) { - x_coordinates_[point_index] = - data_->ReadUByte(x_coordinates_offset_ + x_byte_index); - x_coordinates_[point_index] *= - ((flag & kFLAG_XREPEATSIGN) == kFLAG_XREPEATSIGN) ? 1 : -1; - } - x_byte_index++; - } else { - // double byte coord value - if (!((flag & kFLAG_XREPEATSIGN) == kFLAG_XREPEATSIGN)) { - if (fill_arrays) { - x_coordinates_[point_index] = - data_->ReadShort(x_coordinates_offset_ + x_byte_index); - } - x_byte_index += 2; - } - } - if (fill_arrays && point_index > 0) { - x_coordinates_[point_index] += x_coordinates_[point_index - 1]; - } - - // get the y coordinate - if ((flag & kFLAG_YSHORT) == kFLAG_YSHORT) { - if (fill_arrays) { - y_coordinates_[point_index] = - data_->ReadUByte(y_coordinates_offset_ + y_byte_index); - y_coordinates_[point_index] *= - ((flag & kFLAG_YREPEATSIGN) == kFLAG_YREPEATSIGN) ? 1 : -1; - } - y_byte_index++; - } else { - if (!((flag & kFLAG_YREPEATSIGN) == kFLAG_YREPEATSIGN)) { - if (fill_arrays) { - y_coordinates_[point_index] = - data_->ReadShort(y_coordinates_offset_ + y_byte_index); - } - y_byte_index += 2; - } - } - if (fill_arrays && point_index > 0) { - y_coordinates_[point_index] += y_coordinates_[point_index - 1]; - } - } - flag_byte_count_ = flag_index; - x_byte_count_ = x_byte_index; - y_byte_count_ = y_byte_index; -} - -int32_t GlyphTable::SimpleGlyph::FlagAsInt(int32_t index) { - return data_->ReadUByte(flags_offset_ + index * DataSize::kBYTE); -} - -int32_t GlyphTable::SimpleGlyph::ContourEndPoint(int32_t contour) { - return data_->ReadUShort(contour * DataSize::kUSHORT + - Offset::kSimpleEndPtsOfCountours); -} - -/****************************************************************************** - * GlyphTable::SimpleGlyph::Builder - ******************************************************************************/ -GlyphTable::SimpleGlyph::SimpleGlyphBuilder::~SimpleGlyphBuilder() { -} - -GlyphTable::SimpleGlyph::SimpleGlyphBuilder::SimpleGlyphBuilder( - WritableFontData* data) - : Glyph::Builder(data) { -} - -GlyphTable::SimpleGlyph::SimpleGlyphBuilder::SimpleGlyphBuilder( - ReadableFontData* data) - : Glyph::Builder(data) { -} - -CALLER_ATTACH FontDataTable* - GlyphTable::SimpleGlyph::SimpleGlyphBuilder::SubBuildTable( - ReadableFontData* data) { - FontDataTablePtr table = new SimpleGlyph(data); - return table.Detach(); -} - -/****************************************************************************** - * GlyphTable::CompositeGlyph - ******************************************************************************/ -GlyphTable::CompositeGlyph::CompositeGlyph(ReadableFontData* data) - : GlyphTable::Glyph(data, GlyphType::kComposite), - instruction_size_(0), - instructions_offset_(0), - initialized_(false) { - Initialize(); -} - -GlyphTable::CompositeGlyph::~CompositeGlyph() { -} - -int32_t GlyphTable::CompositeGlyph::Flags(int32_t contour) { - return data_->ReadUShort(contour_index_[contour]); -} - -int32_t GlyphTable::CompositeGlyph::NumGlyphs() { - return contour_index_.size(); -} - -int32_t GlyphTable::CompositeGlyph::GlyphIndex(int32_t contour) { - return data_->ReadUShort(DataSize::kUSHORT + contour_index_[contour]); -} - -int32_t GlyphTable::CompositeGlyph::Argument1(int32_t contour) { - int32_t index = 2 * DataSize::kUSHORT + contour_index_[contour]; - int32_t contour_flags = Flags(contour); - if ((contour_flags & kFLAG_ARG_1_AND_2_ARE_WORDS) == - kFLAG_ARG_1_AND_2_ARE_WORDS) { - return data_->ReadUShort(index); - } - return data_->ReadByte(index); -} - -int32_t GlyphTable::CompositeGlyph::Argument2(int32_t contour) { - int32_t index = 2 * DataSize::kUSHORT + contour_index_[contour]; - int32_t contour_flags = Flags(contour); - if ((contour_flags & kFLAG_ARG_1_AND_2_ARE_WORDS) == - kFLAG_ARG_1_AND_2_ARE_WORDS) { - return data_->ReadUShort(index + DataSize::kUSHORT); - } - return data_->ReadByte(index + DataSize::kUSHORT); -} - -int32_t GlyphTable::CompositeGlyph::TransformationSize(int32_t contour) { - int32_t contour_flags = Flags(contour); - if ((contour_flags & kFLAG_WE_HAVE_A_SCALE) == kFLAG_WE_HAVE_A_SCALE) { - return DataSize::kF2DOT14; - } else if ((contour_flags & kFLAG_WE_HAVE_AN_X_AND_Y_SCALE) == - kFLAG_WE_HAVE_AN_X_AND_Y_SCALE) { - return 2 * DataSize::kF2DOT14; - } else if ((contour_flags & kFLAG_WE_HAVE_A_TWO_BY_TWO) == - kFLAG_WE_HAVE_A_TWO_BY_TWO) { - return 4 * DataSize::kF2DOT14; - } - return 0; -} - -void GlyphTable::CompositeGlyph::Transformation(int32_t contour, - ByteVector* transformation) { - int32_t contour_flags = Flags(contour); - int32_t index = contour_index_[contour] + 2 * DataSize::kUSHORT; - if ((contour_flags & kFLAG_ARG_1_AND_2_ARE_WORDS) == - kFLAG_ARG_1_AND_2_ARE_WORDS) { - index += 2 * DataSize::kSHORT; - } else { - index += 2 * DataSize::kBYTE; - } - int32_t tsize = TransformationSize(contour); - transformation->resize(tsize); - data_->ReadBytes(index, &((*transformation)[0]), 0, tsize); -} - -int32_t GlyphTable::CompositeGlyph::InstructionSize() { - return instruction_size_; -} - -CALLER_ATTACH ReadableFontData* GlyphTable::CompositeGlyph::Instructions() { - return down_cast( - data_->Slice(instructions_offset_, InstructionSize())); -} - -void GlyphTable::CompositeGlyph::Initialize() { - AutoLock lock(initialization_lock_); - if (initialized_) { - return; - } - - int32_t index = 5 * DataSize::kUSHORT; - int32_t flags = kFLAG_MORE_COMPONENTS; - - while ((flags & kFLAG_MORE_COMPONENTS) == kFLAG_MORE_COMPONENTS) { - contour_index_.push_back(index); - flags = data_->ReadUShort(index); - index += 2 * DataSize::kUSHORT; // flags and glyphIndex - if ((flags & kFLAG_ARG_1_AND_2_ARE_WORDS) == kFLAG_ARG_1_AND_2_ARE_WORDS) { - index += 2 * DataSize::kSHORT; - } else { - index += 2 * DataSize::kBYTE; - } - if ((flags & kFLAG_WE_HAVE_A_SCALE) == kFLAG_WE_HAVE_A_SCALE) { - index += DataSize::kF2DOT14; - } else if ((flags & kFLAG_WE_HAVE_AN_X_AND_Y_SCALE) == - kFLAG_WE_HAVE_AN_X_AND_Y_SCALE) { - index += 2 * DataSize::kF2DOT14; - } else if ((flags & kFLAG_WE_HAVE_A_TWO_BY_TWO) == - kFLAG_WE_HAVE_A_TWO_BY_TWO) { - index += 4 * DataSize::kF2DOT14; - } - int32_t non_padded_data_length = index; - if ((flags & kFLAG_WE_HAVE_INSTRUCTIONS) == kFLAG_WE_HAVE_INSTRUCTIONS) { - instruction_size_ = data_->ReadUShort(index); - index += DataSize::kUSHORT; - instructions_offset_ = index; - non_padded_data_length = index + (instruction_size_ * DataSize::kBYTE); - } - set_padding(DataLength() - non_padded_data_length); - } - - initialized_ = true; -} - -/****************************************************************************** - * GlyphTable::CompositeGlyph::Builder - ******************************************************************************/ -GlyphTable::CompositeGlyph::CompositeGlyphBuilder::~CompositeGlyphBuilder() { -} - -GlyphTable::CompositeGlyph::CompositeGlyphBuilder::CompositeGlyphBuilder( - WritableFontData* data) - : Glyph::Builder(data) { -} - -GlyphTable::CompositeGlyph::CompositeGlyphBuilder::CompositeGlyphBuilder( - ReadableFontData* data) - : Glyph::Builder(data) { -} - -CALLER_ATTACH FontDataTable* - GlyphTable::CompositeGlyph::CompositeGlyphBuilder::SubBuildTable( - ReadableFontData* data) { - FontDataTablePtr table = new CompositeGlyph(data); - return table.Detach(); -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/truetype/glyph_table.h b/src/sfntly/src/sfntly/table/truetype/glyph_table.h deleted file mode 100644 index 0836971894..0000000000 --- a/src/sfntly/src/sfntly/table/truetype/glyph_table.h +++ /dev/null @@ -1,335 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_TRUETYPE_GLYPH_TABLE_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TABLE_TRUETYPE_GLYPH_TABLE_H_ - -#include - -#include "sfntly/table/table.h" -#include "sfntly/table/subtable.h" -#include "sfntly/table/subtable_container_table.h" - -namespace sfntly { - -struct GlyphType { - enum { - kSimple = 0, - kComposite = 1 - }; -}; - -class GlyphTable : public SubTableContainerTable, - public RefCounted { - public: - class Builder; - class Glyph : public SubTable { - public: - // Note: Contour is an empty class for the version ported - class Contour { - protected: - Contour() {} - virtual ~Contour() {} - }; - - class Builder : public SubTable::Builder { - public: - virtual ~Builder(); - - protected: - // Incoming table_builder is GlyphTable::Builder*. - // Note: constructor refactored in C++ to avoid heavy lifting. - // caller need to do data->Slice(offset, length) beforehand. - explicit Builder(WritableFontData* data); - explicit Builder(ReadableFontData* data); - - static CALLER_ATTACH Builder* - GetBuilder(GlyphTable::Builder* table_builder, - ReadableFontData* data); - static CALLER_ATTACH Builder* - GetBuilder(GlyphTable::Builder* table_builder, - ReadableFontData* data, - int32_t offset, - int32_t length); - virtual void SubDataSet(); - virtual int32_t SubDataSizeToSerialize(); - virtual bool SubReadyToSerialize(); - virtual int32_t SubSerialize(WritableFontData* new_data); - - private: - int32_t format_; - friend class GlyphTable::Builder; - }; - - virtual ~Glyph(); - static CALLER_ATTACH Glyph* GetGlyph(GlyphTable* table, - ReadableFontData* data, - int32_t offset, - int32_t length); - - virtual int32_t Padding(); - virtual int32_t GlyphType(); - virtual int32_t NumberOfContours(); - virtual int32_t XMin(); - virtual int32_t XMax(); - virtual int32_t YMin(); - virtual int32_t YMax(); - - virtual int32_t InstructionSize() = 0; - virtual ReadableFontData* Instructions() = 0; - - protected: - // Note: constructor refactored in C++ to avoid heavy lifting. - // caller need to do data->Slice(offset, length) beforehand. - Glyph(ReadableFontData* data, int32_t glyph_type); - virtual void Initialize() = 0; - // Note: Derived class to define initialization_lock_. - - private: - static int32_t GlyphType(ReadableFontData* data, - int32_t offset, - int32_t length); - - int32_t glyph_type_; - int32_t number_of_contours_; - }; // class GlyphTable::Glyph - typedef Ptr GlyphBuilderPtr; - typedef std::vector GlyphBuilderList; - - class Builder : public SubTableContainerTable::Builder, - public RefCounted { - public: - // Note: Constructor scope altered to public for base class to instantiate. - Builder(Header* header, ReadableFontData* data); - virtual ~Builder(); - - virtual void SetLoca(const IntegerList& loca); - virtual void GenerateLocaList(IntegerList* locas); - - static CALLER_ATTACH Builder* CreateBuilder(Header* header, - WritableFontData* data); - - // Gets the List of glyph builders for the glyph table builder. These may be - // manipulated in any way by the caller and the changes will be reflected in - // the final glyph table produced. - // If there is no current data for the glyph builder or the glyph builders - // have not been previously set then this will return an empty glyph builder - // List. If there is current data (i.e. data read from an existing font) and - // the loca list has not been set or is null, empty, or - // invalid, then an empty glyph builder List will be returned. - GlyphBuilderList* GlyphBuilders(); - - // Replace the internal glyph builders with the one provided. The provided - // list and all contained objects belong to this builder. - // This call is only required if the entire set of glyphs in the glyph - // table builder are being replaced. If the glyph builder list provided from - // the GlyphTable.Builder::GlyphBuilders() is being used and modified - // then those changes will already be reflected in the glyph table builder. - void SetGlyphBuilders(GlyphBuilderList* glyph_builders); - - // Glyph builder factories - CALLER_ATTACH Glyph::Builder* GlyphBuilder(ReadableFontData* data); - - protected: // internal API for building - virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); - virtual void SubDataSet(); - virtual int32_t SubDataSizeToSerialize(); - virtual bool SubReadyToSerialize(); - virtual int32_t SubSerialize(WritableFontData* new_data); - - private: - void Initialize(ReadableFontData* data, const IntegerList& loca); - GlyphBuilderList* GetGlyphBuilders(); - void Revert(); - - GlyphBuilderList glyph_builders_; - IntegerList loca_; - }; - - class SimpleGlyph : public Glyph, public RefCounted { - public: - static const int32_t kFLAG_ONCURVE; - static const int32_t kFLAG_XSHORT; - static const int32_t kFLAG_YSHORT; - static const int32_t kFLAG_REPEAT; - static const int32_t kFLAG_XREPEATSIGN; - static const int32_t kFLAG_YREPEATSIGN; - - class SimpleContour : public Glyph::Contour { - protected: - SimpleContour() {} - virtual ~SimpleContour() {} - }; - - class SimpleGlyphBuilder : public Glyph::Builder, - public RefCounted { - public: - virtual ~SimpleGlyphBuilder(); - - protected: - // Note: constructor refactored in C++ to avoid heavy lifting. - // caller need to do data->Slice(offset, length) beforehand. - explicit SimpleGlyphBuilder(WritableFontData* data); - explicit SimpleGlyphBuilder(ReadableFontData* data); - virtual CALLER_ATTACH FontDataTable* - SubBuildTable(ReadableFontData* data); - - private: - friend class Glyph::Builder; - }; - - // Note: constructor refactored in C++ to avoid heavy lifting. - // caller need to do data->Slice(offset, length) beforehand. - explicit SimpleGlyph(ReadableFontData* data); - virtual ~SimpleGlyph(); - - virtual int32_t InstructionSize(); - virtual CALLER_ATTACH ReadableFontData* Instructions(); - virtual void Initialize(); - - int32_t NumberOfPoints(int32_t contour); - int32_t XCoordinate(int32_t contour, int32_t point); - int32_t YCoordinate(int32_t contour, int32_t point); - bool OnCurve(int32_t contour, int32_t point); - - private: - void ParseData(bool fill_arrays); - int32_t FlagAsInt(int32_t index); - int32_t ContourEndPoint(int32_t contour); - - bool initialized_; - Lock initialization_lock_; - int32_t instruction_size_; - int32_t number_of_points_; - - // start offsets of the arrays - int32_t instructions_offset_; - int32_t flags_offset_; - int32_t x_coordinates_offset_; - int32_t y_coordinates_offset_; - - int32_t flag_byte_count_; - int32_t x_byte_count_; - int32_t y_byte_count_; - - IntegerList x_coordinates_; - IntegerList y_coordinates_; - std::vector on_curve_; - IntegerList contour_index_; - }; - - class CompositeGlyph : public Glyph, public RefCounted { - public: - static const int32_t kFLAG_ARG_1_AND_2_ARE_WORDS; - static const int32_t kFLAG_ARGS_ARE_XY_VALUES; - static const int32_t kFLAG_ROUND_XY_TO_GRID; - static const int32_t kFLAG_WE_HAVE_A_SCALE; - static const int32_t kFLAG_RESERVED; - static const int32_t kFLAG_MORE_COMPONENTS; - static const int32_t kFLAG_WE_HAVE_AN_X_AND_Y_SCALE; - static const int32_t kFLAG_WE_HAVE_A_TWO_BY_TWO; - static const int32_t kFLAG_WE_HAVE_INSTRUCTIONS; - static const int32_t kFLAG_USE_MY_METRICS; - static const int32_t kFLAG_OVERLAP_COMPOUND; - static const int32_t kFLAG_SCALED_COMPONENT_OFFSET; - static const int32_t kFLAG_UNSCALED_COMPONENT_OFFSET; - - class CompositeGlyphBuilder : public Glyph::Builder, - public RefCounted { - public: - virtual ~CompositeGlyphBuilder(); - - protected: - // Note: constructor refactored in C++ to avoid heavy lifting. - // caller need to do data->Slice(offset, length) beforehand. - explicit CompositeGlyphBuilder(WritableFontData* data); - explicit CompositeGlyphBuilder(ReadableFontData* data); - - virtual CALLER_ATTACH FontDataTable* - SubBuildTable(ReadableFontData* data); - - private: - friend class Glyph::Builder; - }; - - // Note: constructor refactored in C++ to avoid heavy lifting. - // caller need to do data->Slice(offset, length) beforehand. - explicit CompositeGlyph(ReadableFontData* data); - virtual ~CompositeGlyph(); - - int32_t Flags(int32_t contour); - int32_t NumGlyphs(); - int32_t GlyphIndex(int32_t contour); - int32_t Argument1(int32_t contour); - int32_t Argument2(int32_t contour); - int32_t TransformationSize(int32_t contour); - void Transformation(int32_t contour, ByteVector* transformation); - virtual int32_t InstructionSize(); - virtual CALLER_ATTACH ReadableFontData* Instructions(); - - protected: - virtual void Initialize(); - - private: - IntegerList contour_index_; - int32_t instruction_size_; - int32_t instructions_offset_; - bool initialized_; - Lock initialization_lock_; - }; - - virtual ~GlyphTable(); - - // C++ port: rename glyph() to GetGlyph(). - Glyph* GetGlyph(int32_t offset, int32_t length); - - private: - struct Offset { - enum { - // header - kNumberOfContours = 0, - kXMin = 2, - kYMin = 4, - kXMax = 6, - kYMax = 8, - - // Simple Glyph Description - kSimpleEndPtsOfCountours = 10, - // offset from the end of the contours array - kSimpleInstructionLength = 0, - kSimpleInstructions = 2, - // flags - // xCoordinates - // yCoordinates - - // Composite Glyph Description - kCompositeFlags = 0, - kCompositeGyphIndexWithoutFlag = 0, - kCompositeGlyphIndexWithFlag = 2, - }; - }; - - GlyphTable(Header* header, ReadableFontData* data); -}; -typedef Ptr GlyphTablePtr; -typedef Ptr GlyphTableBuilderPtr; -typedef std::vector GlyphTableBuilderList; -typedef Ptr GlyphPtr; -typedef Ptr GlyphBuilderPtr; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_TRUETYPE_GLYPH_TABLE_H_ diff --git a/src/sfntly/src/sfntly/table/truetype/loca_table.cc b/src/sfntly/src/sfntly/table/truetype/loca_table.cc deleted file mode 100644 index 793f9a90ff..0000000000 --- a/src/sfntly/src/sfntly/table/truetype/loca_table.cc +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/table/truetype/loca_table.h" -#include "sfntly/port/exception_type.h" - -namespace sfntly { -/****************************************************************************** - * LocaTable class - ******************************************************************************/ -LocaTable::~LocaTable() {} - -int32_t LocaTable::GlyphOffset(int32_t glyph_id) { - if (glyph_id < 0 || glyph_id >= num_glyphs_) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IndexOutOfBoundException("Glyph ID is out of bounds."); -#endif - return 0; - } - return Loca(glyph_id); -} - -int32_t LocaTable::GlyphLength(int32_t glyph_id) { - if (glyph_id < 0 || glyph_id >= num_glyphs_) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IndexOutOfBoundException("Glyph ID is out of bounds."); -#endif - return 0; - } - return Loca(glyph_id + 1) - Loca(glyph_id); -} - -int32_t LocaTable::NumLocas() { - return num_glyphs_ + 1; -} - -// Changed by Kovid: The following two methods must not have inline -// definitions, otherwise they give incorrect results when compiled with gcc -// and -fPIC, leading to corrupted font generation. -int32_t LocaTable::num_glyphs() { - return num_glyphs_; -} - -int32_t LocaTable::format_version() { - return format_version_; -} - -int32_t LocaTable::Loca(int32_t index) { - if (index > num_glyphs_) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IndexOutOfBoundException(); -#endif - return 0; - } - if (format_version_ == IndexToLocFormat::kShortOffset) { - return 2 * data_->ReadUShort(index * DataSize::kUSHORT); - } - return data_->ReadULongAsInt(index * DataSize::kULONG); -} - -LocaTable::LocaTable(Header* header, - ReadableFontData* data, - int32_t format_version, - int32_t num_glyphs) - : Table(header, data), - format_version_(format_version), - num_glyphs_(num_glyphs) { -} - -/****************************************************************************** - * LocaTable::Iterator class - ******************************************************************************/ -LocaTable::LocaIterator::LocaIterator(LocaTable* table) - : PODIterator(table), index_(-1) { -} - -bool LocaTable::LocaIterator::HasNext() { - return index_ <= container()->num_glyphs_; -} - -int32_t LocaTable::LocaIterator::Next() { - return container()->Loca(index_++); -} - -/****************************************************************************** - * LocaTable::Builder class - ******************************************************************************/ -LocaTable::Builder::Builder(Header* header, WritableFontData* data) - : Table::Builder(header, data), - format_version_(IndexToLocFormat::kLongOffset), - num_glyphs_(-1) { -} - -LocaTable::Builder::Builder(Header* header, ReadableFontData* data) - : Table::Builder(header, data), - format_version_(IndexToLocFormat::kLongOffset), - num_glyphs_(-1) { -} - -LocaTable::Builder::~Builder() {} - -// Changed by Kovid: The following two methods must not have inline -// definitions, otherwise they give incorrect results when compiled with gcc -// and -fPIC, leading to corrupted font generation. -int32_t LocaTable::Builder::format_version() { return format_version_; } - -void LocaTable::Builder::set_format_version(int32_t value) { format_version_ = value; } - -CALLER_ATTACH -LocaTable::Builder* LocaTable::Builder::CreateBuilder(Header* header, - WritableFontData* data) { - Ptr builder; - builder = new LocaTable::Builder(header, data); - return builder.Detach(); -} - -IntegerList* LocaTable::Builder::LocaList() { - return GetLocaList(); -} - -void LocaTable::Builder::SetLocaList(IntegerList* list) { - loca_.clear(); - if (list) { - loca_ = *list; - set_model_changed(); - } -} - -int32_t LocaTable::Builder::GlyphOffset(int32_t glyph_id) { - if (CheckGlyphRange(glyph_id) == -1) { - return 0; - } - return GetLocaList()->at(glyph_id); -} - -int32_t LocaTable::Builder::GlyphLength(int32_t glyph_id) { - if (CheckGlyphRange(glyph_id) == -1) { - return 0; - } - return GetLocaList()->at(glyph_id + 1) - GetLocaList()->at(glyph_id); -} - -void LocaTable::Builder::SetNumGlyphs(int32_t num_glyphs) { - num_glyphs_ = num_glyphs; -} - -int32_t LocaTable::Builder::NumGlyphs() { - return LastGlyphIndex() - 1; -} - -void LocaTable::Builder::Revert() { - loca_.clear(); - set_model_changed(false); -} - -int32_t LocaTable::Builder::NumLocas() { - return GetLocaList()->size(); -} - -int32_t LocaTable::Builder::Loca(int32_t index) { - return GetLocaList()->at(index); -} - -CALLER_ATTACH -FontDataTable* LocaTable::Builder::SubBuildTable(ReadableFontData* data) { - FontDataTablePtr table = - new LocaTable(header(), data, format_version_, num_glyphs_); - return table.Detach(); -} - -void LocaTable::Builder::SubDataSet() { - Initialize(InternalReadData()); -} - -int32_t LocaTable::Builder::SubDataSizeToSerialize() { - if (loca_.empty()) { - return 0; - } - if (format_version_ == IndexToLocFormat::kLongOffset) { - return loca_.size() * DataSize::kULONG; - } - return loca_.size() * DataSize::kUSHORT; -} - -bool LocaTable::Builder::SubReadyToSerialize() { - return !loca_.empty(); -} - -int32_t LocaTable::Builder::SubSerialize(WritableFontData* new_data) { - int32_t size = 0; - for (IntegerList::iterator l = loca_.begin(), end = loca_.end(); - l != end; ++l) { - if (format_version_ == IndexToLocFormat::kLongOffset) { - size += new_data->WriteULong(size, *l); - } else { - size += new_data->WriteUShort(size, *l / 2); - } - } - num_glyphs_ = loca_.size() - 1; - return size; -} - -void LocaTable::Builder::Initialize(ReadableFontData* data) { - ClearLoca(false); - if (data) { - if (NumGlyphs() < 0) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IllegalStateException("numglyphs not set on LocaTable Builder."); -#endif - return; - } - LocaTablePtr table = - new LocaTable(header(), data, format_version_, num_glyphs_); - Ptr loca_iter = - new LocaTable::LocaIterator(table); - while (loca_iter->HasNext()) { - loca_.push_back(loca_iter->Next()); - } - } -} - -int32_t LocaTable::Builder::CheckGlyphRange(int32_t glyph_id) { - if (glyph_id < 0 || glyph_id > LastGlyphIndex()) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IndexOutOfBoundsException("Glyph ID is outside of the allowed range"); -#endif - return -1; - } - return glyph_id; -} - -int32_t LocaTable::Builder::LastGlyphIndex() { - return !loca_.empty() ? loca_.size() - 2 : num_glyphs_ - 1; -} - -IntegerList* LocaTable::Builder::GetLocaList() { - if (loca_.empty()) { - Initialize(InternalReadData()); - set_model_changed(); - } - return &loca_; -} - -void LocaTable::Builder::ClearLoca(bool nullify) { - // Note: in C++ port, nullify is not used at all. - UNREFERENCED_PARAMETER(nullify); - loca_.clear(); - set_model_changed(false); -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/table/truetype/loca_table.h b/src/sfntly/src/sfntly/table/truetype/loca_table.h deleted file mode 100644 index b4e1d3ceab..0000000000 --- a/src/sfntly/src/sfntly/table/truetype/loca_table.h +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_TRUETYPE_LOCA_TABLE_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TABLE_TRUETYPE_LOCA_TABLE_H_ - -#include "sfntly/port/java_iterator.h" -#include "sfntly/table/table.h" -#include "sfntly/table/core/font_header_table.h" - -namespace sfntly { - -// A Loca table - 'loca'. -class LocaTable : public Table, public RefCounted { - public: - class LocaIterator : public PODIterator { - public: - explicit LocaIterator(LocaTable* table); - virtual ~LocaIterator() {} - - virtual bool HasNext(); - virtual int32_t Next(); - - private: - int32_t index_; - }; - - class Builder : public Table::Builder, public RefCounted { - public: - // Constructor scope altered to public for base class to instantiate. - Builder(Header* header, WritableFontData* data); - Builder(Header* header, ReadableFontData* data); - virtual ~Builder(); - - static CALLER_ATTACH Builder* CreateBuilder(Header* header, - WritableFontData* data); - - // Get the format version that will be used when the loca table is - // generated. - // @return the loca table format version - int32_t format_version(); - void set_format_version(int32_t value); - - // Gets the List of locas for loca table builder. These may be manipulated - // in any way by the caller and the changes will be reflected in the final - // loca table produced as long as no subsequent call is made to the - // SetLocaList(List) method. - // If there is no current data for the loca table builder or the loca list - // have not been previously set then this will return an empty List. - IntegerList* LocaList(); - - // Set the list of locas to be used for building this table. If any existing - // list was already retrieved with the LocaList() method then the - // connection of that previous list to this builder will be broken. - void SetLocaList(IntegerList* list); - - // Return the offset for the given glyph id. Valid glyph ids are from 0 to - // one less than the number of glyphs. The zero entry is the special entry - // for the notdef glyph. The final entry beyond the last glyph id is used to - // calculate the size of the last glyph. - // @param glyphId the glyph id to get the offset for; must be less than or - // equal to one more than the number of glyph ids - // @return the offset in the glyph table to the specified glyph id - int32_t GlyphOffset(int32_t glyph_id); - - // Get the length of the data in the glyph table for the specified glyph id. - int32_t GlyphLength(int32_t glyph_id); - - // Set the number of glyphs. - // This method sets the number of glyphs that the builder will attempt to - // parse location data for from the raw binary data. This method only needs - // to be called (and must be) when the raw data for this builder has - // been changed. It does not by itself reset the data or clear any set loca - // list. - void SetNumGlyphs(int32_t num_glyphs); - - // Get the number of glyphs that this builder has support for. - int NumGlyphs(); - - // Revert the loca table builder to the state contained in the last raw data - // set on the builder. That raw data may be that read from a font file when - // the font builder was created, that set by a user of the loca table - // builder, or null data if this builder was created as a new empty builder. - void Revert(); - - // Get the number of locations or locas. This will be one more than the - // number of glyphs for this table since the last loca position is used to - // indicate the size of the final glyph. - int32_t NumLocas(); - - // Get the value from the loca table for the index specified. These are the - // raw values from the table that are used to compute the offset and size of - // a glyph in the glyph table. Valid index values run from 0 to the number - // of glyphs in the font. - int32_t Loca(int32_t index); - - virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); - virtual void SubDataSet(); - virtual int32_t SubDataSizeToSerialize(); - virtual bool SubReadyToSerialize(); - virtual int32_t SubSerialize(WritableFontData* new_data); - - private: - // Initialize the internal state from the data. Done lazily since in many - // cases the builder will be just creating a table object with no parsing - // required. - // @param data the data to initialize from - void Initialize(ReadableFontData* data); - - // Checks that the glyph id is within the correct range. - // @return glyph_id if correct, -1 otherwise. - int32_t CheckGlyphRange(int32_t glyph_id); - - int32_t LastGlyphIndex(); - - // Internal method to get the loca list if already generated and if not to - // initialize the state of the builder. - // @return the loca list - IntegerList* GetLocaList(); - - void ClearLoca(bool nullify); - - int32_t format_version_; // Note: IndexToLocFormat - int32_t num_glyphs_; - IntegerList loca_; - }; - - virtual ~LocaTable(); - - int32_t format_version(); - int32_t num_glyphs(); - - // Return the offset for the given glyph id. Valid glyph ids are from 0 to the - // one less than the number of glyphs. The zero entry is the special entry for - // the notdef glyph. The final entry beyond the last glyph id is used to - // calculate the size of the last glyph. - // @param glyphId the glyph id to get the offset for; must be less than or - // equal to one more than the number of glyph ids - // @return the offset in the glyph table to the specified glyph id - int32_t GlyphOffset(int32_t glyph_id); - - // Get the length of the data in the glyph table for the specified glyph id. - int32_t GlyphLength(int32_t glyph_id); - - // Get the number of locations or locas. This will be one more than the number - // of glyphs for this table since the last loca position is used to indicate - // the size of the final glyph. - int32_t NumLocas(); - - // Get the value from the loca table for the index specified. Valid index - // values run from 0 to the number of glyphs in the font. - int32_t Loca(int32_t index); - - private: - LocaTable(Header* header, - ReadableFontData* data, - int32_t format_version, - int32_t num_glyphs); - - int32_t format_version_; // Note: Java's version, renamed to format_version_ - int32_t num_glyphs_; - - friend class LocaIterator; -}; -typedef Ptr LocaTablePtr; -typedef Ptr LocaTableBuilderPtr; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_TRUETYPE_LOCA_TABLE_H_ diff --git a/src/sfntly/src/sfntly/tag.cc b/src/sfntly/src/sfntly/tag.cc deleted file mode 100644 index c9d8c29878..0000000000 --- a/src/sfntly/src/sfntly/tag.cc +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/tag.h" -#include "sfntly/port/endian.h" - -// Use a macro instead of GenerateTag() because gcc 4.4.3 creates static -// initializers in that case. -#define TAG(a, b, c, d) ((a << 24) | (b << 16) | (c << 8) | d); - -namespace sfntly { - -const int32_t Tag::ttcf = TAG('t', 't', 'c', 'f'); -const int32_t Tag::cmap = TAG('c', 'm', 'a', 'p'); -const int32_t Tag::head = TAG('h', 'e', 'a', 'd'); -const int32_t Tag::hhea = TAG('h', 'h', 'e', 'a'); -const int32_t Tag::hmtx = TAG('h', 'm', 't', 'x'); -const int32_t Tag::maxp = TAG('m', 'a', 'x', 'p'); -const int32_t Tag::name = TAG('n', 'a', 'm', 'e'); -const int32_t Tag::OS_2 = TAG('O', 'S', '/', '2'); -const int32_t Tag::post = TAG('p', 'o', 's', 't'); -const int32_t Tag::cvt = TAG('c', 'v', 't', ' '); -const int32_t Tag::fpgm = TAG('f', 'p', 'g', 'm'); -const int32_t Tag::glyf = TAG('g', 'l', 'y', 'f'); -const int32_t Tag::loca = TAG('l', 'o', 'c', 'a'); -const int32_t Tag::prep = TAG('p', 'r', 'e', 'p'); -const int32_t Tag::CFF = TAG('C', 'F', 'F', ' '); -const int32_t Tag::VORG = TAG('V', 'O', 'R', 'G'); -const int32_t Tag::EBDT = TAG('E', 'B', 'D', 'T'); -const int32_t Tag::EBLC = TAG('E', 'B', 'L', 'C'); -const int32_t Tag::EBSC = TAG('E', 'B', 'S', 'C'); -const int32_t Tag::BASE = TAG('B', 'A', 'S', 'E'); -const int32_t Tag::GDEF = TAG('G', 'D', 'E', 'F'); -const int32_t Tag::GPOS = TAG('G', 'P', 'O', 'S'); -const int32_t Tag::GSUB = TAG('G', 'S', 'U', 'B'); -const int32_t Tag::JSTF = TAG('J', 'S', 'T', 'F'); -const int32_t Tag::DSIG = TAG('D', 'S', 'I', 'G'); -const int32_t Tag::gasp = TAG('g', 'a', 's', 'p'); -const int32_t Tag::hdmx = TAG('h', 'd', 'm', 'x'); -const int32_t Tag::kern = TAG('k', 'e', 'r', 'n'); -const int32_t Tag::LTSH = TAG('L', 'T', 'S', 'H'); -const int32_t Tag::PCLT = TAG('P', 'C', 'L', 'T'); -const int32_t Tag::VDMX = TAG('V', 'D', 'M', 'X'); -const int32_t Tag::vhea = TAG('v', 'h', 'e', 'a'); -const int32_t Tag::vmtx = TAG('v', 'm', 't', 'x'); -const int32_t Tag::bsln = TAG('b', 's', 'l', 'n'); -const int32_t Tag::feat = TAG('f', 'e', 'a', 't'); -const int32_t Tag::lcar = TAG('l', 'c', 'a', 'r'); -const int32_t Tag::morx = TAG('m', 'o', 'r', 'x'); -const int32_t Tag::opbd = TAG('o', 'p', 'b', 'd'); -const int32_t Tag::prop = TAG('p', 'r', 'o', 'p'); -const int32_t Tag::Feat = TAG('F', 'e', 'a', 't'); -const int32_t Tag::Glat = TAG('G', 'l', 'a', 't'); -const int32_t Tag::Gloc = TAG('G', 'l', 'o', 'c'); -const int32_t Tag::Sile = TAG('S', 'i', 'l', 'e'); -const int32_t Tag::Silf = TAG('S', 'i', 'l', 'f'); -const int32_t Tag::bhed = TAG('b', 'h', 'e', 'd'); -const int32_t Tag::bdat = TAG('b', 'd', 'a', 't'); -const int32_t Tag::bloc = TAG('b', 'l', 'o', 'c'); - -const int32_t CFF_TABLE_ORDERING[] = { - Tag::head, - Tag::hhea, - Tag::maxp, - Tag::OS_2, - Tag::name, - Tag::cmap, - Tag::post, - Tag::CFF }; -const size_t CFF_TABLE_ORDERING_SIZE = - sizeof(CFF_TABLE_ORDERING) / sizeof(int32_t); - -const int32_t TRUE_TYPE_TABLE_ORDERING[] = { - Tag::head, - Tag::hhea, - Tag::maxp, - Tag::OS_2, - Tag::hmtx, - Tag::LTSH, - Tag::VDMX, - Tag::hdmx, - Tag::cmap, - Tag::fpgm, - Tag::prep, - Tag::cvt, - Tag::loca, - Tag::glyf, - Tag::kern, - Tag::name, - Tag::post, - Tag::gasp, - Tag::PCLT, - Tag::DSIG }; -const size_t TRUE_TYPE_TABLE_ORDERING_SIZE = - sizeof(TRUE_TYPE_TABLE_ORDERING) / sizeof(int32_t); - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/tag.h b/src/sfntly/src/sfntly/tag.h deleted file mode 100644 index 0ecbab85b4..0000000000 --- a/src/sfntly/src/sfntly/tag.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TAG_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TAG_H_ - -#include - -#include "sfntly/port/type.h" - -namespace sfntly { - -// Font identification tags used for tables, features, etc. -// Tag names are consistent with the OpenType and sfnt specs. -struct Tag { - static const int32_t ttcf; - - // Table Type Tags - // required tables - static const int32_t cmap; - static const int32_t head; - static const int32_t hhea; - static const int32_t hmtx; - static const int32_t maxp; - static const int32_t name; - static const int32_t OS_2; - static const int32_t post; - - // TrueType outline tables - static const int32_t cvt; - static const int32_t fpgm; - static const int32_t glyf; - static const int32_t loca; - static const int32_t prep; - - // PostScript outline tables - static const int32_t CFF; - static const int32_t VORG; - - // opentype bitmap glyph outlines - static const int32_t EBDT; - static const int32_t EBLC; - static const int32_t EBSC; - - // advanced typographic features - static const int32_t BASE; - static const int32_t GDEF; - static const int32_t GPOS; - static const int32_t GSUB; - static const int32_t JSTF; - - // other - static const int32_t DSIG; - static const int32_t gasp; - static const int32_t hdmx; - static const int32_t kern; - static const int32_t LTSH; - static const int32_t PCLT; - static const int32_t VDMX; - static const int32_t vhea; - static const int32_t vmtx; - - // AAT tables - static const int32_t bsln; - static const int32_t feat; - static const int32_t lcar; - static const int32_t morx; - static const int32_t opbd; - static const int32_t prop; - - // Graphite tables - static const int32_t Feat; - static const int32_t Glat; - static const int32_t Gloc; - static const int32_t Sile; - static const int32_t Silf; - - // truetype bitmap font tables - static const int32_t bhed; - static const int32_t bdat; - static const int32_t bloc; -}; - -// Create integer tag value for human readable tag name. -inline int32_t GenerateTag(int32_t a, int32_t b, int32_t c, int32_t d) { - return (a << 24) | (b << 16) | (c << 8) | d; -} - -// Translate tag to human readable string. -// The Caller must delete[] the returned value. -inline char* TagToString(int32_t tag) { - char *name = new char[5]; - name[0] = static_cast((tag & 0xff000000) >> 24); - name[1] = static_cast((tag & 0x00ff0000) >> 16); - name[2] = static_cast((tag & 0x0000ff00) >> 8); - name[3] = static_cast(tag & 0x000000ff); - name[4] = 0; - return name; -} - -// Note: For Java, these two orderings are in Font class. Moved here to avoid -// VC++ bug of not populating correct values. -extern const int32_t CFF_TABLE_ORDERING[]; -extern const size_t CFF_TABLE_ORDERING_SIZE; -extern const int32_t TRUE_TYPE_TABLE_ORDERING[]; -extern const size_t TRUE_TYPE_TABLE_ORDERING_SIZE; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TAG_H_ diff --git a/src/sfntly/src/sfntly/tools/subsetter/glyph_table_subsetter.cc b/src/sfntly/src/sfntly/tools/subsetter/glyph_table_subsetter.cc deleted file mode 100644 index b3d6b07e44..0000000000 --- a/src/sfntly/src/sfntly/tools/subsetter/glyph_table_subsetter.cc +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/tools/subsetter/glyph_table_subsetter.h" - -#include "sfntly/table/truetype/glyph_table.h" -#include "sfntly/table/truetype/loca_table.h" -#include "sfntly/tag.h" -#include "sfntly/tools/subsetter/subsetter.h" -#include "sfntly/port/exception_type.h" - -namespace sfntly { - -const int32_t kGlyphTableSubsetterTags[2] = {Tag::glyf, Tag::loca}; - -GlyphTableSubsetter::GlyphTableSubsetter() - : TableSubsetterImpl(kGlyphTableSubsetterTags, 2) { -} - -GlyphTableSubsetter::~GlyphTableSubsetter() {} - -bool GlyphTableSubsetter::Subset(Subsetter* subsetter, - Font* font, - Font::Builder* font_builder) { - assert(font); - assert(subsetter); - assert(font_builder); - - IntegerList* permutation_table = subsetter->GlyphPermutationTable(); - if (!permutation_table || permutation_table->empty()) - return false; - - GlyphTablePtr glyph_table = down_cast(font->GetTable(Tag::glyf)); - LocaTablePtr loca_table = down_cast(font->GetTable(Tag::loca)); - if (glyph_table == NULL || loca_table == NULL) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw RuntimeException("Font to subset is not valid."); -#endif - return false; - } - - GlyphTableBuilderPtr glyph_table_builder = - down_cast - (font_builder->NewTableBuilder(Tag::glyf)); - LocaTableBuilderPtr loca_table_builder = - down_cast - (font_builder->NewTableBuilder(Tag::loca)); - if (glyph_table_builder == NULL || loca_table_builder == NULL) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw RuntimeException("Builder for subset is not valid."); -#endif - return false; - } - GlyphTable::GlyphBuilderList* glyph_builders = - glyph_table_builder->GlyphBuilders(); - for (IntegerList::iterator old_glyph_id = permutation_table->begin(), - old_glyph_id_end = permutation_table->end(); - old_glyph_id != old_glyph_id_end; ++old_glyph_id) { - int old_offset = loca_table->GlyphOffset(*old_glyph_id); - int old_length = loca_table->GlyphLength(*old_glyph_id); - GlyphPtr glyph; - glyph.Attach(glyph_table->GetGlyph(old_offset, old_length)); - ReadableFontDataPtr data = glyph->ReadFontData(); - WritableFontDataPtr copy_data; - copy_data.Attach(WritableFontData::CreateWritableFontData(data->Length())); - data->CopyTo(copy_data); - GlyphBuilderPtr glyph_builder; - glyph_builder.Attach(glyph_table_builder->GlyphBuilder(copy_data)); - glyph_builders->push_back(glyph_builder); - } - IntegerList loca_list; - glyph_table_builder->GenerateLocaList(&loca_list); - loca_table_builder->SetLocaList(&loca_list); - return true; -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/tools/subsetter/glyph_table_subsetter.h b/src/sfntly/src/sfntly/tools/subsetter/glyph_table_subsetter.h deleted file mode 100644 index 88c704443f..0000000000 --- a/src/sfntly/src/sfntly/tools/subsetter/glyph_table_subsetter.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_GLYPH_TABLE_SUBSETTER_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_GLYPH_TABLE_SUBSETTER_H_ - -#include "sfntly/tools/subsetter/table_subsetter_impl.h" - -namespace sfntly { - -class GlyphTableSubsetter : public TableSubsetterImpl, - public RefCounted { - public: - GlyphTableSubsetter(); - virtual ~GlyphTableSubsetter(); - - virtual bool Subset(Subsetter* subsetter, - Font* font, - Font::Builder* font_builder); -}; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_GLYPH_TABLE_SUBSETTER_H_ diff --git a/src/sfntly/src/sfntly/tools/subsetter/subsetter.cc b/src/sfntly/src/sfntly/tools/subsetter/subsetter.cc deleted file mode 100644 index 7d987796b9..0000000000 --- a/src/sfntly/src/sfntly/tools/subsetter/subsetter.cc +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/tools/subsetter/subsetter.h" - -#include -#include - -#include "sfntly/tools/subsetter/glyph_table_subsetter.h" - -namespace sfntly { - -Subsetter::Subsetter(Font* font, FontFactory* font_factory) { - font_ = font; - font_factory_ = font_factory; - TableSubsetterPtr subsetter = new GlyphTableSubsetter(); - // TODO(arthurhsu): IMPLEMENT: CMap table subsetter - table_subsetters_.push_back(subsetter); -} - -Subsetter::~Subsetter() { - font_factory_.Release(); - font_.Release(); - table_subsetters_.clear(); -} - -void Subsetter::SetGlyphs(IntegerList* glyphs) { - new_to_old_glyphs_ = *glyphs; -} - -void Subsetter::SetCMaps(CMapIdList* cmap_ids, int32_t number) { - UNREFERENCED_PARAMETER(cmap_ids); - UNREFERENCED_PARAMETER(number); - // TODO(arthurhsu): IMPLEMENT -} - -void Subsetter::SetRemoveTables(IntegerSet* remove_tables) { - remove_tables_ = *remove_tables; -} - -CALLER_ATTACH Font::Builder* Subsetter::Subset() { - FontBuilderPtr font_builder; - font_builder.Attach(font_factory_->NewFontBuilder()); - - IntegerSet table_tags; - for (TableMap::const_iterator i = font_->GetTableMap()->begin(), - e = font_->GetTableMap()->end(); i != e; ++i) { - table_tags.insert(i->first); - } - if (!remove_tables_.empty()) { - IntegerSet result; - std::set_difference(table_tags.begin(), table_tags.end(), - remove_tables_.begin(), remove_tables_.end(), - std::inserter(result, result.end())); - table_tags = result; - } - for (TableSubsetterList::iterator - table_subsetter = table_subsetters_.begin(), - table_subsetter_end = table_subsetters_.end(); - table_subsetter != table_subsetter_end; ++table_subsetter) { - bool handled = (*table_subsetter)->Subset(this, font_, font_builder); - if (handled) { - IntegerSet* handled_tags = (*table_subsetter)->TagsHandled(); - IntegerSet result; - std::set_difference(table_tags.begin(), table_tags.end(), - handled_tags->begin(), handled_tags->end(), - std::inserter(result, result.end())); - table_tags = result; - } - } - for (IntegerSet::iterator tag = table_tags.begin(), - tag_end = table_tags.end(); tag != tag_end; ++tag) { - Table* table = font_->GetTable(*tag); - if (table) { - font_builder->NewTableBuilder(*tag, table->ReadFontData()); - } - } - return font_builder.Detach(); -} - -IntegerList* Subsetter::GlyphPermutationTable() { - return &new_to_old_glyphs_; -} - -CMapIdList* Subsetter::CMapId() { - return &cmap_ids_; -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/tools/subsetter/subsetter.h b/src/sfntly/src/sfntly/tools/subsetter/subsetter.h deleted file mode 100644 index 85940a7928..0000000000 --- a/src/sfntly/src/sfntly/tools/subsetter/subsetter.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_SUBSETTER_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_SUBSETTER_H_ - -#include - -#include "sfntly/font.h" -#include "sfntly/font_factory.h" -#include "sfntly/table/core/cmap_table.h" -#include "sfntly/tools/subsetter/table_subsetter.h" - -namespace sfntly { - -class Subsetter : public RefCounted { - public: - Subsetter(Font* font, FontFactory* font_factory); - virtual ~Subsetter(); - - virtual void SetGlyphs(IntegerList* glyphs); - - // Set the cmaps to be used in the subsetted font. The cmaps are listed in - // order of priority and the number parameter gives a count of how many of the - // list should be put into the subsetted font. If there are no matches in the - // font for any of the provided cmap ids which would lead to a font with no - // cmap then an error will be thrown during subsetting. - // The two most common cases would be: - // * a list of one or more cmap ids with a count setting of 1 - // This will use the list of cmap ids as an ordered priority and look for - // an available cmap in the font that matches the requests. Only the first - // such match will be placed in the subsetted font. - // * a list of one or more cmap ids with a count setting equal to the list - // length - // This will use the list of cmap ids and try to place each one specified - // into the subsetted font. - // @param cmapIds the cmap ids to use for the subsetted font - // @param number the maximum number of cmaps to place in the subsetted font - virtual void SetCMaps(CMapIdList* cmap_ids, int32_t number); - - virtual void SetRemoveTables(IntegerSet* remove_tables); - virtual CALLER_ATTACH Font::Builder* Subset(); - virtual IntegerList* GlyphPermutationTable(); - virtual CMapIdList* CMapId(); - - private: - FontPtr font_; - FontFactoryPtr font_factory_; - TableSubsetterList table_subsetters_; - - // Settings from user - IntegerSet remove_tables_; - IntegerList new_to_old_glyphs_; - CMapIdList cmap_ids_; -}; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_SUBSETTER_H_ diff --git a/src/sfntly/src/sfntly/tools/subsetter/table_subsetter.h b/src/sfntly/src/sfntly/tools/subsetter/table_subsetter.h deleted file mode 100644 index 1336615b07..0000000000 --- a/src/sfntly/src/sfntly/tools/subsetter/table_subsetter.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_TABLE_SUBSETTER_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_TABLE_SUBSETTER_H_ - -#include - -#include "sfntly/font.h" - -namespace sfntly { - -class Subsetter; -class TableSubsetter : virtual public RefCount { - public: - virtual IntegerSet* TagsHandled() = 0; - virtual bool TagHandled(int32_t tag) = 0; - virtual bool Subset(Subsetter* subsetter, Font* font, - Font::Builder* font_builder) = 0; -}; -typedef Ptr TableSubsetterPtr; -typedef std::vector TableSubsetterList; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_TABLE_SUBSETTER_H_ diff --git a/src/sfntly/src/sfntly/tools/subsetter/table_subsetter_impl.cc b/src/sfntly/src/sfntly/tools/subsetter/table_subsetter_impl.cc deleted file mode 100644 index f239c78e3c..0000000000 --- a/src/sfntly/src/sfntly/tools/subsetter/table_subsetter_impl.cc +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sfntly/tools/subsetter/table_subsetter_impl.h" - -namespace sfntly { - -TableSubsetterImpl::TableSubsetterImpl(const int32_t* tags, - size_t tags_length) { - for (size_t i = 0; i < tags_length; ++i) { - tags_.insert(tags[i]); - } -} - -TableSubsetterImpl::~TableSubsetterImpl() {} - -bool TableSubsetterImpl::TagHandled(int32_t tag) { - return tags_.find(tag) != tags_.end(); -} - -IntegerSet* TableSubsetterImpl::TagsHandled() { - return &tags_; -} - -} // namespace sfntly diff --git a/src/sfntly/src/sfntly/tools/subsetter/table_subsetter_impl.h b/src/sfntly/src/sfntly/tools/subsetter/table_subsetter_impl.h deleted file mode 100644 index de0d9a98ca..0000000000 --- a/src/sfntly/src/sfntly/tools/subsetter/table_subsetter_impl.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2011 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_TABLE_SUBSETTER_IMPL_H_ -#define SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_TABLE_SUBSETTER_IMPL_H_ - -#include "sfntly/tools/subsetter/table_subsetter.h" - -namespace sfntly { - -class TableSubsetterImpl : public TableSubsetter { - public: - TableSubsetterImpl(const int32_t* tags, size_t tags_length); - virtual ~TableSubsetterImpl(); - virtual bool TagHandled(int32_t tag); - virtual IntegerSet* TagsHandled(); - - protected: - IntegerSet tags_; -}; - -} // namespace sfntly - -#endif // SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_TABLE_SUBSETTER_IMPL_H_ From 5237c269ea4cd7dec559495ad11c0dc721326068 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 6 Nov 2012 12:42:43 +0530 Subject: [PATCH 095/107] ... --- src/calibre/utils/fonts/sfnt/container.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/calibre/utils/fonts/sfnt/container.py b/src/calibre/utils/fonts/sfnt/container.py index 73bb787810..2e08ef3cee 100644 --- a/src/calibre/utils/fonts/sfnt/container.py +++ b/src/calibre/utils/fonts/sfnt/container.py @@ -22,6 +22,8 @@ from calibre.utils.fonts.sfnt.loca import LocaTable from calibre.utils.fonts.sfnt.glyf import GlyfTable from calibre.utils.fonts.sfnt.cmap import CmapTable +# OpenType spec: http://www.microsoft.com/typography/otspec/otff.htm + class Sfnt(object): def __init__(self, raw): From b318b128feade1f386db58644bedd67f7a440013 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 6 Nov 2012 12:56:00 +0530 Subject: [PATCH 096/107] Clearer error message --- src/calibre/utils/filenames.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/calibre/utils/filenames.py b/src/calibre/utils/filenames.py index 22ae1a9306..260671dc7a 100644 --- a/src/calibre/utils/filenames.py +++ b/src/calibre/utils/filenames.py @@ -309,8 +309,11 @@ class WindowsAtomicFolderMove(object): handle = h break if handle is None: - raise ValueError(u'The file %r did not exist when this move' - ' operation was started'%path) + if os.path.exists(path): + raise ValueError(u'The file %r did not exist when this move' + ' operation was started'%path) + else: + raise ValueError(u'The file %r does not exist'%path) try: win32file.CreateHardLink(dest, path) if os.path.getsize(dest) != os.path.getsize(path): From 119c169c07407865e19605dd09fea2076cb60996 Mon Sep 17 00:00:00 2001 From: GRiker Date: Tue, 6 Nov 2012 05:06:00 -0700 Subject: [PATCH 097/107] Added cross_reference_authors switch to CLI and GUI --- src/calibre/gui2/catalog/catalog_epub_mobi.py | 7 ++-- src/calibre/gui2/catalog/catalog_epub_mobi.ui | 33 +++++++++++++++---- src/calibre/library/catalogs/epub_mobi.py | 13 +++++--- .../library/catalogs/epub_mobi_builder.py | 13 ++------ 4 files changed, 43 insertions(+), 23 deletions(-) diff --git a/src/calibre/gui2/catalog/catalog_epub_mobi.py b/src/calibre/gui2/catalog/catalog_epub_mobi.py index 1ed11a55d7..04a5fe9527 100644 --- a/src/calibre/gui2/catalog/catalog_epub_mobi.py +++ b/src/calibre/gui2/catalog/catalog_epub_mobi.py @@ -239,10 +239,11 @@ class PluginWidget(QWidget,Ui_Form): def initialize(self, name, db): ''' - CheckBoxControls (c_type: check_box): - ['generate_titles','generate_series','generate_genres', - 'generate_recently_added','generate_descriptions','include_hr'] + ['cross_reference_authors', + 'generate_titles','generate_series','generate_genres', + 'generate_recently_added','generate_descriptions', + 'include_hr'] ComboBoxControls (c_type: combo_box): ['exclude_source_field','header_note_source_field', 'merge_source_field'] diff --git a/src/calibre/gui2/catalog/catalog_epub_mobi.ui b/src/calibre/gui2/catalog/catalog_epub_mobi.ui index b32e596f54..5c016ffdb5 100644 --- a/src/calibre/gui2/catalog/catalog_epub_mobi.ui +++ b/src/calibre/gui2/catalog/catalog_epub_mobi.ui @@ -305,7 +305,7 @@ The default pattern \[.+\]|\+ excludes tags of the form [tag], e.g., [Test book] Other options - + @@ -372,7 +372,7 @@ The default pattern \[.+\]|\+ excludes tags of the form [tag], e.g., [Test book] - + @@ -397,7 +397,7 @@ The default pattern \[.+\]|\+ excludes tags of the form [tag], e.g., [Test book] - + @@ -413,7 +413,7 @@ The default pattern \[.+\]|\+ excludes tags of the form [tag], e.g., [Test book] - + @@ -447,7 +447,7 @@ The default pattern \[.+\]|\+ excludes tags of the form [tag], e.g., [Test book] - + E&xtra Description note: @@ -460,7 +460,7 @@ The default pattern \[.+\]|\+ excludes tags of the form [tag], e.g., [Test book] - + @@ -561,6 +561,27 @@ The default pattern \[.+\]|\+ excludes tags of the form [tag], e.g., [Test book] + + + + Author cross-references: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + For books with multiple authors, list each author separately + + + + + diff --git a/src/calibre/library/catalogs/epub_mobi.py b/src/calibre/library/catalogs/epub_mobi.py index 251db5cf88..de56e27e6e 100644 --- a/src/calibre/library/catalogs/epub_mobi.py +++ b/src/calibre/library/catalogs/epub_mobi.py @@ -41,6 +41,13 @@ class EPUB_MOBI(CatalogPlugin): help = _('Title of generated catalog used as title in metadata.\n' "Default: '%default'\n" "Applies to: AZW3, ePub, MOBI output formats")), + Option('--cross-reference-authors', + default=False, + dest='cross_reference_authors', + action = 'store_true', + help=_("Create cross-references in Authors section for books with multiple authors.\n" + "Default: '%default'\n" + "Applies to: AZW3, ePub, MOBI output formats")), Option('--debug-pipeline', default=None, dest='debug_pipeline', @@ -58,7 +65,6 @@ class EPUB_MOBI(CatalogPlugin): help=_("Regex describing tags to exclude as genres.\n" "Default: '%default' excludes bracketed tags, e.g. '[Project Gutenberg]', and '+', the default tag for read books.\n" "Applies to: AZW3, ePub, MOBI output formats")), - Option('--exclusion-rules', default="(('Catalogs','Tags','Catalog'),)", dest='exclusion_rules', @@ -72,7 +78,6 @@ class EPUB_MOBI(CatalogPlugin): "When multiple rules are defined, all rules will be applied.\n" "Default: \n" + '"' + '%default' + '"' + "\n" "Applies to AZW3, ePub, MOBI output formats")), - Option('--generate-authors', default=False, dest='generate_authors', @@ -318,8 +323,8 @@ class EPUB_MOBI(CatalogPlugin): build_log.append(" opts:") for key in keys: if key in ['catalog_title','author_clip','connected_kindle','creator', - 'description_clip','exclude_book_marker','exclude_genre', - 'exclude_tags','exclusion_rules', 'fmt', + 'cross_reference_authors','description_clip','exclude_book_marker', + 'exclude_genre','exclude_tags','exclusion_rules', 'fmt', 'header_note_source_field','merge_comments_rule', 'output_profile','prefix_rules','read_book_marker', 'search_text','sort_by','sort_descriptions_by_author','sync', diff --git a/src/calibre/library/catalogs/epub_mobi_builder.py b/src/calibre/library/catalogs/epub_mobi_builder.py index 58712cf3d3..dbc73925b6 100644 --- a/src/calibre/library/catalogs/epub_mobi_builder.py +++ b/src/calibre/library/catalogs/epub_mobi_builder.py @@ -727,7 +727,8 @@ class CatalogBuilder(object): books_by_author = list(self.books_to_catalog) self.detect_author_sort_mismatches(books_by_author) - books_by_author = self.relist_multiple_authors(books_by_author) + if self.opts.cross_reference_authors: + books_by_author = self.relist_multiple_authors(books_by_author) #books_by_author = sorted(list(books_by_author), key=self._kf_books_by_author_sorter_author) @@ -4720,17 +4721,10 @@ class CatalogBuilder(object): with multiple authors Return: - (list): books_by_author with additional entries for books with + (list): books_by_author with additional cloned entries for books with multiple authors """ - # Scan list looking for entries with len(authors) > 1 - # Clone multiples, swapping additional author into first place, - # computing author_sort to match - - # from calibre.ebooks.metadata import authors_to_string - # return authors_to_string(self.authors) - multiple_author_books = [] # Find the multiple author books @@ -4749,7 +4743,6 @@ class CatalogBuilder(object): new_book['authors'] = list(cloned_authors) asl = [author_to_author_sort(auth) for auth in cloned_authors] new_book['author_sort'] = ' & '.join(asl) - #print("'%s' (%s) (%s)" % (new_book['title'], new_book['authors'], new_book['author_sort'])) books_by_author.append(new_book) return books_by_author From a8309e3df6f5d9d0bbad4b00a78b47b1724dd1d0 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Tue, 6 Nov 2012 16:16:58 +0100 Subject: [PATCH 098/107] fix Amazon EU and libre.de stores --- .../gui2/store/stores/amazon_de_plugin.py | 101 ++---------------- .../gui2/store/stores/amazon_es_plugin.py | 79 ++------------ .../gui2/store/stores/amazon_fr_plugin.py | 75 ++----------- .../gui2/store/stores/amazon_it_plugin.py | 79 ++------------ .../gui2/store/stores/amazon_uk_plugin.py | 95 ++++++++-------- .../gui2/store/stores/libri_de_plugin.py | 33 +++--- 6 files changed, 98 insertions(+), 364 deletions(-) diff --git a/src/calibre/gui2/store/stores/amazon_de_plugin.py b/src/calibre/gui2/store/stores/amazon_de_plugin.py index 69e7dcaafc..846903cd4a 100644 --- a/src/calibre/gui2/store/stores/amazon_de_plugin.py +++ b/src/calibre/gui2/store/stores/amazon_de_plugin.py @@ -6,102 +6,19 @@ __license__ = 'GPL 3' __copyright__ = '2011, John Schember ' __docformat__ = 'restructuredtext en' -from contextlib import closing +from calibre.gui2.store.stores.amazon_uk_plugin import AmazonUKKindleStore -from lxml import html - -from PyQt4.Qt import QUrl - -from calibre import browser -from calibre.gui2 import open_url -from calibre.gui2.store import StorePlugin -from calibre.gui2.store.search_result import SearchResult - -class AmazonDEKindleStore(StorePlugin): +class AmazonDEKindleStore(AmazonUKKindleStore): ''' For comments on the implementation, please see amazon_plugin.py ''' - def open(self, parent=None, detail_item=None, external=False): - aff_id = {'tag': 'charhale0a-21'} - store_link = ('http://www.amazon.de/gp/redirect.html?ie=UTF8&site-redirect=de' - '&tag=%(tag)s&linkCode=ur2&camp=1638&creative=19454' - '&location=http://www.amazon.de/ebooks-kindle/b?node=530886031') % aff_id - if detail_item: - aff_id['asin'] = detail_item - store_link = ('http://www.amazon.de/gp/redirect.html?ie=UTF8' + aff_id = {'tag': 'charhale0a-21'} + store_link = ('http://www.amazon.de/gp/redirect.html?ie=UTF8&site-redirect=de' + '&tag=%(tag)s&linkCode=ur2&camp=1638&creative=19454' + '&location=http://www.amazon.de/ebooks-kindle/b?node=530886031') + store_link_details = ('http://www.amazon.de/gp/redirect.html?ie=UTF8' '&location=http://www.amazon.de/dp/%(asin)s&site-redirect=de' - '&tag=%(tag)s&linkCode=ur2&camp=1638&creative=6742') % aff_id - open_url(QUrl(store_link)) + '&tag=%(tag)s&linkCode=ur2&camp=1638&creative=6742') + search_url = 'http://www.amazon.de/s/?url=search-alias%3Ddigital-text&field-keywords=' - def search(self, query, max_results=10, timeout=60): - search_url = 'http://www.amazon.de/s/?url=search-alias%3Ddigital-text&field-keywords=' - url = search_url + query.encode('ascii', 'backslashreplace').replace('%', '%25').replace('\\x', '%').replace(' ', '+') - br = browser() - - counter = max_results - with closing(br.open(url, timeout=timeout)) as f: - # doc = html.fromstring(f.read().decode('latin-1', 'replace')) - # Apparently amazon Europe is responding in UTF-8 now - doc = html.fromstring(f.read()) - - data_xpath = '//div[contains(@class, "result") and contains(@class, "product")]' - format_xpath = './/span[@class="format"]/text()' - cover_xpath = './/img[@class="productImage"]/@src' - - for data in doc.xpath(data_xpath): - if counter <= 0: - break - - # Even though we are searching digital-text only Amazon will still - # put in results for non Kindle books (author pages). So we need - # to explicitly check if the item is a Kindle book and ignore it - # if it isn't. - format = ''.join(data.xpath(format_xpath)) - if 'kindle' not in format.lower(): - continue - - # We must have an asin otherwise we can't easily reference the - # book later. - asin = ''.join(data.xpath("@name")) - - cover_url = ''.join(data.xpath(cover_xpath)) - - title = ''.join(data.xpath('.//a[@class="title"]/text()')) - price = ''.join(data.xpath('.//div[@class="newPrice"]/span[contains(@class, "price")]/text()')) - - author = ''.join(data.xpath('.//h3[@class="title"]/span[@class="ptBrand"]/text()')) - if author.startswith('von '): - author = author[4:] - - counter -= 1 - - s = SearchResult() - s.cover_url = cover_url.strip() - s.title = title.strip() - s.author = author.strip() - s.price = price.strip() - s.detail_item = asin.strip() - s.formats = 'Kindle' - - yield s - - def get_details(self, search_result, timeout): - drm_search_text = u'Gleichzeitige Verwendung von Geräten' - drm_free_text = u'Keine Einschränkung' - url = 'http://amazon.de/dp/' - - br = browser() - with closing(br.open(url + search_result.detail_item, timeout=timeout)) as nf: - idata = html.fromstring(nf.read()) - if idata.xpath('boolean(//div[@class="content"]//li/b[contains(text(), "' + - drm_search_text + '")])'): - if idata.xpath('boolean(//div[@class="content"]//li[contains(., "' + - drm_free_text + '") and contains(b, "' + - drm_search_text + '")])'): - search_result.drm = SearchResult.DRM_UNLOCKED - else: - search_result.drm = SearchResult.DRM_UNKNOWN - else: - search_result.drm = SearchResult.DRM_LOCKED - return True diff --git a/src/calibre/gui2/store/stores/amazon_es_plugin.py b/src/calibre/gui2/store/stores/amazon_es_plugin.py index 094f1e13c9..afd6552272 100644 --- a/src/calibre/gui2/store/stores/amazon_es_plugin.py +++ b/src/calibre/gui2/store/stores/amazon_es_plugin.py @@ -6,78 +6,17 @@ __license__ = 'GPL 3' __copyright__ = '2011, John Schember ' __docformat__ = 'restructuredtext en' -from contextlib import closing +from calibre.gui2.store.stores.amazon_uk_plugin import AmazonUKKindleStore -from lxml import html - -from PyQt4.Qt import QUrl - -from calibre import browser -from calibre.gui2 import open_url -from calibre.gui2.store import StorePlugin -from calibre.gui2.store.search_result import SearchResult - -class AmazonESKindleStore(StorePlugin): +class AmazonESKindleStore(AmazonUKKindleStore): ''' For comments on the implementation, please see amazon_plugin.py ''' - def open(self, parent=None, detail_item=None, external=False): - aff_id = {'tag': 'charhale09-21'} - store_link = 'http://www.amazon.es/ebooks-kindle/b?_encoding=UTF8&node=827231031&tag=%(tag)s&ie=UTF8&linkCode=ur2&camp=3626&creative=24790' % aff_id - if detail_item: - aff_id['asin'] = detail_item - store_link = 'http://www.amazon.es/gp/redirect.html?ie=UTF8&location=http://www.amazon.es/dp/%(asin)s&tag=%(tag)s&linkCode=ur2&camp=3626&creative=24790' % aff_id - open_url(QUrl(store_link)) - - def search(self, query, max_results=10, timeout=60): - search_url = 'http://www.amazon.es/s/?url=search-alias%3Ddigital-text&field-keywords=' - url = search_url + query.encode('ascii', 'backslashreplace').replace('%', '%25').replace('\\x', '%').replace(' ', '+') - br = browser() - - counter = max_results - with closing(br.open(url, timeout=timeout)) as f: - # doc = html.fromstring(f.read().decode('latin-1', 'replace')) - # Apparently amazon Europe is responding in UTF-8 now - doc = html.fromstring(f.read()) - - data_xpath = '//div[contains(@class, "result") and contains(@class, "product")]' - format_xpath = './/span[@class="format"]/text()' - cover_xpath = './/img[@class="productImage"]/@src' - - for data in doc.xpath(data_xpath): - if counter <= 0: - break - - # Even though we are searching digital-text only Amazon will still - # put in results for non Kindle books (author pages). So we need - # to explicitly check if the item is a Kindle book and ignore it - # if it isn't. - format = ''.join(data.xpath(format_xpath)) - if 'kindle' not in format.lower(): - continue - - # We must have an asin otherwise we can't easily reference the - # book later. - asin = ''.join(data.xpath("@name")) - - cover_url = ''.join(data.xpath(cover_xpath)) - - title = ''.join(data.xpath('.//a[@class="title"]/text()')) - price = ''.join(data.xpath('.//div[@class="newPrice"]/span[contains(@class, "price")]/text()')) - author = unicode(''.join(data.xpath('.//h3[@class="title"]/span[@class="ptBrand"]/text()'))) - if author.startswith('de '): - author = author[3:] - - counter -= 1 - - s = SearchResult() - s.cover_url = cover_url.strip() - s.title = title.strip() - s.author = author.strip() - s.price = price.strip() - s.detail_item = asin.strip() - s.formats = 'Kindle' - s.drm = SearchResult.DRM_UNKNOWN - - yield s + aff_id = {'tag': 'charhale09-21'} + store_link = ('http://www.amazon.es/ebooks-kindle/b?_encoding=UTF8&' + 'node=827231031&tag=%(tag)s&ie=UTF8&linkCode=ur2&camp=3626&creative=24790') + store_link_details = ('http://www.amazon.es/gp/redirect.html?ie=UTF8&' + 'location=http://www.amazon.es/dp/%(asin)s&tag=%(tag)s' + '&linkCode=ur2&camp=3626&creative=24790') + search_url = 'http://www.amazon.es/s/?url=search-alias%3Ddigital-text&field-keywords=' \ No newline at end of file diff --git a/src/calibre/gui2/store/stores/amazon_fr_plugin.py b/src/calibre/gui2/store/stores/amazon_fr_plugin.py index 4e31d69ca5..97a6179d7b 100644 --- a/src/calibre/gui2/store/stores/amazon_fr_plugin.py +++ b/src/calibre/gui2/store/stores/amazon_fr_plugin.py @@ -6,79 +6,16 @@ __license__ = 'GPL 3' __copyright__ = '2011, John Schember ' __docformat__ = 'restructuredtext en' -from contextlib import closing -from lxml import html +from calibre.gui2.store.stores.amazon_uk_plugin import AmazonUKKindleStore -from PyQt4.Qt import QUrl - -from calibre import browser -from calibre.gui2 import open_url -from calibre.gui2.store import StorePlugin -from calibre.gui2.store.search_result import SearchResult - -class AmazonFRKindleStore(StorePlugin): +class AmazonFRKindleStore(AmazonUKKindleStore): ''' For comments on the implementation, please see amazon_plugin.py ''' - def open(self, parent=None, detail_item=None, external=False): - aff_id = {'tag': 'charhale-21'} - store_link = 'http://www.amazon.fr/livres-kindle/b?ie=UTF8&node=695398031&ref_=sa_menu_kbo1&_encoding=UTF8&tag=%(tag)s&linkCode=ur2&camp=1642&creative=19458' % aff_id + aff_id = {'tag': 'charhale-21'} + store_link = 'http://www.amazon.fr/livres-kindle/b?ie=UTF8&node=695398031&ref_=sa_menu_kbo1&_encoding=UTF8&tag=%(tag)s&linkCode=ur2&camp=1642&creative=19458' % aff_id + store_link_details = 'http://www.amazon.fr/gp/redirect.html?ie=UTF8&location=http://www.amazon.fr/dp/%(asin)s&tag=%(tag)s&linkCode=ur2&camp=1634&creative=6738' + search_url = 'http://www.amazon.fr/s/?url=search-alias%3Ddigital-text&field-keywords=' - if detail_item: - aff_id['asin'] = detail_item - store_link = 'http://www.amazon.fr/gp/redirect.html?ie=UTF8&location=http://www.amazon.fr/dp/%(asin)s&tag=%(tag)s&linkCode=ur2&camp=1634&creative=6738' % aff_id - open_url(QUrl(store_link)) - - def search(self, query, max_results=10, timeout=60): - search_url = 'http://www.amazon.fr/s/?url=search-alias%3Ddigital-text&field-keywords=' - url = search_url + query.encode('ascii', 'backslashreplace').replace('%', '%25').replace('\\x', '%').replace(' ', '+') - br = browser() - - counter = max_results - with closing(br.open(url, timeout=timeout)) as f: - # doc = html.fromstring(f.read().decode('latin-1', 'replace')) - # Apparently amazon Europe is responding in UTF-8 now - doc = html.fromstring(f.read()) - - data_xpath = '//div[contains(@class, "result") and contains(@class, "product")]' - format_xpath = './/span[@class="format"]/text()' - cover_xpath = './/img[@class="productImage"]/@src' - - for data in doc.xpath(data_xpath): - if counter <= 0: - break - - # Even though we are searching digital-text only Amazon will still - # put in results for non Kindle books (author pages). So we need - # to explicitly check if the item is a Kindle book and ignore it - # if it isn't. - format = ''.join(data.xpath(format_xpath)) - if 'kindle' not in format.lower(): - continue - - # We must have an asin otherwise we can't easily reference the - # book later. - asin = ''.join(data.xpath("@name")) - - cover_url = ''.join(data.xpath(cover_xpath)) - - title = ''.join(data.xpath('.//a[@class="title"]/text()')) - price = ''.join(data.xpath('.//div[@class="newPrice"]/span[contains(@class, "price")]/text()')) - author = unicode(''.join(data.xpath('.//h3[@class="title"]/span[@class="ptBrand"]/text()'))) - if author.startswith('de '): - author = author[3:] - - counter -= 1 - - s = SearchResult() - s.cover_url = cover_url.strip() - s.title = title.strip() - s.author = author.strip() - s.price = price.strip() - s.detail_item = asin.strip() - s.formats = 'Kindle' - s.drm = SearchResult.DRM_UNKNOWN - - yield s diff --git a/src/calibre/gui2/store/stores/amazon_it_plugin.py b/src/calibre/gui2/store/stores/amazon_it_plugin.py index 39dd1ee0ce..563c26bfa1 100644 --- a/src/calibre/gui2/store/stores/amazon_it_plugin.py +++ b/src/calibre/gui2/store/stores/amazon_it_plugin.py @@ -6,78 +6,17 @@ __license__ = 'GPL 3' __copyright__ = '2011, John Schember ' __docformat__ = 'restructuredtext en' -from contextlib import closing +from calibre.gui2.store.stores.amazon_uk_plugin import AmazonUKKindleStore -from lxml import html - -from PyQt4.Qt import QUrl - -from calibre import browser -from calibre.gui2 import open_url -from calibre.gui2.store import StorePlugin -from calibre.gui2.store.search_result import SearchResult - -class AmazonITKindleStore(StorePlugin): +class AmazonITKindleStore(AmazonUKKindleStore): ''' For comments on the implementation, please see amazon_plugin.py ''' - def open(self, parent=None, detail_item=None, external=False): - aff_id = {'tag': 'httpcharles07-21'} - store_link = 'http://www.amazon.it/ebooks-kindle/b?_encoding=UTF8&node=827182031&tag=%(tag)s&ie=UTF8&linkCode=ur2&camp=3370&creative=23322' % aff_id - if detail_item: - aff_id['asin'] = detail_item - store_link = 'http://www.amazon.it/gp/redirect.html?ie=UTF8&location=http://www.amazon.it/dp/%(asin)s&tag=%(tag)s&linkCode=ur2&camp=3370&creative=23322' % aff_id - open_url(QUrl(store_link)) - - def search(self, query, max_results=10, timeout=60): - search_url = 'http://www.amazon.it/s/?url=search-alias%3Ddigital-text&field-keywords=' - url = search_url + query.encode('ascii', 'backslashreplace').replace('%', '%25').replace('\\x', '%').replace(' ', '+') - br = browser() - - counter = max_results - with closing(br.open(url, timeout=timeout)) as f: - # doc = html.fromstring(f.read().decode('latin-1', 'replace')) - # Apparently amazon Europe is responding in UTF-8 now - doc = html.fromstring(f.read()) - - data_xpath = '//div[contains(@class, "result") and contains(@class, "product")]' - format_xpath = './/span[@class="format"]/text()' - cover_xpath = './/img[@class="productImage"]/@src' - - for data in doc.xpath(data_xpath): - if counter <= 0: - break - - # Even though we are searching digital-text only Amazon will still - # put in results for non Kindle books (author pages). So we need - # to explicitly check if the item is a Kindle book and ignore it - # if it isn't. - format = ''.join(data.xpath(format_xpath)) - if 'kindle' not in format.lower(): - continue - - # We must have an asin otherwise we can't easily reference the - # book later. - asin = ''.join(data.xpath("@name")) - - cover_url = ''.join(data.xpath(cover_xpath)) - - title = ''.join(data.xpath('.//a[@class="title"]/text()')) - price = ''.join(data.xpath('.//div[@class="newPrice"]/span[contains(@class, "price")]/text()')) - author = unicode(''.join(data.xpath('.//h3[@class="title"]/span[@class="ptBrand"]/text()'))) - if author.startswith('di '): - author = author[3:] - - counter -= 1 - - s = SearchResult() - s.cover_url = cover_url.strip() - s.title = title.strip() - s.author = author.strip() - s.price = price.strip() - s.detail_item = asin.strip() - s.formats = 'Kindle' - s.drm = SearchResult.DRM_UNKNOWN - - yield s + aff_id = {'tag': 'httpcharles07-21'} + store_link = ('http://www.amazon.it/ebooks-kindle/b?_encoding=UTF8&' + 'node=827182031&tag=%(tag)s&ie=UTF8&linkCode=ur2&camp=3370&creative=23322') + store_link_details = ('http://www.amazon.it/gp/redirect.html?ie=UTF8&' + 'location=http://www.amazon.it/dp/%(asin)s&tag=%(tag)s&' + 'linkCode=ur2&camp=3370&creative=23322') + search_url = 'http://www.amazon.it/s/?url=search-alias%3Ddigital-text&field-keywords=' diff --git a/src/calibre/gui2/store/stores/amazon_uk_plugin.py b/src/calibre/gui2/store/stores/amazon_uk_plugin.py index 7fb1cec2d3..15980a3e8c 100644 --- a/src/calibre/gui2/store/stores/amazon_uk_plugin.py +++ b/src/calibre/gui2/store/stores/amazon_uk_plugin.py @@ -6,8 +6,9 @@ __license__ = 'GPL 3' __copyright__ = '2011, John Schember ' __docformat__ = 'restructuredtext en' -from contextlib import closing +import re +from contextlib import closing from lxml import html from PyQt4.Qt import QUrl @@ -18,57 +19,80 @@ from calibre.gui2.store import StorePlugin from calibre.gui2.store.search_result import SearchResult class AmazonUKKindleStore(StorePlugin): + aff_id = {'tag': 'calcharles-21'} + store_link = ('http://www.amazon.co.uk/gp/redirect.html?ie=UTF8&' + 'location=http://www.amazon.co.uk/Kindle-eBooks/b?' + 'ie=UTF8&node=341689031&ref_=sa_menu_kbo2&tag=%(tag)s&' + 'linkCode=ur2&camp=1634&creative=19450') + store_link_details = ('http://www.amazon.co.uk/gp/redirect.html?ie=UTF8&' + 'location=http://www.amazon.co.uk/dp/%(asin)s&tag=%(tag)s&' + 'linkCode=ur2&camp=1634&creative=6738') + search_url = 'http://www.amazon.co.uk/s/?url=search-alias%3Ddigital-text&field-keywords=' + ''' For comments on the implementation, please see amazon_plugin.py ''' def open(self, parent=None, detail_item=None, external=False): - aff_id = {'tag': 'calcharles-21'} - store_link = 'http://www.amazon.co.uk/gp/redirect.html?ie=UTF8&location=http://www.amazon.co.uk/Kindle-eBooks/b?ie=UTF8&node=341689031&ref_=sa_menu_kbo2&tag=%(tag)s&linkCode=ur2&camp=1634&creative=19450' % aff_id + store_link = self.store_link % self.aff_id if detail_item: - aff_id['asin'] = detail_item - store_link = 'http://www.amazon.co.uk/gp/redirect.html?ie=UTF8&location=http://www.amazon.co.uk/dp/%(asin)s&tag=%(tag)s&linkCode=ur2&camp=1634&creative=6738' % aff_id + self.aff_id['asin'] = detail_item + store_link = self.store_link_details % self.aff_id open_url(QUrl(store_link)) def search(self, query, max_results=10, timeout=60): - search_url = 'http://www.amazon.co.uk/s/?url=search-alias%3Ddigital-text&field-keywords=' - url = search_url + query.encode('ascii', 'backslashreplace').replace('%', '%25').replace('\\x', '%').replace(' ', '+') + url = self.search_url + query.encode('ascii', 'backslashreplace').replace('%', '%25').replace('\\x', '%').replace(' ', '+') br = browser() counter = max_results with closing(br.open(url, timeout=timeout)) as f: - # Apparently amazon Europe is responding in UTF-8 now - doc = html.fromstring(f.read()) + doc = html.fromstring(f.read())#.decode('latin-1', 'replace')) - data_xpath = '//div[contains(@class, "result") and contains(@class, "product")]' - format_xpath = './/span[@class="format"]/text()' + data_xpath = '//div[contains(@class, "prod")]' + format_xpath = './/ul[contains(@class, "rsltL")]//span[contains(@class, "lrg") and not(contains(@class, "bld"))]/text()' + asin_xpath = './/div[@class="image"]/a[1]' cover_xpath = './/img[@class="productImage"]/@src' + title_xpath = './/h3[@class="newaps"]/a//text()' + author_xpath = './/h3[@class="newaps"]//span[contains(@class, "reg")]/text()' + price_xpath = './/ul[contains(@class, "rsltL")]//span[contains(@class, "lrg") and contains(@class, "bld")]/text()' for data in doc.xpath(data_xpath): if counter <= 0: break # Even though we are searching digital-text only Amazon will still - # put in results for non Kindle books (author pages). So we need + # put in results for non Kindle books (author pages). Se we need # to explicitly check if the item is a Kindle book and ignore it # if it isn't. - format = ''.join(data.xpath(format_xpath)) - if 'kindle' not in format.lower(): + format_ = ''.join(data.xpath(format_xpath)) + if 'kindle' not in format_.lower(): continue # We must have an asin otherwise we can't easily reference the # book later. - asin = ''.join(data.xpath("@name")) + asin_href = None + asin_a = data.xpath(asin_xpath) + if asin_a: + asin_href = asin_a[0].get('href', '') + m = re.search(r'/dp/(?P.+?)(/|$)', asin_href) + if m: + asin = m.group('asin') + else: + continue + else: + continue cover_url = ''.join(data.xpath(cover_xpath)) - title = ''.join(data.xpath('.//a[@class="title"]/text()')) - price = ''.join(data.xpath('.//div[@class="newPrice"]/span[contains(@class, "price")]/text()')) + title = ''.join(data.xpath(title_xpath)) + author = ''.join(data.xpath(author_xpath)) + try: + author = author.split('by ', 1)[1].split(" (")[0] + except: + pass - author = ''.join(data.xpath('.//h3[@class="title"]/span[@class="ptBrand"]/text()')) - if author.startswith('by '): - author = author[3:] + price = ''.join(data.xpath(price_xpath)) counter -= 1 @@ -78,37 +102,10 @@ class AmazonUKKindleStore(StorePlugin): s.author = author.strip() s.price = price.strip() s.detail_item = asin.strip() + s.drm = SearchResult.DRM_UNKNOWN s.formats = 'Kindle' yield s def get_details(self, search_result, timeout): - # We might already have been called. - if search_result.drm: - return - - url = 'http://amazon.co.uk/dp/' - drm_search_text = u'Simultaneous Device Usage' - drm_free_text = u'Unlimited' - - br = browser() - with closing(br.open(url + search_result.detail_item, timeout=timeout)) as nf: - idata = html.fromstring(nf.read()) - if not search_result.author: - search_result.author = ''.join(idata.xpath('//div[@class="buying" and contains(., "Author")]/a/text()')) - is_kindle = idata.xpath('boolean(//div[@class="buying"]/h1/span/span[contains(text(), "Kindle Edition")])') - if is_kindle: - search_result.formats = 'Kindle' - if idata.xpath('boolean(//div[@class="content"]//li/b[contains(text(), "' + - drm_search_text + '")])'): - if idata.xpath('boolean(//div[@class="content"]//li[contains(., "' + - drm_free_text + '") and contains(b, "' + - drm_search_text + '")])'): - search_result.drm = SearchResult.DRM_UNLOCKED - else: - search_result.drm = SearchResult.DRM_UNKNOWN - else: - search_result.drm = SearchResult.DRM_LOCKED - return True - - + pass diff --git a/src/calibre/gui2/store/stores/libri_de_plugin.py b/src/calibre/gui2/store/stores/libri_de_plugin.py index 643cac3d99..a87928da78 100644 --- a/src/calibre/gui2/store/stores/libri_de_plugin.py +++ b/src/calibre/gui2/store/stores/libri_de_plugin.py @@ -25,7 +25,7 @@ class LibreDEStore(BasicStoreConfig, StorePlugin): def open(self, parent=None, detail_item=None, external=False): url = 'http://ad.zanox.com/ppc/?18817073C15644254T' url_details = ('http://ad.zanox.com/ppc/?18817073C15644254T&ULP=[[' - 'http://www.libri.de/shop/action/productDetails?artiId={0}]]') + 'http://www.ebook.de/shop/action/productDetails?artiId={0}]]') if external or self.config.get('open_external', False): if detail_item: @@ -41,33 +41,38 @@ class LibreDEStore(BasicStoreConfig, StorePlugin): d.exec_() def search(self, query, max_results=10, timeout=60): - url = ('http://www.libri.de/shop/action/quickSearch?facetNodeId=6' - '&mainsearchSubmit=Los!&searchString=' + urllib2.quote(query)) + url = ('http://www.ebook.de/de/pathSearch?nav=52122&searchString=' + + urllib2.quote(query)) br = browser() counter = max_results with closing(br.open(url, timeout=timeout)) as f: doc = html.fromstring(f.read()) - for data in doc.xpath('//div[contains(@class, "item")]'): + for data in doc.xpath('//div[contains(@class, "articlecontainer")]'): if counter <= 0: break - details = data.xpath('./div[@class="beschreibungContainer"]') + details = data.xpath('./div[@class="articleinfobox"]') if not details: continue details = details[0] - id = ''.join(details.xpath('./div[@class="text"]/a/@name')).strip() - if not id: + id_ = ''.join(details.xpath('./a/@name')).strip() + if not id_: continue - cover_url = ''.join(details.xpath('.//div[@class="coverImg"]/a/img/@src')) - title = ''.join(details.xpath('./div[@class="text"]/span[@class="titel"]/a/text()')).strip() - author = ''.join(details.xpath('./div[@class="text"]/span[@class="author"]/text()')).strip() + title = ''.join(details.xpath('.//a[@class="su1_c_l_titel"]/text()')).strip() + + author = ''.join(details.xpath('.//div[@class="author"]/text()')).strip() + if author.startswith('von'): + author = author[4:] + pdf = details.xpath( - 'boolean(.//span[@class="format" and contains(text(), "pdf")]/text())') + 'boolean(.//span[@class="bindername" and contains(text(), "pdf")]/text())') epub = details.xpath( - 'boolean(.//span[@class="format" and contains(text(), "epub")]/text())') + 'boolean(.//span[@class="bindername" and contains(text(), "epub")]/text())') mobi = details.xpath( - 'boolean(.//span[@class="format" and contains(text(), "mobipocket")]/text())') + 'boolean(.//span[@class="bindername" and contains(text(), "mobipocket")]/text())') + + cover_url = ''.join(data.xpath('.//div[@class="coverImg"]/a/img/@src')) price = ''.join(data.xpath('.//span[@class="preis"]/text()')).replace('*', '').strip() counter -= 1 @@ -78,7 +83,7 @@ class LibreDEStore(BasicStoreConfig, StorePlugin): s.author = author.strip() s.price = price s.drm = SearchResult.DRM_UNKNOWN - s.detail_item = id + s.detail_item = id_ formats = [] if epub: formats.append('ePub') From 33ea83d118334cb7ee04c93449e6dde2ae214d5f Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Tue, 6 Nov 2012 16:56:20 +0100 Subject: [PATCH 099/107] Fix save_to_disk not handling identifiers correctly. Kovid fixed the other part of this bug. --- src/calibre/library/save_to_disk.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/calibre/library/save_to_disk.py b/src/calibre/library/save_to_disk.py index d7ef189d7f..550ac3251e 100644 --- a/src/calibre/library/save_to_disk.py +++ b/src/calibre/library/save_to_disk.py @@ -200,6 +200,11 @@ def get_components(template, mi, id, timefmt='%b %Y', length=250, template = re.sub(r'\{series_index[^}]*?\}', '', template) if mi.rating is not None: format_args['rating'] = mi.format_rating(divide_by=2.0) + if mi.identifiers: + format_args['identifiers'] = mi.format_field_extended('identifiers')[1] + else: + format_args['identifiers'] = '' + if hasattr(mi.timestamp, 'timetuple'): format_args['timestamp'] = strftime(timefmt, mi.timestamp.timetuple()) if hasattr(mi.pubdate, 'timetuple'): From 88a0bb48e7da1c1291b15dbb203a37ec8a1ad700 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 6 Nov 2012 21:47:23 +0530 Subject: [PATCH 100/107] Start work on subsetting CFF tables --- src/calibre/utils/fonts/sfnt/cff.py | 153 ++++++++++++++ src/calibre/utils/fonts/sfnt/cff/__init__.py | 11 + src/calibre/utils/fonts/sfnt/cff/dict_data.py | 200 ++++++++++++++++++ src/calibre/utils/fonts/sfnt/cff/table.py | 159 ++++++++++++++ src/calibre/utils/fonts/sfnt/container.py | 2 + src/calibre/utils/fonts/sfnt/subset.py | 11 +- 6 files changed, 535 insertions(+), 1 deletion(-) create mode 100644 src/calibre/utils/fonts/sfnt/cff.py create mode 100644 src/calibre/utils/fonts/sfnt/cff/__init__.py create mode 100644 src/calibre/utils/fonts/sfnt/cff/dict_data.py create mode 100644 src/calibre/utils/fonts/sfnt/cff/table.py diff --git a/src/calibre/utils/fonts/sfnt/cff.py b/src/calibre/utils/fonts/sfnt/cff.py new file mode 100644 index 0000000000..641fa17d97 --- /dev/null +++ b/src/calibre/utils/fonts/sfnt/cff.py @@ -0,0 +1,153 @@ +#!/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 ' +__docformat__ = 'restructuredtext en' + +from struct import unpack_from, unpack + +from calibre.utils.fonts.sfnt import UnknownTable +from calibre.utils.fonts.sfnt.errors import UnsupportedFont + +# Useful links +# http://www.adobe.com/content/dam/Adobe/en/devnet/font/pdfs/5176.CFF.pdf +# http://www.adobe.com/content/dam/Adobe/en/devnet/font/pdfs/5177.Type2.pdf + +class CFF(object): + + def __init__(self, raw): + (self.major_version, self.minor_version, self.header_size, + self.offset_size) = unpack_from(b'>4B', raw) + if (self.major_version, self.minor_version) != (1, 0): + raise UnsupportedFont('The CFF table has unknown version: ' + '(%d, %d)'%(self.major_version, self.minor_version)) + offset = self.header_size + + # Read Names Index + self.font_names = Index(raw, offset) + offset = self.font_names.pos + if len(self.font_names) > 1: + raise UnsupportedFont('CFF table has more than one font.') + # Read Top Dict + self.top_index = Index(raw, offset) + offset = self.top_index.pos + + # Read strings + self.strings = Strings(raw, offset) + offset = self.strings.pos + print (self.strings[len(cff_standard_strings):]) + +class Index(list): + + def __init__(self, raw, offset): + list.__init__(self) + + count = unpack_from(b'>H', raw, offset)[0] + offset += 2 + self.pos = offset + + if count > 0: + self.offset_size = unpack_from(b'>B', raw, offset)[0] + offset += 1 + if self.offset_size == 3: + offsets = [unpack(b'>L', b'\0' + raw[i:i+3])[0] + for i in xrange(offset, 3*(count+2), 3)] + else: + fmt = {1:'B', 2:'H', 4:'L'}.get(self.offset_size) + fmt = ('>%d%s'%(count+1, fmt)).encode('ascii') + offsets = unpack_from(fmt, raw, offset) + offset += self.offset_size * (count+1) - 1 + + for i in xrange(len(offsets)-1): + off, noff = offsets[i:i+2] + obj = raw[offset+i:offset+noff] + self.append(obj) + + self.pos = offset + offsets[-1] + +class Strings(Index): + + def __init__(self, raw, offset): + super(Strings, self).__init__(raw, offset) + for x in reversed(cff_standard_strings): + self.insert(0, x) + +class CFFTable(UnknownTable): + + def decompile(self): + self.cff = CFF(self.raw) + +# cff_standard_strings {{{ +# The 391 Standard Strings as used in the CFF format. +# from Adobe Technical None #5176, version 1.0, 18 March 1998 + +cff_standard_strings = [ +'.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', +'ampersand', 'quoteright', 'parenleft', 'parenright', 'asterisk', 'plus', +'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four', +'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal', +'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', +'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', +'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore', +'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', +'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', +'bar', 'braceright', 'asciitilde', 'exclamdown', 'cent', 'sterling', +'fraction', 'yen', 'florin', 'section', 'currency', 'quotesingle', +'quotedblleft', 'guillemotleft', 'guilsinglleft', 'guilsinglright', 'fi', 'fl', +'endash', 'dagger', 'daggerdbl', 'periodcentered', 'paragraph', 'bullet', +'quotesinglbase', 'quotedblbase', 'quotedblright', 'guillemotright', +'ellipsis', 'perthousand', 'questiondown', 'grave', 'acute', 'circumflex', +'tilde', 'macron', 'breve', 'dotaccent', 'dieresis', 'ring', 'cedilla', +'hungarumlaut', 'ogonek', 'caron', 'emdash', 'AE', 'ordfeminine', 'Lslash', +'Oslash', 'OE', 'ordmasculine', 'ae', 'dotlessi', 'lslash', 'oslash', 'oe', +'germandbls', 'onesuperior', 'logicalnot', 'mu', 'trademark', 'Eth', 'onehalf', +'plusminus', 'Thorn', 'onequarter', 'divide', 'brokenbar', 'degree', 'thorn', +'threequarters', 'twosuperior', 'registered', 'minus', 'eth', 'multiply', +'threesuperior', 'copyright', 'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', +'Aring', 'Atilde', 'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave', +'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute', +'Ocircumflex', 'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute', +'Ucircumflex', 'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron', +'aacute', 'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde', 'ccedilla', +'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute', 'icircumflex', +'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex', 'odieresis', +'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex', 'udieresis', 'ugrave', +'yacute', 'ydieresis', 'zcaron', 'exclamsmall', 'Hungarumlautsmall', +'dollaroldstyle', 'dollarsuperior', 'ampersandsmall', 'Acutesmall', +'parenleftsuperior', 'parenrightsuperior', 'twodotenleader', 'onedotenleader', +'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle', +'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', +'nineoldstyle', 'commasuperior', 'threequartersemdash', 'periodsuperior', +'questionsmall', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior', +'esuperior', 'isuperior', 'lsuperior', 'msuperior', 'nsuperior', 'osuperior', +'rsuperior', 'ssuperior', 'tsuperior', 'ff', 'ffi', 'ffl', 'parenleftinferior', +'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall', +'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', +'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall', +'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall', 'Xsmall', +'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah', 'Tildesmall', +'exclamdownsmall', 'centoldstyle', 'Lslashsmall', 'Scaronsmall', 'Zcaronsmall', +'Dieresissmall', 'Brevesmall', 'Caronsmall', 'Dotaccentsmall', 'Macronsmall', +'figuredash', 'hypheninferior', 'Ogoneksmall', 'Ringsmall', 'Cedillasmall', +'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths', +'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'foursuperior', +'fivesuperior', 'sixsuperior', 'sevensuperior', 'eightsuperior', +'ninesuperior', 'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior', +'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior', +'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior', +'periodinferior', 'commainferior', 'Agravesmall', 'Aacutesmall', +'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall', 'AEsmall', +'Ccedillasmall', 'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall', +'Edieresissmall', 'Igravesmall', 'Iacutesmall', 'Icircumflexsmall', +'Idieresissmall', 'Ethsmall', 'Ntildesmall', 'Ogravesmall', 'Oacutesmall', +'Ocircumflexsmall', 'Otildesmall', 'Odieresissmall', 'OEsmall', 'Oslashsmall', +'Ugravesmall', 'Uacutesmall', 'Ucircumflexsmall', 'Udieresissmall', +'Yacutesmall', 'Thornsmall', 'Ydieresissmall', '001.000', '001.001', '001.002', +'001.003', 'Black', 'Bold', 'Book', 'Light', 'Medium', 'Regular', 'Roman', +'Semibold' +] +# }}} + diff --git a/src/calibre/utils/fonts/sfnt/cff/__init__.py b/src/calibre/utils/fonts/sfnt/cff/__init__.py new file mode 100644 index 0000000000..743a9d0561 --- /dev/null +++ b/src/calibre/utils/fonts/sfnt/cff/__init__.py @@ -0,0 +1,11 @@ +#!/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 ' +__docformat__ = 'restructuredtext en' + + + diff --git a/src/calibre/utils/fonts/sfnt/cff/dict_data.py b/src/calibre/utils/fonts/sfnt/cff/dict_data.py new file mode 100644 index 0000000000..df573bb26c --- /dev/null +++ b/src/calibre/utils/fonts/sfnt/cff/dict_data.py @@ -0,0 +1,200 @@ +#!/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 ' +__docformat__ = 'restructuredtext en' + +from struct import unpack + +t1_operand_encoding = [None] * 256 +t1_operand_encoding[0:32] = (32) * ["do_operator"] +t1_operand_encoding[32:247] = (247 - 32) * ["read_byte"] +t1_operand_encoding[247:251] = (251 - 247) * ["read_small_int1"] +t1_operand_encoding[251:255] = (255 - 251) * ["read_small_int2"] +t1_operand_encoding[255] = "read_long_int" + +t2_operand_encoding = t1_operand_encoding[:] +t2_operand_encoding[28] = "read_short_int" +t2_operand_encoding[255] = "read_fixed_1616" + +cff_dict_operand_encoding = t2_operand_encoding[:] +cff_dict_operand_encoding[29] = "read_long_int" +cff_dict_operand_encoding[30] = "read_real_number" +cff_dict_operand_encoding[255] = "reserved" + +real_nibbles = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '.', 'E', 'E-', None, '-'] + +class SimpleConverter(object): + + def read(self, parent, value): + return value + + def write(self, parent, value): + return value + +class TODO(SimpleConverter): + pass + +class Reader(dict): + + def read_byte(self, b0, data, index): + return b0 - 139, index + + def read_small_int1(self, b0, data, index): + b1 = ord(data[index]) + return (b0-247)*256 + b1 + 108, index+1 + + def read_small_int2(self, b0, data, index): + b1 = ord(data[index]) + return -(b0-251)*256 - b1 - 108, index+1 + + def read_short_int(self, b0, data, index): + bin = data[index] + data[index+1] + value, = unpack(b">h", bin) + return value, index+2 + + def read_long_int(self, b0, data, index): + bin = data[index] + data[index+1] + data[index+2] + data[index+3] + value, = unpack(b">l", bin) + return value, index+4 + + def read_fixed_1616(self, b0, data, index): + bin = data[index] + data[index+1] + data[index+2] + data[index+3] + value, = unpack(b">l", bin) + return value / 65536.0, index+4 + + def read_real_number(self, b0, data, index): + number = '' + while True: + b = ord(data[index]) + index = index + 1 + nibble0 = (b & 0xf0) >> 4 + nibble1 = b & 0x0f + if nibble0 == 0xf: + break + number = number + real_nibbles[nibble0] + if nibble1 == 0xf: + break + number = number + real_nibbles[nibble1] + return float(number), index + +class Dict(Reader): + + operand_encoding = cff_dict_operand_encoding + TABLE = [] + + def __init__(self): + Reader.__init__(self) + table = self.TABLE[:] + for i in xrange(len(table)): + op, name, arg, default, conv = table[i] + if conv is not None: + continue + if arg in ("delta", "array", 'number', 'SID'): + conv = SimpleConverter() + else: + raise Exception('Should not happen') + table[i] = op, name, arg, default, conv + + + self.operators = {op:(name, arg) for op, name, arg, default, conv in + table} + + def decompile(self, strings, data): + self.strings = strings + self.stack = [] + index = 0 + while index < len(data): + b0 = ord(data[index]) + index += 1 + handler = getattr(self, self.operand_encoding[b0]) + value, index = handler(b0, data, index) + if value is not None: + self.stack.append(value) + + def do_operator(self, b0, data, index): + if b0 == 12: + op = (b0, ord(data[index])) + index += 1 + else: + op = b0 + operator, arg_type = self.operators[op] + self.handle_operator(operator, arg_type) + return None, index + + def handle_operator(self, operator, arg_type): + if isinstance(arg_type, tuple): + value = () + for i in xrange(len(arg_type)-1, -1, -1): + arg = arg_type[i] + arghandler = getattr(self, 'arg_' + arg) + value = (arghandler(operator),) + value + else: + arghandler = getattr(self, 'arg_' + arg_type) + value = arghandler(operator) + self[operator] = value + + def arg_number(self, name): + return self.stack.pop() + + def arg_SID(self, name): + return self.strings[self.stack.pop()] + + def arg_array(self, name): + ans = self.stack[:] + del self.stack[:] + return ans + + def arg_delta(self, name): + out = [] + current = 0 + for v in self.stack: + current = current + v + out.append(current) + del self.stack[:] + return out + +class TopDict(Dict): + + TABLE = [ + #opcode name argument type default converter + ((12, 30), 'ROS', ('SID','SID','number'), None, SimpleConverter()), + ((12, 20), 'SyntheticBase', 'number', None, None), + (0, 'version', 'SID', None, None), + (1, 'Notice', 'SID', None, None), + ((12, 0), 'Copyright', 'SID', None, None), + (2, 'FullName', 'SID', None, None), + ((12, 38), 'FontName', 'SID', None, None), + (3, 'FamilyName', 'SID', None, None), + (4, 'Weight', 'SID', None, None), + ((12, 1), 'isFixedPitch', 'number', 0, None), + ((12, 2), 'ItalicAngle', 'number', 0, None), + ((12, 3), 'UnderlinePosition', 'number', None, None), + ((12, 4), 'UnderlineThickness', 'number', 50, None), + ((12, 5), 'PaintType', 'number', 0, None), + ((12, 6), 'CharstringType', 'number', 2, None), + ((12, 7), 'FontMatrix', 'array', [0.001,0,0,0.001,0,0], None), + (13, 'UniqueID', 'number', None, None), + (5, 'FontBBox', 'array', [0,0,0,0], None), + ((12, 8), 'StrokeWidth', 'number', 0, None), + (14, 'XUID', 'array', None, None), + ((12, 21), 'PostScript', 'SID', None, None), + ((12, 22), 'BaseFontName', 'SID', None, None), + ((12, 23), 'BaseFontBlend', 'delta', None, None), + ((12, 31), 'CIDFontVersion', 'number', 0, None), + ((12, 32), 'CIDFontRevision', 'number', 0, None), + ((12, 33), 'CIDFontType', 'number', 0, None), + ((12, 34), 'CIDCount', 'number', 8720, None), + (15, 'charset', 'number', 0, TODO()), + ((12, 35), 'UIDBase', 'number', None, None), + (16, 'Encoding', 'number', 0, TODO()), + (18, 'Private', ('number','number'), None, TODO()), + ((12, 37), 'FDSelect', 'number', None, TODO()), + ((12, 36), 'FDArray', 'number', None, TODO()), + (17, 'CharStrings', 'number', None, TODO()), + ] + diff --git a/src/calibre/utils/fonts/sfnt/cff/table.py b/src/calibre/utils/fonts/sfnt/cff/table.py new file mode 100644 index 0000000000..af76d1f254 --- /dev/null +++ b/src/calibre/utils/fonts/sfnt/cff/table.py @@ -0,0 +1,159 @@ +#!/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 ' +__docformat__ = 'restructuredtext en' + +from struct import unpack_from, unpack + +from calibre.utils.fonts.sfnt import UnknownTable +from calibre.utils.fonts.sfnt.errors import UnsupportedFont +from calibre.utils.fonts.sfnt.cff.dict_data import TopDict + +# Useful links +# http://www.adobe.com/content/dam/Adobe/en/devnet/font/pdfs/5176.CFF.pdf +# http://www.adobe.com/content/dam/Adobe/en/devnet/font/pdfs/5177.Type2.pdf + +class CFF(object): + + def __init__(self, raw): + (self.major_version, self.minor_version, self.header_size, + self.offset_size) = unpack_from(b'>4B', raw) + if (self.major_version, self.minor_version) != (1, 0): + raise UnsupportedFont('The CFF table has unknown version: ' + '(%d, %d)'%(self.major_version, self.minor_version)) + offset = self.header_size + + # Read Names Index + self.font_names = Index(raw, offset) + offset = self.font_names.pos + if len(self.font_names) > 1: + raise UnsupportedFont('CFF table has more than one font.') + + # Read Top Dict + self.top_index = Index(raw, offset) + self.top_dict = TopDict() + offset = self.top_index.pos + + # Read strings + self.strings = Strings(raw, offset) + offset = self.strings.pos + + # Decompile Top Dict + self.top_dict.decompile(self.strings, self.top_index[0]) + import pprint + pprint.pprint(self.top_dict) + +class Index(list): + + def __init__(self, raw, offset, prepend=()): + list.__init__(self) + self.extend(prepend) + + count = unpack_from(b'>H', raw, offset)[0] + offset += 2 + self.pos = offset + + if count > 0: + self.offset_size = unpack_from(b'>B', raw, offset)[0] + offset += 1 + if self.offset_size == 3: + offsets = [unpack(b'>L', b'\0' + raw[i:i+3])[0] + for i in xrange(offset, 3*(count+2), 3)] + else: + fmt = {1:'B', 2:'H', 4:'L'}.get(self.offset_size) + fmt = ('>%d%s'%(count+1, fmt)).encode('ascii') + offsets = unpack_from(fmt, raw, offset) + offset += self.offset_size * (count+1) - 1 + + for i in xrange(len(offsets)-1): + off, noff = offsets[i:i+2] + obj = raw[offset+off:offset+noff] + self.append(obj) + + self.pos = offset + offsets[-1] + +class Strings(Index): + + def __init__(self, raw, offset): + super(Strings, self).__init__(raw, offset, prepend=cff_standard_strings) + +class CFFTable(UnknownTable): + + def decompile(self): + self.cff = CFF(self.raw) + +# cff_standard_strings {{{ +# The 391 Standard Strings as used in the CFF format. +# from Adobe Technical None #5176, version 1.0, 18 March 1998 + +cff_standard_strings = [ +'.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', +'ampersand', 'quoteright', 'parenleft', 'parenright', 'asterisk', 'plus', +'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four', +'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal', +'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', +'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', +'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore', +'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', +'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', +'bar', 'braceright', 'asciitilde', 'exclamdown', 'cent', 'sterling', +'fraction', 'yen', 'florin', 'section', 'currency', 'quotesingle', +'quotedblleft', 'guillemotleft', 'guilsinglleft', 'guilsinglright', 'fi', 'fl', +'endash', 'dagger', 'daggerdbl', 'periodcentered', 'paragraph', 'bullet', +'quotesinglbase', 'quotedblbase', 'quotedblright', 'guillemotright', +'ellipsis', 'perthousand', 'questiondown', 'grave', 'acute', 'circumflex', +'tilde', 'macron', 'breve', 'dotaccent', 'dieresis', 'ring', 'cedilla', +'hungarumlaut', 'ogonek', 'caron', 'emdash', 'AE', 'ordfeminine', 'Lslash', +'Oslash', 'OE', 'ordmasculine', 'ae', 'dotlessi', 'lslash', 'oslash', 'oe', +'germandbls', 'onesuperior', 'logicalnot', 'mu', 'trademark', 'Eth', 'onehalf', +'plusminus', 'Thorn', 'onequarter', 'divide', 'brokenbar', 'degree', 'thorn', +'threequarters', 'twosuperior', 'registered', 'minus', 'eth', 'multiply', +'threesuperior', 'copyright', 'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', +'Aring', 'Atilde', 'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave', +'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute', +'Ocircumflex', 'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute', +'Ucircumflex', 'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron', +'aacute', 'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde', 'ccedilla', +'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute', 'icircumflex', +'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex', 'odieresis', +'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex', 'udieresis', 'ugrave', +'yacute', 'ydieresis', 'zcaron', 'exclamsmall', 'Hungarumlautsmall', +'dollaroldstyle', 'dollarsuperior', 'ampersandsmall', 'Acutesmall', +'parenleftsuperior', 'parenrightsuperior', 'twodotenleader', 'onedotenleader', +'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle', +'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', +'nineoldstyle', 'commasuperior', 'threequartersemdash', 'periodsuperior', +'questionsmall', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior', +'esuperior', 'isuperior', 'lsuperior', 'msuperior', 'nsuperior', 'osuperior', +'rsuperior', 'ssuperior', 'tsuperior', 'ff', 'ffi', 'ffl', 'parenleftinferior', +'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall', +'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', +'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall', +'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall', 'Xsmall', +'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah', 'Tildesmall', +'exclamdownsmall', 'centoldstyle', 'Lslashsmall', 'Scaronsmall', 'Zcaronsmall', +'Dieresissmall', 'Brevesmall', 'Caronsmall', 'Dotaccentsmall', 'Macronsmall', +'figuredash', 'hypheninferior', 'Ogoneksmall', 'Ringsmall', 'Cedillasmall', +'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths', +'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'foursuperior', +'fivesuperior', 'sixsuperior', 'sevensuperior', 'eightsuperior', +'ninesuperior', 'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior', +'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior', +'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior', +'periodinferior', 'commainferior', 'Agravesmall', 'Aacutesmall', +'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall', 'AEsmall', +'Ccedillasmall', 'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall', +'Edieresissmall', 'Igravesmall', 'Iacutesmall', 'Icircumflexsmall', +'Idieresissmall', 'Ethsmall', 'Ntildesmall', 'Ogravesmall', 'Oacutesmall', +'Ocircumflexsmall', 'Otildesmall', 'Odieresissmall', 'OEsmall', 'Oslashsmall', +'Ugravesmall', 'Uacutesmall', 'Ucircumflexsmall', 'Udieresissmall', +'Yacutesmall', 'Thornsmall', 'Ydieresissmall', '001.000', '001.001', '001.002', +'001.003', 'Black', 'Bold', 'Book', 'Light', 'Medium', 'Regular', 'Roman', +'Semibold' +] +# }}} + diff --git a/src/calibre/utils/fonts/sfnt/container.py b/src/calibre/utils/fonts/sfnt/container.py index 2e08ef3cee..a6c0c5c81d 100644 --- a/src/calibre/utils/fonts/sfnt/container.py +++ b/src/calibre/utils/fonts/sfnt/container.py @@ -21,6 +21,7 @@ from calibre.utils.fonts.sfnt.maxp import MaxpTable from calibre.utils.fonts.sfnt.loca import LocaTable from calibre.utils.fonts.sfnt.glyf import GlyfTable from calibre.utils.fonts.sfnt.cmap import CmapTable +from calibre.utils.fonts.sfnt.cff.table import CFFTable # OpenType spec: http://www.microsoft.com/typography/otspec/otff.htm @@ -42,6 +43,7 @@ class Sfnt(object): b'loca' : LocaTable, b'glyf' : GlyfTable, b'cmap' : CmapTable, + b'CFF ' : CFFTable, }.get(table_tag, UnknownTable)(table) def __getitem__(self, key): diff --git a/src/calibre/utils/fonts/sfnt/subset.py b/src/calibre/utils/fonts/sfnt/subset.py index e3883c180d..c7e3ec8c34 100644 --- a/src/calibre/utils/fonts/sfnt/subset.py +++ b/src/calibre/utils/fonts/sfnt/subset.py @@ -66,6 +66,11 @@ def subset_truetype(sfnt, character_map): # }}} +def subset_postscript(sfnt, character_map): + cff = sfnt[b'CFF '] + cff.decompile() + raise Exception('TODO: Implement CFF subsetting') + def subset(raw, individual_chars, ranges=()): chars = list(map(ord, individual_chars)) for r in ranges: @@ -91,7 +96,11 @@ def subset(raw, individual_chars, ranges=()): subset_truetype(sfnt, character_map) elif b'CFF ' in sfnt: # PostScript Outlines - raise UnsupportedFont('This font contains PostScript outlines, ' + from calibre.utils.config_base import tweaks + if tweaks['subset_cff_table']: + subset_postscript(sfnt, character_map) + else: + raise UnsupportedFont('This font contains PostScript outlines, ' 'subsetting not supported') else: raise UnsupportedFont('This font does not contain TrueType ' From 985c9c857f20606fd07aaca627b4110cec04f0cd Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 7 Nov 2012 09:13:41 +0530 Subject: [PATCH 101/107] ... --- src/calibre/utils/fonts/sfnt/cff/dict_data.py | 3 ++- src/calibre/utils/fonts/sfnt/cff/table.py | 9 ++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/calibre/utils/fonts/sfnt/cff/dict_data.py b/src/calibre/utils/fonts/sfnt/cff/dict_data.py index df573bb26c..2238a514a3 100644 --- a/src/calibre/utils/fonts/sfnt/cff/dict_data.py +++ b/src/calibre/utils/fonts/sfnt/cff/dict_data.py @@ -104,8 +104,9 @@ class Dict(Reader): self.operators = {op:(name, arg) for op, name, arg, default, conv in table} - def decompile(self, strings, data): + def decompile(self, strings, global_subrs, data): self.strings = strings + self.global_subrs = global_subrs self.stack = [] index = 0 while index < len(data): diff --git a/src/calibre/utils/fonts/sfnt/cff/table.py b/src/calibre/utils/fonts/sfnt/cff/table.py index af76d1f254..47dc891346 100644 --- a/src/calibre/utils/fonts/sfnt/cff/table.py +++ b/src/calibre/utils/fonts/sfnt/cff/table.py @@ -42,8 +42,12 @@ class CFF(object): self.strings = Strings(raw, offset) offset = self.strings.pos + # Read global subroutines + self.global_subrs = GlobalSubrs(raw, offset) + offset = self.global_subrs.pos + # Decompile Top Dict - self.top_dict.decompile(self.strings, self.top_index[0]) + self.top_dict.decompile(self.strings, self.global_subrs, self.top_index[0]) import pprint pprint.pprint(self.top_dict) @@ -81,6 +85,9 @@ class Strings(Index): def __init__(self, raw, offset): super(Strings, self).__init__(raw, offset, prepend=cff_standard_strings) +class GlobalSubrs(Index): + pass + class CFFTable(UnknownTable): def decompile(self): From 0b25ffee6c2c11536ec2d0170ab9d811f22cabe8 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 7 Nov 2012 11:00:21 +0530 Subject: [PATCH 102/107] Windows: Fix a long standing bug in the device eject code that for some reason only manifested in 0.9.5. Fixes #1075782 (Device | Eject not ejecting device) --- src/calibre/devices/usbms/device.py | 7 +++++-- src/calibre/utils/windows/winutil.c | 16 +++++++++++----- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/calibre/devices/usbms/device.py b/src/calibre/devices/usbms/device.py index 49d766c67f..598522799c 100644 --- a/src/calibre/devices/usbms/device.py +++ b/src/calibre/devices/usbms/device.py @@ -901,8 +901,11 @@ class Device(DeviceConfig, DevicePlugin): for d in drives: try: winutil.eject_drive(bytes(d)[0]) - except: - pass + except Exception as e: + try: + prints(as_unicode(e)) + except: + pass t = Thread(target=do_it, args=[drives]) t.daemon = True diff --git a/src/calibre/utils/windows/winutil.c b/src/calibre/utils/windows/winutil.c index 53ebfcca89..bedf6e966e 100644 --- a/src/calibre/utils/windows/winutil.c +++ b/src/calibre/utils/windows/winutil.c @@ -467,11 +467,11 @@ eject_drive_letter(WCHAR DriveLetter) { DeviceNumber = -1; - hVolume = CreateFile(szVolumeAccessPath, 0, + hVolume = CreateFileW(szVolumeAccessPath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (hVolume == INVALID_HANDLE_VALUE) { - PyErr_SetString(PyExc_ValueError, "Invalid handle value for drive letter"); + PyErr_SetFromWindowsErr(0); return FALSE; } @@ -529,11 +529,17 @@ eject_drive_letter(WCHAR DriveLetter) { static PyObject * winutil_eject_drive(PyObject *self, PyObject *args) { - char DriveLetter; + char letter = '0'; + WCHAR DriveLetter = L'0'; - if (!PyArg_ParseTuple(args, "c", &DriveLetter)) return NULL; + if (!PyArg_ParseTuple(args, "c", &letter)) return NULL; - if (!eject_drive_letter((WCHAR)DriveLetter)) return NULL; + if (mbtowc(&DriveLetter, &letter, 1) == -1) { + PyErr_SetString(PyExc_ValueError, "Failed to convert drive letter to wchar"); + return NULL; + } + + if (!eject_drive_letter(DriveLetter)) return NULL; Py_RETURN_NONE; } From 1bc9ce513d10d0496a755e52e193e29b1eec2f42 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 7 Nov 2012 12:24:16 +0530 Subject: [PATCH 103/107] ... --- manual/faq.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/manual/faq.rst b/manual/faq.rst index 8163861863..b434927c04 100644 --- a/manual/faq.rst +++ b/manual/faq.rst @@ -327,9 +327,8 @@ You can browse your |app| collection on your Android device is by using the calibre content server, which makes your collection available over the net. First perform the following steps in |app| - * Set the :guilabel:`Preferred Output Format` in |app| to EPUB (The output format can be set under :guilabel:`Preferences->Interface->Behavior`) - * Set the output profile to Tablet (this will work for phones as well), under :guilabel:`Preferences->Conversion->Common Options->Page Setup` - * Convert the books you want to read on your device to EPUB format by selecting them and clicking the Convert button. + * Set the :guilabel:`Preferred Output Format` in |app| to EPUB for normal Android devices or MOBI for Kindles (The output format can be set under :guilabel:`Preferences->Interface->Behavior`) + * Convert the books you want to read on your device to EPUB/MOBI format by selecting them and clicking the Convert button. * Turn on the Content Server in |app|'s preferences and leave |app| running. Now on your Android device, open the browser and browse to From f39768680461066692703f385fdee58539f20c1e Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 7 Nov 2012 12:59:26 +0530 Subject: [PATCH 104/107] Do not use a local dependent mb->wc conversion --- src/calibre/utils/windows/winutil.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/calibre/utils/windows/winutil.c b/src/calibre/utils/windows/winutil.c index bedf6e966e..f0bb6b6f77 100644 --- a/src/calibre/utils/windows/winutil.c +++ b/src/calibre/utils/windows/winutil.c @@ -534,8 +534,8 @@ winutil_eject_drive(PyObject *self, PyObject *args) { if (!PyArg_ParseTuple(args, "c", &letter)) return NULL; - if (mbtowc(&DriveLetter, &letter, 1) == -1) { - PyErr_SetString(PyExc_ValueError, "Failed to convert drive letter to wchar"); + if (MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, &letter, 1, &DriveLetter, 1) == 0) { + PyErr_SetFromWindowsErr(0); return NULL; } From 9f570abd9b039dffe043904a7c6bbd710f398c6c Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 7 Nov 2012 17:23:03 +0530 Subject: [PATCH 105/107] EPUB Input: Try to workaround EPUBs that have missing or damaged ZIP central directories. calibre should now be able to read/convert such an EPUB file, provided it does not suffer from further corruption. --- .../ebooks/conversion/plugins/epub_input.py | 11 +- src/calibre/ebooks/metadata/epub.py | 39 ++- src/calibre/utils/localunzip.py | 267 ++++++++++++++++++ 3 files changed, 307 insertions(+), 10 deletions(-) create mode 100644 src/calibre/utils/localunzip.py diff --git a/src/calibre/ebooks/conversion/plugins/epub_input.py b/src/calibre/ebooks/conversion/plugins/epub_input.py index f0af2d28c5..70a561226d 100644 --- a/src/calibre/ebooks/conversion/plugins/epub_input.py +++ b/src/calibre/ebooks/conversion/plugins/epub_input.py @@ -150,8 +150,15 @@ class EPUBInput(InputFormatPlugin): from calibre import walk from calibre.ebooks import DRMError from calibre.ebooks.metadata.opf2 import OPF - zf = ZipFile(stream) - zf.extractall(os.getcwdu()) + try: + zf = ZipFile(stream) + zf.extractall(os.getcwdu()) + except: + log.exception('EPUB appears to be invalid ZIP file, trying a' + ' more forgiving ZIP parser') + from calibre.utils.localunzip import extractall + stream.seek(0) + extractall(stream) encfile = os.path.abspath(os.path.join('META-INF', 'encryption.xml')) opf = self.find_opf() if opf is None: diff --git a/src/calibre/ebooks/metadata/epub.py b/src/calibre/ebooks/metadata/epub.py index c62f265633..bc81df5a79 100644 --- a/src/calibre/ebooks/metadata/epub.py +++ b/src/calibre/ebooks/metadata/epub.py @@ -10,6 +10,7 @@ from cStringIO import StringIO from contextlib import closing from calibre.utils.zipfile import ZipFile, BadZipfile, safe_replace +from calibre.utils.localunzip import LocalZipFile from calibre.ebooks.BeautifulSoup import BeautifulStoneSoup from calibre.ebooks.metadata import MetaInformation from calibre.ebooks.metadata.opf2 import OPF @@ -105,10 +106,13 @@ class OCFReader(OCF): class OCFZipReader(OCFReader): def __init__(self, stream, mode='r', root=None): - try: - self.archive = ZipFile(stream, mode=mode) - except BadZipfile: - raise EPubException("not a ZIP .epub OCF container") + if isinstance(stream, (LocalZipFile, ZipFile)): + self.archive = stream + else: + try: + self.archive = ZipFile(stream, mode=mode) + except BadZipfile: + raise EPubException("not a ZIP .epub OCF container") self.root = root if self.root is None: name = getattr(stream, 'name', False) @@ -119,8 +123,18 @@ class OCFZipReader(OCFReader): super(OCFZipReader, self).__init__() def open(self, name, mode='r'): + if isinstance(self.archive, LocalZipFile): + return self.archive.open(name) return StringIO(self.archive.read(name)) +def get_zip_reader(stream, root=None): + try: + zf = ZipFile(stream, mode='r') + except: + stream.seek(0) + zf = LocalZipFile(stream) + return OCFZipReader(zf, root=root) + class OCFDirReader(OCFReader): def __init__(self, path): self.root = path @@ -184,7 +198,12 @@ def render_cover(opf, opf_path, zf, reader=None): def get_cover(opf, opf_path, stream, reader=None): raster_cover = opf.raster_cover stream.seek(0) - zf = ZipFile(stream) + try: + zf = ZipFile(stream) + except: + stream.seek(0) + zf = LocalZipFile(stream) + if raster_cover: base = posixpath.dirname(opf_path) cpath = posixpath.normpath(posixpath.join(base, raster_cover)) @@ -207,7 +226,7 @@ def get_cover(opf, opf_path, stream, reader=None): def get_metadata(stream, extract_cover=True): """ Return metadata as a :class:`Metadata` object """ stream.seek(0) - reader = OCFZipReader(stream) + reader = get_zip_reader(stream) mi = reader.opf.to_book_metadata() if extract_cover: try: @@ -232,7 +251,7 @@ def _write_new_cover(new_cdata, cpath): def set_metadata(stream, mi, apply_null=False, update_timestamp=False): stream.seek(0) - reader = OCFZipReader(stream, root=os.getcwdu()) + reader = get_zip_reader(stream, root=os.getcwdu()) raster_cover = reader.opf.raster_cover mi = MetaInformation(mi) new_cdata = None @@ -283,7 +302,11 @@ def set_metadata(stream, mi, apply_null=False, update_timestamp=False): reader.opf.timestamp = mi.timestamp newopf = StringIO(reader.opf.render()) - safe_replace(stream, reader.container[OPF.MIMETYPE], newopf, + if isinstance(reader.archive, LocalZipFile): + reader.archive.safe_replace(reader.container[OPF.MIMETYPE], newopf, + extra_replacements=replacements) + else: + safe_replace(stream, reader.container[OPF.MIMETYPE], newopf, extra_replacements=replacements) try: if cpath is not None: diff --git a/src/calibre/utils/localunzip.py b/src/calibre/utils/localunzip.py new file mode 100644 index 0000000000..48c51b7af6 --- /dev/null +++ b/src/calibre/utils/localunzip.py @@ -0,0 +1,267 @@ +#!/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 ' +__docformat__ = 'restructuredtext en' + +''' +Try to read invalid zip files with missing or damaged central directories. +These are apparently produced in large numbers by the fruitcakes over at B&N. + +Tries to only use the local headers to extract data from the damaged zip file. +''' + +import os, sys, zlib, shutil +from struct import calcsize, unpack, pack +from collections import namedtuple, OrderedDict +from tempfile import SpooledTemporaryFile + +HEADER_SIG = 0x04034b50 +HEADER_BYTE_SIG = pack(b' 20: + raise ValueError('This ZIP file uses unsupported features') + if header.flags & 0b1: + raise ValueError('This ZIP file is encrypted') + if header.flags & (1 << 3): + raise ValueError('This ZIP file uses data descriptors. This is unsupported') + if header.flags & (1 << 13): + raise ValueError('This ZIP file uses masking, unsupported.') + if header.compression_method not in {ZIP_STORED, ZIP_DEFLATED}: + raise ValueError('This ZIP file uses an unsupported compression method') + fname = extra = None + if header.filename_length > 0: + fname = f.read(header.filename_length) + if len(fname) != header.filename_length: + return + try: + fname = fname.decode('ascii') + except UnicodeDecodeError: + if header.flags & (1 << 11): + try: + fname = fname.decode('utf-8') + except UnicodeDecodeError: + pass + fname = decode_arcname(fname).replace('\\', '/') + if header.extra_length > 0: + extra = f.read(header.extra_length) + if len(extra) != header.extra_length: + return + return LocalHeader(*( + header[:-2] + (fname, extra) + )) + +def read_compressed_data(f, header): + cdata = f.read(header.compressed_size) + return cdata + +def copy_stored_file(src, size, dest): + read = 0 + amt = min(size, 20*1024) + while read < size: + raw = src.read(min(size-read, amt)) + if not raw: + raise ValueError('Premature end of file') + dest.write(raw) + read += len(raw) + +def copy_compressed_file(src, size, dest): + d = zlib.decompressobj(-15) + read = 0 + amt = min(size, 20*1024) + while read < size: + raw = src.read(min(size-read, amt)) + read += len(raw) + dest.write(d.decompress(raw, 200*1024)) + count = 0 + while d.unconsumed_tail: + count += 1 + dest.write(d.decompress(d.unconsumed_tail, 200*1024)) + + if count > 100: + raise ValueError('This ZIP file contains a ZIP bomb in %s'% + os.path.basename(dest.name)) + +def _extractall(f, path=None, file_info=None): + found = False + while True: + header = read_local_file_header(f) + if not header: + break + found = True + parts = header.filename.split('/') + if header.uncompressed_size == 0: + # Directory + f.seek(f.tell() + header.compressed_size) + if path is not None: + bdir = os.path.join(path, *parts) + if not os.path.exists(bdir): + os.makedirs(bdir) + continue + + # File + if file_info is not None: + file_info[header.filename] = (f.tell(), header) + if path is not None: + bdir = os.path.join(path, *(parts[:-1])) + if not os.path.exists(bdir): + os.makedirs(bdir) + dest = os.path.join(path, *parts) + with open(dest, 'wb') as o: + if header.compression_method == ZIP_STORED: + copy_stored_file(f, header.compressed_size, o) + else: + copy_compressed_file(f, header.compressed_size, o) + else: + f.seek(f.tell() + header.compressed_size) + + if not found: + raise ValueError('Not a ZIP file') + + +def extractall(path_or_stream, path=None): + f = path_or_stream + close_at_end = False + if not hasattr(f, 'read'): + f = open(f, 'rb') + close_at_end = True + if path is None: + path = os.getcwdu() + pos = f.tell() + try: + _extractall(f, path) + finally: + f.seek(pos) + if close_at_end: + f.close() + + +class LocalZipFile(object): + + def __init__(self, stream): + self.file_info = OrderedDict() + _extractall(stream, file_info=self.file_info) + self.stream = stream + + def open(self, name, spool_size=5*1024*1024): + if isinstance(name, LocalHeader): + name = name.filename + try: + offset, header = self.file_info.get(name) + except KeyError: + raise ValueError('This ZIP container has no file named: %s'%name) + + self.stream.seek(offset) + dest = SpooledTemporaryFile(max_size=spool_size) + + if header.compression_method == ZIP_STORED: + copy_stored_file(self.stream, header.compressed_size, dest) + else: + copy_compressed_file(self.stream, header.compressed_size, dest) + dest.seek(0) + return dest + + def getinfo(self, name): + try: + offset, header = self.file_info.get(name) + except KeyError: + raise ValueError('This ZIP container has no file named: %s'%name) + return header + + def read(self, name, spool_size=5*1024*1024): + with self.open(name, spool_size=spool_size) as f: + return f.read() + + def extractall(self, path=None): + self.stream.seek(0) + _extractall(self.stream, path=(path or os.getcwdu())) + + def close(self): + pass + + def safe_replace(self, name, datastream, extra_replacements={}, + add_missing=False): + from calibre.utils.zipfile import ZipFile, ZipInfo + replacements = {name:datastream} + replacements.update(extra_replacements) + names = frozenset(replacements.keys()) + found = set([]) + with SpooledTemporaryFile(max_size=100*1024*1024) as temp: + ztemp = ZipFile(temp, 'w') + for offset, header in self.file_info.itervalues(): + if header.filename in names: + zi = ZipInfo(header.filename) + zi.compress_type = header.compression_method + ztemp.writestr(zi, replacements[header.filename].read()) + found.add(header.filename) + else: + ztemp.writestr(header.filename, self.read(header.filename, + spool_size=0)) + if add_missing: + for name in names - found: + ztemp.writestr(name, replacements[name].read()) + ztemp.close() + zipstream = self.stream + temp.seek(0) + zipstream.seek(0) + zipstream.truncate() + shutil.copyfileobj(temp, zipstream) + zipstream.flush() + +if __name__ == '__main__': + extractall(sys.argv[-1]) + From 50a8fb6d7a0ca11d238cd0aa9e1153e202d1ac60 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 7 Nov 2012 17:48:12 +0530 Subject: [PATCH 106/107] Put tabes in optimal order in subsetted font --- src/calibre/utils/fonts/sfnt/container.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/calibre/utils/fonts/sfnt/container.py b/src/calibre/utils/fonts/sfnt/container.py index a6c0c5c81d..5ef3c157c6 100644 --- a/src/calibre/utils/fonts/sfnt/container.py +++ b/src/calibre/utils/fonts/sfnt/container.py @@ -55,12 +55,24 @@ class Sfnt(object): def __delitem__(self, key): del self.tables[key] + def __iter__(self): + '''Iterate over the table tags in optimal order as per + http://partners.adobe.com/public/developer/opentype/index_recs.html''' + keys = list(self.tables.keys()) + order = {x:i for i, x in enumerate((b'head', b'hhea', b'maxp', b'OS/2', + b'hmtx', b'LTSH', b'VDMX', b'hdmx', b'cmap', b'fpgm', b'prep', + b'cvt ', b'loca', b'glyf', b'CFF ', b'kern', b'name', b'post', + b'gasp', b'PCLT', b'DSIG'))} + keys.sort(key=lambda x:order.get(x, 1000)) + for x in keys: + yield x + def pop(self, key, default=None): return self.tables.pop(key, default) def sizes(self): ans = OrderedDict() - for tag in sorted(self.tables): + for tag in self: ans[tag] = len(self[tag]) return ans @@ -84,7 +96,7 @@ class Sfnt(object): table_data = [] offset = stream.tell() + ( calcsize(b'>4s3L') * num_tables ) sizes = OrderedDict() - for tag in sorted(self.tables): + for tag in self: table = self.tables[tag] raw = table() table_len = len(raw) From 01c361e7fe561e602f940dc3d003b0c85898662f Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Wed, 7 Nov 2012 18:15:16 +0100 Subject: [PATCH 107/107] Update last_modified when deleting values from custom columns using the tag browser. --- src/calibre/library/custom_columns.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/calibre/library/custom_columns.py b/src/calibre/library/custom_columns.py index 453f03f38a..2401ef3026 100644 --- a/src/calibre/library/custom_columns.py +++ b/src/calibre/library/custom_columns.py @@ -292,6 +292,7 @@ class CustomColumns(object): if num is not None: data = self.custom_column_num_map[num] table,lt = self.custom_table_names(data['num']) + self.dirty_books_referencing('#'+data['label'], id, commit=False) self.conn.execute('DELETE FROM %s WHERE value=?'%lt, (id,)) self.conn.execute('DELETE FROM %s WHERE id=?'%table, (id,)) self.conn.commit()