private static void ApplyIllustrationLayoutAttributes(AbstractRenderer renderer, PdfDictionary attributes)
        {
            Rectangle bbox = renderer.GetOccupiedArea().GetBBox();

            attributes.Put(PdfName.BBox, new PdfArray(bbox));
            UnitValue width = renderer.GetProperty <UnitValue>(Property.WIDTH);

            if (width != null && width.IsPointValue())
            {
                attributes.Put(PdfName.Width, new PdfNumber(width.GetValue()));
            }
            else
            {
                attributes.Put(PdfName.Width, new PdfNumber(bbox.GetWidth()));
            }
            UnitValue height = renderer.GetProperty <UnitValue>(Property.HEIGHT);

            if (height != null)
            {
                attributes.Put(PdfName.Height, new PdfNumber(height.GetValue()));
            }
            else
            {
                attributes.Put(PdfName.Height, new PdfNumber(bbox.GetHeight()));
            }
        }
Ejemplo n.º 2
0
        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);
        }
Ejemplo n.º 3
0
        public static void ApplyListAttributes(AbstractRenderer renderer)
        {
            if (!(renderer.GetModelElement() is List))
            {
                return;
            }
            PdfDictionary attributes     = new PdfDictionary();
            PdfName       attributesType = PdfName.List;

            attributes.Put(PdfName.O, attributesType);
            Object listSymbol = renderer.GetProperty <Object>(Property.LIST_SYMBOL);

            if (listSymbol is ListNumberingType)
            {
                ListNumberingType numberingType = (ListNumberingType)listSymbol;
                attributes.Put(PdfName.ListNumbering, TransformNumberingTypeToName(numberingType));
            }
            if (attributes.Size() > 1)
            {
                AccessibilityProperties properties = ((IAccessibleElement)renderer.GetModelElement()).GetAccessibilityProperties
                                                         ();
                RemoveSameAttributesTypeIfPresent(properties, attributesType);
                properties.AddAttributes(attributes);
            }
        }
Ejemplo n.º 4
0
 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) {
         float? fontSize = renderer.GetPropertyAsFloat(Property.FONT_SIZE);
         Underline underline = null;
         if (underlines is IList && !((IList<Object>)underlines).IsEmpty() && ((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((float)fontSize) > 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((float)fontSize)));
         }
     }
 }
Ejemplo n.º 5
0
 private static void ApplyCommonLayoutAttributes(AbstractRenderer renderer, PdfDictionary attributes) {
     Background background = renderer.GetProperty<Background>(Property.BACKGROUND);
     if (background != null && background.GetColor() is DeviceRgb) {
         attributes.Put(PdfName.BackgroundColor, new PdfArray(background.GetColor().GetColorValue()));
     }
     //TODO NOTE: applying border attributes for cells is temporarily turned off on purpose. Remove this 'if' in future.
     // The reason is that currently, we can't distinguish if all cells have same border style or not.
     // Therefore for every cell in every table we have to write the same border attributes, which creates lots of clutter.
     if (!(renderer.GetModelElement() is Cell)) {
         ApplyBorderAttributes(renderer, attributes);
     }
     ApplyPaddingAttribute(renderer, attributes);
     Color color = renderer.GetPropertyAsColor(Property.FONT_COLOR);
     if (color != null && color is DeviceRgb) {
         attributes.Put(PdfName.Color, new PdfArray(color.GetColorValue()));
     }
 }
Ejemplo n.º 6
0
        /// <summary>Returns a property with a certain key, as a floating point value.</summary>
        /// <param name="property">
        /// an
        /// <see cref="Property">enum value</see>
        /// </param>
        /// <param name="defaultValue">default value to be returned if property is not found</param>
        /// <returns>
        /// a
        /// <see cref="float?"/>
        /// </returns>
        public static float?GetPropertyAsFloat(this AbstractRenderer renderer, int property, float?defaultValue)
        {
            Object value = renderer.GetProperty <Object>(property, defaultValue);

            return((value is sbyte ||
                    value is byte ||
                    value is short ||
                    value is ushort ||
                    value is int ||
                    value is uint ||
                    value is long ||
                    value is ulong ||
                    value is float ||
                    value is double ||
                    value is decimal)
                ? Convert.ToSingle(value) : (float?)null);
        }
Ejemplo n.º 7
0
        /// <summary>Returns a property with a certain key, as an integer value.</summary>
        /// <param name="property">
        /// an
        /// <see cref="Property">enum value</see>
        /// </param>
        /// <returns>
        /// a
        /// <see cref="int?"/>
        /// </returns>
        public static int?GetPropertyAsInteger(this AbstractRenderer renderer, int property)
        {
            Object value = renderer.GetProperty <Object>(property);

            return((value is sbyte ||
                    value is byte ||
                    value is short ||
                    value is ushort ||
                    value is int ||
                    value is uint ||
                    value is long ||
                    value is ulong ||
                    value is float ||
                    value is double ||
                    value is decimal)
                ? Convert.ToInt32(value) : (int?)null);
        }
        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()))
                                   );
                }
            }
        }
Ejemplo n.º 9
0
        /// <summary>This method tries to calculate width of not rotated renderer, so after rotation it fits availableWidth.
        ///     </summary>
        /// <remarks>
        /// This method tries to calculate width of not rotated renderer, so after rotation it fits availableWidth.
        /// This method uses heuristics of
        /// <see cref="iText.Layout.Minmaxwidth.RotationMinMaxWidth.Calculate(double, double, iText.Layout.Minmaxwidth.MinMaxWidth, double)
        ///     "/>.
        /// It doesn't take into account any of height properties of renderer or height of layoutArea.
        /// The minMaxWidth calculations and initial layout may take long time, but they won't be called if the renderer have width property.
        /// </remarks>
        /// <param name="availableWidth">the width of layoutArea</param>
        /// <param name="renderer">the actual renderer</param>
        /// <returns>
        /// the width that should be set as width of layout area to properly layout element, or fallback to
        /// <see cref="AbstractRenderer.RetrieveWidth(float)"/>
        /// in case it can not be calculated, or renderer isn't rotated.
        /// </returns>
        public static float?RetrieveRotatedLayoutWidth(float availableWidth, AbstractRenderer renderer)
        {
            RotationUtils.PropertiesBackup backup = new RotationUtils.PropertiesBackup(renderer);
            float?rotation = backup.StoreFloatProperty(Property.ROTATION_ANGLE);

            if (rotation != null && renderer.GetProperty <UnitValue>(Property.WIDTH) == null)
            {
                float angle = (float)rotation;
                backup.StoreProperty <UnitValue>(Property.HEIGHT);
                backup.StoreProperty <UnitValue>(Property.MIN_HEIGHT);
                backup.StoreProperty <UnitValue>(Property.MAX_HEIGHT);
                MinMaxWidth minMaxWidth = renderer.GetMinMaxWidth();
                //Using this width for initial layout helps in case of small elements. They may have more free spaces but it's more likely they fit.
                float        length       = (minMaxWidth.GetMaxWidth() + minMaxWidth.GetMinWidth()) / 2 + MinMaxWidthUtils.GetEps();
                LayoutResult layoutResult = renderer.Layout(new LayoutContext(new LayoutArea(1, new Rectangle(length, AbstractRenderer
                                                                                                              .INF))));
                backup.RestoreProperty(Property.HEIGHT);
                backup.RestoreProperty(Property.MIN_HEIGHT);
                backup.RestoreProperty(Property.MAX_HEIGHT);
                Rectangle additions = new Rectangle(0, 0);
                renderer.ApplyPaddings(additions, true);
                renderer.ApplyBorderBox(additions, true);
                renderer.ApplyMargins(additions, true);
                if (layoutResult.GetOccupiedArea() != null)
                {
                    double area = layoutResult.GetOccupiedArea().GetBBox().GetWidth() * layoutResult.GetOccupiedArea().GetBBox
                                      ().GetHeight();
                    RotationMinMaxWidth result = RotationMinMaxWidth.Calculate(angle, area, minMaxWidth, availableWidth);
                    if (result != null)
                    {
                        backup.RestoreProperty(Property.ROTATION_ANGLE);
                        if (result.GetMaxWidthHeight() > result.GetMinWidthHeight())
                        {
                            return((float)(result.GetMinWidthOrigin() - additions.GetWidth() + MinMaxWidthUtils.GetEps()));
                        }
                        else
                        {
                            return((float)(result.GetMaxWidthOrigin() - additions.GetWidth() + MinMaxWidthUtils.GetEps()));
                        }
                    }
                }
            }
            backup.RestoreProperty(Property.ROTATION_ANGLE);
            return(renderer.RetrieveWidth(availableWidth));
        }
        public static PdfStructureAttributes GetListAttributes(AbstractRenderer renderer, TagTreePointer taggingPointer
                                                               )
        {
            IRoleMappingResolver resolvedMapping = null;

            resolvedMapping = ResolveMappingToStandard(taggingPointer);
            if (resolvedMapping == null || !StandardRoles.L.Equals(resolvedMapping.GetRole()))
            {
                return(null);
            }
            PdfDictionary attributes = new PdfDictionary();

            attributes.Put(PdfName.O, PdfName.List);
            Object listSymbol       = renderer.GetProperty <Object>(Property.LIST_SYMBOL);
            bool   tagStructurePdf2 = IsTagStructurePdf2(resolvedMapping.GetNamespace());

            if (listSymbol is ListNumberingType)
            {
                ListNumberingType numberingType = (ListNumberingType)listSymbol;
                attributes.Put(PdfName.ListNumbering, TransformNumberingTypeToName(numberingType, tagStructurePdf2));
            }
            else
            {
                if (tagStructurePdf2)
                {
                    if (listSymbol is IListSymbolFactory)
                    {
                        attributes.Put(PdfName.ListNumbering, PdfName.Ordered);
                    }
                    else
                    {
                        attributes.Put(PdfName.ListNumbering, PdfName.Unordered);
                    }
                }
            }
            return(attributes.Size() > 1 ? new PdfStructureAttributes(attributes) : null);
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Calculates the bounding box of the content in the coordinate system of the pdf entity on which content is placed,
        /// e.g. document page or form xObject. This is particularly useful for the cases when element is nested in the rotated
        /// element.
        /// </summary>
        /// <returns>a <see cref="Rectangle"/> which is a bbox of the content not relative to the parent's layout area but rather to
        /// the some pdf entity coordinate system.</returns>
        protected Rectangle CalculateAbsolutePdfBBox()
        {
            Rectangle        contentBox       = GetOccupiedAreaBBox();
            IList <Point>    contentBoxPoints = RectangleToPointsList(contentBox);
            AbstractRenderer renderer         = this;

            while (renderer.parent != null)
            {
                if (renderer is BlockRenderer)
                {
                    float?angle = renderer.GetProperty <float?>(Property.ROTATION_ANGLE);
                    if (angle != null)
                    {
                        BlockRenderer   blockRenderer     = (BlockRenderer)renderer;
                        AffineTransform rotationTransform = blockRenderer.CreateRotationTransformInsideOccupiedArea();
                        TransformPoints(contentBoxPoints, rotationTransform);
                    }
                }

                renderer = (AbstractRenderer)renderer.parent;
            }

            return(CalculateBBox(contentBoxPoints));
        }
        private static void ApplyBorderAttributes(AbstractRenderer renderer, PdfDictionary attributes)
        {
            bool specificBorderProperties = renderer.GetProperty <Border>(Property.BORDER_TOP) != null || renderer.GetProperty
                                            <Border>(Property.BORDER_RIGHT) != null || renderer.GetProperty <Border>(Property.BORDER_BOTTOM) != null ||
                                            renderer.GetProperty <Border>(Property.BORDER_LEFT) != null;
            bool generalBorderProperties = !specificBorderProperties && renderer.GetProperty <Object>(Property.BORDER)
                                           != null;

            if (generalBorderProperties)
            {
                Border generalBorder      = renderer.GetProperty <Border>(Property.BORDER);
                Color  generalBorderColor = generalBorder.GetColor();
                int    borderType         = generalBorder.GetBorderType();
                float  borderWidth        = generalBorder.GetWidth();
                if (generalBorderColor is DeviceRgb)
                {
                    attributes.Put(PdfName.BorderColor, new PdfArray(generalBorderColor.GetColorValue()));
                    attributes.Put(PdfName.BorderStyle, TransformBorderTypeToName(borderType));
                    attributes.Put(PdfName.BorderThickness, new PdfNumber(borderWidth));
                }
            }
            if (specificBorderProperties)
            {
                PdfArray borderColors   = new PdfArray();
                PdfArray borderTypes    = new PdfArray();
                PdfArray borderWidths   = new PdfArray();
                bool     atLeastOneRgb  = false;
                Border[] borders        = renderer.GetBorders();
                bool     allColorsEqual = true;
                bool     allTypesEqual  = true;
                bool     allWidthsEqual = true;
                for (int i = 1; i < borders.Length; i++)
                {
                    Border border = borders[i];
                    if (border != null)
                    {
                        if (null == borders[0] || !border.GetColor().Equals(borders[0].GetColor()))
                        {
                            allColorsEqual = false;
                        }
                        if (null == borders[0] || border.GetWidth() != borders[0].GetWidth())
                        {
                            allWidthsEqual = false;
                        }
                        if (null == borders[0] || border.GetBorderType() != borders[0].GetBorderType())
                        {
                            allTypesEqual = false;
                        }
                    }
                }
                int[] borderOrder = new int[] { 0, 1, 2, 3 };
                //TODO set depending on writing direction
                foreach (int i in borderOrder)
                {
                    if (borders[i] != null)
                    {
                        if (borders[i].GetColor() is DeviceRgb)
                        {
                            borderColors.Add(new PdfArray(borders[i].GetColor().GetColorValue()));
                            atLeastOneRgb = true;
                        }
                        else
                        {
                            borderColors.Add(PdfNull.PDF_NULL);
                        }
                        borderTypes.Add(TransformBorderTypeToName(borders[i].GetBorderType()));
                        borderWidths.Add(new PdfNumber(borders[i].GetWidth()));
                    }
                    else
                    {
                        borderColors.Add(PdfNull.PDF_NULL);
                        borderTypes.Add(PdfName.None);
                        borderWidths.Add(PdfNull.PDF_NULL);
                    }
                }
                if (atLeastOneRgb)
                {
                    if (allColorsEqual)
                    {
                        attributes.Put(PdfName.BorderColor, borderColors.Get(0));
                    }
                    else
                    {
                        attributes.Put(PdfName.BorderColor, borderColors);
                    }
                }
                if (allTypesEqual)
                {
                    attributes.Put(PdfName.BorderStyle, borderTypes.Get(0));
                }
                else
                {
                    attributes.Put(PdfName.BorderStyle, borderTypes);
                }
                if (allWidthsEqual)
                {
                    attributes.Put(PdfName.BorderThickness, borderWidths.Get(0));
                }
                else
                {
                    attributes.Put(PdfName.BorderThickness, borderWidths);
                }
            }
        }
        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));
                }
            }
        }
Ejemplo n.º 14
0
 private static void ApplyBlockLevelLayoutAttributes(PdfName role, AbstractRenderer renderer, PdfDictionary
      attributes, PdfDocument doc) {
     float?[] margins = new float?[] { renderer.GetPropertyAsFloat(Property.MARGIN_TOP), renderer.GetPropertyAsFloat
         (Property.MARGIN_BOTTOM), renderer.GetPropertyAsFloat(Property.MARGIN_LEFT), renderer.GetPropertyAsFloat
         (Property.MARGIN_RIGHT) };
     int[] marginsOrder = new int[] { 0, 1, 2, 3 };
     //TODO set depending on writing direction
     float? spaceBefore = margins[marginsOrder[0]];
     if (spaceBefore != null && spaceBefore != 0) {
         attributes.Put(PdfName.SpaceBefore, new PdfNumber((float)spaceBefore));
     }
     float? spaceAfter = margins[marginsOrder[1]];
     if (spaceAfter != null && spaceAfter != 0) {
         attributes.Put(PdfName.SpaceAfter, new PdfNumber((float)spaceAfter));
     }
     float? startIndent = margins[marginsOrder[2]];
     if (startIndent != null && startIndent != 0) {
         attributes.Put(PdfName.StartIndent, new PdfNumber((float)startIndent));
     }
     float? endIndent = margins[marginsOrder[3]];
     if (endIndent != null && endIndent != 0) {
         attributes.Put(PdfName.EndIndent, new PdfNumber((float)endIndent));
     }
     float? firstLineIndent = renderer.GetProperty<float?>(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(PdfName.TH) && !role.Equals(PdfName.TD))) {
         //for table cells there is an InlineAlign attribute (see below)
         attributes.Put(PdfName.TextAlign, TransformTextAlignmentValueToName(textAlignment));
     }
     bool connectedToTag = doc.GetTagStructureContext().IsElementConnectedToTag((IAccessibleElement)renderer.GetModelElement
         ());
     bool elementIsOnSinglePage = !connectedToTag && renderer.isLastRendererForModelElement;
     if (elementIsOnSinglePage) {
         Rectangle bbox = renderer.GetOccupiedArea().GetBBox();
         attributes.Put(PdfName.BBox, new PdfArray(bbox));
     }
     if (role.Equals(PdfName.TH) || role.Equals(PdfName.TD) || role.Equals(PdfName.Table)) {
         UnitValue width = renderer.GetProperty<UnitValue>(Property.WIDTH);
         if (width != null && width.IsPointValue()) {
             attributes.Put(PdfName.Width, new PdfNumber(width.GetValue()));
         }
         float? height = renderer.GetPropertyAsFloat(Property.HEIGHT);
         if (height != null) {
             attributes.Put(PdfName.Height, new PdfNumber((float)height));
         }
     }
     if (role.Equals(PdfName.TH) || role.Equals(PdfName.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));
         }
     }
 }