org.odftoolkit.odfdom.converter.internal.itext.StyleEngineForIText.java Source code

Java tutorial

Introduction

Here is the source code for org.odftoolkit.odfdom.converter.internal.itext.StyleEngineForIText.java

Source

/**
 * Copyright (C) 2011 Angelo Zerr <angelo.zerr@gmail.com> and Pascal Leclercq <pascal.leclercq@gmail.com>
 *
 * All rights reserved.
 *
 * Permission is hereby granted, free  of charge, to any person obtaining
 * a  copy  of this  software  and  associated  documentation files  (the
 * "Software"), to  deal in  the Software without  restriction, including
 * without limitation  the rights to  use, copy, modify,  merge, publish,
 * distribute,  sublicense, and/or sell  copies of  the Software,  and to
 * permit persons to whom the Software  is furnished to do so, subject to
 * the following conditions:
 *
 * The  above  copyright  notice  and  this permission  notice  shall  be
 * included in all copies or substantial portions of the Software.
 *
 * THE  SOFTWARE IS  PROVIDED  "AS  IS", WITHOUT  WARRANTY  OF ANY  KIND,
 * EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF
 * MERCHANTABILITY,    FITNESS    FOR    A   PARTICULAR    PURPOSE    AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE,  ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
package org.odftoolkit.odfdom.converter.internal.itext;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.odftoolkit.odfdom.converter.internal.AbstractStyleEngine;
import org.odftoolkit.odfdom.converter.internal.itext.stylable.StylableImage;
import org.odftoolkit.odfdom.converter.internal.itext.styles.Style;
import org.odftoolkit.odfdom.converter.internal.itext.styles.StyleBorder;
import org.odftoolkit.odfdom.converter.internal.itext.styles.StyleBreak;
import org.odftoolkit.odfdom.converter.internal.itext.styles.StyleColumnProperties;
import org.odftoolkit.odfdom.converter.internal.itext.styles.StyleColumnsProperties;
import org.odftoolkit.odfdom.converter.internal.itext.styles.StyleGraphicProperties;
import org.odftoolkit.odfdom.converter.internal.itext.styles.StyleHeaderFooterProperties;
import org.odftoolkit.odfdom.converter.internal.itext.styles.StyleLineHeight;
import org.odftoolkit.odfdom.converter.internal.itext.styles.StyleListProperties;
import org.odftoolkit.odfdom.converter.internal.itext.styles.StyleNumFormat;
import org.odftoolkit.odfdom.converter.internal.itext.styles.StylePageLayoutProperties;
import org.odftoolkit.odfdom.converter.internal.itext.styles.StyleParagraphProperties;
import org.odftoolkit.odfdom.converter.internal.itext.styles.StyleSectionProperties;
import org.odftoolkit.odfdom.converter.internal.itext.styles.StyleTableCellProperties;
import org.odftoolkit.odfdom.converter.internal.itext.styles.StyleTableProperties;
import org.odftoolkit.odfdom.converter.internal.itext.styles.StyleTableRowProperties;
import org.odftoolkit.odfdom.converter.internal.itext.styles.StyleTextProperties;
import org.odftoolkit.odfdom.converter.internal.utils.ODFUtils;
import org.odftoolkit.odfdom.converter.itext.PDFViaITextOptions;
import org.odftoolkit.odfdom.doc.OdfDocument;
import org.odftoolkit.odfdom.dom.attribute.fo.FoBreakBeforeAttribute;
import org.odftoolkit.odfdom.dom.attribute.fo.FoFontStyleAttribute;
import org.odftoolkit.odfdom.dom.attribute.fo.FoFontWeightAttribute;
import org.odftoolkit.odfdom.dom.attribute.fo.FoKeepTogetherAttribute;
import org.odftoolkit.odfdom.dom.attribute.style.StyleNumFormatAttribute;
import org.odftoolkit.odfdom.dom.attribute.style.StyleTextLineThroughStyleAttribute;
import org.odftoolkit.odfdom.dom.attribute.style.StyleTextUnderlineStyleAttribute;
import org.odftoolkit.odfdom.dom.attribute.style.StyleWrapAttribute;
import org.odftoolkit.odfdom.dom.element.OdfStyleBase;
import org.odftoolkit.odfdom.dom.element.office.OfficeAutomaticStylesElement;
import org.odftoolkit.odfdom.dom.element.office.OfficeMasterStylesElement;
import org.odftoolkit.odfdom.dom.element.office.OfficeStylesElement;
import org.odftoolkit.odfdom.dom.element.style.StyleColumnElement;
import org.odftoolkit.odfdom.dom.element.style.StyleColumnsElement;
import org.odftoolkit.odfdom.dom.element.style.StyleDefaultStyleElement;
import org.odftoolkit.odfdom.dom.element.style.StyleFooterStyleElement;
import org.odftoolkit.odfdom.dom.element.style.StyleGraphicPropertiesElement;
import org.odftoolkit.odfdom.dom.element.style.StyleHeaderFooterPropertiesElement;
import org.odftoolkit.odfdom.dom.element.style.StyleListLevelLabelAlignmentElement;
import org.odftoolkit.odfdom.dom.element.style.StyleListLevelPropertiesElement;
import org.odftoolkit.odfdom.dom.element.style.StylePageLayoutElement;
import org.odftoolkit.odfdom.dom.element.style.StylePageLayoutPropertiesElement;
import org.odftoolkit.odfdom.dom.element.style.StyleParagraphPropertiesElement;
import org.odftoolkit.odfdom.dom.element.style.StyleSectionPropertiesElement;
import org.odftoolkit.odfdom.dom.element.style.StyleStyleElement;
import org.odftoolkit.odfdom.dom.element.style.StyleTableCellPropertiesElement;
import org.odftoolkit.odfdom.dom.element.style.StyleTablePropertiesElement;
import org.odftoolkit.odfdom.dom.element.style.StyleTableRowPropertiesElement;
import org.odftoolkit.odfdom.dom.element.style.StyleTextPropertiesElement;
import org.odftoolkit.odfdom.dom.element.text.TextListLevelStyleBulletElement;
import org.odftoolkit.odfdom.dom.element.text.TextListLevelStyleImageElement;
import org.odftoolkit.odfdom.dom.element.text.TextListLevelStyleNumberElement;
import org.odftoolkit.odfdom.dom.element.text.TextListStyleElement;
import org.w3c.dom.Node;

import com.lowagie.text.Element;
import com.lowagie.text.Font;
import com.lowagie.text.Image;

import fr.opensagres.xdocreport.itext.extension.PageOrientation;
import fr.opensagres.xdocreport.utils.BorderType;
import fr.opensagres.xdocreport.utils.StringUtils;

/**
 * fixes for pdf conversion by Leszek Piotrowicz <leszekp@safe-mail.net>
 */
public class StyleEngineForIText extends AbstractStyleEngine {

    private static final String PORTRAIT = "portrait";

    private static final String LANDSCAPE = "landscape";

    private static final String BOTTOM = "bottom";

    private static final String MIDDLE = "middle";

    private static final String TOP = "top";

    private static final String BASELINE = "baseline";

    private Style currentStyle = null;

    private Integer currentTextLevel;

    private final PDFViaITextOptions options;

    private final Map<String, Style> stylesMap = new HashMap<String, Style>();

    public StyleEngineForIText(OdfDocument odfDocument, PDFViaITextOptions options) {
        super(odfDocument);
        this.options = options != null ? options : PDFViaITextOptions.create();
    }

    public void visit(OfficeStylesElement ele) {
        super.visit(ele);
    }

    public void visit(OfficeAutomaticStylesElement ele) {
        super.visit(ele);
    }

    public void visit(OfficeMasterStylesElement ele) {
        super.visit(ele);
    }

    public void visit(StyleDefaultStyleElement ele) {
        computeStyle(ele, true);
    }

    public void visit(StyleStyleElement ele) {
        computeStyle(ele, false);
    }

    public void visit(StylePageLayoutElement ele) {
        computeStyle(ele, false);
    }

    private Style computeStyle(OdfStyleBase styleBase, boolean isDefaultStyle) {
        if (styleBase == null) {
            return null;
        }
        // 1) Check if style is in the cache
        String familyName = styleBase.getFamilyName();
        String styleName = null;
        String masterPageName = null;
        if (!isDefaultStyle) {
            if (styleBase instanceof StyleStyleElement) {
                StyleStyleElement styleElement = (StyleStyleElement) styleBase;
                styleName = styleElement.getStyleNameAttribute();
                masterPageName = styleElement.getStyleMasterPageNameAttribute();
            } else if (styleBase instanceof StylePageLayoutElement) {
                styleName = ((StylePageLayoutElement) styleBase).getStyleNameAttribute();
            } else if (styleBase instanceof TextListStyleElement) {
                styleName = ((TextListStyleElement) styleBase).getStyleNameAttribute();
            }
        }

        String styleId = getStyleId(familyName, styleName);
        Style style = stylesMap.get(styleId);
        if (style != null) {
            // style already computed
            return style;
        }

        // 3) Create style
        style = new Style(styleName, familyName, masterPageName);

        // 4) Apply default style if needed
        // Style defaultStyle = null;
        // if (!isDefaultStyle) {
        // OdfDefaultStyle odfDefaultStyle = odfDocument.getDocumentStyles()
        // .getDefaultStyle(styleBase.getFamily());
        // if (odfDefaultStyle != null) {
        // defaultStyle = computeStyle(odfDefaultStyle, true);
        // }
        // if (defaultStyle != null) {
        // style.merge(defaultStyle);
        // }
        // }

        // 5) Apply Parent style
        List<Style> parentsStyles = null;
        OdfStyleBase parentStyleBase = styleBase.getParentStyle();
        while (parentStyleBase != null) {
            Style parentStyle = computeStyle(parentStyleBase, isDefaultStyle);
            if (parentStyle != null) {
                if (parentsStyles == null) {
                    parentsStyles = new ArrayList<Style>();
                }
                parentsStyles.add(0, parentStyle);
            }
            parentStyleBase = parentStyleBase.getParentStyle();
        }

        if (parentsStyles != null) {
            for (Style parentsStyle : parentsStyles) {
                style.merge(parentsStyle);
            }
        }
        // 6) Apply current style
        currentStyle = style;
        super.visit(styleBase);

        // 7) register style in the cache
        stylesMap.put(styleId, style);
        return style;
    }

    public void visit(StylePageLayoutPropertiesElement ele) {
        StylePageLayoutProperties pageLayoutProperties = currentStyle.getPageLayoutProperties();
        if (pageLayoutProperties == null) {
            pageLayoutProperties = new StylePageLayoutProperties();
            currentStyle.setPageLayoutProperties(pageLayoutProperties);
        }

        // background-color
        String backgroundColor = ele.getFoBackgroundColorAttribute();
        if (StringUtils.isNotEmpty(backgroundColor)) {
            // cssStyleSheet.setCSSProperty("background-color",
            // backgroundColor);
        }

        // border
        String border = ele.getFoBorderAttribute();
        if (StringUtils.isNotEmpty(border)) {
            // cssStyleSheet.setCSSProperty("border", border);
        }

        // border-bottom
        String borderBottom = ele.getFoBorderBottomAttribute();
        if (StringUtils.isNotEmpty(borderBottom)) {
            // cssStyleSheet.setCSSProperty("border-bottom", borderBottom);
        }

        // border-left
        String borderLeft = ele.getFoBorderLeftAttribute();
        if (StringUtils.isNotEmpty(borderLeft)) {
            // cssStyleSheet.setCSSProperty("border-left", borderLeft);
        }

        // border-bottom
        String borderRight = ele.getFoBorderRightAttribute();
        if (StringUtils.isNotEmpty(borderRight)) {
            // cssStyleSheet.setCSSProperty("border-right", borderRight);
        }

        // border-top
        String borderTop = ele.getFoBorderTopAttribute();
        if (StringUtils.isNotEmpty(borderTop)) {
            // cssStyleSheet.setCSSProperty("border-top", borderTop);
        }

        // margin
        String margin = ele.getFoMarginAttribute();
        if (StringUtils.isNotEmpty(margin)) {
            pageLayoutProperties.setMargin(ODFUtils.getDimensionAsPoint(margin));
        }

        // margin-bottom
        String marginBottom = ele.getFoMarginBottomAttribute();
        if (StringUtils.isNotEmpty(marginBottom)) {
            pageLayoutProperties.setMarginBottom(ODFUtils.getDimensionAsPoint(marginBottom));
        }

        // margin-left
        String marginLeft = ele.getFoMarginLeftAttribute();
        if (StringUtils.isNotEmpty(marginLeft)) {
            pageLayoutProperties.setMarginLeft(ODFUtils.getDimensionAsPoint(marginLeft));
        }

        // margin-right
        String marginRight = ele.getFoMarginRightAttribute();
        if (StringUtils.isNotEmpty(marginRight)) {
            pageLayoutProperties.setMarginRight(ODFUtils.getDimensionAsPoint(marginRight));
        }

        // margin-top
        String marginTop = ele.getFoMarginTopAttribute();
        if (StringUtils.isNotEmpty(marginTop)) {
            pageLayoutProperties.setMarginTop(ODFUtils.getDimensionAsPoint(marginTop));
        }

        // padding
        String padding = ele.getFoPaddingAttribute();
        if (StringUtils.isNotEmpty(padding)) {
            // cssStyleSheet.setCSSProperty("padding", padding);
        }

        // padding-bottom
        String paddingBottom = ele.getFoPaddingBottomAttribute();
        if (StringUtils.isNotEmpty(paddingBottom)) {
            // cssStyleSheet.setCSSProperty("padding-bottom", paddingBottom);
        }

        // padding-left
        String paddingLeft = ele.getFoPaddingLeftAttribute();
        if (StringUtils.isNotEmpty(paddingLeft)) {
            // cssStyleSheet.setCSSProperty("padding-left", paddingLeft);
        }

        // padding-bottom
        String paddingRight = ele.getFoPaddingRightAttribute();
        if (StringUtils.isNotEmpty(paddingRight)) {
            // cssStyleSheet.setCSSProperty("padding-right", paddingRight);
        }

        // padding-top
        String paddingTop = ele.getFoPaddingTopAttribute();
        if (StringUtils.isNotEmpty(paddingTop)) {
            // cssStyleSheet.setCSSProperty("padding-top", paddingTop);
        }

        // height
        String height = ele.getFoPageHeightAttribute();
        if (StringUtils.isNotEmpty(height)) {
            pageLayoutProperties.setHeight(ODFUtils.getDimensionAsPoint(height));
        }

        // width
        String width = ele.getFoPageWidthAttribute();
        if (StringUtils.isNotEmpty(width)) {
            pageLayoutProperties.setWidth(ODFUtils.getDimensionAsPoint(width));
        }

        // orientation
        String orientation = ele.getStylePrintOrientationAttribute();
        if (StringUtils.isNotEmpty(orientation)) {
            if (LANDSCAPE.equals(orientation)) {
                pageLayoutProperties.setOrientation(PageOrientation.Landscape);
            } else if (PORTRAIT.equals(orientation)) {
                pageLayoutProperties.setOrientation(PageOrientation.Portrait);
            }

        }
        super.visit(ele);

    }

    public void visit(StyleHeaderFooterPropertiesElement ele) {
        Node parentNode = ele.getParentNode();
        boolean footer = StyleFooterStyleElement.ELEMENT_NAME.getLocalName().equals(parentNode.getLocalName());

        StyleHeaderFooterProperties headerFooterProperties = null;
        if (!footer) {
            headerFooterProperties = currentStyle.getHeaderProperties();
            if (headerFooterProperties == null) {
                headerFooterProperties = new StyleHeaderFooterProperties();
                currentStyle.setHeaderProperties(headerFooterProperties);
            }
        } else {
            headerFooterProperties = currentStyle.getFooterProperties();
            if (headerFooterProperties == null) {
                headerFooterProperties = new StyleHeaderFooterProperties();
                currentStyle.setFooterProperties(headerFooterProperties);
            }
        }

        // min-height
        String minHeight = ele.getFoMinHeightAttribute();
        if (StringUtils.isNotEmpty(minHeight)) {
            headerFooterProperties.setMinHeight(ODFUtils.getDimensionAsPoint(minHeight));
        }

        // margin
        String margin = ele.getFoMarginAttribute();
        if (StringUtils.isNotEmpty(margin)) {
            headerFooterProperties.setMargin(ODFUtils.getDimensionAsPoint(margin));
        }

        // margin-bottom
        String marginBottom = ele.getFoMarginBottomAttribute();
        if (StringUtils.isNotEmpty(marginBottom)) {
            headerFooterProperties.setMarginBottom(ODFUtils.getDimensionAsPoint(marginBottom));
        }

        // margin-left
        String marginLeft = ele.getFoMarginLeftAttribute();
        if (StringUtils.isNotEmpty(marginLeft)) {
            headerFooterProperties.setMarginLeft(ODFUtils.getDimensionAsPoint(marginLeft));
        }

        // margin-right
        String marginRight = ele.getFoMarginRightAttribute();
        if (StringUtils.isNotEmpty(marginRight)) {
            headerFooterProperties.setMarginRight(ODFUtils.getDimensionAsPoint(marginRight));
        }
        // margin-top
        String marginTop = ele.getFoMarginTopAttribute();
        if (StringUtils.isNotEmpty(marginTop)) {
            headerFooterProperties.setMarginTop(ODFUtils.getDimensionAsPoint(marginTop));
        }
    }

    // visit //style:paragraph-properties
    @Override
    public void visit(StyleParagraphPropertiesElement ele) {

        StyleParagraphProperties paragraphProperties = currentStyle.getParagraphProperties();
        if (paragraphProperties == null) {
            paragraphProperties = new StyleParagraphProperties();
            currentStyle.setParagraphProperties(paragraphProperties);
        }

        // background-color
        String backgroundColor = ele.getFoBackgroundColorAttribute();
        if (StringUtils.isNotEmpty(backgroundColor)) {
            paragraphProperties.setBackgroundColor(ColorRegistry.getInstance().getColor(backgroundColor));
        }

        // border
        String border = ele.getFoBorderAttribute();
        if (StringUtils.isNotEmpty(border)) {
            paragraphProperties.setBorder(new StyleBorder(border, BorderType.ALL));
        }
        // border-bottom
        String borderBottom = ele.getFoBorderBottomAttribute();
        if (StringUtils.isNotEmpty(borderBottom)) {
            paragraphProperties.setBorderBottom(new StyleBorder(borderBottom, BorderType.BOTTOM));
        }

        // border-left
        String borderLeft = ele.getFoBorderLeftAttribute();
        if (StringUtils.isNotEmpty(borderLeft)) {
            paragraphProperties.setBorderLeft(new StyleBorder(borderLeft, BorderType.LEFT));
        }

        // border-bottom
        String borderRight = ele.getFoBorderRightAttribute();
        if (StringUtils.isNotEmpty(borderRight)) {
            paragraphProperties.setBorderRight(new StyleBorder(borderRight, BorderType.RIGHT));
        }

        // border-top
        String borderTop = ele.getFoBorderTopAttribute();
        if (StringUtils.isNotEmpty(borderTop)) {
            paragraphProperties.setBorderTop(new StyleBorder(borderTop, BorderType.TOP));
        }

        // line-height
        String lineHeight = ele.getFoLineHeightAttribute();
        if (StringUtils.isNotEmpty(lineHeight)) {
            paragraphProperties.setLineHeight(new StyleLineHeight(ODFUtils.getDimensionAsPoint(lineHeight),
                    ODFUtils.hasPercentUnit(lineHeight)));
        }

        // margin
        String margin = ele.getFoMarginAttribute();
        if (StringUtils.isNotEmpty(margin)) {
            paragraphProperties.setMargin(ODFUtils.getDimensionAsPoint(margin));
        }

        // margin-bottom
        String marginBottom = ele.getFoMarginBottomAttribute();
        if (StringUtils.isNotEmpty(marginBottom)) {
            paragraphProperties.setMarginBottom(ODFUtils.getDimensionAsPoint(marginBottom));
        }

        // margin-left
        String marginLeft = ele.getFoMarginLeftAttribute();
        if (StringUtils.isNotEmpty(marginLeft)) {
            paragraphProperties.setMarginLeft(ODFUtils.getDimensionAsPoint(marginLeft));
        }

        // margin-right
        String marginRight = ele.getFoMarginRightAttribute();
        if (StringUtils.isNotEmpty(marginRight)) {
            paragraphProperties.setMarginRight(ODFUtils.getDimensionAsPoint(marginRight));
        }

        // margin-top
        String marginTop = ele.getFoMarginTopAttribute();
        if (StringUtils.isNotEmpty(marginTop)) {
            paragraphProperties.setMarginTop(ODFUtils.getDimensionAsPoint(marginTop));
        }

        // padding
        String padding = ele.getFoPaddingAttribute();
        if (StringUtils.isNotEmpty(padding)) {
            // cssStyleSheet.setCSSProperty("padding", padding);
        }

        // padding-bottom
        String paddingBottom = ele.getFoPaddingBottomAttribute();
        if (StringUtils.isNotEmpty(paddingBottom)) {
            // cssStyleSheet.setCSSProperty("padding-bottom", paddingBottom);
        }

        // padding-left
        String paddingLeft = ele.getFoPaddingLeftAttribute();
        if (StringUtils.isNotEmpty(paddingLeft)) {
            // cssStyleSheet.setCSSProperty("padding-left", paddingLeft);
        }

        // padding-bottom
        String paddingRight = ele.getFoPaddingRightAttribute();
        if (StringUtils.isNotEmpty(paddingRight)) {
            // cssStyleSheet.setCSSProperty("padding-right", paddingRight);
        }

        // padding-top
        String paddingTop = ele.getFoPaddingTopAttribute();
        if (StringUtils.isNotEmpty(paddingTop)) {
            // cssStyleSheet.setCSSProperty("padding-top", paddingTop);
        }

        // text-align
        String textAlign = ele.getFoTextAlignAttribute();
        if (StringUtils.isNotEmpty(textAlign)) {
            int alignment = Element.ALIGN_UNDEFINED;
            if ("start".equals(textAlign)) {
                alignment = Element.ALIGN_LEFT;
            } else if ("end".equals(textAlign)) {
                alignment = Element.ALIGN_RIGHT;
            } else if ("left".equals(textAlign)) {
                alignment = Element.ALIGN_LEFT;
            } else if ("right".equals(textAlign)) {
                alignment = Element.ALIGN_RIGHT;
            } else if ("center".equals(textAlign)) {
                alignment = Element.ALIGN_CENTER;
            } else if ("justify".equals(textAlign)) {
                alignment = Element.ALIGN_JUSTIFIED;
            }
            paragraphProperties.setAlignment(alignment);
        }

        // auto-text-indent
        Boolean autoTextIndent = ele.getStyleAutoTextIndentAttribute();
        if (autoTextIndent != null) {
            paragraphProperties.setAutoTextIndent(autoTextIndent);
        }

        // text-indent
        String textIndent = ele.getFoTextIndentAttribute();
        if (StringUtils.isNotEmpty(textIndent)) {
            paragraphProperties.setTextIndent(ODFUtils.getDimensionAsPoint(textIndent));
        }

        // keep-together
        String keepTogether = ele.getFoKeepTogetherAttribute();
        if (StringUtils.isNotEmpty(keepTogether)) {
            if (FoKeepTogetherAttribute.Value.ALWAYS.toString().equals(keepTogether)) {
                paragraphProperties.setKeepTogether(Boolean.TRUE);
            } else {
                paragraphProperties.setKeepTogether(Boolean.FALSE);
            }
        }

        // fo:break-before
        String breakBefore = ele.getFoBreakBeforeAttribute();
        if (StringUtils.isNotEmpty(breakBefore)) {
            if (FoBreakBeforeAttribute.Value.PAGE.toString().equals(breakBefore)) {
                paragraphProperties.setBreakBefore(StyleBreak.createWithPageBreak());
            } else if (FoBreakBeforeAttribute.Value.COLUMN.toString().equals(breakBefore)) {
                paragraphProperties.setBreakBefore(StyleBreak.createWithColumnBreak());
            } else {
                paragraphProperties.setBreakBefore(StyleBreak.createWithNoBreak());
            }
        }

        super.visit(ele);
    }

    public void visit(StyleTextPropertiesElement ele) {
        StyleTextProperties textProperties = currentStyle.getTextProperties();
        if (textProperties == null) {
            textProperties = new StyleTextProperties();
            currentStyle.setTextProperties(textProperties);
        }

        // set font encoding from options
        textProperties.setFontEncoding(options.getFontEncoding());

        // background-color
        String backgroundColor = ele.getFoBackgroundColorAttribute();
        if (StringUtils.isNotEmpty(backgroundColor)) {
            textProperties.setBackgroundColor(ColorRegistry.getInstance().getColor(backgroundColor));
        }

        // color
        String color = ele.getFoColorAttribute();
        if (StringUtils.isNotEmpty(color)) {
            textProperties.setFontColor(ColorRegistry.getInstance().getColor(color));
        }

        // font-family
        String fontFamily = ele.getFoFontFamilyAttribute();
        if (StringUtils.isNotEmpty(fontFamily)) {
            textProperties.setFontName(fontFamily);
        }

        // font-name
        String fontName = ele.getStyleFontNameAttribute();
        if (StringUtils.isNotEmpty(fontName)) {
            textProperties.setFontName(fontName);
        }

        // font-size
        String fontSize = ele.getFoFontSizeAttribute();
        if (StringUtils.isNotEmpty(fontSize)) {
            if (ODFUtils.hasPercentUnit(fontSize)) {
                // relative
                if (textProperties.getFontSize() != Font.UNDEFINED) {
                    textProperties
                            .setFontSize(textProperties.getFontSize() * ODFUtils.getDimensionAsPoint(fontSize));
                }
            } else {
                // absolute
                textProperties.setFontSize(ODFUtils.getDimensionAsPoint(fontSize));
            }
        }

        // font-style
        String fontStyle = ele.getFoFontStyleAttribute();
        if (StringUtils.isNotEmpty(fontStyle)) {
            if (FoFontStyleAttribute.Value.NORMAL.toString().equals(fontStyle)) {
                textProperties.setFontItalic(Boolean.FALSE);
            } else {
                // interpret other values as italic
                textProperties.setFontItalic(Boolean.TRUE);
            }
        }

        // font-variant
        String fontVariant = ele.getFoFontVariantAttribute();
        if (StringUtils.isNotEmpty(fontVariant)) {
        }

        // font-weight
        String fontWeight = ele.getFoFontWeightAttribute();
        if (StringUtils.isNotEmpty(fontWeight)) {
            if (FoFontWeightAttribute.Value.NORMAL.toString().equals(fontWeight)) {
                textProperties.setFontBold(Boolean.FALSE);
            } else {
                // interpret other values as bold
                textProperties.setFontBold(Boolean.TRUE);
            }
        }

        // text-underline-style
        String underlineStyle = ele.getStyleTextUnderlineStyleAttribute();
        if (StringUtils.isNotEmpty(underlineStyle)) {
            if (StyleTextUnderlineStyleAttribute.Value.NONE.toString().equals(underlineStyle)) {
                textProperties.setFontUnderline(Boolean.FALSE);
            } else {
                // interpret other values as underline
                textProperties.setFontUnderline(Boolean.TRUE);
            }
        }

        // text-underline-type
        String underlineType = ele.getStyleTextUnderlineTypeAttribute();
        if (StringUtils.isNotEmpty(underlineType)) {
        }

        // text-line-through-style
        String lineThroughStyle = ele.getStyleTextLineThroughStyleAttribute();
        if (StringUtils.isNotEmpty(lineThroughStyle)) {
            if (StyleTextLineThroughStyleAttribute.Value.NONE.toString().equals(lineThroughStyle)) {
                textProperties.setFontStrikeThru(Boolean.FALSE);
            } else {
                // interpret other values as strike thru
                textProperties.setFontStrikeThru(Boolean.TRUE);
            }
        }

        super.visit(ele);
    }

    public void visit(StyleTablePropertiesElement ele) {

        StyleTableProperties tableProperties = new StyleTableProperties();
        currentStyle.setTableProperties(tableProperties);

        // background-color
        String backgroundColor = ele.getFoBackgroundColorAttribute();
        if (StringUtils.isNotEmpty(backgroundColor)) {
            tableProperties.setBackgroundColor(ColorRegistry.getInstance().getColor(backgroundColor));

        }

        // // margin
        // String margin = ele.getFoMarginAttribute();
        // if (StringUtils.isNotEmpty(margin)) {
        // cssStyleSheet.setCSSProperty("margin", margin);
        // }
        //
        // // margin-bottom
        // String marginBottom = ele.getFoMarginBottomAttribute();
        // if (StringUtils.isNotEmpty(marginBottom)) {
        // cssStyleSheet.setCSSProperty("margin-bottom", marginBottom);
        // }
        //
        // // margin-left
        // String marginLeft = ele.getFoMarginLeftAttribute();
        // if (StringUtils.isNotEmpty(marginLeft)) {
        // cssStyleSheet.setCSSProperty("margin-left", marginLeft);
        // }
        //
        // // margin-bottom
        // String marginRight = ele.getFoMarginRightAttribute();
        // if (StringUtils.isNotEmpty(marginRight)) {
        // cssStyleSheet.setCSSProperty("margin-right", marginRight);
        // }
        //
        // // margin-top
        // String marginTop = ele.getFoMarginTopAttribute();
        // if (StringUtils.isNotEmpty(marginTop)) {
        // cssStyleSheet.setCSSProperty("margin-top", marginTop);
        // }

        // width
        String width = ele.getStyleWidthAttribute();
        if (StringUtils.isNotEmpty(width)) {
            tableProperties.setWidth(ODFUtils.getDimensionAsPoint(width));
        }

        super.visit(ele);
    }

    // visit <style:style style:name="Tableau1.1"
    // style:family="table-row"><style:table-row-properties
    // style:row-height="0.801cm" style:keep-together="true" ...
    @Override
    public void visit(StyleTableRowPropertiesElement ele) {

        StyleTableRowProperties tableRowProperties = currentStyle.getTableRowProperties();
        if (tableRowProperties == null) {
            tableRowProperties = new StyleTableRowProperties();
            currentStyle.setTableRowProperties(tableRowProperties);
        }

        // min-height
        String minHeight = ele.getStyleMinRowHeightAttribute();
        if (StringUtils.isNotEmpty(minHeight)) {
            tableRowProperties.setMinRowHeight(ODFUtils.getDimensionAsPoint(minHeight));
        }

        // height
        String height = ele.getStyleRowHeightAttribute();
        if (StringUtils.isNotEmpty(height)) {
            tableRowProperties.setRowHeight(ODFUtils.getDimensionAsPoint(height));
        }

    }

    // visit <style:style ...
    // style:family="table-cell">/style:table-cell-properties

    @Override
    public void visit(StyleTableCellPropertiesElement ele) {
        StyleTableCellProperties tableCellProperties = currentStyle.getTableCellProperties();
        if (tableCellProperties == null) {
            tableCellProperties = new StyleTableCellProperties();
            currentStyle.setTableCellProperties(tableCellProperties);
        }

        // background-color
        String backgroundColor = ele.getFoBackgroundColorAttribute();
        if (StringUtils.isNotEmpty(backgroundColor)) {
            tableCellProperties.setBackgroundColor(ColorRegistry.getInstance().getColor(backgroundColor));
        }

        // border
        String border = ele.getFoBorderAttribute();
        if (StringUtils.isNotEmpty(border)) {
            tableCellProperties.setBorder(new StyleBorder(border, BorderType.ALL));
        }

        // border-bottom
        String borderBottom = ele.getFoBorderBottomAttribute();
        if (StringUtils.isNotEmpty(borderBottom)) {
            tableCellProperties.setBorderBottom(new StyleBorder(borderBottom, BorderType.BOTTOM));
        }

        // border-left
        String borderLeft = ele.getFoBorderLeftAttribute();
        if (StringUtils.isNotEmpty(borderLeft)) {
            tableCellProperties.setBorderLeft(new StyleBorder(borderLeft, BorderType.LEFT));
        }

        // border-bottom
        String borderRight = ele.getFoBorderRightAttribute();
        if (StringUtils.isNotEmpty(borderRight)) {
            tableCellProperties.setBorderRight(new StyleBorder(borderRight, BorderType.RIGHT));
        }

        // border-top
        String borderTop = ele.getFoBorderTopAttribute();
        if (StringUtils.isNotEmpty(borderTop)) {
            tableCellProperties.setBorderTop(new StyleBorder(borderTop, BorderType.TOP));
        }

        // padding
        String padding = ele.getFoPaddingAttribute();
        if (StringUtils.isNotEmpty(padding)) {
            tableCellProperties.setPadding(ODFUtils.getDimensionAsPoint(padding));
        }

        // padding-bottom
        String paddingBottom = ele.getFoPaddingBottomAttribute();
        if (StringUtils.isNotEmpty(paddingBottom)) {
            tableCellProperties.setPaddingBottom(ODFUtils.getDimensionAsPoint(paddingBottom));
        }

        // padding-left
        String paddingLeft = ele.getFoPaddingLeftAttribute();
        if (StringUtils.isNotEmpty(paddingLeft)) {
            tableCellProperties.setPaddingLeft(ODFUtils.getDimensionAsPoint(paddingLeft));
        }

        // padding-right
        String paddingRight = ele.getFoPaddingRightAttribute();
        if (StringUtils.isNotEmpty(paddingRight)) {
            tableCellProperties.setPaddingRight(ODFUtils.getDimensionAsPoint(paddingRight));
        }

        // padding-top
        String paddingTop = ele.getFoPaddingTopAttribute();
        if (StringUtils.isNotEmpty(paddingTop)) {
            tableCellProperties.setPaddingTop(ODFUtils.getDimensionAsPoint(paddingTop));
        }

        // vertical-align
        String verticalAlign = ele.getStyleVerticalAlignAttribute();
        if (StringUtils.isNotEmpty(verticalAlign)) {
            if (BASELINE.equals(verticalAlign)) {
                tableCellProperties.setVerticalAlignment(Element.ALIGN_BASELINE);
            } else if (TOP.equals(verticalAlign)) {
                tableCellProperties.setVerticalAlignment(Element.ALIGN_TOP);
            } else if (MIDDLE.equals(verticalAlign)) {
                tableCellProperties.setVerticalAlignment(Element.ALIGN_MIDDLE);
            } else if (BOTTOM.equals(verticalAlign)) {
                tableCellProperties.setVerticalAlignment(Element.ALIGN_BOTTOM);
            }
        }

        super.visit(ele);
    }

    // visit //style:graphic-properties
    @Override
    public void visit(StyleGraphicPropertiesElement ele) {
        StyleGraphicProperties graphicProperties = currentStyle.getGraphicProperties();
        if (graphicProperties == null) {
            graphicProperties = new StyleGraphicProperties();
            currentStyle.setGraphicProperties(graphicProperties);
        }

        // wrap
        String wrap = ele.getStyleWrapAttribute();
        if (StringUtils.isNotEmpty(wrap)) {
            if (StyleWrapAttribute.Value.RUN_THROUGH.toString().equals(wrap)) {
                graphicProperties.setRunThrough(Boolean.TRUE);
            } else {
                // other values are not supported
                graphicProperties.setRunThrough(Boolean.FALSE);
            }
        }

        super.visit(ele);
    }

    // list styling is a bit complicated because of nesting
    // we flatten the structure into a map of {list-level->StyleListProperties}
    //
    // 1st level - text:list-style --- enclosing style
    // 2nd level --- text:list-level-style-bullet --- if list item label is a char
    // 2nd level --- text:list-level-style-image --- if list item label is an image
    // 2nd level --- text:list-level-style-number --- if list item label is a number
    // 3rd level ----- style:list-level-properties --- optional image dimensions
    // 4th level ------- style:list-level-label-alignment --- indentation info
    @Override
    public void visit(TextListStyleElement ele) {
        computeStyle(ele, false);
    }

    @Override
    public void visit(TextListLevelStyleBulletElement ele) {
        Integer textLevel = ele.getTextLevelAttribute();
        if (textLevel == null) {
            return;
        }
        currentTextLevel = textLevel;
        StyleListProperties listProperties = getStyleListProperties();

        // text style to apply to list item label
        String styleName = ele.getTextStyleNameAttribute();
        if (StringUtils.isNotEmpty(styleName)) {
            // TODO what if this style is not computed yet?
            Style style = getStyle("text", styleName, null);
            currentStyle.merge(style);
        }

        // bullet-char
        String bulletChar = ele.getTextBulletCharAttribute();
        if (StringUtils.isNotEmpty(bulletChar)) {
            listProperties.setBulletChar(bulletChar);
        }

        // num-prefix
        String numPrefix = ele.getStyleNumPrefixAttribute();
        if (StringUtils.isNotEmpty(numPrefix)) {
            listProperties.setNumPrefix(numPrefix);
        }

        // num-suffix
        String numSuffix = ele.getStyleNumSuffixAttribute();
        if (StringUtils.isNotEmpty(numSuffix)) {
            listProperties.setNumSuffix(numSuffix);
        }

        super.visit(ele);
        currentTextLevel = 0;
    }

    @Override
    public void visit(TextListLevelStyleImageElement ele) {
        Integer textLevel = ele.getTextLevelAttribute();
        if (textLevel == null) {
            return;
        }
        currentTextLevel = textLevel;
        StyleListProperties listProperties = getStyleListProperties();

        // image href
        String href = ele.getXlinkHrefAttribute();
        if (StringUtils.isNotEmpty(href)) {
            byte[] imageStream = odfDocument.getPackage().getBytes(href);
            if (imageStream != null) {
                Image imageObj = StylableImage.getImage(imageStream);
                if (imageObj != null) {
                    listProperties.setImage(imageObj);
                }
            }
        }

        super.visit(ele);
        currentTextLevel = 0;
    }

    @Override
    public void visit(TextListLevelStyleNumberElement ele) {
        Integer textLevel = ele.getTextLevelAttribute();
        if (textLevel == null) {
            return;
        }
        currentTextLevel = textLevel;
        StyleListProperties listProperties = getStyleListProperties();

        // text style to apply to list item label
        String styleName = ele.getTextStyleNameAttribute();
        if (StringUtils.isNotEmpty(styleName)) {
            // TODO what if this style is not computed yet?
            Style style = getStyle("text", styleName, null);
            currentStyle.merge(style);
        }

        // start-value
        Integer startValue = ele.getTextStartValueAttribute();
        if (startValue != null) {
            listProperties.setStartValue(startValue);
        }

        // num-prefix
        String numPrefix = ele.getStyleNumPrefixAttribute();
        if (StringUtils.isNotEmpty(numPrefix)) {
            listProperties.setNumPrefix(numPrefix);
        }

        // num-suffix
        String numSuffix = ele.getStyleNumSuffixAttribute();
        if (StringUtils.isNotEmpty(numSuffix)) {
            listProperties.setNumSuffix(numSuffix);
        }

        // num-format
        String numFormat = ele.getStyleNumFormatAttribute();
        if (StringUtils.isNotEmpty(numFormat)) {
            if (StyleNumFormatAttribute.Value.a.toString().equals(numFormat)) {
                listProperties.setNumFormat(StyleNumFormat.createAlphabetical(true));
            } else if (StyleNumFormatAttribute.Value.A.toString().equals(numFormat)) {
                listProperties.setNumFormat(StyleNumFormat.createAlphabetical(false));
            } else if (StyleNumFormatAttribute.Value.i.toString().equals(numFormat)) {
                listProperties.setNumFormat(StyleNumFormat.createRoman(true));
            } else if (StyleNumFormatAttribute.Value.I.toString().equals(numFormat)) {
                listProperties.setNumFormat(StyleNumFormat.createRoman(false));
            } else {
                listProperties.setNumFormat(StyleNumFormat.createNumerical());
            }
        }

        super.visit(ele);
        currentTextLevel = 0;
    }

    @Override
    public void visit(StyleListLevelPropertiesElement ele) {
        if (currentTextLevel == null) {
            return;
        }
        StyleListProperties listProperties = getStyleListProperties();

        // width
        String width = ele.getFoWidthAttribute();
        if (StringUtils.isNotEmpty(width)) {
            listProperties.setWidth(ODFUtils.getDimensionAsPoint(width));
        }

        // height
        String height = ele.getFoHeightAttribute();
        if (StringUtils.isNotEmpty(height)) {
            listProperties.setHeight(ODFUtils.getDimensionAsPoint(height));
        }

        super.visit(ele);
    }

    @Override
    public void visit(StyleListLevelLabelAlignmentElement ele) {
        if (currentTextLevel == null) {
            return;
        }
        StyleListProperties listProperties = getStyleListProperties();

        // margin-left
        String marginLeft = ele.getFoMarginLeftAttribute();
        if (StringUtils.isNotEmpty(marginLeft)) {
            listProperties.setMarginLeft(ODFUtils.getDimensionAsPoint(marginLeft));
        }

        // text-indent
        String textIndent = ele.getFoTextIndentAttribute();
        if (StringUtils.isNotEmpty(textIndent)) {
            listProperties.setTextIndent(ODFUtils.getDimensionAsPoint(textIndent));
        }

        super.visit(ele);
    }

    private StyleListProperties getStyleListProperties() {
        Map<Integer, StyleListProperties> listPropertiesMap = currentStyle.getListPropertiesMap();
        if (listPropertiesMap == null) {
            listPropertiesMap = new HashMap<Integer, StyleListProperties>();
            currentStyle.setListPropertiesMap(listPropertiesMap);
        }
        StyleListProperties listProperties = listPropertiesMap.get(currentTextLevel);
        if (listProperties == null) {
            listProperties = new StyleListProperties();
            listPropertiesMap.put(currentTextLevel, listProperties);
        }
        return listProperties;
    }

    // visit //style:section-properties
    @Override
    public void visit(StyleSectionPropertiesElement ele) {
        StyleSectionProperties sectionProperties = currentStyle.getSectionProperties();
        if (sectionProperties == null) {
            sectionProperties = new StyleSectionProperties();
            currentStyle.setSectionProperties(sectionProperties);
        }

        // background-color
        String backgroundColor = ele.getFoBackgroundColorAttribute();
        if (StringUtils.isNotEmpty(backgroundColor)) {
            sectionProperties.setBackgroundColor(ColorRegistry.getInstance().getColor(backgroundColor));
        }

        // dont-balance-text-columns
        Boolean dontBalanceTextColumns = ele.getTextDontBalanceTextColumnsAttribute();
        if (dontBalanceTextColumns != null) {
            sectionProperties.setDontBalanceTextColumns(dontBalanceTextColumns);
        }

        // margin-left
        String marginLeft = ele.getFoMarginLeftAttribute();
        if (StringUtils.isNotEmpty(marginLeft)) {
            sectionProperties.setMarginLeft(ODFUtils.getDimensionAsPoint(marginLeft));
        }

        // margin-right
        String marginRight = ele.getFoMarginRightAttribute();
        if (StringUtils.isNotEmpty(marginRight)) {
            sectionProperties.setMarginRight(ODFUtils.getDimensionAsPoint(marginRight));
        }

        super.visit(ele);
    }

    // visit //style:columns
    @Override
    public void visit(StyleColumnsElement ele) {
        StyleColumnsProperties columnsProperties = currentStyle.getColumnsProperties();
        if (columnsProperties == null) {
            columnsProperties = new StyleColumnsProperties();
            currentStyle.setColumnsProperties(columnsProperties);
        }

        // column-count
        Integer columnCount = ele.getFoColumnCountAttribute();
        if (columnCount != null) {
            columnsProperties.setColumnCount(columnCount);
        }

        // column-gap
        String columnGap = ele.getFoColumnGapAttribute();
        if (StringUtils.isNotEmpty(columnGap)) {
            columnsProperties.setColumnGap(ODFUtils.getDimensionAsPoint(columnGap));
        }

        super.visit(ele);
    }

    // visit //style:column
    @Override
    public void visit(StyleColumnElement ele) {
        List<StyleColumnProperties> styleColumnPropertiesList = currentStyle.getColumnPropertiesList();
        if (styleColumnPropertiesList == null) {
            styleColumnPropertiesList = new ArrayList<StyleColumnProperties>();
            currentStyle.setColumnPropertiesList(styleColumnPropertiesList);
        }
        StyleColumnProperties columnProperties = new StyleColumnProperties();

        // rel-width
        String relWidth = ele.getStyleRelWidthAttribute();
        if (StringUtils.isNotEmpty(relWidth)) {
            columnProperties.setRelWidth(ODFUtils.getRelativeSize(relWidth));
        }

        // start-indent
        String startIndent = ele.getFoStartIndentAttribute();
        if (StringUtils.isNotEmpty(startIndent)) {
            columnProperties.setStartIndent(ODFUtils.getDimensionAsPoint(startIndent));
        }

        // end-indent
        String endIndent = ele.getFoEndIndentAttribute();
        if (StringUtils.isNotEmpty(endIndent)) {
            columnProperties.setEndIndent(ODFUtils.getDimensionAsPoint(endIndent));
        }

        styleColumnPropertiesList.add(columnProperties);

        super.visit(ele);
    }

    private String getStyleId(String familyName, String styleName) {
        StringBuilder className = new StringBuilder();
        // style:family
        className.append(familyName);
        // style:name
        if (styleName != null) {
            className.append('_');
            className.append(StringUtils.replaceAll(styleName, ".", "_"));
        }
        return className.toString();
    }

    private Style getStyle(String familyName, String styleName) {
        return stylesMap.get(getStyleId(familyName, styleName));
    }

    public Style getStyle(String familyName, String styleName, Style parentElementStyle) {
        String newStyleName = null;
        String newFamilyName = null;
        String newMasterPageName = null;
        Style style = getStyle(familyName, styleName);
        if (style != null) {
            newStyleName = style.getStyleName();
            newFamilyName = style.getFamilyName();
            newMasterPageName = style.getMasterPageName();
        } else if (parentElementStyle != null) {
            newStyleName = parentElementStyle.getStyleName();
            newFamilyName = parentElementStyle.getFamilyName();
            newMasterPageName = parentElementStyle.getMasterPageName();
        }
        // create style
        // merge order should be:
        // 1 default style
        // 2 parent element style
        // 3 current style
        Style newStyle = new Style(newStyleName, newFamilyName, newMasterPageName);
        if (parentElementStyle != null) {
            // parent element style contains default style
            newStyle.merge(parentElementStyle);
        } else {
            // merge default styles
            for (Style s : stylesMap.values()) {
                if (s.getStyleName() == null) {
                    newStyle.merge(s);
                }
            }
        }
        // merge current style
        if (style != null) {
            newStyle.merge(style);
        }
        return newStyle;
    }
}