📄 parser.c
字号:
AddAttribute(node, "id", name->value); }}void MoveToHead(Lexer *lexer, Node *element, Node *node){ Node *head; if (node->type == StartTag || node->type == StartEndTag) { ReportWarning(lexer, element, node, TAG_NOT_ALLOWED_IN); while (element->tag != tag_html) element = element->parent; for (head = element->content; head; head = head->next) { if (head->tag == tag_head) { InsertNodeAtEnd(head, node); break; } } if (node->tag->parser) ParseTag(lexer, node, IgnoreWhitespace); } else { ReportWarning(lexer, element, node, DISCARDING_UNEXPECTED); FreeNode(node); }}/* element is node created by the lexer upon seeing the start tag, or by the parser when the start tag is inferred*/void ParseBlock(Lexer *lexer, Node *element, uint mode){ Node *node, *parent; Bool checkstack; uint istackbase; checkstack = yes; if (element->tag->model & CM_EMPTY) return; if (element->tag == tag_form && DescendantOf(element, tag_form)) ReportWarning(lexer, element, null, ILLEGAL_NESTING); /* InlineDup() asks the lexer to insert inline emphasis tags currently pushed on the istack, but take care to avoid propagating inline emphasis inside OBJECT or APPLET. For these elements a fresh inline stack context is created and disposed of upon reaching the end of the element. They thus behave like table cells in this respect. */ if (element->tag->model & CM_OBJECT) { istackbase = lexer->istackbase; lexer->istackbase = lexer->istacksize; } if (!(element->tag->model & CM_MIXED)) InlineDup(lexer, null); mode = IgnoreWhitespace; while ((node = GetToken(lexer, mode /*MixedContent*/)) != null) { /* end tag for this element */ if (node->type == EndTag && (node->tag == element->tag || element->was == node->tag)) { FreeNode(node); if (element->tag->model & CM_OBJECT) { /* pop inline stack */ while (lexer->istacksize > lexer->istackbase) PopInline(lexer, null); lexer->istackbase = istackbase; } element->closed = yes; TrimSpace(lexer, element->last); TrimEmptyElement(lexer, element); return; } if (node->tag == tag_html || node->tag == tag_head || node->tag == tag_body) { if (node->type == StartTag || node->type == StartEndTag) ReportWarning(lexer, element, node, DISCARDING_UNEXPECTED); FreeNode(node); continue; } if (node->type == EndTag) { if (node->tag == tag_br) node->type = StartTag; else if (node->tag == tag_p) { CoerceNode(lexer, node, tag_br); InsertNodeAtEnd(element, node); node = InferredTag(lexer, "br"); } else { /* if this is the end tag for an ancestor element then infer end tag for this element */ for (parent = element->parent; parent != null; parent = parent->parent) { if (node->tag == parent->tag) { if (!(element->tag->model & CM_OPT)) ReportWarning(lexer, element, node, MISSING_ENDTAG_BEFORE); UngetToken(lexer); if (element->tag->model & CM_OBJECT) { /* pop inline stack */ while (lexer->istacksize > lexer->istackbase) PopInline(lexer, null); lexer->istackbase = istackbase; } TrimSpace(lexer, element->last); TrimEmptyElement(lexer, element); return; } } /* special case </tr> etc. for stuff moved in front of table */ if (lexer->exiled && node->tag->model && (node->tag->model & CM_TABLE)) { UngetToken(lexer); TrimTrailingSpace(lexer, element->last); TrimEmptyElement(lexer, element); return; } } } /* mixed content model permits text */ if (node->type == TextNode) { if (checkstack) { checkstack = no; if (!(element->tag->model & CM_MIXED)) { if (InlineDup(lexer, node) > 0) continue; } } InsertNodeAtEnd(element, node); mode = MixedContent; continue; } if (InsertMisc(element, node)) continue; /* allow PARAM elements? */ if (node->tag == tag_param) { if ((element->tag->model & CM_PARAM) && node->type == StartTag) { InsertNodeAtEnd(element, node); continue; } /* otherwise discard it */ ReportWarning(lexer, element, node, DISCARDING_UNEXPECTED); FreeNode(node); continue; } /* allow AREA elements? */ if (node->tag == tag_area) { if ((element->tag == tag_map) && (node->type == StartTag || node->type == StartEndTag)) { InsertNodeAtEnd(element, node); continue; } /* otherwise discard it */ ReportWarning(lexer, element, node, DISCARDING_UNEXPECTED); FreeNode(node); continue; } /* ignore unknown start/end tags */ if (node->tag == null) { ReportWarning(lexer, element, node, DISCARDING_UNEXPECTED); FreeNode(node); continue; } /* Allow CM_INLINE elements here. Allow CM_BLOCK elements here unless lexer->excludeBlocks is yes. LI and DD are special cased. Otherwise infer end tag for this element. */ if (!(node->tag->model & CM_INLINE)) { if (node->type != StartTag && node->type != StartEndTag) { ReportWarning(lexer, element, node, DISCARDING_UNEXPECTED); continue; } if (element->tag == tag_td || element->tag == tag_th) { /* if parent is a table cell, avoid inferring the end of the cell */ if (node->tag->model & CM_HEAD) { MoveToHead(lexer, element, node); continue; } if (node->tag->model & CM_LIST) { UngetToken(lexer); node = InferredTag(lexer, "ul"); AddAttribute(node, "style", "margin-left: -2em"); lexer->excludeBlocks = yes; } else if (node->tag->model & CM_DEFLIST) { UngetToken(lexer); node = InferredTag(lexer, "dl"); lexer->excludeBlocks = yes; } /* infer end of current table cell */ if (!(node->tag->model & CM_BLOCK)) { UngetToken(lexer); TrimSpace(lexer, element->last); TrimEmptyElement(lexer, element); return; } } else if (node->tag->model & CM_BLOCK) { if (lexer->excludeBlocks) { if (!(element->tag->model & CM_OPT)) ReportWarning(lexer, element, node, MISSING_ENDTAG_BEFORE); UngetToken(lexer); if (element->tag->model & CM_OBJECT) lexer->istackbase = istackbase; TrimSpace(lexer, element->last); TrimEmptyElement(lexer, element); return; } } else /* things like list items */ { if (!(element->tag->model & CM_OPT) && !element->implicit) ReportWarning(lexer, element, node, MISSING_ENDTAG_BEFORE); if (node->tag->model & CM_HEAD) { MoveToHead(lexer, element, node); continue; } UngetToken(lexer); if (node->tag->model & CM_LIST) { if (element->parent && element->parent->tag && element->parent->tag->parser == ParseList) { TrimSpace(lexer, element->last); TrimEmptyElement(lexer, element); return; } node = InferredTag(lexer, "ul"); AddAttribute(node, "style", "margin-left: -2em"); } else if (node->tag->model & CM_DEFLIST) { if (element->parent->tag == tag_dl) { TrimSpace(lexer, element->last); TrimEmptyElement(lexer, element); return; } node = InferredTag(lexer, "dl"); } else if (node->tag->model & CM_TABLE || node->tag->model & CM_ROW) { node = InferredTag(lexer, "table"); } else if (element->tag->model & CM_OBJECT) { /* pop inline stack */ while (lexer->istacksize > lexer->istackbase) PopInline(lexer, null); lexer->istackbase = istackbase; TrimSpace(lexer, element->last); TrimEmptyElement(lexer, element); return; } else { TrimSpace(lexer, element->last); TrimEmptyElement(lexer, element); return; } } } /* parse known element */ if (node->type == StartTag || node->type == StartEndTag) { if (node->tag->model & CM_INLINE) { if (checkstack && !node->implicit) { checkstack = no; if (InlineDup(lexer, node) > 0) continue; } mode = MixedContent; } else { checkstack = yes; mode = IgnoreWhitespace; } /* trim white space before <br> */ if (node->tag == tag_br) TrimSpace(lexer, element->last); InsertNodeAtEnd(element, node); if (node->implicit) ReportWarning(lexer, element, node, INSERTING_TAG); ParseTag(lexer, node, IgnoreWhitespace /*MixedContent*/); continue; } /* discard unexpected tags */ if (node->type == EndTag) PopInline(lexer, node); /* if inline end tag */ ReportWarning(lexer, element, node, DISCARDING_UNEXPECTED); FreeNode(node); } if (!(element->tag->model & CM_OPT)) ReportWarning(lexer, element, node, MISSING_ENDTAG_FOR); if (element->tag->model & CM_OBJECT) { /* pop inline stack */ while (lexer->istacksize > lexer->istackbase) PopInline(lexer, null); lexer->istackbase = istackbase; } TrimSpace(lexer, element->last); TrimEmptyElement(lexer, element);}void ParseInline(Lexer *lexer, Node *element, uint mode){ Node *node, *parent; if (element->tag->model & CM_EMPTY) return; if (element->tag == tag_a) { if (element->attributes == null) { ReportWarning(lexer, element->parent, element, DISCARDING_UNEXPECTED); DiscardElement(element); return; } } /* ParseInline is used for some block level elements like H1 to H6 For such elements we need to insert inline emphasis tags currently on the inline stack. For Inline elements, we normally push them onto the inline stack provided they aren't implicit or OBJECT/APPLET. This test is carried out in PushInline and PopInline, see istack.c We don't push A or SPAN to replicate current browser behavior */ if (element->tag->model & CM_BLOCK) InlineDup(lexer, null); else if (element->tag->model & CM_INLINE && element->tag != tag_a && element->tag != tag_span) PushInline(lexer, element); if (element->tag == tag_nobr) lexer->badLayout |= USING_NOBR; else if (element->tag == tag_font) lexer->badLayout |= USING_FONT; /* Inline elements may or may not be within a preformatted element */ if (mode != Preformatted) mode = MixedContent; while ((node = GetToken(lexer, mode)) != null) { /* end tag for current element */ if (node->tag == element->tag && node->type == EndTag) { if (element->tag->model & CM_INLINE && element->tag != tag_a) PopInline(lexer, node); FreeNode(node); if (!(mode & Preformatted)) TrimTrailingSpace(lexer, element->last); /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -