home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2011 January / maximum-cd-2011-01.iso / DiscContents / calibre-0.7.26.msi / file_982 (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2010-10-31  |  14.8 KB  |  501 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. NOT_VTAGS = HEADER_TAGS | NESTABLE_TAGS | TABLE_TAGS | SPECIAL_TAGS | CONTENT_TAGS
  52. PAGE_BREAKS = set([
  53.     'always',
  54.     'left',
  55.     'right'])
  56. COLLAPSE = re.compile('[ \\t\\r\\n\\v]+')
  57.  
  58. def asfloat(value):
  59.     if not isinstance(value, (int, long, float)):
  60.         return 0
  61.     return float(value)
  62.  
  63.  
  64. class BlockState(object):
  65.     
  66.     def __init__(self, body):
  67.         self.body = body
  68.         self.nested = []
  69.         self.para = None
  70.         self.inline = None
  71.         self.anchor = None
  72.         self.vpadding = 0
  73.         self.vmargin = 0
  74.         self.pbreak = False
  75.         self.istate = None
  76.         self.content = False
  77.  
  78.  
  79.  
  80. class FormatState(object):
  81.     
  82.     def __init__(self):
  83.         self.rendered = False
  84.         self.left = 0
  85.         self.halign = 'auto'
  86.         self.indent = 0
  87.         self.fsize = 3
  88.         self.ids = set()
  89.         self.italic = False
  90.         self.bold = False
  91.         self.strikethrough = False
  92.         self.underline = False
  93.         self.preserve = False
  94.         self.family = 'serif'
  95.         self.bgcolor = 'transparent'
  96.         self.fgcolor = 'black'
  97.         self.href = None
  98.         self.list_num = 0
  99.         self.attrib = { }
  100.  
  101.     
  102.     def __eq__(self, other):
  103.         if self.fsize == other.fsize and self.italic == other.italic and self.bold == other.bold and self.href == other.href 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:
  104.             pass
  105.         return self.underline == other.underline
  106.  
  107.     
  108.     def __ne__(self, other):
  109.         return not self.__eq__(other)
  110.  
  111.  
  112.  
  113. class MobiMLizer(object):
  114.     
  115.     def __init__(self, ignore_tables = False):
  116.         self.ignore_tables = ignore_tables
  117.  
  118.     
  119.     def __call__(self, oeb, context):
  120.         oeb.logger.info('Converting XHTML to Mobipocket markup...')
  121.         self.oeb = oeb
  122.         self.opts = context
  123.         self.profile = profile = context.dest
  124.         self.fnums = fnums = dict((lambda .0: for k, v in .0:
  125. (v, k))(profile.fnums.items()))
  126.         self.fmap = KeyMapper(profile.fbase, profile.fbase, fnums.keys())
  127.         self.remove_html_cover()
  128.         self.mobimlize_spine()
  129.  
  130.     
  131.     def remove_html_cover(self):
  132.         oeb = self.oeb
  133.         if not (oeb.metadata.cover) or 'cover' not in oeb.guide:
  134.             return None
  135.         href = oeb.guide['cover'].href
  136.         del oeb.guide['cover']
  137.         item = oeb.manifest.hrefs[href]
  138.         if item.spine_position is not None:
  139.             oeb.spine.remove(item)
  140.             if item.media_type in OEB_DOCS:
  141.                 self.oeb.manifest.remove(item)
  142.             
  143.         
  144.  
  145.     
  146.     def mobimlize_spine(self):
  147.         for item in self.oeb.spine:
  148.             stylizer = Stylizer(item.data, item.href, self.oeb, self.opts, self.profile)
  149.             body = item.data.find(XHTML('body'))
  150.             nroot = etree.Element(XHTML('html'), nsmap = MOBI_NSMAP)
  151.             nbody = etree.SubElement(nroot, XHTML('body'))
  152.             self.mobimlize_elem(body, stylizer, BlockState(nbody), [
  153.                 FormatState()])
  154.             item.data = nroot
  155.         
  156.  
  157.     
  158.     def mobimlize_font(self, ptsize):
  159.         return self.fnums[self.fmap[ptsize]]
  160.  
  161.     
  162.     def mobimlize_measure(self, ptsize):
  163.         if isinstance(ptsize, basestring):
  164.             return ptsize
  165.         embase = self.profile.fbase
  166.         if round(ptsize) < embase:
  167.             return '%dpt' % int(round(ptsize))
  168.         return '%dem' % int(round(ptsize / embase))
  169.  
  170.     
  171.     def preize_text(self, text):
  172.         text = unicode(text).replace(u' ', u'┬á')
  173.         text = text.replace('\r\n', '\n')
  174.         text = text.replace('\r', '\n')
  175.         lines = text.split('\n')
  176.         result = lines[:1]
  177.         for line in lines[1:]:
  178.             result.append(etree.Element(XHTML('br')))
  179.             if line:
  180.                 result.append(line)
  181.                 continue
  182.         
  183.         return result
  184.  
  185.     
  186.     def mobimlize_content(self, tag, text, bstate, istates):
  187.         if text or tag != 'br':
  188.             bstate.content = True
  189.         
  190.         istate = istates[-1]
  191.         para = bstate.para
  192.         if tag in SPECIAL_TAGS and not text:
  193.             para = None if para is not None else bstate.body
  194.         elif para is None or tag in ('td', 'th'):
  195.             body = bstate.body
  196.             if bstate.pbreak:
  197.                 etree.SubElement(body, MBP('pagebreak'))
  198.                 bstate.pbreak = False
  199.             
  200.             bstate.istate = None
  201.             bstate.anchor = None
  202.             parent = None if bstate.nested else bstate.body
  203.             indent = istate.indent
  204.             left = istate.left
  205.             if isinstance(indent, basestring):
  206.                 indent = 0
  207.             
  208.             if indent < 0 and abs(indent) < left:
  209.                 left += indent
  210.                 indent = 0
  211.             elif indent != 0 and abs(indent) < self.profile.fbase:
  212.                 indent = (indent / abs(indent)) * self.profile.fbase
  213.             
  214.             if tag in NESTABLE_TAGS and not (istate.rendered):
  215.                 para = wrapper = etree.SubElement(parent, XHTML(tag), attrib = istate.attrib)
  216.                 bstate.nested.append(para)
  217.                 if tag == 'li' and len(istates) > 1:
  218.                     istates[-2].list_num += 1
  219.                     para.attrib['value'] = str(istates[-2].list_num)
  220.                 
  221.             elif tag in NESTABLE_TAGS and istate.rendered:
  222.                 para = wrapper = bstate.nested[-1]
  223.             elif left > 0 and indent >= 0:
  224.                 ems = self.profile.mobi_ems_per_blockquote
  225.                 para = wrapper = etree.SubElement(parent, XHTML('blockquote'))
  226.                 para = wrapper
  227.                 emleft = int(round(left / self.profile.fbase)) - ems
  228.                 emleft = min((emleft, 10))
  229.                 while emleft > ems / 2:
  230.                     para = etree.SubElement(para, XHTML('blockquote'))
  231.                     emleft -= ems
  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, ignore_valign = False):
  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.         if 'id' in elem.attrib:
  375.             istate.ids.add(elem.attrib['id'])
  376.         
  377.         if 'name' in elem.attrib:
  378.             istate.ids.add(elem.attrib['name'])
  379.         
  380.         if tag == 'a' and 'href' in elem.attrib:
  381.             istate.href = elem.attrib['href']
  382.         
  383.         istate.attrib.clear()
  384.         if tag == 'img' and 'src' in elem.attrib:
  385.             istate.attrib['src'] = elem.attrib['src']
  386.             istate.attrib['align'] = 'baseline'
  387.             for prop in ('width', 'height'):
  388.                 if style[prop] != 'auto':
  389.                     value = style[prop]
  390.                     if value == getattr(self.profile, prop):
  391.                         result = '100%'
  392.                     else:
  393.                         
  394.                         try:
  395.                             ems = int(round(float(value) / self.profile.fbase))
  396.                         except:
  397.                             continue
  398.  
  399.                         result = '%dem' % ems
  400.                     istate.attrib[prop] = result
  401.                     continue
  402.             
  403.         elif tag == 'hr' and asfloat(style['width']) > 0:
  404.             prop = style['width'] / self.profile.width
  405.             istate.attrib['width'] = '%d%%' % int(round(prop * 100))
  406.         elif display == 'table':
  407.             tag = 'table'
  408.         elif display == 'table-row':
  409.             tag = 'tr'
  410.         elif display == 'table-cell':
  411.             tag = 'td'
  412.         
  413.         if tag in TABLE_TAGS and self.ignore_tables:
  414.             tag = None if tag == 'td' else 'div'
  415.         
  416.         if tag in TABLE_TAGS:
  417.             for attr in ('rowspan', 'colspan', 'width', 'border', 'scope'):
  418.                 if attr in elem.attrib:
  419.                     istate.attrib[attr] = elem.attrib[attr]
  420.                     continue
  421.             
  422.         
  423.         text = None
  424.         if elem.text:
  425.             if istate.preserve:
  426.                 text = elem.text
  427.             elif len(elem) > 0 and elem.text.isspace():
  428.                 text = None
  429.             else:
  430.                 text = COLLAPSE.sub(' ', elem.text)
  431.         
  432.         valign = style['vertical-align']
  433.         not_baseline = valign in ('super', 'sub', 'text-top', 'text-bottom')
  434.         vtag = None if valign in ('super', 'text-top') else 'sub'
  435.         if not_baseline and not ignore_valign and tag not in NOT_VTAGS and not isblock:
  436.             nroot = etree.Element(XHTML('html'), nsmap = MOBI_NSMAP)
  437.             vbstate = BlockState(etree.SubElement(nroot, XHTML('body')))
  438.             vbstate.para = etree.SubElement(vbstate.body, XHTML('p'))
  439.             self.mobimlize_elem(elem, stylizer, vbstate, istates, ignore_valign = True)
  440.             if len(istates) > 0:
  441.                 istates.pop()
  442.             
  443.             if len(istates) == 0:
  444.                 istates.append(FormatState())
  445.             
  446.             at_start = bstate.para is None
  447.             if at_start:
  448.                 self.mobimlize_content('span', '', bstate, istates)
  449.             
  450.             parent = None if bstate.inline is None else bstate.inline
  451.             if parent is not None:
  452.                 vtag = etree.SubElement(parent, XHTML(vtag))
  453.                 for child in vbstate.para:
  454.                     vtag.append(child)
  455.                 
  456.                 return None
  457.         
  458.         if text and tag in CONTENT_TAGS or tag in NESTABLE_TAGS:
  459.             self.mobimlize_content(tag, text, bstate, istates)
  460.         
  461.         for child in elem:
  462.             self.mobimlize_elem(child, stylizer, bstate, istates)
  463.             tail = None
  464.             if child.tail:
  465.                 if istate.preserve:
  466.                     tail = child.tail
  467.                 elif bstate.para is None and child.tail.isspace():
  468.                     tail = None
  469.                 else:
  470.                     tail = COLLAPSE.sub(' ', child.tail)
  471.             
  472.             if tail:
  473.                 self.mobimlize_content(tag, tail, bstate, istates)
  474.                 continue
  475.         
  476.         if bstate.content and style['page-break-after'] in PAGE_BREAKS:
  477.             bstate.pbreak = True
  478.         
  479.         if isblock:
  480.             para = bstate.para
  481.             if para is not None and para.text == u'┬á':
  482.                 para.getparent().replace(para, etree.Element(XHTML('br')))
  483.             
  484.             bstate.para = None
  485.             bstate.istate = None
  486.             vmargin = asfloat(style['margin-bottom'])
  487.             bstate.vmargin = max((bstate.vmargin, vmargin))
  488.             vpadding = asfloat(style['padding-bottom'])
  489.             if vpadding > 0:
  490.                 bstate.vpadding += bstate.vmargin
  491.                 bstate.vmargin = 0
  492.                 bstate.vpadding += vpadding
  493.             
  494.         
  495.         if bstate.nested and bstate.nested[-1].tag == elem.tag:
  496.             bstate.nested.pop()
  497.         
  498.         istates.pop()
  499.  
  500.  
  501.