def transform_declaration(decl): decl = StyleDeclaration(decl) changed = False for prop, parent_prop in tuple(decl): if prop.name in page_break_properties: changed = True name = prop.name.partition('-')[2] for prefix in ('', '-webkit-column-'): # Note that Firefox does not support break-after at all # https://bugzil.la/549114 decl.set_property(prefix + name, prop.value, prop.priority) decl.remove_property(prop, parent_prop) elif prop.name == 'font-size': raw = prop.value afs = absolute_font_sizes.get(raw) if afs is not None: changed = True decl.change_property(prop, parent_prop, afs) continue l, unit = parse_css_length(raw) if unit in absolute_units: changed = True l = convert_fontsize(l, unit) decl.change_property(prop, parent_prop, unicode_type(l) + 'rem') return changed
def parse_css_length_or_number(raw, default_unit=None): if isinstance(raw, (int, long, float)): return raw, default_unit try: return float(raw), default_unit except Exception: return parse_css_length(raw)
def transform_declaration(decl): decl = StyleDeclaration(decl) changed = False for prop, parent_prop in tuple(decl): if prop.name in {'page-break-before', 'page-break-after', 'page-break-inside'}: changed = True name = prop.name.partition('-')[2] for prefix in ('', '-webkit-column-'): # Note that Firefox does not support break-after at all # https://bugzil.la/549114 decl.set_property(prefix + name, prop.value, prop.priority) decl.remove_property(prop, parent_prop) elif prop.name == 'font-size': l, unit = parse_css_length(prop.value) if unit in absolute_units: changed = True l = convert_fontsize(l, unit) decl.change_property(prop, parent_prop, str(l) + 'rem') return changed
def transform_declaration(decl): decl = StyleDeclaration(decl) changed = False nonstandard_writing_mode_props = {} standard_writing_mode_props = {} for prop, parent_prop in tuple(decl): if prop.name in page_break_properties: changed = True name = prop.name.partition('-')[2] for prefix in ('', '-webkit-column-'): # Note that Firefox does not support break-after at all # https://bugzil.la/549114 decl.set_property(prefix + name, prop.value, prop.priority) decl.remove_property(prop, parent_prop) elif prop.name == 'font-size': raw = prop.value afs = absolute_font_sizes.get(raw) if afs is not None: changed = True decl.change_property(prop, parent_prop, afs) continue l, unit = parse_css_length(raw) if unit in absolute_units: changed = True l = convert_fontsize(l, unit) decl.change_property(prop, parent_prop, unicode_type(l) + 'rem') elif prop.name in nonstandard_writing_mode_property_names: nonstandard_writing_mode_props[prop.value] = prop.priority elif prop.name == 'writing-mode': standard_writing_mode_props[prop.value] = True # Add standard writing-mode properties if they don't exist so that # all of the browsers supported by the viewer work in vertical modes for value, priority in nonstandard_writing_mode_props.items(): if value not in standard_writing_mode_props: decl.set_property('writing-mode', value, priority) changed = True return changed
def serialize_properties(self, pPr, normal_style): makeelement, w = self.makeelement, self.w spacing = makeelement(pPr, 'spacing') for edge, attr in iteritems({'top': 'before', 'bottom': 'after'}): getter = attrgetter('css_margin_' + edge) css_val, css_unit = parse_css_length(getter(self)) if css_unit in ('em', 'ex'): lines = max(0, int(css_val * (50 if css_unit == 'ex' else 100))) if (self is normal_style and lines > 0) or getter(self) != getter(normal_style): spacing.set(w(attr + 'Lines'), unicode_type(lines)) else: getter = attrgetter('margin_' + edge) val = getter(self) if (self is normal_style and val > 0) or val != getter(normal_style): spacing.set(w(attr), unicode_type(val)) if self is normal_style or self.line_height != normal_style.line_height: spacing.set(w('line'), unicode_type(self.line_height)) spacing.set(w('lineRule'), 'atLeast') if spacing.attrib: pPr.append(spacing) ind = makeelement(pPr, 'ind') for edge in ('left', 'right'): getter = attrgetter('css_margin_' + edge) css_val, css_unit = parse_css_length(getter(self)) if css_unit in ('em', 'ex'): chars = max(0, int(css_val * (50 if css_unit == 'ex' else 100))) if (self is normal_style and chars > 0) or getter(self) != getter(normal_style): ind.set(w(edge + 'Chars'), unicode_type(chars)) else: getter = attrgetter('margin_' + edge) val = getter(self) if (self is normal_style and val > 0) or val != getter(normal_style): ind.set(w(edge), unicode_type(val)) ind.set( w(edge + 'Chars'), '0' ) # This is needed to override any declaration in the parent style css_val, css_unit = parse_css_length(self.css_text_indent) if css_unit in ('em', 'ex'): chars = int(css_val * (50 if css_unit == 'ex' else 100)) if css_val >= 0: if (self is normal_style and chars > 0 ) or self.css_text_indent != normal_style.css_text_indent: ind.set(w('firstLineChars'), unicode_type(chars)) else: if (self is normal_style and chars < 0 ) or self.css_text_indent != normal_style.css_text_indent: ind.set(w('hangingChars'), unicode_type(abs(chars))) else: val = self.text_indent if val >= 0: if (self is normal_style and val > 0 ) or self.text_indent != normal_style.text_indent: ind.set(w('firstLine'), unicode_type(val)) ind.set( w('firstLineChars'), '0' ) # This is needed to override any declaration in the parent style else: if (self is normal_style and val < 0 ) or self.text_indent != normal_style.text_indent: ind.set(w('hanging'), unicode_type(abs(val))) ind.set(w('hangingChars'), '0') if ind.attrib: pPr.append(ind) if (self is normal_style and self.background_color ) or self.background_color != normal_style.background_color: pPr.append( makeelement(pPr, 'shd', val='clear', color='auto', fill=self.background_color or 'auto')) pbdr = self.serialize_borders(pPr.makeelement(w('pBdr')), normal_style) if len(pbdr): pPr.append(pbdr) if self is normal_style or self.text_align != normal_style.text_align: pPr.append(makeelement(pPr, 'jc', val=self.text_align)) if self is not normal_style and self.next_style is not None: pPr.append(makeelement(pPr, 'next', val=self.next_style))
def serialize(self, styles, normal_style): w, makeelement = self.w, self.makeelement style_root = DOCXStyle.serialize(self, styles, normal_style) style = makeelement(style_root, 'pPr') spacing = makeelement(style, 'spacing') for edge, attr in {'top': 'before', 'bottom': 'after'}.iteritems(): getter = attrgetter('css_margin_' + edge) css_val, css_unit = parse_css_length(getter(self)) if css_unit in ('em', 'ex'): lines = max(0, int(css_val * (50 if css_unit == 'ex' else 100))) if (self is normal_style and lines > 0) or getter(self) != getter(normal_style): spacing.set(w(attr + 'Lines'), str(lines)) else: getter = attrgetter('margin_' + edge) val = getter(self) if (self is normal_style and val > 0) or val != getter(normal_style): spacing.set(w(attr), str(val)) if self is normal_style or self.line_height != normal_style.line_height: spacing.set(w('line'), str(self.line_height)) spacing.set(w('lineRule'), 'atLeast') if spacing.attrib: style.append(spacing) ind = makeelement(style, 'ind') for edge in ('left', 'right'): getter = attrgetter('css_margin_' + edge) css_val, css_unit = parse_css_length(getter(self)) if css_unit in ('em', 'ex'): chars = max(0, int(css_val * (50 if css_unit == 'ex' else 100))) if (self is normal_style and chars > 0) or getter(self) != getter(normal_style): ind.set(w(edge + 'Chars'), str(chars)) else: getter = attrgetter('margin_' + edge) val = getter(self) if (self is normal_style and val > 0) or val != getter(normal_style): ind.set(w(edge), str(val)) css_val, css_unit = parse_css_length(self.css_text_indent) if css_unit in ('em', 'ex'): chars = max(0, int(css_val * (50 if css_unit == 'ex' else 100))) if (self is normal_style and chars > 0 ) or self.css_text_indent != normal_style.css_text_indent: ind.set('firstLineChars', str(chars)) else: val = self.text_indent if (self is normal_style and val > 0) or self.text_indent != normal_style.text_indent: ind.set('firstLine', str(val)) if ind.attrib: style.append(ind) if (self is normal_style and self.background_color ) or self.background_color != normal_style.background_color: style.append( makeelement(style, 'shd', val='clear', color='auto', fill=self.background_color or 'auto')) pbdr = self.serialize_borders(style.makeelement(w('pBdr')), normal_style) if len(pbdr): style.append(pbdr) if self is normal_style or self.text_align != normal_style.text_align: style.append(makeelement(style, 'jc', val=self.text_align)) if (self is normal_style and self.page_break_before ) or self.page_break_before != normal_style.page_break_before: style.append( makeelement(style, 'pageBreakBefore', val=bmap(self.page_break_before))) if (self is normal_style and self.keep_lines) or self.keep_lines != normal_style.keep_lines: style.append( makeelement(style, 'keepLines', val=bmap(self.keep_lines))) if self is not normal_style and self.next_style is not None: style.append(makeelement(style, 'next', val=self.next_style)) if len(style) > 0: style_root.append(style) return style_root
def serialize(self, styles, normal_style): style_root = DOCXStyle.serialize(self, styles, normal_style) style = makeelement(style_root, 'pPr') spacing = makeelement(style, 'spacing') for edge, attr in {'top':'before', 'bottom':'after'}.iteritems(): getter = attrgetter('css_margin_' + edge) css_val, css_unit = parse_css_length(getter(self)) if css_unit in ('em', 'ex'): lines = max(0, int(css_val * (50 if css_unit == 'ex' else 100))) if (self is normal_style and lines > 0) or getter(self) != getter(normal_style): spacing.set(w(attr + 'Lines'), str(lines)) else: getter = attrgetter('margin_' + edge) val = getter(self) if (self is normal_style and val > 0) or val != getter(normal_style): spacing.set(w(attr), str(val)) if (self is normal_style and self.css_line_height != 'normal') or self.css_line_height != normal_style.css_line_height: try: css_val, css_unit = float(self.css_line_height), 'ratio' except Exception: css_val, css_unit = parse_css_length(self.css_line_height) if css_unit in {'em', 'ex', '%', 'ratio'}: mult = {'ex':0.5, '%':0.01}.get(css_unit, 1) val = int(css_val * 240 * mult) spacing.set(w('line'), str(val)) else: spacing.set(w('line'), str(0 if self.css_line_height == 'normal' else self.line_height)) spacing.set(w('lineRule'), 'exactly') if spacing.attrib: style.append(spacing) ind = makeelement(style, 'ind') for edge in ('left', 'right'): getter = attrgetter('css_margin_' + edge) css_val, css_unit = parse_css_length(getter(self)) if css_unit in ('em', 'ex'): chars = max(0, int(css_val * (50 if css_unit == 'ex' else 100))) if (self is normal_style and chars > 0) or getter(self) != getter(normal_style): ind.set(w(edge + 'Chars'), str(chars)) else: getter = attrgetter('margin_' + edge) val = getter(self) if (self is normal_style and val > 0) or val != getter(normal_style): ind.set(w(edge), str(val)) css_val, css_unit = parse_css_length(self.css_text_indent) if css_unit in ('em', 'ex'): chars = max(0, int(css_val * (50 if css_unit == 'ex' else 100))) if (self is normal_style and chars > 0) or self.css_text_indent != normal_style.css_text_indent: ind.set('firstLineChars', str(chars)) else: val = self.text_indent if (self is normal_style and val > 0) or self.text_indent != normal_style.text_indent: ind.set('firstLine', str(val)) if ind.attrib: style.append(ind) if (self is normal_style and self.background_color) or self.background_color != normal_style.background_color: style.append(makeelement(style, 'shd', val='clear', color='auto', fill=self.background_color or 'auto')) pbdr = self.serialize_borders(style.makeelement(w('pBdr')), normal_style) if len(pbdr): style.append(pbdr) if self is normal_style or self.text_align != normal_style.text_align: style.append(makeelement(style, 'jc', val=self.text_align)) if (self is normal_style and self.page_break_before) or self.page_break_before != normal_style.page_break_before: style.append(makeelement(style, 'pageBreakBefore', val=bmap(self.page_break_before))) if (self is normal_style and self.keep_lines) or self.keep_lines != normal_style.keep_lines: style.append(makeelement(style, 'keepLines', bmap(self.keep_lines))) if self is not normal_style and self.next_style is not None: style.append(makeelement(style, 'next', val=self.next_style)) if len(style) > 0: style_root.append(style) return style_root
def serialize(self, styles, normal_style): w, makeelement = self.w, self.makeelement style_root = DOCXStyle.serialize(self, styles, normal_style) style = makeelement(style_root, 'pPr') spacing = makeelement(style, 'spacing') for edge, attr in {'top':'before', 'bottom':'after'}.iteritems(): getter = attrgetter('css_margin_' + edge) css_val, css_unit = parse_css_length(getter(self)) if css_unit in ('em', 'ex'): lines = max(0, int(css_val * (50 if css_unit == 'ex' else 100))) if (self is normal_style and lines > 0) or getter(self) != getter(normal_style): spacing.set(w(attr + 'Lines'), str(lines)) else: getter = attrgetter('margin_' + edge) val = getter(self) if (self is normal_style and val > 0) or val != getter(normal_style): spacing.set(w(attr), str(val)) if self is normal_style or self.line_height != normal_style.line_height: spacing.set(w('line'), str(self.line_height)) spacing.set(w('lineRule'), 'atLeast') if spacing.attrib: style.append(spacing) ind = makeelement(style, 'ind') for edge in ('left', 'right'): getter = attrgetter('css_margin_' + edge) css_val, css_unit = parse_css_length(getter(self)) if css_unit in ('em', 'ex'): chars = max(0, int(css_val * (50 if css_unit == 'ex' else 100))) if (self is normal_style and chars > 0) or getter(self) != getter(normal_style): ind.set(w(edge + 'Chars'), str(chars)) else: getter = attrgetter('margin_' + edge) val = getter(self) if (self is normal_style and val > 0) or val != getter(normal_style): ind.set(w(edge), str(val)) ind.set(w(edge + 'Chars'), '0') # This is needed to override any declaration in the parent style css_val, css_unit = parse_css_length(self.css_text_indent) if css_unit in ('em', 'ex'): chars = int(css_val * (50 if css_unit == 'ex' else 100)) if css_val >= 0: if (self is normal_style and chars > 0) or self.css_text_indent != normal_style.css_text_indent: ind.set(w('firstLineChars'), str(chars)) else: if (self is normal_style and chars < 0) or self.css_text_indent != normal_style.css_text_indent: ind.set(w('hangingChars'), str(abs(chars))) else: val = self.text_indent if val >= 0: if (self is normal_style and val > 0) or self.text_indent != normal_style.text_indent: ind.set(w('firstLine'), str(val)) ind.set(w('firstLineChars'), '0') # This is needed to override any declaration in the parent style else: if (self is normal_style and val < 0) or self.text_indent != normal_style.text_indent: ind.set(w('hanging'), str(abs(val))) ind.set(w('hangingChars'), '0') if ind.attrib: style.append(ind) if (self is normal_style and self.background_color) or self.background_color != normal_style.background_color: style.append(makeelement(style, 'shd', val='clear', color='auto', fill=self.background_color or 'auto')) pbdr = self.serialize_borders(style.makeelement(w('pBdr')), normal_style) if len(pbdr): style.append(pbdr) if self is normal_style or self.text_align != normal_style.text_align: style.append(makeelement(style, 'jc', val=self.text_align)) if (self is normal_style and self.page_break_before) or self.page_break_before != normal_style.page_break_before: style.append(makeelement(style, 'pageBreakBefore', val=bmap(self.page_break_before))) if (self is normal_style and self.keep_lines) or self.keep_lines != normal_style.keep_lines: style.append(makeelement(style, 'keepLines', val=bmap(self.keep_lines))) if self is not normal_style and self.next_style is not None: style.append(makeelement(style, 'next', val=self.next_style)) if len(style) > 0: style_root.append(style) return style_root
def serialize(self, style): spacing = style.makeelement(w('spacing')) for edge, attr in {'top':'before', 'bottom':'after'}.iteritems(): css_val, css_unit = parse_css_length(getattr(self, 'css_margin_' + edge)) if css_unit in ('em', 'ex'): lines = max(0, int(css_val * (50 if css_unit == 'ex' else 100))) if lines > 0: spacing.set(w(attr + 'Lines'), str(lines)) else: val = getattr(self, 'margin_' + edge) if val > 0: spacing.set(w(attr), str(val)) if self.css_line_height != 'normal': try: css_val, css_unit = float(self.css_line_height), 'ratio' except Exception: css_val, css_unit = parse_css_length(self.css_line_height) if css_unit in {'em', 'ex', '%', 'ratio'}: mult = {'ex':0.5, '%':0.01}.get(css_unit, 1) val = int(css_val * 240 * mult) spacing.set(w('line'), str(val)) else: spacing.set(w('line'), str(self.line_height)) spacing.set(w('lineRule', 'exactly')) if spacing.attrib: style.append(spacing) ind = style.makeelement(w('ind')) for edge in ('left', 'right'): css_val, css_unit = parse_css_length(getattr(self, 'css_margin_' + edge)) if css_unit in ('em', 'ex'): chars = max(0, int(css_val * (50 if css_unit == 'ex' else 100))) if chars > 0: ind.set(w(edge + 'Chars'), str(chars)) else: val = getattr(self, 'margin_' + edge) if val > 0: ind.set(w(attr), str(val)) css_val, css_unit = parse_css_length(self.css_text_indent) if css_unit in ('em', 'ex'): chars = max(0, int(css_val * (50 if css_unit == 'ex' else 100))) if chars > 0: ind.set('firstLineChars', str(chars)) else: val = self.text_indent if val > 0: ind.set('firstLine', str(val)) if ind.attrib: style.append(ind) if self.background_color: shd = style.makeelement(w('shd')) style.append(shd) shd.set(w('val'), 'clear'), shd.set(w('fill'), self.background_color), shd.set(w('color'), 'auto') pbdr = self.serialize_borders(style.makeelement(w('pBdr'))) if len(pbdr): style.append(pbdr) jc = style.makeelement(w('jc')) jc.set(w('val'), self.text_align) style.append(jc) if self.page_break_before: style.append(style.makeelement(w('pageBreakBefore'), **{w('val'):'on'})) if self.keep_lines: style.append(style.makeelement(w('keepLines'), **{w('val'):'on'})) return style
def serialize_properties(self, pPr, normal_style): makeelement, w = self.makeelement, self.w spacing = makeelement(pPr, "spacing") for edge, attr in {"top": "before", "bottom": "after"}.iteritems(): getter = attrgetter("css_margin_" + edge) css_val, css_unit = parse_css_length(getter(self)) if css_unit in ("em", "ex"): lines = max(0, int(css_val * (50 if css_unit == "ex" else 100))) if (self is normal_style and lines > 0) or getter(self) != getter(normal_style): spacing.set(w(attr + "Lines"), str(lines)) else: getter = attrgetter("margin_" + edge) val = getter(self) if (self is normal_style and val > 0) or val != getter(normal_style): spacing.set(w(attr), str(val)) if self is normal_style or self.line_height != normal_style.line_height: spacing.set(w("line"), str(self.line_height)) spacing.set(w("lineRule"), "atLeast") if spacing.attrib: pPr.append(spacing) ind = makeelement(pPr, "ind") for edge in ("left", "right"): getter = attrgetter("css_margin_" + edge) css_val, css_unit = parse_css_length(getter(self)) if css_unit in ("em", "ex"): chars = max(0, int(css_val * (50 if css_unit == "ex" else 100))) if (self is normal_style and chars > 0) or getter(self) != getter(normal_style): ind.set(w(edge + "Chars"), str(chars)) else: getter = attrgetter("margin_" + edge) val = getter(self) if (self is normal_style and val > 0) or val != getter(normal_style): ind.set(w(edge), str(val)) ind.set(w(edge + "Chars"), "0") # This is needed to override any declaration in the parent style css_val, css_unit = parse_css_length(self.css_text_indent) if css_unit in ("em", "ex"): chars = int(css_val * (50 if css_unit == "ex" else 100)) if css_val >= 0: if (self is normal_style and chars > 0) or self.css_text_indent != normal_style.css_text_indent: ind.set(w("firstLineChars"), str(chars)) else: if (self is normal_style and chars < 0) or self.css_text_indent != normal_style.css_text_indent: ind.set(w("hangingChars"), str(abs(chars))) else: val = self.text_indent if val >= 0: if (self is normal_style and val > 0) or self.text_indent != normal_style.text_indent: ind.set(w("firstLine"), str(val)) ind.set(w("firstLineChars"), "0") # This is needed to override any declaration in the parent style else: if (self is normal_style and val < 0) or self.text_indent != normal_style.text_indent: ind.set(w("hanging"), str(abs(val))) ind.set(w("hangingChars"), "0") if ind.attrib: pPr.append(ind) if (self is normal_style and self.background_color) or self.background_color != normal_style.background_color: pPr.append(makeelement(pPr, "shd", val="clear", color="auto", fill=self.background_color or "auto")) pbdr = self.serialize_borders(pPr.makeelement(w("pBdr")), normal_style) if len(pbdr): pPr.append(pbdr) if self is normal_style or self.text_align != normal_style.text_align: pPr.append(makeelement(pPr, "jc", val=self.text_align)) if self is not normal_style and self.next_style is not None: pPr.append(makeelement(pPr, "next", val=self.next_style))
def serialize_properties(self, pPr, normal_style): makeelement, w = self.makeelement, self.w spacing = makeelement(pPr, 'spacing') for edge, attr in iteritems({'top':'before', 'bottom':'after'}): getter = attrgetter('css_margin_' + edge) css_val, css_unit = parse_css_length(getter(self)) if css_unit in ('em', 'ex'): lines = max(0, int(css_val * (50 if css_unit == 'ex' else 100))) if (self is normal_style and lines > 0) or getter(self) != getter(normal_style): spacing.set(w(attr + 'Lines'), str(lines)) else: getter = attrgetter('margin_' + edge) val = getter(self) if (self is normal_style and val > 0) or val != getter(normal_style): spacing.set(w(attr), str(val)) if self is normal_style or self.line_height != normal_style.line_height: spacing.set(w('line'), str(self.line_height)) spacing.set(w('lineRule'), 'atLeast') if spacing.attrib: pPr.append(spacing) ind = makeelement(pPr, 'ind') for edge in ('left', 'right'): getter = attrgetter('css_margin_' + edge) css_val, css_unit = parse_css_length(getter(self)) if css_unit in ('em', 'ex'): chars = max(0, int(css_val * (50 if css_unit == 'ex' else 100))) if (self is normal_style and chars > 0) or getter(self) != getter(normal_style): ind.set(w(edge + 'Chars'), str(chars)) else: getter = attrgetter('margin_' + edge) val = getter(self) if (self is normal_style and val > 0) or val != getter(normal_style): ind.set(w(edge), str(val)) ind.set(w(edge + 'Chars'), '0') # This is needed to override any declaration in the parent style css_val, css_unit = parse_css_length(self.css_text_indent) if css_unit in ('em', 'ex'): chars = int(css_val * (50 if css_unit == 'ex' else 100)) if css_val >= 0: if (self is normal_style and chars > 0) or self.css_text_indent != normal_style.css_text_indent: ind.set(w('firstLineChars'), str(chars)) else: if (self is normal_style and chars < 0) or self.css_text_indent != normal_style.css_text_indent: ind.set(w('hangingChars'), str(abs(chars))) else: val = self.text_indent if val >= 0: if (self is normal_style and val > 0) or self.text_indent != normal_style.text_indent: ind.set(w('firstLine'), str(val)) ind.set(w('firstLineChars'), '0') # This is needed to override any declaration in the parent style else: if (self is normal_style and val < 0) or self.text_indent != normal_style.text_indent: ind.set(w('hanging'), str(abs(val))) ind.set(w('hangingChars'), '0') if ind.attrib: pPr.append(ind) if (self is normal_style and self.background_color) or self.background_color != normal_style.background_color: pPr.append(makeelement(pPr, 'shd', val='clear', color='auto', fill=self.background_color or 'auto')) pbdr = self.serialize_borders(pPr.makeelement(w('pBdr')), normal_style) if len(pbdr): pPr.append(pbdr) if self is normal_style or self.text_align != normal_style.text_align: pPr.append(makeelement(pPr, 'jc', val=self.text_align)) if self is not normal_style and self.next_style is not None: pPr.append(makeelement(pPr, 'next', val=self.next_style))