DOCX Output: Proper handling of inheritance for border/padding CSS properties

This commit is contained in:
Kovid Goyal 2015-03-17 10:22:25 +05:30
parent bf152707b3
commit 8d7a936cec
2 changed files with 21 additions and 15 deletions

View File

@ -98,8 +98,8 @@ class Block(object):
self.keep_next = False self.keep_next = False
self.runs = [] self.runs = []
def add_text(self, text, style, ignore_leading_whitespace=False, html_parent=None): def add_text(self, text, style, ignore_leading_whitespace=False, html_parent=None, is_parent_style=False):
ts = self.styles_manager.create_text_style(style) ts = self.styles_manager.create_text_style(style, is_parent_style=is_parent_style)
ws = style['white-space'] ws = style['white-space']
if self.runs and ts == self.runs[-1].style: if self.runs and ts == self.runs[-1].style:
run = self.runs[-1] run = self.runs[-1]
@ -178,7 +178,7 @@ class Convert(object):
if block_style.is_hidden: if block_style.is_hidden:
return return
if html_block.text: if html_block.text:
docx_block.add_text(html_block.text, block_style, ignore_leading_whitespace=True) docx_block.add_text(html_block.text, block_style, ignore_leading_whitespace=True, is_parent_style=True)
for child in html_block.iterchildren(etree.Element): for child in html_block.iterchildren(etree.Element):
tag = barename(child.tag) tag = barename(child.tag)
@ -198,7 +198,7 @@ class Convert(object):
if b is not self.blocks[-1]: if b is not self.blocks[-1]:
b = Block(self.styles_manager, html_block, block_style) b = Block(self.styles_manager, html_block, block_style)
self.blocks.append(b) self.blocks.append(b)
b.add_text(html_block.tail, stylizer.style(html_block.getparent())) b.add_text(html_block.tail, stylizer.style(html_block.getparent()), is_parent_style=True)
if block_style['page-break-after'] == 'avoid': if block_style['page-break-after'] == 'avoid':
self.blocks[-1].keep_next = True self.blocks[-1].keep_next = True
@ -226,7 +226,7 @@ class Convert(object):
self.process_inline(child, self.blocks[-1], stylizer) self.process_inline(child, self.blocks[-1], stylizer)
if html_child.tail: if html_child.tail:
self.blocks[-1].add_text(html_child.tail, stylizer.style(html_child.getparent()), html_parent=html_child.getparent()) self.blocks[-1].add_text(html_child.tail, stylizer.style(html_child.getparent()), html_parent=html_child.getparent(), is_parent_style=True)
def write(self): def write(self):
dn = {k:v for k, v in namespaces.iteritems() if k in {'w', 'r', 'm', 've', 'o', 'wp', 'w10', 'wne'}} dn = {k:v for k, v in namespaces.iteritems() if k in {'w', 'r', 'm', 've', 'o', 'wp', 'w10', 'wne'}}

View File

@ -123,7 +123,7 @@ class TextStyle(DOCXStyle):
x%edge for edge in border_edges for x in border_props) x%edge for edge in border_edges for x in border_props)
TYPE = 'character' TYPE = 'character'
def __init__(self, css): def __init__(self, css, is_parent_style=False):
self.font_family = css_font_family_to_docx(css['font-family']) self.font_family = css_font_family_to_docx(css['font-family'])
try: try:
self.font_size = max(0, int(float(css['font-size']) * 2)) # stylizer normalizes all font sizes into pts self.font_size = max(0, int(float(css['font-size']) * 2)) # stylizer normalizes all font sizes into pts
@ -134,7 +134,7 @@ class TextStyle(DOCXStyle):
self.bold = fw.lower() in {'bold', 'bolder'} or int_or_zero(fw) >= 700 self.bold = fw.lower() in {'bold', 'bolder'} or int_or_zero(fw) >= 700
self.italic = css['font-style'].lower() in {'italic', 'oblique'} self.italic = css['font-style'].lower() in {'italic', 'oblique'}
self.color = convert_color(css['color']) self.color = convert_color(css['color'])
self.background_color = convert_color(css.backgroundColor) self.background_color = None if is_parent_style else convert_color(css.backgroundColor)
td = set((css.effective_text_decoration or '').split()) td = set((css.effective_text_decoration or '').split())
self.underline = 'underline' in td self.underline = 'underline' in td
self.dstrike = 'line-through' in td and 'overline' in td self.dstrike = 'line-through' in td and 'overline' in td
@ -149,12 +149,18 @@ class TextStyle(DOCXStyle):
self.spacing = None self.spacing = None
self.vertical_align = css['vertical-align'] self.vertical_align = css['vertical-align']
for edge in border_edges: for edge in border_edges:
# In DOCX padding can only be a positive integer if is_parent_style:
setattr(self, 'padding_' + edge, max(0, int(css['padding-' + edge]))) setattr(self, 'padding_' + edge, 0)
val = min(96, max(2, int({'thin':0.2, 'medium':1, 'thick':2}.get(css['border-%s-width' % edge], 0) * 8))) setattr(self, 'border_%s_width' % edge, 0)
setattr(self, 'border_%s_width' % edge, val) setattr(self, 'border_%s_color' % edge, None)
setattr(self, 'border_%s_color' % edge, convert_color(css['border-%s-color' % edge])) setattr(self, 'border_%s_style' % edge, 'none')
setattr(self, 'border_%s_style' % edge, LINE_STYLES.get(css['border-%s-style' % edge].lower(), 'none')) else:
# In DOCX padding can only be a positive integer
setattr(self, 'padding_' + edge, max(0, int(css['padding-' + edge])))
val = min(96, max(2, int({'thin':0.2, 'medium':1, 'thick':2}.get(css['border-%s-width' % edge], 0) * 8)))
setattr(self, 'border_%s_width' % edge, val)
setattr(self, 'border_%s_color' % edge, convert_color(css['border-%s-color' % edge]))
setattr(self, 'border_%s_style' % edge, LINE_STYLES.get(css['border-%s-style' % edge].lower(), 'none'))
DOCXStyle.__init__(self) DOCXStyle.__init__(self)
@ -331,8 +337,8 @@ class StylesManager(object):
def __init__(self): def __init__(self):
self.block_styles, self.text_styles = {}, {} self.block_styles, self.text_styles = {}, {}
def create_text_style(self, css_style): def create_text_style(self, css_style, is_parent_style=False):
ans = TextStyle(css_style) ans = TextStyle(css_style, is_parent_style=is_parent_style)
existing = self.text_styles.get(ans, None) existing = self.text_styles.get(ans, None)
if existing is None: if existing is None:
self.text_styles[ans] = ans self.text_styles[ans] = ans