/// <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)); } }
/// <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])); }
/// <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])); } }
/// <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); }
/// <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)); } }