~ubuntu-branches/ubuntu/karmic/calibre/karmic

« back to all changes in this revision

Viewing changes to src/calibre/ebooks/oeb/stylizer.py

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2009-07-30 12:49:41 UTC
  • mfrom: (1.3.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20090730124941-qjdsmri25zt8zocn
Tags: 0.6.3+dfsg-0ubuntu1
* New upstream release. Please see http://calibre.kovidgoyal.net/new_in_6/
  for the list of new features and changes.
* remove_postinstall.patch: Update for new version.
* build_debug.patch: Does not apply any more, disable for now. Might not be
  necessary any more.
* debian/copyright: Fix reference to versionless GPL.
* debian/rules: Drop obsolete dh_desktop call.
* debian/rules: Add workaround for weird Python 2.6 setuptools behaviour of
  putting compiled .so files into src/calibre/plugins/calibre/plugins
  instead of src/calibre/plugins.
* debian/rules: Drop hal fdi moving, new upstream version does not use hal
  any more. Drop hal dependency, too.
* debian/rules: Install udev rules into /lib/udev/rules.d.
* Add debian/calibre.preinst: Remove unmodified
  /etc/udev/rules.d/95-calibre.rules on upgrade.
* debian/control: Bump Python dependencies to 2.6, since upstream needs
  it now.

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
import os
12
12
import itertools
13
13
import re
 
14
import logging
14
15
import copy
15
16
from weakref import WeakKeyDictionary
16
17
from xml.dom import SyntaxErr as CSSSyntaxError
106
107
class Stylizer(object):
107
108
    STYLESHEETS = WeakKeyDictionary()
108
109
 
109
 
    def __init__(self, tree, path, oeb, profile=PROFILES['PRS505']):
 
110
    def __init__(self, tree, path, oeb, profile=PROFILES['PRS505'],
 
111
            extra_css='', user_css=''):
110
112
        self.oeb = oeb
111
113
        self.profile = profile
112
114
        self.logger = oeb.logger
115
117
        cssname = os.path.splitext(basename)[0] + '.css'
116
118
        stylesheets = [HTML_CSS_STYLESHEET]
117
119
        head = xpath(tree, '/h:html/h:head')[0]
118
 
        parser = cssutils.CSSParser()
119
 
        parser.setFetcher(self._fetch_css_file)
 
120
        parser = cssutils.CSSParser(fetcher=self._fetch_css_file,
 
121
                log=logging.getLogger('calibre.css'))
120
122
        for elem in head:
121
123
            if elem.tag == XHTML('style') and elem.text \
122
124
               and elem.get('type', CSS_MIME) in OEB_STYLES:
135
137
                        'Stylesheet %r referenced by file %r not in manifest' %
136
138
                        (path, item.href))
137
139
                    continue
138
 
                if sitem in self.STYLESHEETS:
139
 
                    stylesheet = self.STYLESHEETS[sitem]
140
 
                else:
141
 
                    data = self._fetch_css_file(path)[1]
142
 
                    stylesheet = parser.parseString(data, href=path)
143
 
                    stylesheet.namespaces['h'] = XHTML_NS
144
 
                    self.STYLESHEETS[sitem] = stylesheet
 
140
                stylesheets.append(sitem.data)
 
141
        for x in (extra_css, user_css):
 
142
            if x:
 
143
                text = XHTML_CSS_NAMESPACE + x
 
144
                stylesheet = parser.parseString(text, href=cssname)
 
145
                stylesheet.namespaces['h'] = XHTML_NS
145
146
                stylesheets.append(stylesheet)
146
147
        rules = []
147
148
        index = 0
156
157
        rules.sort()
157
158
        self.rules = rules
158
159
        self._styles = {}
 
160
        class_sel_pat = re.compile(r'\.[a-z]+', re.IGNORECASE)
159
161
        for _, _, cssdict, text, _ in rules:
160
162
            try:
161
163
                selector = CSSSelector(text)
162
 
            except (AssertionError, ExpressionError, etree.XPathSyntaxError,\
163
 
                NameError, # gets thrown on OS X instead of SelectorSyntaxError
164
 
                SelectorSyntaxError):
 
164
            except (AssertionError, ExpressionError, etree.XPathSyntaxError,
 
165
                    NameError, # thrown on OS X instead of SelectorSyntaxError
 
166
                    SelectorSyntaxError):
165
167
                continue
166
 
            for elem in selector(tree):
 
168
            matches = selector(tree)
 
169
            if not matches and class_sel_pat.match(text):
 
170
                found = False
 
171
                for x in tree.xpath('//*[@class]'):
 
172
                    if text.lower().endswith('.'+x.get('class').lower()) and \
 
173
                            text.lower() != text:
 
174
                        matches.append(x)
 
175
                        found = True
 
176
                if found:
 
177
                    self.logger.warn('Ignoring case mismatches for CSS selector: %s in %s'
 
178
                        %(text, item.href))
 
179
            for elem in matches:
167
180
                self.style(elem)._update_cssdict(cssdict)
168
181
        for elem in xpath(tree, '//h:*[@style]'):
169
182
            self.style(elem)._apply_style_attr()
171
184
    def _fetch_css_file(self, path):
172
185
        hrefs = self.oeb.manifest.hrefs
173
186
        if path not in hrefs:
174
 
            return (None, None)
175
 
        data = hrefs[path].data
176
 
        data = XHTML_CSS_NAMESPACE + data
 
187
            self.logger.warn('CSS import of missing file %r' % path)
 
188
            return (None, None)
 
189
        item = hrefs[path]
 
190
        if item.media_type not in OEB_STYLES:
 
191
            self.logger.warn('CSS import of non-CSS file %r' % path)
 
192
            return (None, None)
 
193
        data = item.data.cssText
177
194
        return ('utf-8', data)
178
195
 
179
196
    def flatten_rule(self, rule, href, index):
274
291
 
275
292
 
276
293
class Style(object):
277
 
    UNIT_RE = re.compile(r'^(-*[0-9]*[.]?[0-9]*)\s*(%|em|px|mm|cm|in|pt|pc)$')
 
294
    UNIT_RE = re.compile(r'^(-*[0-9]*[.]?[0-9]*)\s*(%|em|ex|en|px|mm|cm|in|pt|pc)$')
278
295
 
279
296
    def __init__(self, element, stylizer):
280
297
        self._element = element
287
304
        self._lineHeight = None
288
305
        stylizer._styles[element] = self
289
306
 
 
307
    def set(self, prop, val):
 
308
        self._style[prop] = val
 
309
 
290
310
    def _update_cssdict(self, cssdict):
291
311
        self._style.update(cssdict)
292
312
 
354
374
            elif unit == 'em':
355
375
                font = font or self.fontSize
356
376
                result = value * font
 
377
            elif unit in ('ex', 'en'):
 
378
                # This is a hack for ex since we have no way to know
 
379
                # the x-height of the font
 
380
                font = font or self.fontSize
 
381
                result = value * font * 0.5
357
382
            elif unit == 'pc':
358
383
                result = value * 12.0
359
384
            elif unit == 'mm':
386
411
                    result = size
387
412
            else:
388
413
                result = self._unit_convert(value, base=base, font=base)
 
414
                if not isinstance(result, (int, float, long)):
 
415
                    return base
389
416
                if result < 0:
390
417
                    result = normalize_fontsize("smaller", base)
391
418
            if factor: