Example #1
0
        /// <summary>
        /// Creates a new
        /// <see cref="HtmlTagWorker"/>
        /// instance.
        /// </summary>
        /// <param name="element">the element</param>
        /// <param name="context">the context</param>
        public HtmlTagWorker(IElementNode element, ProcessorContext context)
        {
            bool        immediateFlush = context.IsImmediateFlush() && !context.GetCssContext().IsPagesCounterPresent();
            PdfDocument pdfDocument    = context.GetPdfDocument();

            document = new Document(pdfDocument, pdfDocument.GetDefaultPageSize(), immediateFlush);
            document.SetRenderer(new HtmlDocumentRenderer(document, immediateFlush));
            document.SetProperty(Property.COLLAPSING_MARGINS, true);
            document.SetFontProvider(context.GetFontProvider());
            if (context.GetTempFonts() != null)
            {
                document.SetProperty(Property.FONT_SET, context.GetTempFonts());
            }
            String fontFamily = element.GetStyles().Get(CssConstants.FONT_FAMILY);
            // TODO DEVSIX-2534
            IList <String> fontFamilies = FontFamilySplitter.SplitFontFamily(fontFamily);

            document.SetProperty(Property.FONT, fontFamilies.ToArray(new String[fontFamilies.Count]));
            inlineHelper = new WaitingInlineElementsHelper(element.GetStyles().Get(CssConstants.WHITE_SPACE), element.
                                                           GetStyles().Get(CssConstants.TEXT_TRANSFORM));
            String lang = element.GetAttribute(AttributeConstants.LANG);

            if (lang != null)
            {
                pdfDocument.GetCatalog().SetLang(new PdfString(lang, PdfEncodings.UNICODE_BIG));
            }
        }
Example #2
0
 /// <summary>
 /// Create a
 /// <see cref="FontFace"/>
 /// instance from a list of
 /// CSS font attributes ("font-family" or "src").
 /// </summary>
 /// <param name="properties">the font properties</param>
 /// <returns>
 /// the
 /// <see cref="FontFace"/>
 /// instance
 /// </returns>
 public static iText.Svg.Processors.Impl.Font.FontFace Create(IList<CssDeclaration> properties) {
     String fontFamily = null;
     String srcs = null;
     foreach (CssDeclaration descriptor in properties) {
         if ("font-family".Equals(descriptor.GetProperty())) {
             fontFamily = FontFamilySplitter.RemoveQuotes(descriptor.GetExpression());
         }
         else {
             if ("src".Equals(descriptor.GetProperty())) {
                 srcs = descriptor.GetExpression();
             }
         }
     }
     if (fontFamily == null || srcs == null) {
         // 'font-family' and 'src' is required according to spec:
         // https://www.w3.org/TR/2013/CR-css-fonts-3-20131003/#descdef-font-family\
         // https://www.w3.org/TR/2013/CR-css-fonts-3-20131003/#descdef-src
         return null;
     }
     IList<FontFace.FontFaceSrc> sources = new List<FontFace.FontFaceSrc>();
     // ttc collection are supported via url(Arial.ttc#1), url(Arial.ttc#2), etc.
     foreach (String src in SplitSourcesSequence(srcs)) {
         //local|url("ideal-sans-serif.woff")( format("woff"))?
         FontFace.FontFaceSrc source = FontFace.FontFaceSrc.Create(src.Trim());
         if (source != null) {
             sources.Add(source);
         }
     }
     if (sources.Count > 0) {
         return new iText.Svg.Processors.Impl.Font.FontFace(fontFamily, sources);
     }
     else {
         return null;
     }
 }
Example #3
0
        /// <summary>
        /// Creates a new
        /// <see cref="BrTagWorker"/>
        /// instance.
        /// </summary>
        /// <param name="element">the element</param>
        /// <param name="context">the context</param>
        public BrTagWorker(IElementNode element, ProcessorContext context)
        {
            //There is no mappings for BR element in DefaultTagCssApplierMapping,
            // because only font-family should be applied to <br /> element.
            String fontFamily = element.GetStyles().Get(CssConstants.FONT_FAMILY);
            // TODO DEVSIX-2534
            IList <String> splitFontFamily = FontFamilySplitter.SplitFontFamily(fontFamily);

            newLine.SetFontFamily(splitFontFamily.ToArray(new String[splitFontFamily.Count]));
        }
Example #4
0
        /// <summary>Sets properties to top-level layout elements converted from HTML.</summary>
        /// <remarks>
        /// Sets properties to top-level layout elements converted from HTML.
        /// This enables features set by user via HTML converter API and also changes properties defaults
        /// to the ones specific to HTML-like behavior.
        /// </remarks>
        /// <param name="cssProperties">HTML document-level css properties.</param>
        /// <param name="context">processor context specific to the current HTML conversion.</param>
        /// <param name="propertyContainer">top-level layout element converted from HTML.</param>
        public static void SetConvertedRootElementProperties(IDictionary <String, String> cssProperties, ProcessorContext
                                                             context, IPropertyContainer propertyContainer)
        {
            propertyContainer.SetProperty(Property.COLLAPSING_MARGINS, true);
            propertyContainer.SetProperty(Property.RENDERING_MODE, RenderingMode.HTML_MODE);
            propertyContainer.SetProperty(Property.FONT_PROVIDER, context.GetFontProvider());
            if (context.GetTempFonts() != null)
            {
                propertyContainer.SetProperty(Property.FONT_SET, context.GetTempFonts());
            }
            // TODO DEVSIX-2534
            IList <String> fontFamilies = FontFamilySplitter.SplitFontFamily(cssProperties.Get(CssConstants.FONT_FAMILY
                                                                                               ));

            if (fontFamilies != null && !propertyContainer.HasOwnProperty(Property.FONT))
            {
                propertyContainer.SetProperty(Property.FONT, fontFamilies.ToArray(new String[0]));
            }
        }
Example #5
0
        /// <summary>Applies font styles to an element.</summary>
        /// <param name="cssProps">the CSS props</param>
        /// <param name="context">the processor context</param>
        /// <param name="stylesContainer">the styles container</param>
        /// <param name="element">the element</param>
        public static void ApplyFontStyles(IDictionary <String, String> cssProps, ProcessorContext context, IStylesContainer
                                           stylesContainer, IPropertyContainer element)
        {
            float em  = CssDimensionParsingUtils.ParseAbsoluteLength(cssProps.Get(CssConstants.FONT_SIZE));
            float rem = context.GetCssContext().GetRootFontSize();

            if (em != 0)
            {
                element.SetProperty(Property.FONT_SIZE, UnitValue.CreatePointValue(em));
            }
            if (cssProps.Get(CssConstants.FONT_FAMILY) != null)
            {
                // TODO DEVSIX-2534
                IList <String> fontFamilies = FontFamilySplitter.SplitFontFamily(cssProps.Get(CssConstants.FONT_FAMILY));
                element.SetProperty(Property.FONT, fontFamilies.ToArray(new String[fontFamilies.Count]));
            }
            if (cssProps.Get(CssConstants.FONT_WEIGHT) != null)
            {
                element.SetProperty(Property.FONT_WEIGHT, cssProps.Get(CssConstants.FONT_WEIGHT));
            }
            if (cssProps.Get(CssConstants.FONT_STYLE) != null)
            {
                element.SetProperty(Property.FONT_STYLE, cssProps.Get(CssConstants.FONT_STYLE));
            }
            String cssColorPropValue = cssProps.Get(CssConstants.COLOR);

            if (cssColorPropValue != null)
            {
                TransparentColor transparentColor;
                if (!CssConstants.TRANSPARENT.Equals(cssColorPropValue))
                {
                    float[] rgbaColor = CssDimensionParsingUtils.ParseRgbaColor(cssColorPropValue);
                    Color   color     = new DeviceRgb(rgbaColor[0], rgbaColor[1], rgbaColor[2]);
                    float   opacity   = rgbaColor[3];
                    transparentColor = new TransparentColor(color, opacity);
                }
                else
                {
                    transparentColor = new TransparentColor(ColorConstants.BLACK, 0f);
                }
                element.SetProperty(Property.FONT_COLOR, transparentColor);
            }
            // Make sure to place that before text-align applier
            String direction = cssProps.Get(CssConstants.DIRECTION);

            if (CssConstants.RTL.Equals(direction))
            {
                element.SetProperty(Property.BASE_DIRECTION, BaseDirection.RIGHT_TO_LEFT);
                element.SetProperty(Property.TEXT_ALIGNMENT, TextAlignment.RIGHT);
            }
            else
            {
                if (CssConstants.LTR.Equals(direction))
                {
                    element.SetProperty(Property.BASE_DIRECTION, BaseDirection.LEFT_TO_RIGHT);
                    element.SetProperty(Property.TEXT_ALIGNMENT, TextAlignment.LEFT);
                }
            }
            if (stylesContainer is IElementNode && ((IElementNode)stylesContainer).ParentNode() is IElementNode && CssConstants
                .RTL.Equals(((IElementNode)((IElementNode)stylesContainer).ParentNode()).GetStyles().Get(CssConstants.
                                                                                                         DIRECTION)) && !element.HasProperty(Property.HORIZONTAL_ALIGNMENT))
            {
                // We should only apply horizontal alignment if parent has dir attribute or direction property
                element.SetProperty(Property.HORIZONTAL_ALIGNMENT, HorizontalAlignment.RIGHT);
            }
            // Make sure to place that after direction applier
            String align = cssProps.Get(CssConstants.TEXT_ALIGN);

            if (CssConstants.LEFT.Equals(align))
            {
                element.SetProperty(Property.TEXT_ALIGNMENT, TextAlignment.LEFT);
            }
            else
            {
                if (CssConstants.RIGHT.Equals(align))
                {
                    element.SetProperty(Property.TEXT_ALIGNMENT, TextAlignment.RIGHT);
                }
                else
                {
                    if (CssConstants.CENTER.Equals(align))
                    {
                        element.SetProperty(Property.TEXT_ALIGNMENT, TextAlignment.CENTER);
                    }
                    else
                    {
                        if (CssConstants.JUSTIFY.Equals(align))
                        {
                            element.SetProperty(Property.TEXT_ALIGNMENT, TextAlignment.JUSTIFIED);
                            element.SetProperty(Property.SPACING_RATIO, 1f);
                        }
                    }
                }
            }
            String whiteSpace           = cssProps.Get(CssConstants.WHITE_SPACE);
            bool   textWrappingDisabled = CssConstants.NOWRAP.Equals(whiteSpace) || CssConstants.PRE.Equals(whiteSpace);

            element.SetProperty(Property.NO_SOFT_WRAP_INLINE, textWrappingDisabled);
            if (!textWrappingDisabled)
            {
                String overflowWrap = cssProps.Get(CssConstants.OVERFLOW_WRAP);
                if (CssConstants.ANYWHERE.Equals(overflowWrap))
                {
                    element.SetProperty(Property.OVERFLOW_WRAP, OverflowWrapPropertyValue.ANYWHERE);
                }
                else
                {
                    if (CssConstants.BREAK_WORD.Equals(overflowWrap))
                    {
                        element.SetProperty(Property.OVERFLOW_WRAP, OverflowWrapPropertyValue.BREAK_WORD);
                    }
                    else
                    {
                        element.SetProperty(Property.OVERFLOW_WRAP, OverflowWrapPropertyValue.NORMAL);
                    }
                }
                String wordBreak = cssProps.Get(CssConstants.WORD_BREAK);
                if (CssConstants.BREAK_ALL.Equals(wordBreak))
                {
                    element.SetProperty(Property.SPLIT_CHARACTERS, new BreakAllSplitCharacters());
                }
                else
                {
                    if (CssConstants.KEEP_ALL.Equals(wordBreak))
                    {
                        element.SetProperty(Property.SPLIT_CHARACTERS, new KeepAllSplitCharacters());
                    }
                    else
                    {
                        if (CssConstants.BREAK_WORD.Equals(wordBreak))
                        {
                            // CSS specification cite that describes the reason for overflow-wrap overriding:
                            // "For compatibility with legacy content, the word-break property also supports
                            //  a deprecated break-word keyword. When specified, this has the same effect
                            //  as word-break: normal and overflow-wrap: anywhere, regardless of the actual value
                            //  of the overflow-wrap property."
                            element.SetProperty(Property.OVERFLOW_WRAP, OverflowWrapPropertyValue.BREAK_WORD);
                            element.SetProperty(Property.SPLIT_CHARACTERS, new DefaultSplitCharacters());
                        }
                        else
                        {
                            element.SetProperty(Property.SPLIT_CHARACTERS, new DefaultSplitCharacters());
                        }
                    }
                }
            }
            float[] colors = new float[4];
            Color   textDecorationColor;
            float   opacity_1 = 1f;
            String  textDecorationColorProp = cssProps.Get(CssConstants.TEXT_DECORATION_COLOR);

            if (textDecorationColorProp == null || CssConstants.CURRENTCOLOR.Equals(textDecorationColorProp))
            {
                if (element.GetProperty <TransparentColor>(Property.FONT_COLOR) != null)
                {
                    TransparentColor transparentColor = element.GetProperty <TransparentColor>(Property.FONT_COLOR);
                    textDecorationColor = transparentColor.GetColor();
                    opacity_1           = transparentColor.GetOpacity();
                }
                else
                {
                    textDecorationColor = ColorConstants.BLACK;
                }
            }
            else
            {
                if (textDecorationColorProp.StartsWith("hsl"))
                {
                    logger.Error(iText.Html2pdf.LogMessageConstant.HSL_COLOR_NOT_SUPPORTED);
                    textDecorationColor = ColorConstants.BLACK;
                }
                else
                {
                    colors = CssDimensionParsingUtils.ParseRgbaColor(textDecorationColorProp);
                    textDecorationColor = new DeviceRgb(colors[0], colors[1], colors[2]);
                    opacity_1           = colors[3];
                }
            }
            String textDecorationLineProp = cssProps.Get(CssConstants.TEXT_DECORATION_LINE);

            if (textDecorationLineProp != null)
            {
                String[]          textDecorationLines = iText.IO.Util.StringUtil.Split(textDecorationLineProp, "\\s+");
                IList <Underline> underlineList       = new List <Underline>();
                foreach (String textDecorationLine in textDecorationLines)
                {
                    if (CssConstants.BLINK.Equals(textDecorationLine))
                    {
                        logger.Error(iText.Html2pdf.LogMessageConstant.TEXT_DECORATION_BLINK_NOT_SUPPORTED);
                    }
                    else
                    {
                        if (CssConstants.LINE_THROUGH.Equals(textDecorationLine))
                        {
                            underlineList.Add(new Underline(textDecorationColor, opacity_1, .75f, 0, 0, 1 / 4f, PdfCanvasConstants.LineCapStyle
                                                            .BUTT));
                        }
                        else
                        {
                            if (CssConstants.OVERLINE.Equals(textDecorationLine))
                            {
                                underlineList.Add(new Underline(textDecorationColor, opacity_1, .75f, 0, 0, 9 / 10f, PdfCanvasConstants.LineCapStyle
                                                                .BUTT));
                            }
                            else
                            {
                                if (CssConstants.UNDERLINE.Equals(textDecorationLine))
                                {
                                    underlineList.Add(new Underline(textDecorationColor, opacity_1, .75f, 0, 0, -1 / 10f, PdfCanvasConstants.LineCapStyle
                                                                    .BUTT));
                                }
                                else
                                {
                                    if (CssConstants.NONE.Equals(textDecorationLine))
                                    {
                                        underlineList = null;
                                        // if none and any other decoration are used together, none is displayed
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
                element.SetProperty(Property.UNDERLINE, underlineList);
            }
            String textIndent = cssProps.Get(CssConstants.TEXT_INDENT);

            if (textIndent != null)
            {
                UnitValue textIndentValue = CssDimensionParsingUtils.ParseLengthValueToPt(textIndent, em, rem);
                if (textIndentValue != null)
                {
                    if (textIndentValue.IsPointValue())
                    {
                        element.SetProperty(Property.FIRST_LINE_INDENT, textIndentValue.GetValue());
                    }
                    else
                    {
                        logger.Error(MessageFormatUtil.Format(iText.Html2pdf.LogMessageConstant.CSS_PROPERTY_IN_PERCENTS_NOT_SUPPORTED
                                                              , CssConstants.TEXT_INDENT));
                    }
                }
            }
            String letterSpacing = cssProps.Get(CssConstants.LETTER_SPACING);

            if (letterSpacing != null && !CssConstants.NORMAL.Equals(letterSpacing))
            {
                UnitValue letterSpacingValue = CssDimensionParsingUtils.ParseLengthValueToPt(letterSpacing, em, rem);
                if (letterSpacingValue.IsPointValue())
                {
                    element.SetProperty(Property.CHARACTER_SPACING, letterSpacingValue.GetValue());
                }
            }
            // browsers ignore values in percents
            String wordSpacing = cssProps.Get(CssConstants.WORD_SPACING);

            if (wordSpacing != null)
            {
                UnitValue wordSpacingValue = CssDimensionParsingUtils.ParseLengthValueToPt(wordSpacing, em, rem);
                if (wordSpacingValue != null)
                {
                    if (wordSpacingValue.IsPointValue())
                    {
                        element.SetProperty(Property.WORD_SPACING, wordSpacingValue.GetValue());
                    }
                }
            }
            // browsers ignore values in percents
            String lineHeight = cssProps.Get(CssConstants.LINE_HEIGHT);

            SetLineHeight(element, lineHeight, em, rem);
            SetLineHeightByLeading(element, lineHeight, em, rem);
        }
Example #6
0
        /// <summary>Applies font styles to an element.</summary>
        /// <param name="cssProps">the CSS props</param>
        /// <param name="context">the processor context</param>
        /// <param name="stylesContainer">the styles container</param>
        /// <param name="element">the element</param>
        public static void ApplyFontStyles(IDictionary <String, String> cssProps, ProcessorContext context, IStylesContainer
                                           stylesContainer, IPropertyContainer element)
        {
            float em  = CssUtils.ParseAbsoluteLength(cssProps.Get(CssConstants.FONT_SIZE));
            float rem = context.GetCssContext().GetRootFontSize();

            if (em != 0)
            {
                element.SetProperty(Property.FONT_SIZE, UnitValue.CreatePointValue(em));
            }
            if (cssProps.Get(CssConstants.FONT_FAMILY) != null)
            {
                // TODO DEVSIX-2534
                IList <String> fontFamilies = FontFamilySplitter.SplitFontFamily(cssProps.Get(CssConstants.FONT_FAMILY));
                element.SetProperty(Property.FONT, fontFamilies.ToArray(new String[fontFamilies.Count]));
            }
            if (cssProps.Get(CssConstants.FONT_WEIGHT) != null)
            {
                element.SetProperty(Property.FONT_WEIGHT, cssProps.Get(CssConstants.FONT_WEIGHT));
            }
            if (cssProps.Get(CssConstants.FONT_STYLE) != null)
            {
                element.SetProperty(Property.FONT_STYLE, cssProps.Get(CssConstants.FONT_STYLE));
            }
            String cssColorPropValue = cssProps.Get(CssConstants.COLOR);

            if (cssColorPropValue != null)
            {
                TransparentColor transparentColor;
                if (!CssConstants.TRANSPARENT.Equals(cssColorPropValue))
                {
                    float[] rgbaColor = CssUtils.ParseRgbaColor(cssColorPropValue);
                    Color   color     = new DeviceRgb(rgbaColor[0], rgbaColor[1], rgbaColor[2]);
                    float   opacity   = rgbaColor[3];
                    transparentColor = new TransparentColor(color, opacity);
                }
                else
                {
                    transparentColor = new TransparentColor(ColorConstants.BLACK, 0f);
                }
                element.SetProperty(Property.FONT_COLOR, transparentColor);
            }
            // Make sure to place that before text-align applier
            String direction = cssProps.Get(CssConstants.DIRECTION);

            if (CssConstants.RTL.Equals(direction))
            {
                element.SetProperty(Property.BASE_DIRECTION, BaseDirection.RIGHT_TO_LEFT);
                element.SetProperty(Property.TEXT_ALIGNMENT, TextAlignment.RIGHT);
            }
            else
            {
                if (CssConstants.LTR.Equals(direction))
                {
                    element.SetProperty(Property.BASE_DIRECTION, BaseDirection.LEFT_TO_RIGHT);
                    element.SetProperty(Property.TEXT_ALIGNMENT, TextAlignment.LEFT);
                }
            }
            if (stylesContainer is IElementNode && ((IElementNode)stylesContainer).ParentNode() is IElementNode && CssConstants
                .RTL.Equals(((IElementNode)((IElementNode)stylesContainer).ParentNode()).GetStyles().Get(CssConstants.
                                                                                                         DIRECTION)) && !element.HasProperty(Property.HORIZONTAL_ALIGNMENT))
            {
                // We should only apply horizontal alignment if parent has dir attribute or direction property
                element.SetProperty(Property.HORIZONTAL_ALIGNMENT, HorizontalAlignment.RIGHT);
            }
            // Make sure to place that after direction applier
            String align = cssProps.Get(CssConstants.TEXT_ALIGN);

            if (CssConstants.LEFT.Equals(align))
            {
                element.SetProperty(Property.TEXT_ALIGNMENT, TextAlignment.LEFT);
            }
            else
            {
                if (CssConstants.RIGHT.Equals(align))
                {
                    element.SetProperty(Property.TEXT_ALIGNMENT, TextAlignment.RIGHT);
                }
                else
                {
                    if (CssConstants.CENTER.Equals(align))
                    {
                        element.SetProperty(Property.TEXT_ALIGNMENT, TextAlignment.CENTER);
                    }
                    else
                    {
                        if (CssConstants.JUSTIFY.Equals(align))
                        {
                            element.SetProperty(Property.TEXT_ALIGNMENT, TextAlignment.JUSTIFIED);
                            element.SetProperty(Property.SPACING_RATIO, 1f);
                        }
                    }
                }
            }
            String whiteSpace = cssProps.Get(CssConstants.WHITE_SPACE);

            element.SetProperty(Property.NO_SOFT_WRAP_INLINE, CssConstants.NOWRAP.Equals(whiteSpace) || CssConstants.PRE
                                .Equals(whiteSpace));
            String textDecorationProp = cssProps.Get(CssConstants.TEXT_DECORATION);

            if (textDecorationProp != null)
            {
                String[]          textDecorations = iText.IO.Util.StringUtil.Split(textDecorationProp, "\\s+");
                IList <Underline> underlineList   = new List <Underline>();
                foreach (String textDecoration in textDecorations)
                {
                    if (CssConstants.BLINK.Equals(textDecoration))
                    {
                        logger.Error(iText.Html2pdf.LogMessageConstant.TEXT_DECORATION_BLINK_NOT_SUPPORTED);
                    }
                    else
                    {
                        if (CssConstants.LINE_THROUGH.Equals(textDecoration))
                        {
                            underlineList.Add(new Underline(null, .75f, 0, 0, 1 / 4f, PdfCanvasConstants.LineCapStyle.BUTT));
                        }
                        else
                        {
                            if (CssConstants.OVERLINE.Equals(textDecoration))
                            {
                                underlineList.Add(new Underline(null, .75f, 0, 0, 9 / 10f, PdfCanvasConstants.LineCapStyle.BUTT));
                            }
                            else
                            {
                                if (CssConstants.UNDERLINE.Equals(textDecoration))
                                {
                                    underlineList.Add(new Underline(null, .75f, 0, 0, -1 / 10f, PdfCanvasConstants.LineCapStyle.BUTT));
                                }
                                else
                                {
                                    if (CssConstants.NONE.Equals(textDecoration))
                                    {
                                        underlineList = null;
                                        // if none and any other decoration are used together, none is displayed
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
                element.SetProperty(Property.UNDERLINE, underlineList);
            }
            String textIndent = cssProps.Get(CssConstants.TEXT_INDENT);

            if (textIndent != null)
            {
                UnitValue textIndentValue = CssUtils.ParseLengthValueToPt(textIndent, em, rem);
                if (textIndentValue != null)
                {
                    if (textIndentValue.IsPointValue())
                    {
                        element.SetProperty(Property.FIRST_LINE_INDENT, textIndentValue.GetValue());
                    }
                    else
                    {
                        logger.Error(MessageFormatUtil.Format(iText.Html2pdf.LogMessageConstant.CSS_PROPERTY_IN_PERCENTS_NOT_SUPPORTED
                                                              , CssConstants.TEXT_INDENT));
                    }
                }
            }
            String letterSpacing = cssProps.Get(CssConstants.LETTER_SPACING);

            if (letterSpacing != null && !letterSpacing.Equals(CssConstants.NORMAL))
            {
                UnitValue letterSpacingValue = CssUtils.ParseLengthValueToPt(letterSpacing, em, rem);
                if (letterSpacingValue.IsPointValue())
                {
                    element.SetProperty(Property.CHARACTER_SPACING, letterSpacingValue.GetValue());
                }
            }
            // browsers ignore values in percents
            String wordSpacing = cssProps.Get(CssConstants.WORD_SPACING);

            if (wordSpacing != null)
            {
                UnitValue wordSpacingValue = CssUtils.ParseLengthValueToPt(wordSpacing, em, rem);
                if (wordSpacingValue != null)
                {
                    if (wordSpacingValue.IsPointValue())
                    {
                        element.SetProperty(Property.WORD_SPACING, wordSpacingValue.GetValue());
                    }
                }
            }
            // browsers ignore values in percents
            String lineHeight = cssProps.Get(CssConstants.LINE_HEIGHT);

            // specification does not give auto as a possible lineHeight value
            // nevertheless some browsers compute it as normal so we apply the same behaviour.
            // What's more, it's basically the same thing as if lineHeight is not set in the first place
            if (lineHeight != null && !CssConstants.NORMAL.Equals(lineHeight) && !CssConstants.AUTO.Equals(lineHeight)
                )
            {
                if (CssUtils.IsNumericValue(lineHeight))
                {
                    float?mult = CssUtils.ParseFloat(lineHeight);
                    if (mult != null)
                    {
                        element.SetProperty(Property.LEADING, new Leading(Leading.MULTIPLIED, (float)mult));
                    }
                }
                else
                {
                    UnitValue lineHeightValue = CssUtils.ParseLengthValueToPt(lineHeight, em, rem);
                    if (lineHeightValue != null && lineHeightValue.IsPointValue())
                    {
                        element.SetProperty(Property.LEADING, new Leading(Leading.FIXED, lineHeightValue.GetValue()));
                    }
                    else
                    {
                        if (lineHeightValue != null)
                        {
                            element.SetProperty(Property.LEADING, new Leading(Leading.MULTIPLIED, lineHeightValue.GetValue() / 100));
                        }
                    }
                }
            }
            else
            {
                element.SetProperty(Property.LEADING, new Leading(Leading.MULTIPLIED, 1.2f));
            }
        }