internal static float CalculateLineHeight(AbstractRenderer renderer)
        {
            LineHeight lineHeight = renderer.GetProperty <LineHeight>(Property.LINE_HEIGHT);
            float      fontSize   = renderer.GetPropertyAsUnitValue(Property.FONT_SIZE).GetValue();
            float      lineHeightValue;

            if (lineHeight == null || lineHeight.IsNormalValue() || lineHeight.GetValue() < 0)
            {
                lineHeightValue = DEFAULT_LINE_HEIGHT_COEFF * fontSize;
                float[] fontAscenderDescender    = GetFontAscenderDescenderNormalized(renderer);
                float   fontAscenderDescenderSum = fontAscenderDescender[0] - fontAscenderDescender[1];
                if (fontAscenderDescenderSum > lineHeightValue)
                {
                    lineHeightValue = fontAscenderDescenderSum;
                }
            }
            else
            {
                if (lineHeight.IsFixedValue())
                {
                    lineHeightValue = lineHeight.GetValue();
                }
                else
                {
                    lineHeightValue = lineHeight.GetValue() * fontSize;
                }
            }
            return(lineHeightValue);
        }
        private static void ApplyPaddingAttribute(AbstractRenderer renderer, PdfDictionary attributes)
        {
            UnitValue[] paddingsUV = new UnitValue[] { renderer.GetPropertyAsUnitValue(Property.PADDING_TOP), renderer
                                                       .GetPropertyAsUnitValue(Property.PADDING_RIGHT), renderer.GetPropertyAsUnitValue(Property.PADDING_BOTTOM
                                                                                                                                        ), renderer.GetPropertyAsUnitValue(Property.PADDING_LEFT) };
            if (!paddingsUV[0].IsPointValue())
            {
                ILog logger = LogManager.GetLogger(typeof(AccessibleAttributesApplier));
                logger.Error(MessageFormatUtil.Format(iText.IO.LogMessageConstant.PROPERTY_IN_PERCENTS_NOT_SUPPORTED, Property
                                                      .PADDING_TOP));
            }
            if (!paddingsUV[1].IsPointValue())
            {
                ILog logger = LogManager.GetLogger(typeof(AccessibleAttributesApplier));
                logger.Error(MessageFormatUtil.Format(iText.IO.LogMessageConstant.PROPERTY_IN_PERCENTS_NOT_SUPPORTED, Property
                                                      .PADDING_RIGHT));
            }
            if (!paddingsUV[2].IsPointValue())
            {
                ILog logger = LogManager.GetLogger(typeof(AccessibleAttributesApplier));
                logger.Error(MessageFormatUtil.Format(iText.IO.LogMessageConstant.PROPERTY_IN_PERCENTS_NOT_SUPPORTED, Property
                                                      .PADDING_BOTTOM));
            }
            if (!paddingsUV[3].IsPointValue())
            {
                ILog logger = LogManager.GetLogger(typeof(AccessibleAttributesApplier));
                logger.Error(MessageFormatUtil.Format(iText.IO.LogMessageConstant.PROPERTY_IN_PERCENTS_NOT_SUPPORTED, Property
                                                      .PADDING_LEFT));
            }
            float[] paddings = new float[] { paddingsUV[0].GetValue(), paddingsUV[1].GetValue(), paddingsUV[2].GetValue
                                                 (), paddingsUV[3].GetValue() };
            PdfObject padding = null;

            if (paddings[0] == paddings[1] && paddings[0] == paddings[2] && paddings[0] == paddings[3])
            {
                if (paddings[0] != 0)
                {
                    padding = new PdfNumber(paddings[0]);
                }
            }
            else
            {
                PdfArray paddingArray  = new PdfArray();
                int[]    paddingsOrder = new int[] { 0, 1, 2, 3 };
                //TODO set depending on writing direction
                foreach (int i in paddingsOrder)
                {
                    paddingArray.Add(new PdfNumber(paddings[i]));
                }
                padding = paddingArray;
            }
            if (padding != null)
            {
                attributes.Put(PdfName.Padding, padding);
            }
        }
        internal static float[] GetFontAscenderDescenderNormalized(AbstractRenderer renderer)
        {
            PdfFont font     = renderer.ResolveFirstPdfFont();
            float   fontSize = renderer.GetPropertyAsUnitValue(Property.FONT_SIZE).GetValue();

            float[] fontAscenderDescenderFromMetrics = TextRenderer.CalculateAscenderDescender(font, RenderingMode.HTML_MODE
                                                                                               );
            float fontAscender  = fontAscenderDescenderFromMetrics[0] / FontProgram.UNITS_NORMALIZATION * fontSize;
            float fontDescender = fontAscenderDescenderFromMetrics[1] / FontProgram.UNITS_NORMALIZATION * fontSize;

            return(new float[] { fontAscender, fontDescender });
        }
        private static void ApplyInlineLevelLayoutAttributes(AbstractRenderer renderer, PdfDictionary attributes)
        {
            float?textRise = renderer.GetPropertyAsFloat(Property.TEXT_RISE);

            if (textRise != null && textRise != 0)
            {
                attributes.Put(PdfName.BaselineShift, new PdfNumber((float)textRise));
            }
            Object underlines = renderer.GetProperty <Object>(Property.UNDERLINE);

            if (underlines != null)
            {
                UnitValue fontSize = renderer.GetPropertyAsUnitValue(Property.FONT_SIZE);
                if (!fontSize.IsPointValue())
                {
                    ILog logger = LogManager.GetLogger(typeof(AccessibleAttributesApplier));
                    logger.Error(MessageFormatUtil.Format(iText.IO.LogMessageConstant.PROPERTY_IN_PERCENTS_NOT_SUPPORTED, Property
                                                          .FONT_SIZE));
                }
                Underline underline = null;
                if (underlines is IList && ((IList)underlines).Count > 0 && ((IList)underlines)[0] is Underline)
                {
                    // in standard attributes only one text decoration could be described for an element. That's why we take only the first underline from the list.
                    underline = (Underline)((IList)underlines)[0];
                }
                else
                {
                    if (underlines is Underline)
                    {
                        underline = (Underline)underlines;
                    }
                }
                if (underline != null)
                {
                    attributes.Put(PdfName.TextDecorationType, underline.GetYPosition(fontSize.GetValue()) > 0 ? PdfName.LineThrough
                         : PdfName.Underline);
                    if (underline.GetColor() is DeviceRgb)
                    {
                        attributes.Put(PdfName.TextDecorationColor, new PdfArray(underline.GetColor().GetColorValue()));
                    }
                    attributes.Put(PdfName.TextDecorationThickness, new PdfNumber(underline.GetThickness(fontSize.GetValue()))
                                   );
                }
            }
        }
        private static void ApplyBlockLevelLayoutAttributes(String role, AbstractRenderer renderer, PdfDictionary
                                                            attributes)
        {
            UnitValue[] margins = new UnitValue[] { renderer.GetPropertyAsUnitValue(Property.MARGIN_TOP), renderer.GetPropertyAsUnitValue
                                                        (Property.MARGIN_BOTTOM), renderer.GetPropertyAsUnitValue(Property.MARGIN_LEFT), renderer.GetPropertyAsUnitValue
                                                        (Property.MARGIN_RIGHT) };
            int[] marginsOrder = new int[] { 0, 1, 2, 3 };
            //TODO set depending on writing direction
            UnitValue spaceBefore = margins[marginsOrder[0]];

            if (spaceBefore != null)
            {
                if (!spaceBefore.IsPointValue())
                {
                    ILog logger = LogManager.GetLogger(typeof(AccessibleAttributesApplier));
                    logger.Error(MessageFormatUtil.Format(iText.IO.LogMessageConstant.PROPERTY_IN_PERCENTS_NOT_SUPPORTED, Property
                                                          .MARGIN_TOP));
                }
                if (0 != spaceBefore.GetValue())
                {
                    attributes.Put(PdfName.SpaceBefore, new PdfNumber(spaceBefore.GetValue()));
                }
            }
            UnitValue spaceAfter = margins[marginsOrder[1]];

            if (spaceAfter != null)
            {
                if (!spaceAfter.IsPointValue())
                {
                    ILog logger = LogManager.GetLogger(typeof(AccessibleAttributesApplier));
                    logger.Error(MessageFormatUtil.Format(iText.IO.LogMessageConstant.PROPERTY_IN_PERCENTS_NOT_SUPPORTED, Property
                                                          .MARGIN_BOTTOM));
                }
                if (0 != spaceAfter.GetValue())
                {
                    attributes.Put(PdfName.SpaceAfter, new PdfNumber(spaceAfter.GetValue()));
                }
            }
            UnitValue startIndent = margins[marginsOrder[2]];

            if (startIndent != null)
            {
                if (!startIndent.IsPointValue())
                {
                    ILog logger = LogManager.GetLogger(typeof(AccessibleAttributesApplier));
                    logger.Error(MessageFormatUtil.Format(iText.IO.LogMessageConstant.PROPERTY_IN_PERCENTS_NOT_SUPPORTED, Property
                                                          .MARGIN_LEFT));
                }
                if (0 != startIndent.GetValue())
                {
                    attributes.Put(PdfName.StartIndent, new PdfNumber(startIndent.GetValue()));
                }
            }
            UnitValue endIndent = margins[marginsOrder[3]];

            if (endIndent != null)
            {
                if (!endIndent.IsPointValue())
                {
                    ILog logger = LogManager.GetLogger(typeof(AccessibleAttributesApplier));
                    logger.Error(MessageFormatUtil.Format(iText.IO.LogMessageConstant.PROPERTY_IN_PERCENTS_NOT_SUPPORTED, Property
                                                          .MARGIN_RIGHT));
                }
                if (0 != endIndent.GetValue())
                {
                    attributes.Put(PdfName.EndIndent, new PdfNumber(endIndent.GetValue()));
                }
            }
            float?firstLineIndent = renderer.GetPropertyAsFloat(Property.FIRST_LINE_INDENT);

            if (firstLineIndent != null && firstLineIndent != 0)
            {
                attributes.Put(PdfName.TextIndent, new PdfNumber((float)firstLineIndent));
            }
            TextAlignment?textAlignment = renderer.GetProperty <TextAlignment?>(Property.TEXT_ALIGNMENT);

            if (textAlignment != null && (!role.Equals(StandardRoles.TH) && !role.Equals(StandardRoles.TD)))
            {
                //for table cells there is an InlineAlign attribute (see below)
                attributes.Put(PdfName.TextAlign, TransformTextAlignmentValueToName(textAlignment));
            }
            // attributes are applied only on the first renderer
            if (renderer.isLastRendererForModelElement)
            {
                Rectangle bbox = renderer.GetOccupiedArea().GetBBox();
                attributes.Put(PdfName.BBox, new PdfArray(bbox));
            }
            if (role.Equals(StandardRoles.TH) || role.Equals(StandardRoles.TD) || role.Equals(StandardRoles.TABLE))
            {
                // For large tables the width can be changed from flush to flush so the Width attribute shouldn't be applied.
                // There are also technical issues with large tables widths being explicitly set as property on element during layouting
                // (even if user didn't explcitly specfied it). This is required due to specificity of large elements implementation,
                // however in this case we cannot distinguish layout-specific and user-specified width properties.
                if (!(renderer is TableRenderer) || ((Table)renderer.GetModelElement()).IsComplete())
                {
                    UnitValue width = renderer.GetProperty <UnitValue>(Property.WIDTH);
                    if (width != null && width.IsPointValue())
                    {
                        attributes.Put(PdfName.Width, new PdfNumber(width.GetValue()));
                    }
                }
                UnitValue height = renderer.GetProperty <UnitValue>(Property.HEIGHT);
                if (height != null && height.IsPointValue())
                {
                    attributes.Put(PdfName.Height, new PdfNumber(height.GetValue()));
                }
            }
            if (role.Equals(StandardRoles.TH) || role.Equals(StandardRoles.TD))
            {
                HorizontalAlignment?horizontalAlignment = renderer.GetProperty <HorizontalAlignment?>(Property.HORIZONTAL_ALIGNMENT
                                                                                                      );
                if (horizontalAlignment != null)
                {
                    attributes.Put(PdfName.BlockAlign, TransformBlockAlignToName(horizontalAlignment));
                }
                if (textAlignment != null && (textAlignment != TextAlignment.JUSTIFIED && textAlignment != TextAlignment.JUSTIFIED_ALL
                                              ))
                {
                    //there is no justified alignment for InlineAlign attribute
                    attributes.Put(PdfName.InlineAlign, TransformTextAlignmentValueToName(textAlignment));
                }
            }
        }