/// <summary> /// Move inside the current tag related to table (td, thead, tr, ...) and converts some common /// attributes to their OpenXml equivalence. /// </summary> /// <param name="en">The Html enumerator positionned on a <i>table (or related)</i> tag.</param> /// <param name="runStyleAttributes">The collection of attributes where to store new discovered attributes.</param> public void ProcessCommonAttributes(HtmlEnumerator en, IList <OpenXmlElement> runStyleAttributes) { List <OpenXmlElement> containerStyleAttributes = new List <OpenXmlElement>(); var colorValue = en.StyleAttributes.GetAsColor("background-color"); // "background-color" is also handled by RunStyleCollection which duplicate this attribute (bug #13212). Let's ignore it if (!colorValue.IsEmpty && en.CurrentTag.Equals("<td>", StringComparison.InvariantCultureIgnoreCase)) { colorValue = System.Drawing.Color.Empty; } if (colorValue.IsEmpty) { colorValue = en.Attributes.GetAsColor("bgcolor"); } if (!colorValue.IsEmpty) { containerStyleAttributes.Add( new Shading() { Val = ShadingPatternValues.Clear, Color = "auto", Fill = colorValue.ToHexString() }); } var htmlAlign = en.StyleAttributes["vertical-align"]; if (htmlAlign == null) { htmlAlign = en.Attributes["valign"]; } if (htmlAlign != null) { TableVerticalAlignmentValues?valign = ConverterUtility.FormatVAlign(htmlAlign); if (valign.HasValue) { containerStyleAttributes.Add(new TableCellVerticalAlignment() { Val = valign }); } } htmlAlign = en.StyleAttributes["text-align"]; if (htmlAlign == null) { htmlAlign = en.Attributes["align"]; } if (htmlAlign != null) { JustificationValues?halign = ConverterUtility.FormatParagraphAlign(htmlAlign); if (halign.HasValue) { this.BeginTagForParagraph(en.CurrentTag, new KeepNext(), new Justification { Val = halign }); } } // implemented by ddforge String[] classes = en.Attributes.GetAsClass(); if (classes != null) { for (int i = 0; i < classes.Length; i++) { string className = documentStyle.GetStyle(classes[i], StyleValues.Table, ignoreCase: true); if (className != null) // only one Style can be applied in OpenXml and dealing with inheritance is out of scope { containerStyleAttributes.Add(new RunStyle() { Val = className }); break; } } } this.BeginTag(en.CurrentTag, containerStyleAttributes); // Process general run styles documentStyle.Runs.ProcessCommonAttributes(en, runStyleAttributes); }
/// <summary> /// There is a few attributes shared by a large number of tags. This method will check them for a limited /// number of tags (<p>, <pre>, <div>, <span> and <body>). /// </summary> /// <returns>Returns true if the processing of this tag should generate a new paragraph.</returns> public bool ProcessCommonAttributes(HtmlEnumerator en, IList <OpenXmlElement> styleAttributes) { if (en.Attributes.Count == 0) { return(false); } bool newParagraph = false; List <OpenXmlElement> containerStyleAttributes = new List <OpenXmlElement>(); string attrValue = en.Attributes["lang"]; if (attrValue != null && attrValue.Length > 0) { try { var ci = System.Globalization.CultureInfo.GetCultureInfo(attrValue); bool rtl = ci.TextInfo.IsRightToLeft; Languages lang = new Languages() { Val = ci.TwoLetterISOLanguageName }; if (rtl) { lang.Bidi = ci.Name; styleAttributes.Add(new Languages() { Bidi = ci.Name }); // notify table documentStyle.Tables.BeginTag(en.CurrentTag, new TableJustification() { Val = TableRowAlignmentValues.Right }); } containerStyleAttributes.Add(new ParagraphMarkRunProperties(lang)); containerStyleAttributes.Add(new BiDi() { Val = OnOffValue.FromBoolean(rtl) }); } catch (ArgumentException) { // lang not valid, ignore it } } attrValue = en.StyleAttributes["text-align"]; if (attrValue != null && en.CurrentTag != "<font>") { JustificationValues?align = ConverterUtility.FormatParagraphAlign(attrValue); if (align.HasValue) { containerStyleAttributes.Add(new Justification { Val = align }); } } // according to w3c, dir should be used in conjonction with lang. But whatever happens, we'll apply the RTL layout attrValue = en.Attributes["dir"]; if (attrValue != null) { if (attrValue.Equals("rtl", StringComparison.OrdinalIgnoreCase)) { styleAttributes.Add(new RightToLeftText()); containerStyleAttributes.Add(new Justification() { Val = JustificationValues.Right }); } else if (attrValue.Equals("ltr", StringComparison.OrdinalIgnoreCase)) { containerStyleAttributes.Add(new Justification() { Val = JustificationValues.Left }); } } // <span> and <font> are considered as semi-container attribute. When converted to OpenXml, there are Runs but not Paragraphs if (en.CurrentTag == "<p>" || en.CurrentTag == "<div>" || en.CurrentTag == "<pre>") { var border = en.StyleAttributes.GetAsBorder("border"); if (!border.IsEmpty) { ParagraphBorders borders = new ParagraphBorders(); if (border.Top.IsValid) { borders.Append( new TopBorder() { Val = border.Top.Style, Color = border.Top.Color.ToHexString(), Size = (uint)border.Top.Width.ValueInPx * 4, Space = 1U }); } if (border.Left.IsValid) { borders.Append( new LeftBorder() { Val = border.Left.Style, Color = border.Left.Color.ToHexString(), Size = (uint)border.Left.Width.ValueInPx * 4, Space = 1U }); } if (border.Bottom.IsValid) { borders.Append( new BottomBorder() { Val = border.Bottom.Style, Color = border.Bottom.Color.ToHexString(), Size = (uint)border.Bottom.Width.ValueInPx * 4, Space = 1U }); } if (border.Right.IsValid) { borders.Append( new RightBorder() { Val = border.Right.Style, Color = border.Right.Color.ToHexString(), Size = (uint)border.Right.Width.ValueInPx * 4, Space = 1U }); } containerStyleAttributes.Add(borders); newParagraph = true; } } else if (en.CurrentTag == "<span>" || en.CurrentTag == "<font>") { // OpenXml limits the border to 4-side of the same color and style. SideBorder border = en.StyleAttributes.GetAsSideBorder("border"); if (border.IsValid) { styleAttributes.Add(new DocumentFormat.OpenXml.Wordprocessing.Border() { Val = border.Style, Color = border.Color.ToHexString(), Size = (uint)border.Width.ValueInPx * 4, Space = 1U }); } } String[] classes = en.Attributes.GetAsClass(); if (classes != null) { for (int i = 0; i < classes.Length; i++) { string className = documentStyle.GetStyle(classes[i], StyleValues.Paragraph, ignoreCase: true); if (className != null) { containerStyleAttributes.Add(new ParagraphStyleId() { Val = className }); newParagraph = true; break; } } } Margin margin = en.StyleAttributes.GetAsMargin("margin"); Indentation indentation = null; if (!margin.IsEmpty) { if (margin.Top.IsFixed || margin.Bottom.IsFixed) { SpacingBetweenLines spacing = new SpacingBetweenLines(); if (margin.Top.IsFixed) { spacing.Before = margin.Top.ValueInDxa.ToString(CultureInfo.InvariantCulture); } if (margin.Bottom.IsFixed) { spacing.After = margin.Bottom.ValueInDxa.ToString(CultureInfo.InvariantCulture); } containerStyleAttributes.Add(spacing); } if (margin.Left.IsFixed || margin.Right.IsFixed) { indentation = new Indentation(); if (margin.Left.IsFixed) { indentation.Left = margin.Left.ValueInDxa.ToString(CultureInfo.InvariantCulture); } if (margin.Right.IsFixed) { indentation.Right = margin.Right.ValueInDxa.ToString(CultureInfo.InvariantCulture); } containerStyleAttributes.Add(indentation); } } // implemented by giorand (feature #13787) Unit textIndent = en.StyleAttributes.GetAsUnit("text-indent"); if (textIndent.IsValid && (en.CurrentTag == "<p>" || en.CurrentTag == "<div>")) { if (indentation == null) { indentation = new Indentation(); } indentation.FirstLine = textIndent.ValueInDxa.ToString(CultureInfo.InvariantCulture); containerStyleAttributes.Add(indentation); } this.BeginTag(en.CurrentTag, containerStyleAttributes); // Process general run styles documentStyle.Runs.ProcessCommonAttributes(en, styleAttributes); return(newParagraph); }