public virtual void Check(Lexer lexer, Node node) { node.CheckUniqueAttributes(lexer); AttVal lang = node.GetAttrByName("language"); AttVal type = node.GetAttrByName("type"); if (type == null) { Report.AttrError(lexer, node, "type", Report.MISSING_ATTRIBUTE); /* check for javascript */ if (lang != null) { string str = lang.Val; if (str.Length > 10) { str = str.Substring(0, 10); } if ((String.CompareOrdinal(str, "javascript") == 0) || (String.CompareOrdinal(str, "jscript") == 0)) { node.AddAttribute("type", "text/javascript"); } } else { node.AddAttribute("type", "text/javascript"); } } }
/* Replace implicit blockquote by div with an indent taking care to reduce nested blockquotes to a single div with the indent set to match the nesting depth */ public virtual void Bq2Div(Node node) { while (node != null) { if (node.Tag == _tt.TagBlockquote && node.Isimplicit) { int indent = 1; while (node.HasOneChild() && node.Content.Tag == _tt.TagBlockquote && node.Isimplicit) { ++indent; StripOnlyChild(node); } if (node.Content != null) { Bq2Div(node.Content); } string indentBuf = "margin-left: " + (2*indent).ToString() + "em"; node.Element = _tt.TagDiv.Name; node.Tag = _tt.TagDiv; node.AddAttribute("style", indentBuf); } else if (node.Content != null) { Bq2Div(node.Content); } node = node.Next; } }
protected internal virtual void PreTraverse(Node node) { if (node == null) { return; } if (node.Type == Node.START_TAG || node.Type == Node.START_END_TAG) { if (_currIndex <= _maxIndex && (_tagName.Equals("*") || _tagName.Equals(node.Element))) { _currIndex += 1; _currNode = node; } } if (_currIndex > _maxIndex) { return; } node = node.Content; while (node != null) { PreTraverse(node); node = node.Next; } }
public virtual void Check(Lexer lexer, Node node) { AttVal attval; string val = null; node.CheckUniqueAttributes(lexer); for (attval = node.Attributes; attval != null; attval = attval.Next) { if (String.CompareOrdinal(attval.Attribute, "align") == 0) { val = attval.Val; break; } } if (val != null) { if (String.CompareOrdinal(val, "left") == 0 || String.CompareOrdinal(val, "right") == 0) { lexer.Versions &= HtmlVersion.Html40Loose | HtmlVersion.Frames; } else if (String.CompareOrdinal(val, "top") == 0 || String.CompareOrdinal(val, "bottom") == 0) { lexer.Versions &= HtmlVersion.From32; } else { Report.AttrError(lexer, node, val, Report.BAD_ATTRIBUTE_VALUE); } } }
public virtual void Check(Lexer lexer, Node node, AttVal attval) { string val = attval.Val; if (val == null) { Report.AttrError(lexer, node, attval.Attribute, Report.MISSING_ATTR_VALUE); } else if (String.CompareOrdinal(val, "top") == 0 || String.CompareOrdinal(val, "middle") == 0 || String.CompareOrdinal(val, "bottom") == 0 || String.CompareOrdinal(val, "baseline") == 0) { /* all is fine */ } else if (String.CompareOrdinal(val, "left") == 0 || String.CompareOrdinal(val, "right") == 0) { if (!(node.Tag != null && ((node.Tag.Model & ContentModel.IMG) != 0))) { Report.AttrError(lexer, node, val, Report.BAD_ATTRIBUTE_VALUE); } } else if (String.CompareOrdinal(val, "texttop") == 0 || String.CompareOrdinal(val, "absmiddle") == 0 || String.CompareOrdinal(val, "absbottom") == 0 || String.CompareOrdinal(val, "textbottom") == 0) { lexer.Versions &= HtmlVersion.Proprietary; Report.AttrError(lexer, node, val, Report.PROPRIETARY_ATTR_VALUE); } else { Report.AttrError(lexer, node, val, Report.BAD_ATTRIBUTE_VALUE); } }
public AttVal(AttVal next, Attribute dict, Node asp, Node php, int delim, string attribute, string val) { Next = next; _dict = dict; _asp = asp; Php = php; Delim = delim; Attribute = attribute; Val = val; }
public AttVal(AttVal next, Attribute dict, int delim, string attribute, string val) { Next = next; _dict = dict; _asp = null; Php = null; Delim = delim; Attribute = attribute; Val = val; }
public AttVal() { Next = null; _dict = null; _asp = null; Php = null; Delim = 0; Attribute = null; Val = null; }
public virtual void Check(Lexer lexer, Node node, AttVal attval) { /* IMG, OBJECT, APPLET and EMBED use align for vertical position */ if (node.Tag != null && ((node.Tag.Model & ContentModel.IMG) != 0)) { AttrCheckImpl.CheckValign.Check(lexer, node, attval); return; } string val = attval.Val; if (val == null) { Report.AttrError(lexer, node, attval.Attribute, Report.MISSING_ATTR_VALUE); } else if ( !(String.CompareOrdinal(val, "left") == 0 || String.CompareOrdinal(val, "center") == 0 || String.CompareOrdinal(val, "right") == 0 || String.CompareOrdinal(val, "justify") == 0)) { Report.AttrError(lexer, node, attval.Val, Report.BAD_ATTRIBUTE_VALUE); } }
protected internal DomElementImpl(Node adaptee) : base(adaptee) { }
/* Called from printTree to print the content of a slide from the node slidecontent. On return slidecontent points to the node starting the next slide or null. The variables slide and count are used to customise the navigation bar. */ public virtual void PrintSlide(Out fout, int mode, int indent, Lexer lexer) { TagCollection tt = _options.TagTable; /* insert div for onclick handler */ string s = "<div onclick=\"document.location='slide" + (_slide < _count ? _slide + 1 : 1).ToString() + ".html'\">"; PrintString(s); CondFlushLine(fout, indent); /* first print the h2 element and navbar */ if (_slidecontent.Tag == tt.TagH2) { PrintNavBar(fout, indent); /* now print an hr after h2 */ AddC('<', _linelen++); AddC(Lexer.FoldCase('h', _options.UpperCaseTags, _options.XmlTags), _linelen++); AddC(Lexer.FoldCase('r', _options.UpperCaseTags, _options.XmlTags), _linelen++); if (_options.XmlOut) { PrintString(" />"); } else { AddC('>', _linelen++); } if (_options.IndentContent) { CondFlushLine(fout, indent); } /* PrintVertSpacer(fout, indent); */ /*CondFlushLine(fout, indent); */ /* print the h2 element */ PrintTree(fout, mode, (_options.IndentContent ? indent + _options.Spaces : indent), lexer, _slidecontent); _slidecontent = _slidecontent.Next; } /* now continue until we reach the next h2 */ Node last = null; Node content = _slidecontent; for (; content != null; content = content.Next) { if (content.Tag == tt.TagH2) { break; } /* kludge for naked text before block level tag */ if (last != null && !_options.IndentContent && last.Type == Node.TEXT_NODE && content.Tag != null && (content.Tag.Model & ContentModel.BLOCK) != 0) { FlushLine(fout, indent); FlushLine(fout, indent); } PrintTree(fout, mode, (_options.IndentContent ? indent + _options.Spaces : indent), lexer, content); last = content; } _slidecontent = content; /* now print epilog */ CondFlushLine(fout, indent); PrintString("<br clear=\"all\">"); CondFlushLine(fout, indent); AddC('<', _linelen++); AddC(Lexer.FoldCase('h', _options.UpperCaseTags, _options.XmlTags), _linelen++); AddC(Lexer.FoldCase('r', _options.UpperCaseTags, _options.XmlTags), _linelen++); if (_options.XmlOut) { PrintString(" />"); } else { AddC('>', _linelen++); } if (_options.IndentContent) { CondFlushLine(fout, indent); } PrintNavBar(fout, indent); /* end tag for div */ PrintString("</div>"); CondFlushLine(fout, indent); }
protected internal DomNodeListByTagNameImpl(Node first, string tagName) { _first = first; _tagName = tagName; }
private void PrintPi(Out fout, int indent, Node node) { if (indent + _linelen < _options.WrapLen) { _wraphere = _linelen; } AddC('<', _linelen++); AddC('?', _linelen++); /* set CDATA to pass < and > unescaped */ PrintText(fout, CDATA, indent, node.Textarray, node.Start, node.End); if (node.Textarray[node.End - 1] != (byte) '?') { AddC('?', _linelen++); } AddC('>', _linelen++); CondFlushLine(fout, indent); }
private void PrintAttrs(Out fout, int indent, Node node, AttVal attr) { if (attr != null) { if (attr.Next != null) { PrintAttrs(fout, indent, node, attr.Next); } if (attr.Attribute != null) { PrintAttribute(fout, indent, node, attr); } else if (attr.Asp != null) { AddC(' ', _linelen++); PrintAsp(fout, indent, attr.Asp); } else if (attr.Php != null) { AddC(' ', _linelen++); PrintPhp(fout, indent, attr.Php); } } /* add xml:space attribute to pre and other elements */ if (_options.XmlOut && _options.XmlSpace && ParserImpl.XmlPreserveWhiteSpace(node, _options.TagTable) && node.GetAttrByName("xml:space") == null) { PrintString(" xml:space=\"preserve\""); } }
private void PrintTag(Lexer lexer, Out fout, int mode, int indent, Node node) { TagCollection tt = _options.TagTable; AddC('<', _linelen++); if (node.Type == Node.END_TAG) { AddC('/', _linelen++); } string p = node.Element; for (int i = 0; i < p.Length; i++) { AddC(Lexer.FoldCase(p[i], _options.UpperCaseTags, _options.XmlTags), _linelen++); } PrintAttrs(fout, indent, node, node.Attributes); if ((_options.XmlOut || lexer != null && lexer.Isvoyager) && (node.Type == Node.START_END_TAG || (node.Tag.Model & ContentModel.EMPTY) != 0)) { AddC(' ', _linelen++); /* compatibility hack */ AddC('/', _linelen++); } AddC('>', _linelen++); if (node.Type == Node.START_END_TAG || (mode & PREFORMATTED) != 0) return; if (indent + _linelen >= _options.WrapLen) { WrapLine(fout, indent); } if (indent + _linelen < _options.WrapLen) { /* wrap after start tag if is <br/> or if it's not inline or it is an empty tag followed by </a> */ if (AfterSpace(node)) { if ((mode & NOWRAP) == 0 && ((node.Tag.Model & ContentModel.INLINE) == 0 || (node.Tag == tt.TagBr) || (((node.Tag.Model & ContentModel.EMPTY) != 0) && node.Next == null && node.Parent.Tag == tt.TagA))) { _wraphere = _linelen; } } } else { CondFlushLine(fout, indent); } }
/* note ASP and JSTE share <% ... %> syntax */ private void PrintAsp(Out fout, int indent, Node node) { int savewraplen = _options.WrapLen; /* disable wrapping if so requested */ if (!_options.WrapAsp || !_options.WrapJste) { _options.WrapLen = 0xFFFFFF; } /* a very large number */ AddC('<', _linelen++); AddC('%', _linelen++); PrintText(fout, (_options.WrapAsp ? CDATA : COMMENT), indent, node.Textarray, node.Start, node.End); AddC('%', _linelen++); AddC('>', _linelen++); /* CondFlushLine(fout, indent); */ _options.WrapLen = savewraplen; }
private void PrintAttribute(Out fout, int indent, Node node, AttVal attr) { bool wrappable = false; if (_options.IndentAttributes) { FlushLine(fout, indent); indent += _options.Spaces; } string name = attr.Attribute; if (indent + _linelen >= _options.WrapLen) { WrapLine(fout, indent); } if (!_options.XmlTags && !_options.XmlOut && attr.Dict != null) { if (AttributeTable.DefaultAttributeTable.IsScript(name)) { wrappable = _options.WrapScriptlets; } else if (!attr.Dict.Nowrap && _options.WrapAttVals) { wrappable = true; } } if (indent + _linelen < _options.WrapLen) { _wraphere = _linelen; AddC(' ', _linelen++); } else { CondFlushLine(fout, indent); AddC(' ', _linelen++); } for (int i = 0; i < name.Length; i++) { AddC(Lexer.FoldCase(name[i], _options.UpperCaseAttrs, _options.XmlTags), _linelen++); } if (indent + _linelen >= _options.WrapLen) { WrapLine(fout, indent); } if (attr.Val == null) { if (_options.XmlTags || _options.XmlOut) { PrintAttrValue(fout, indent, attr.Attribute, attr.Delim, true); } else if (!attr.BoolAttribute && !Node.IsNewNode(node)) { PrintAttrValue(fout, indent, "", attr.Delim, true); } else if (indent + _linelen < _options.WrapLen) { _wraphere = _linelen; } } else { PrintAttrValue(fout, indent, attr.Val, attr.Delim, wrappable); } }
protected internal DomDocumentImpl(Node adaptee) : base(adaptee) { _tt = new TagCollection(); }
private bool ShouldIndent(Node node) { TagCollection tt = _options.TagTable; if (!_options.IndentContent) return false; if (_options.SmartIndent) { if (node.Content != null && ((node.Tag.Model & ContentModel.NO_INDENT) != 0)) { for (node = node.Content; node != null; node = node.Next) { if (node.Tag != null && (node.Tag.Model & ContentModel.BLOCK) != 0) { return true; } } return false; } if ((node.Tag.Model & ContentModel.HEADING) != 0) { return false; } if (node.Tag == tt.TagP) { return false; } if (node.Tag == tt.TagTitle) { return false; } } if ((node.Tag.Model & (ContentModel.FIELD | ContentModel.OBJECT)) != 0) { return true; } if (node.Tag == tt.TagMap) { return true; } return (node.Tag.Model & ContentModel.INLINE) == 0; }
public virtual IElement CreateElement(string tagName) { var node = new Node(Node.START_END_TAG, null, 0, 0, tagName, _tt); if (node.Tag == null) node.Tag = _tt.XmlTags; return (IElement) node.Adapter; }
protected internal DomProcessingInstructionImpl(Node adaptee) : base(adaptee) { }
public virtual void CreateSlides(Lexer lexer, Node root) { Out output = new OutImpl(); Node body = root.FindBody(lexer.Options.TagTable); _count = CountSlides(body); _slidecontent = body.Content; AddTransitionEffect(lexer, root, EFFECT_BLEND, 3.0); for (_slide = 1; _slide <= _count; ++_slide) { string buf = "slide" + _slide + ".html"; output.State = StreamIn.FSM_ASCII; output.Encoding = _options.CharEncoding; try { output.Output = new MemoryStream(); PrintTree(output, 0, 0, lexer, root); FlushLine(output, 0); } catch (IOException e) { Debug.WriteLine(buf + e); } } }
/* split parse tree by h2 elements and output to separate files */ /* counts number of h2 children belonging to node */ public virtual int CountSlides(Node node) { int n = 1; TagCollection tt = _options.TagTable; for (node = node.Content; node != null; node = node.Next) { if (node.Tag == tt.TagH2) { ++n; } } return n; }
/* Add meta element for page transition effect, this works on IE but not NS */ public virtual void AddTransitionEffect(Lexer lexer, Node root, short effect, double duration) { Node head = root.FindHead(lexer.Options.TagTable); string transition; if (0 <= effect && effect <= 23) { transition = "revealTrans(Duration=" + (duration).ToString() + ",Transition=" + effect + ")"; } else { transition = "blendTrans(Duration=" + (duration).ToString() + ")"; } if (head != null) { Node meta = lexer.InferredTag("meta"); meta.AddAttribute("http-equiv", "Page-Enter"); meta.AddAttribute("content", transition); Node.InsertNodeAtStart(head, meta); } }
public virtual IComment CreateComment(string data) { byte[] textarray = Lexer.GetBytes(data); var node = new Node(Node.COMMENT_TAG, textarray, 0, textarray.Length); return (IComment) node.Adapter; }
public virtual void PrintTree(Out fout, int mode, int indent, Lexer lexer, Node node) { Node content; TagCollection tt = _options.TagTable; if (node == null) return; if (node.Type == Node.TEXT_NODE) { PrintText(fout, mode, indent, node.Textarray, node.Start, node.End); } else if (node.Type == Node.COMMENT_TAG) { PrintComment(fout, indent, node); } else if (node.Type == Node.ROOT_NODE) { for (content = node.Content; content != null; content = content.Next) { PrintTree(fout, mode, indent, lexer, content); } } else if (node.Type == Node.DOC_TYPE_TAG) { PrintDocType(fout, indent, node); } else if (node.Type == Node.PROC_INS_TAG) { PrintPi(fout, indent, node); } else if (node.Type == Node.CDATA_TAG) { PrintCdata(fout, indent, node); } else if (node.Type == Node.SECTION_TAG) { PrintSection(fout, indent, node); } else if (node.Type == Node.ASP_TAG) { PrintAsp(fout, indent, node); } else if (node.Type == Node.JSTE_TAG) { PrintJste(fout, indent, node); } else if (node.Type == Node.PHP_TAG) { PrintPhp(fout, indent, node); } else if ((node.Tag.Model & ContentModel.EMPTY) != 0 || node.Type == Node.START_END_TAG) { if ((node.Tag.Model & ContentModel.INLINE) == 0) { CondFlushLine(fout, indent); } if (node.Tag == tt.TagBr && node.Prev != null && node.Prev.Tag != tt.TagBr && _options.BreakBeforeBr) { FlushLine(fout, indent); } if (_options.MakeClean && node.Tag == tt.TagWbr) { PrintString(" "); } else { PrintTag(lexer, fout, mode, indent, node); } if (node.Tag == tt.TagParam || node.Tag == tt.TagArea) { CondFlushLine(fout, indent); } else if (node.Tag == tt.TagBr || node.Tag == tt.TagHr) { FlushLine(fout, indent); } } else { /* some kind of container element */ if (node.Tag != null && node.Tag.Parser == ParserImpl.ParsePre) { CondFlushLine(fout, indent); indent = 0; CondFlushLine(fout, indent); PrintTag(lexer, fout, mode, indent, node); FlushLine(fout, indent); for (content = node.Content; content != null; content = content.Next) { PrintTree(fout, (mode | PREFORMATTED | NOWRAP), indent, lexer, content); } CondFlushLine(fout, indent); PrintEndTag(node); FlushLine(fout, indent); if (_options.IndentContent == false && node.Next != null) { FlushLine(fout, indent); } } else if (node.Tag == tt.TagStyle || node.Tag == tt.TagScript) { CondFlushLine(fout, indent); indent = 0; CondFlushLine(fout, indent); PrintTag(lexer, fout, mode, indent, node); FlushLine(fout, indent); for (content = node.Content; content != null; content = content.Next) { PrintTree(fout, (mode | PREFORMATTED | NOWRAP | CDATA), indent, lexer, content); } CondFlushLine(fout, indent); PrintEndTag(node); FlushLine(fout, indent); if (_options.IndentContent == false && node.Next != null) { FlushLine(fout, indent); } } else if ((node.Tag.Model & ContentModel.INLINE) != 0) { if (_options.MakeClean) { /* discards <font> and </font> tags */ if (node.Tag == tt.TagFont) { for (content = node.Content; content != null; content = content.Next) { PrintTree(fout, mode, indent, lexer, content); } return; } /* replace <nobr>...</nobr> by or   etc. */ if (node.Tag == tt.TagNobr) { for (content = node.Content; content != null; content = content.Next) { PrintTree(fout, (mode | NOWRAP), indent, lexer, content); } return; } } /* otherwise a normal inline element */ PrintTag(lexer, fout, mode, indent, node); /* indent content for SELECT, TEXTAREA, MAP, OBJECT and APPLET */ if (ShouldIndent(node)) { CondFlushLine(fout, indent); indent += _options.Spaces; for (content = node.Content; content != null; content = content.Next) { PrintTree(fout, mode, indent, lexer, content); } CondFlushLine(fout, indent); indent -= _options.Spaces; CondFlushLine(fout, indent); } else { for (content = node.Content; content != null; content = content.Next) { PrintTree(fout, mode, indent, lexer, content); } } PrintEndTag(node); } else { /* other tags */ CondFlushLine(fout, indent); if (_options.SmartIndent && node.Prev != null) { FlushLine(fout, indent); } if (_options.HideEndTags == false || !(node.Tag != null && ((node.Tag.Model & ContentModel.OMIT_ST) != 0))) { PrintTag(lexer, fout, mode, indent, node); if (ShouldIndent(node)) { CondFlushLine(fout, indent); } else if ((node.Tag.Model & ContentModel.HTML) != 0 || node.Tag == tt.TagNoframes || ((node.Tag.Model & ContentModel.HEAD) != 0 && node.Tag != tt.TagTitle)) { FlushLine(fout, indent); } } if (node.Tag == tt.TagBody && _options.BurstSlides) { PrintSlide(fout, mode, (_options.IndentContent ? indent + _options.Spaces : indent), lexer); } else { Node last = null; for (content = node.Content; content != null; content = content.Next) { /* kludge for naked text before block level tag */ if (last != null && !_options.IndentContent && last.Type == Node.TEXT_NODE && content.Tag != null && (content.Tag.Model & ContentModel.BLOCK) != 0) { FlushLine(fout, indent); FlushLine(fout, indent); } PrintTree(fout, mode, (ShouldIndent(node) ? indent + _options.Spaces : indent), lexer, content); last = content; } } /* don't flush line for td and th */ if (ShouldIndent(node) || (((node.Tag.Model & ContentModel.HTML) != 0 || node.Tag == tt.TagNoframes || ((node.Tag.Model & ContentModel.HEAD) != 0 && node.Tag != tt.TagTitle)) && _options.HideEndTags == false)) { CondFlushLine(fout, (_options.IndentContent ? indent + _options.Spaces : indent)); if (_options.HideEndTags == false || (node.Tag.Model & ContentModel.OPT) == 0) { PrintEndTag(node); FlushLine(fout, indent); } } else { if (_options.HideEndTags == false || (node.Tag.Model & ContentModel.OPT) == 0) { PrintEndTag(node); } FlushLine(fout, indent); } if (_options.IndentContent == false && node.Next != null && _options.HideEndTags == false && (node.Tag.Model & (ContentModel.BLOCK | ContentModel.LIST | ContentModel.DEFLIST | ContentModel.TABLE)) != 0) { FlushLine(fout, indent); } } } }
public virtual IText CreateTextNode(string data) { byte[] textarray = Lexer.GetBytes(data); var node = new Node(Node.TEXT_NODE, textarray, 0, textarray.Length); return (IText) node.Adapter; }
public virtual void PrintXmlTree(Out fout, int mode, int indent, Lexer lexer, Node node) { TagCollection tt = _options.TagTable; if (node == null) { return; } if (node.Type == Node.TEXT_NODE) { PrintText(fout, mode, indent, node.Textarray, node.Start, node.End); } else if (node.Type == Node.COMMENT_TAG) { CondFlushLine(fout, indent); PrintComment(fout, 0, node); CondFlushLine(fout, 0); } else if (node.Type == Node.ROOT_NODE) { Node content; for (content = node.Content; content != null; content = content.Next) { PrintXmlTree(fout, mode, indent, lexer, content); } } else if (node.Type == Node.DOC_TYPE_TAG) { PrintDocType(fout, indent, node); } else if (node.Type == Node.PROC_INS_TAG) { PrintPi(fout, indent, node); } else if (node.Type == Node.SECTION_TAG) { PrintSection(fout, indent, node); } else if (node.Type == Node.ASP_TAG) { PrintAsp(fout, indent, node); } else if (node.Type == Node.JSTE_TAG) { PrintJste(fout, indent, node); } else if (node.Type == Node.PHP_TAG) { PrintPhp(fout, indent, node); } else if ((node.Tag.Model & ContentModel.EMPTY) != 0 || node.Type == Node.START_END_TAG) { CondFlushLine(fout, indent); PrintTag(lexer, fout, mode, indent, node); FlushLine(fout, indent); if (node.Next != null) { FlushLine(fout, indent); } } else { /* some kind of container element */ Node content; bool mixed = false; int cindent; for (content = node.Content; content != null; content = content.Next) { if (content.Type == Node.TEXT_NODE) { mixed = true; break; } } CondFlushLine(fout, indent); if (ParserImpl.XmlPreserveWhiteSpace(node, tt)) { indent = 0; cindent = 0; mixed = false; } else if (mixed) { cindent = indent; } else { cindent = indent + _options.Spaces; } PrintTag(lexer, fout, mode, indent, node); if (!mixed) { FlushLine(fout, indent); } for (content = node.Content; content != null; content = content.Next) { PrintXmlTree(fout, mode, cindent, lexer, content); } if (!mixed) { CondFlushLine(fout, cindent); } PrintEndTag(node); CondFlushLine(fout, indent); if (node.Next != null) { FlushLine(fout, indent); } } }
protected internal DomCdataSectionImpl(Node adaptee) : base(adaptee) { }
/* Line can be wrapped immediately after inline start tag provided if follows a text node ending in a space, or it parent is an inline element that that rule applies to. This behaviour was reverse engineered from Netscape 3.0 */ private static bool AfterSpace(Node node) { if (node == null || node.Tag == null || (node.Tag.Model & ContentModel.INLINE) == 0) { return true; } Node prev = node.Prev; if (prev != null) { if (prev.Type == Node.TEXT_NODE && prev.End > prev.Start) { int c = (prev.Textarray[prev.End - 1]) & 0xFF; if (c == 160 || c == ' ' || c == '\n') { return true; } } return false; } return AfterSpace(node.Parent); }