home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2010 November / maximum-cd-2010-11.iso / DiscContents / calibre-0.7.13.msi / file_984 (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2010-08-06  |  14.6 KB  |  484 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. from __future__ import with_statement
  5. __license__ = 'GPL v3'
  6. __copyright__ = '2008, Marshall T. Vandegrift <llasram@gmail.cam>'
  7. import copy
  8. import re
  9. from lxml import etree
  10. from calibre.ebooks.oeb.base import namespace, barename
  11. from calibre.ebooks.oeb.base import XHTML, XHTML_NS, OEB_DOCS
  12. from calibre.ebooks.oeb.stylizer import Stylizer
  13. from calibre.ebooks.oeb.transforms.flatcss import KeyMapper
  14. MBP_NS = 'http://mobipocket.com/ns/mbp'
  15.  
  16. def MBP(name):
  17.     return '{%s}%s' % (MBP_NS, name)
  18.  
  19. MOBI_NSMAP = {
  20.     None: XHTML_NS,
  21.     'mbp': MBP_NS }
  22. HEADER_TAGS = set([
  23.     'h1',
  24.     'h2',
  25.     'h3',
  26.     'h4',
  27.     'h5',
  28.     'h6'])
  29. NESTABLE_TAGS = set([
  30.     'ol',
  31.     'ul',
  32.     'li',
  33.     'table',
  34.     'tr',
  35.     'td',
  36.     'th',
  37.     'caption'])
  38. TABLE_TAGS = set([
  39.     'table',
  40.     'tr',
  41.     'td',
  42.     'th',
  43.     'caption'])
  44. SPECIAL_TAGS = set([
  45.     'hr',
  46.     'br'])
  47. CONTENT_TAGS = set([
  48.     'img',
  49.     'hr',
  50.     'br'])
  51. PAGE_BREAKS = set([
  52.     'always',
  53.     'left',
  54.     'right'])
  55. COLLAPSE = re.compile('[ \\t\\r\\n\\v]+')
  56.  
  57. def asfloat(value):
  58.     if not isinstance(value, (int, long, float)):
  59.         return 0
  60.     return float(value)
  61.  
  62.  
  63. class BlockState(object):
  64.     
  65.     def __init__(self, body):
  66.         self.body = body
  67.         self.nested = []
  68.         self.para = None
  69.         self.inline = None
  70.         self.anchor = None
  71.         self.vpadding = 0
  72.         self.vmargin = 0
  73.         self.pbreak = False
  74.         self.istate = None
  75.         self.content = False
  76.  
  77.  
  78.  
  79. class FormatState(object):
  80.     
  81.     def __init__(self):
  82.         self.rendered = False
  83.         self.left = 0
  84.         self.halign = 'auto'
  85.         self.indent = 0
  86.         self.fsize = 3
  87.         self.ids = set()
  88.         self.valign = 'baseline'
  89.         self.nest = False
  90.         self.italic = False
  91.         self.bold = False
  92.         self.strikethrough = False
  93.         self.underline = False
  94.         self.preserve = False
  95.         self.family = 'serif'
  96.         self.bgcolor = 'transparent'
  97.         self.fgcolor = 'black'
  98.         self.href = None
  99.         self.list_num = 0
  100.         self.attrib = { }
  101.  
  102.     
  103.     def __eq__(self, other):
  104.         if self.fsize == other.fsize and self.italic == other.italic and self.bold == other.bold and self.href == other.href and self.valign == other.valign and self.preserve == other.preserve and self.family == other.family and self.bgcolor == other.bgcolor and self.fgcolor == other.fgcolor and self.strikethrough == other.strikethrough:
  105.             pass
  106.         return self.underline == other.underline
  107.  
  108.     
  109.     def __ne__(self, other):
  110.         return not self.__eq__(other)
  111.  
  112.  
  113.  
  114. class MobiMLizer(object):
  115.     
  116.     def __init__(self, ignore_tables = False):
  117.         self.ignore_tables = ignore_tables
  118.  
  119.     
  120.     def __call__(self, oeb, context):
  121.         oeb.logger.info('Converting XHTML to Mobipocket markup...')
  122.         self.oeb = oeb
  123.         self.opts = context
  124.         self.profile = profile = context.dest
  125.         self.fnums = fnums = dict((lambda .0: for k, v in .0:
  126. (v, k))(profile.fnums.items()))
  127.         self.fmap = KeyMapper(profile.fbase, profile.fbase, fnums.keys())
  128.         self.remove_html_cover()
  129.         self.mobimlize_spine()
  130.  
  131.     
  132.     def remove_html_cover(self):
  133.         oeb = self.oeb
  134.         if not (oeb.metadata.cover) or 'cover' not in oeb.guide:
  135.             return None
  136.         href = oeb.guide['cover'].href
  137.         del oeb.guide['cover']
  138.         item = oeb.manifest.hrefs[href]
  139.         if item.spine_position is not None:
  140.             oeb.spine.remove(item)
  141.             if item.media_type in OEB_DOCS:
  142.                 self.oeb.manifest.remove(item)
  143.             
  144.         
  145.  
  146.     
  147.     def mobimlize_spine(self):
  148.         for item in self.oeb.spine:
  149.             stylizer = Stylizer(item.data, item.href, self.oeb, self.opts, self.profile)
  150.             body = item.data.find(XHTML('body'))
  151.             nroot = etree.Element(XHTML('html'), nsmap = MOBI_NSMAP)
  152.             nbody = etree.SubElement(nroot, XHTML('body'))
  153.             self.mobimlize_elem(body, stylizer, BlockState(nbody), [
  154.                 FormatState()])
  155.             item.data = nroot
  156.         
  157.  
  158.     
  159.     def mobimlize_font(self, ptsize):
  160.         return self.fnums[self.fmap[ptsize]]
  161.  
  162.     
  163.     def mobimlize_measure(self, ptsize):
  164.         if isinstance(ptsize, basestring):
  165.             return ptsize
  166.         embase = self.profile.fbase
  167.         if round(ptsize) < embase:
  168.             return '%dpt' % int(round(ptsize))
  169.         return '%dem' % int(round(ptsize / embase))
  170.  
  171.     
  172.     def preize_text(self, text):
  173.         text = unicode(text).replace(u' ', u'┬á')
  174.         text = text.replace('\r\n', '\n')
  175.         text = text.replace('\r', '\n')
  176.         lines = text.split('\n')
  177.         result = lines[:1]
  178.         for line in lines[1:]:
  179.             result.append(etree.Element(XHTML('br')))
  180.             if line:
  181.                 result.append(line)
  182.                 continue
  183.         
  184.         return result
  185.  
  186.     
  187.     def mobimlize_content(self, tag, text, bstate, istates):
  188.         if text or tag != 'br':
  189.             bstate.content = True
  190.         
  191.         istate = istates[-1]
  192.         para = bstate.para
  193.         if tag in SPECIAL_TAGS and not text:
  194.             para = None if para is not None else bstate.body
  195.         elif para is None or tag in ('td', 'th'):
  196.             body = bstate.body
  197.             if bstate.pbreak:
  198.                 etree.SubElement(body, MBP('pagebreak'))
  199.                 bstate.pbreak = False
  200.             
  201.             bstate.istate = None
  202.             bstate.anchor = None
  203.             parent = None if bstate.nested else bstate.body
  204.             indent = istate.indent
  205.             left = istate.left
  206.             if isinstance(indent, basestring):
  207.                 indent = 0
  208.             
  209.             if indent < 0 and abs(indent) < left:
  210.                 left += indent
  211.                 indent = 0
  212.             elif indent != 0 and abs(indent) < self.profile.fbase:
  213.                 indent = (indent / abs(indent)) * self.profile.fbase
  214.             
  215.             if tag in NESTABLE_TAGS and not (istate.rendered):
  216.                 para = wrapper = etree.SubElement(parent, XHTML(tag), attrib = istate.attrib)
  217.                 bstate.nested.append(para)
  218.                 if tag == 'li' and len(istates) > 1:
  219.                     istates[-2].list_num += 1
  220.                     para.attrib['value'] = str(istates[-2].list_num)
  221.                 
  222.             elif tag in NESTABLE_TAGS and istate.rendered:
  223.                 para = wrapper = bstate.nested[-1]
  224.             elif left > 0 and indent >= 0:
  225.                 para = wrapper = etree.SubElement(parent, XHTML('blockquote'))
  226.                 para = wrapper
  227.                 emleft = int(round(left / self.profile.fbase)) - 1
  228.                 emleft = min((emleft, 10))
  229.                 while emleft > 0:
  230.                     para = etree.SubElement(para, XHTML('blockquote'))
  231.                     emleft -= 1
  232.             else:
  233.                 para = wrapper = etree.SubElement(parent, XHTML('p'))
  234.             bstate.inline = bstate.para = para
  235.             vspace = bstate.vpadding + bstate.vmargin
  236.             bstate.vpadding = bstate.vmargin = 0
  237.             if tag not in TABLE_TAGS:
  238.                 wrapper.attrib['height'] = self.mobimlize_measure(vspace)
  239.                 para.attrib['width'] = self.mobimlize_measure(indent)
  240.             elif tag == 'table' and vspace > 0:
  241.                 vspace = int(round(vspace / self.profile.fbase))
  242.                 while vspace > 0:
  243.                     wrapper.addprevious(etree.Element(XHTML('br')))
  244.                     vspace -= 1
  245.             
  246.             if istate.halign != 'auto' and isinstance(istate.halign, (str, unicode)):
  247.                 para.attrib['align'] = istate.halign
  248.             
  249.         
  250.         istate.rendered = True
  251.         pstate = bstate.istate
  252.         if tag in CONTENT_TAGS:
  253.             bstate.inline = para
  254.             pstate = None
  255.             bstate.istate = None
  256.             etree.SubElement(para, XHTML(tag), attrib = istate.attrib)
  257.         elif tag in TABLE_TAGS:
  258.             para.attrib['valign'] = 'top'
  259.         
  260.         if istate.ids:
  261.             last = bstate.body[-1]
  262.             for id in istate.ids:
  263.                 last.addprevious(etree.Element(XHTML('a'), attrib = {
  264.                     'id': id }))
  265.             
  266.             istate.ids.clear()
  267.         
  268.         if not text:
  269.             return None
  270.         bstate.istate = istate
  271.         inline = bstate.inline
  272.         content = None if not pstate or istate != pstate else text if istate.preserve else [
  273.             text]
  274.         for item in content:
  275.             if isinstance(item, basestring):
  276.                 if len(inline) == 0:
  277.                     if not inline.text:
  278.                         pass
  279.                     inline.text = '' + item
  280.                 else:
  281.                     last = inline[-1]
  282.                     if not last.tail:
  283.                         pass
  284.                     last.tail = '' + item
  285.             len(inline) == 0
  286.             inline.append(item)
  287.         
  288.  
  289.     
  290.     def mobimlize_elem(self, elem, stylizer, bstate, istates):
  291.         if not isinstance(elem.tag, basestring) or namespace(elem.tag) != XHTML_NS:
  292.             return None
  293.         style = stylizer.style(elem)
  294.         if style['display'] in ('none', 'oeb-page-head', 'oeb-page-foot') or style['visibility'] == 'hidden':
  295.             return None
  296.         tag = barename(elem.tag)
  297.         istate = copy.copy(istates[-1])
  298.         istate.rendered = False
  299.         istate.list_num = 0
  300.         istates.append(istate)
  301.         left = 0
  302.         display = style['display']
  303.         isblock = not display.startswith('inline')
  304.         if isblock:
  305.             pass
  306.         isblock = style['float'] == 'none'
  307.         if isblock:
  308.             pass
  309.         isblock = tag != 'br'
  310.         if isblock:
  311.             bstate.para = None
  312.             istate.halign = style['text-align']
  313.             istate.indent = style['text-indent']
  314.             margin = asfloat(style['margin-left'])
  315.             padding = asfloat(style['padding-left'])
  316.             if tag != 'body':
  317.                 left = margin + padding
  318.             
  319.             istate.left += left
  320.             vmargin = asfloat(style['margin-top'])
  321.             bstate.vmargin = max((bstate.vmargin, vmargin))
  322.             vpadding = asfloat(style['padding-top'])
  323.             if vpadding > 0:
  324.                 bstate.vpadding += bstate.vmargin
  325.                 bstate.vmargin = 0
  326.                 bstate.vpadding += vpadding
  327.             
  328.         elif not istate.href:
  329.             margin = asfloat(style['margin-left'])
  330.             padding = asfloat(style['padding-left'])
  331.             lspace = margin + padding
  332.             if lspace > 0:
  333.                 spaces = int(round(lspace * 3 / style['font-size']))
  334.                 if not elem.text:
  335.                     pass
  336.                 elem.text = u'┬á' * spaces + ''
  337.             
  338.             margin = asfloat(style['margin-right'])
  339.             padding = asfloat(style['padding-right'])
  340.             rspace = margin + padding
  341.             if rspace > 0:
  342.                 spaces = int(round(rspace * 3 / style['font-size']))
  343.                 if len(elem) == 0:
  344.                     if not elem.text:
  345.                         pass
  346.                     elem.text = '' + u'┬á' * spaces
  347.                 else:
  348.                     last = elem[-1]
  349.                     if not last.text:
  350.                         pass
  351.                     last.text = '' + u'┬á' * spaces
  352.             
  353.         
  354.         if bstate.content and style['page-break-before'] in PAGE_BREAKS:
  355.             bstate.pbreak = True
  356.         
  357.         istate.fsize = self.mobimlize_font(style['font-size'])
  358.         istate.italic = None if style['font-style'] == 'italic' else False
  359.         weight = style['font-weight']
  360.         if not weight in ('bold', 'bolder'):
  361.             pass
  362.         istate.bold = asfloat(weight) > 400
  363.         istate.preserve = style['white-space'] in ('pre', 'pre-wrap')
  364.         istate.bgcolor = style['background-color']
  365.         istate.fgcolor = style['color']
  366.         istate.strikethrough = style['text-decoration'] == 'line-through'
  367.         istate.underline = style['text-decoration'] == 'underline'
  368.         if 'monospace' in style['font-family']:
  369.             istate.family = 'monospace'
  370.         elif 'sans-serif' in style['font-family']:
  371.             istate.family = 'sans-serif'
  372.         else:
  373.             istate.family = 'serif'
  374.         valign = style['vertical-align']
  375.         if valign in ('super', 'text-top') or asfloat(valign) > 0:
  376.             istate.nest = istate.valign in ('sub', 'super')
  377.             istate.valign = 'super'
  378.         elif valign == 'sub' or asfloat(valign) < 0:
  379.             istate.nest = istate.valign in ('sub', 'super')
  380.             istate.valign = 'sub'
  381.         else:
  382.             istate.valign = 'baseline'
  383.         if 'id' in elem.attrib:
  384.             istate.ids.add(elem.attrib['id'])
  385.         
  386.         if 'name' in elem.attrib:
  387.             istate.ids.add(elem.attrib['name'])
  388.         
  389.         if tag == 'a' and 'href' in elem.attrib:
  390.             istate.href = elem.attrib['href']
  391.         
  392.         istate.attrib.clear()
  393.         if tag == 'img' and 'src' in elem.attrib:
  394.             istate.attrib['src'] = elem.attrib['src']
  395.             istate.attrib['align'] = 'baseline'
  396.             for prop in ('width', 'height'):
  397.                 if style[prop] != 'auto':
  398.                     value = style[prop]
  399.                     if value == getattr(self.profile, prop):
  400.                         result = '100%'
  401.                     else:
  402.                         
  403.                         try:
  404.                             ems = int(round(float(value) / self.profile.fbase))
  405.                         except:
  406.                             continue
  407.  
  408.                         result = '%dem' % ems
  409.                     istate.attrib[prop] = result
  410.                     continue
  411.             
  412.         elif tag == 'hr' and asfloat(style['width']) > 0:
  413.             prop = style['width'] / self.profile.width
  414.             istate.attrib['width'] = '%d%%' % int(round(prop * 100))
  415.         elif display == 'table':
  416.             tag = 'table'
  417.         elif display == 'table-row':
  418.             tag = 'tr'
  419.         elif display == 'table-cell':
  420.             tag = 'td'
  421.         
  422.         if tag in TABLE_TAGS and self.ignore_tables:
  423.             tag = None if tag == 'td' else 'div'
  424.         
  425.         if tag in TABLE_TAGS:
  426.             for attr in ('rowspan', 'colspan', 'width', 'border', 'scope'):
  427.                 if attr in elem.attrib:
  428.                     istate.attrib[attr] = elem.attrib[attr]
  429.                     continue
  430.             
  431.         
  432.         text = None
  433.         if elem.text:
  434.             if istate.preserve:
  435.                 text = elem.text
  436.             elif len(elem) > 0 and elem.text.isspace():
  437.                 text = None
  438.             else:
  439.                 text = COLLAPSE.sub(' ', elem.text)
  440.         
  441.         if text and tag in CONTENT_TAGS or tag in NESTABLE_TAGS:
  442.             self.mobimlize_content(tag, text, bstate, istates)
  443.         
  444.         for child in elem:
  445.             self.mobimlize_elem(child, stylizer, bstate, istates)
  446.             tail = None
  447.             if child.tail:
  448.                 if istate.preserve:
  449.                     tail = child.tail
  450.                 elif bstate.para is None and child.tail.isspace():
  451.                     tail = None
  452.                 else:
  453.                     tail = COLLAPSE.sub(' ', child.tail)
  454.             
  455.             if tail:
  456.                 self.mobimlize_content(tag, tail, bstate, istates)
  457.                 continue
  458.         
  459.         if bstate.content and style['page-break-after'] in PAGE_BREAKS:
  460.             bstate.pbreak = True
  461.         
  462.         if isblock:
  463.             para = bstate.para
  464.             if para is not None and para.text == u'┬á':
  465.                 para.getparent().replace(para, etree.Element(XHTML('br')))
  466.             
  467.             bstate.para = None
  468.             bstate.istate = None
  469.             vmargin = asfloat(style['margin-bottom'])
  470.             bstate.vmargin = max((bstate.vmargin, vmargin))
  471.             vpadding = asfloat(style['padding-bottom'])
  472.             if vpadding > 0:
  473.                 bstate.vpadding += bstate.vmargin
  474.                 bstate.vmargin = 0
  475.                 bstate.vpadding += vpadding
  476.             
  477.         
  478.         if bstate.nested and bstate.nested[-1].tag == elem.tag:
  479.             bstate.nested.pop()
  480.         
  481.         istates.pop()
  482.  
  483.  
  484.