Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(68)

Side by Side Diff: third_party/WebKit/Source/core/html/parser/HTMLConstructionSite.cpp

Issue 2842933002: De-duplicate create element code paths in the HTML parser. (Closed)
Patch Set: Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/WebKit/Source/core/html/parser/HTMLConstructionSite.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2010 Google, Inc. All Rights Reserved. 2 * Copyright (C) 2010 Google, Inc. All Rights Reserved.
3 * Copyright (C) 2011 Apple Inc. All rights reserved. 3 * Copyright (C) 2011 Apple Inc. All rights reserved.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 6 * modification, are permitted provided that the following conditions
7 * are met: 7 * are met:
8 * 1. Redistributions of source code must retain the above copyright 8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright 10 * 2. Redistributions in binary form must reproduce the above copyright
(...skipping 659 matching lines...) Expand 10 before | Expand all | Expand 10 after
670 670
671 void HTMLConstructionSite::InsertCommentOnHTMLHtmlElement( 671 void HTMLConstructionSite::InsertCommentOnHTMLHtmlElement(
672 AtomicHTMLToken* token) { 672 AtomicHTMLToken* token) {
673 DCHECK_EQ(token->GetType(), HTMLToken::kComment); 673 DCHECK_EQ(token->GetType(), HTMLToken::kComment);
674 ContainerNode* parent = open_elements_.RootNode(); 674 ContainerNode* parent = open_elements_.RootNode();
675 AttachLater(parent, Comment::Create(parent->GetDocument(), token->Comment())); 675 AttachLater(parent, Comment::Create(parent->GetDocument(), token->Comment()));
676 } 676 }
677 677
678 void HTMLConstructionSite::InsertHTMLHeadElement(AtomicHTMLToken* token) { 678 void HTMLConstructionSite::InsertHTMLHeadElement(AtomicHTMLToken* token) {
679 DCHECK(!ShouldFosterParent()); 679 DCHECK(!ShouldFosterParent());
680 head_ = HTMLStackItem::Create(CreateHTMLElement(token), token); 680 head_ = HTMLStackItem::Create(CreateElement(token, xhtmlNamespaceURI), token);
681 AttachLater(CurrentNode(), head_->GetElement()); 681 AttachLater(CurrentNode(), head_->GetElement());
682 open_elements_.PushHTMLHeadElement(head_); 682 open_elements_.PushHTMLHeadElement(head_);
683 } 683 }
684 684
685 void HTMLConstructionSite::InsertHTMLBodyElement(AtomicHTMLToken* token) { 685 void HTMLConstructionSite::InsertHTMLBodyElement(AtomicHTMLToken* token) {
686 DCHECK(!ShouldFosterParent()); 686 DCHECK(!ShouldFosterParent());
687 HTMLElement* body = CreateHTMLElement(token); 687 Element* body = CreateElement(token, xhtmlNamespaceURI);
688 AttachLater(CurrentNode(), body); 688 AttachLater(CurrentNode(), body);
689 open_elements_.PushHTMLBodyElement(HTMLStackItem::Create(body, token)); 689 open_elements_.PushHTMLBodyElement(HTMLStackItem::Create(body, token));
690 if (document_) 690 if (document_)
691 document_->WillInsertBody(); 691 document_->WillInsertBody();
692 } 692 }
693 693
694 void HTMLConstructionSite::InsertHTMLFormElement(AtomicHTMLToken* token, 694 void HTMLConstructionSite::InsertHTMLFormElement(AtomicHTMLToken* token,
695 bool is_demoted) { 695 bool is_demoted) {
696 HTMLElement* element = CreateHTMLElement(token); 696 Element* element = CreateElement(token, xhtmlNamespaceURI);
697 DCHECK(isHTMLFormElement(element)); 697 DCHECK(isHTMLFormElement(element));
698 HTMLFormElement* form_element = toHTMLFormElement(element); 698 HTMLFormElement* form_element = toHTMLFormElement(element);
699 if (!OpenElements()->HasTemplateInHTMLScope()) 699 if (!OpenElements()->HasTemplateInHTMLScope())
700 form_ = form_element; 700 form_ = form_element;
701 form_element->SetDemoted(is_demoted); 701 form_element->SetDemoted(is_demoted);
702 AttachLater(CurrentNode(), form_element); 702 AttachLater(CurrentNode(), form_element);
703 open_elements_.Push(HTMLStackItem::Create(form_element, token)); 703 open_elements_.Push(HTMLStackItem::Create(form_element, token));
704 } 704 }
705 705
706 void HTMLConstructionSite::InsertHTMLElement(AtomicHTMLToken* token) { 706 void HTMLConstructionSite::InsertHTMLElement(AtomicHTMLToken* token) {
707 HTMLElement* element = CreateHTMLElement(token); 707 Element* element = CreateElement(token, xhtmlNamespaceURI);
708 AttachLater(CurrentNode(), element); 708 AttachLater(CurrentNode(), element);
709 open_elements_.Push(HTMLStackItem::Create(element, token)); 709 open_elements_.Push(HTMLStackItem::Create(element, token));
710 } 710 }
711 711
712 void HTMLConstructionSite::InsertSelfClosingHTMLElementDestroyingToken( 712 void HTMLConstructionSite::InsertSelfClosingHTMLElementDestroyingToken(
713 AtomicHTMLToken* token) { 713 AtomicHTMLToken* token) {
714 DCHECK_EQ(token->GetType(), HTMLToken::kStartTag); 714 DCHECK_EQ(token->GetType(), HTMLToken::kStartTag);
715 // Normally HTMLElementStack is responsible for calling finishParsingChildren, 715 // Normally HTMLElementStack is responsible for calling finishParsingChildren,
716 // but self-closing elements are never in the element stack so the stack 716 // but self-closing elements are never in the element stack so the stack
717 // doesn't get a chance to tell them that we're done parsing their children. 717 // doesn't get a chance to tell them that we're done parsing their children.
718 AttachLater(CurrentNode(), CreateHTMLElement(token), true); 718 AttachLater(CurrentNode(), CreateElement(token, xhtmlNamespaceURI), true);
719 // FIXME: Do we want to acknowledge the token's self-closing flag? 719 // FIXME: Do we want to acknowledge the token's self-closing flag?
720 // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.ht ml#acknowledge-self-closing-flag 720 // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.ht ml#acknowledge-self-closing-flag
721 } 721 }
722 722
723 void HTMLConstructionSite::InsertFormattingElement(AtomicHTMLToken* token) { 723 void HTMLConstructionSite::InsertFormattingElement(AtomicHTMLToken* token) {
724 // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#th e-stack-of-open-elements 724 // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#th e-stack-of-open-elements
725 // Possible active formatting elements include: 725 // Possible active formatting elements include:
726 // a, b, big, code, em, font, i, nobr, s, small, strike, strong, tt, and u. 726 // a, b, big, code, em, font, i, nobr, s, small, strike, strong, tt, and u.
727 InsertHTMLElement(token); 727 InsertHTMLElement(token);
728 active_formatting_elements_.Append(CurrentElementRecord()->StackItem()); 728 active_formatting_elements_.Append(CurrentElementRecord()->StackItem());
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
835 HTMLConstructionSiteTask task(HTMLConstructionSiteTask::kTakeAllChildren); 835 HTMLConstructionSiteTask task(HTMLConstructionSiteTask::kTakeAllChildren);
836 task.parent = new_parent->GetNode(); 836 task.parent = new_parent->GetNode();
837 task.child = old_parent->GetNode(); 837 task.child = old_parent->GetNode();
838 QueueTask(task); 838 QueueTask(task);
839 } 839 }
840 840
841 CreateElementFlags HTMLConstructionSite::GetCreateElementFlags() const { 841 CreateElementFlags HTMLConstructionSite::GetCreateElementFlags() const {
842 return is_parsing_fragment_ ? kCreatedByFragmentParser : kCreatedByParser; 842 return is_parsing_fragment_ ? kCreatedByFragmentParser : kCreatedByParser;
843 } 843 }
844 844
845 Element* HTMLConstructionSite::CreateElement(
846 AtomicHTMLToken* token,
847 const AtomicString& namespace_uri) {
848 QualifiedName tag_name(g_null_atom, token->GetName(), namespace_uri);
849 Element* element = OwnerDocumentForCurrentNode().createElement(
850 tag_name, GetCreateElementFlags());
851 SetAttributes(element, token, parser_content_policy_);
852 return element;
853 }
854
855 inline Document& HTMLConstructionSite::OwnerDocumentForCurrentNode() { 845 inline Document& HTMLConstructionSite::OwnerDocumentForCurrentNode() {
856 if (isHTMLTemplateElement(*CurrentNode())) 846 if (isHTMLTemplateElement(*CurrentNode()))
857 return toHTMLTemplateElement(CurrentElement())->content()->GetDocument(); 847 return toHTMLTemplateElement(CurrentElement())->content()->GetDocument();
858 return CurrentNode()->GetDocument(); 848 return CurrentNode()->GetDocument();
859 } 849 }
860 850
861 // "look up a custom element definition" for a token 851 // "look up a custom element definition" for a token
862 // https://html.spec.whatwg.org/#look-up-a-custom-element-definition 852 // https://html.spec.whatwg.org/#look-up-a-custom-element-definition
863 CustomElementDefinition* HTMLConstructionSite::LookUpCustomElementDefinition( 853 CustomElementDefinition* HTMLConstructionSite::LookUpCustomElementDefinition(
864 Document& document, 854 Document& document,
(...skipping 13 matching lines...) Expand all
878 const Attribute* is_attribute = token->GetAttributeItem(HTMLNames::isAttr); 868 const Attribute* is_attribute = token->GetAttributeItem(HTMLNames::isAttr);
879 const AtomicString& name = is_attribute ? is_attribute->Value() : local_name; 869 const AtomicString& name = is_attribute ? is_attribute->Value() : local_name;
880 CustomElementDescriptor descriptor(name, local_name); 870 CustomElementDescriptor descriptor(name, local_name);
881 871
882 // 4.-6. 872 // 4.-6.
883 return registry->DefinitionFor(descriptor); 873 return registry->DefinitionFor(descriptor);
884 } 874 }
885 875
886 // "create an element for a token" 876 // "create an element for a token"
887 // https://html.spec.whatwg.org/multipage/syntax.html#create-an-element-for-the- token 877 // https://html.spec.whatwg.org/multipage/syntax.html#create-an-element-for-the- token
888 // TODO(dominicc): When form association is separate from creation, unify this 878 Element* HTMLConstructionSite::CreateElement(
889 // with foreign element creation. Add a namespace parameter and check for HTML 879 AtomicHTMLToken* token,
890 // namespace to lookupCustomElementDefinition. 880 const AtomicString& namespace_uri) {
891 HTMLElement* HTMLConstructionSite::CreateHTMLElement(AtomicHTMLToken* token) {
892 // "1. Let document be intended parent's node document." 881 // "1. Let document be intended parent's node document."
893 Document& document = OwnerDocumentForCurrentNode(); 882 Document& document = OwnerDocumentForCurrentNode();
894 883
895 // Only associate the element with the current form if we're creating the new
896 // element in a document with a browsing context (rather than in <template>
897 // contents).
898 // TODO(dominicc): Change form to happen after element creation when
899 // implementing customized built-in elements.
900 HTMLFormElement* form = document.GetFrame() ? form_.Get() : nullptr;
901
902 // "2. Let local name be the tag name of the token." 884 // "2. Let local name be the tag name of the token."
903 // "3. Let is be the value of the "is" attribute in the giev token ..." etc. 885 QualifiedName tag_name(g_null_atom, token->GetName(), namespace_uri);
886 // "3. Let is be the value of the "is" attribute in the given token ..." etc.
904 // "4. Let definition be the result of looking up a custom element ..." etc. 887 // "4. Let definition be the result of looking up a custom element ..." etc.
905 CustomElementDefinition* definition = 888 CustomElementDefinition* definition =
906 is_parsing_fragment_ ? nullptr 889 is_parsing_fragment_ ? nullptr
907 : LookUpCustomElementDefinition(document, token); 890 : LookUpCustomElementDefinition(document, token);
908 // "5. If definition is non-null and the parser was not originally created 891 // "5. If definition is non-null and the parser was not originally created
909 // for the HTML fragment parsing algorithm, then let will execute script 892 // for the HTML fragment parsing algorithm, then let will execute script
910 // be true." 893 // be true."
911 bool will_execute_script = definition && !is_parsing_fragment_; 894 bool will_execute_script = definition && !is_parsing_fragment_;
912 895
913 HTMLElement* element; 896 Element* element;
914 897
915 if (will_execute_script) { 898 if (will_execute_script) {
916 // "6.1 Increment the document's throw-on-dynamic-insertion counter." 899 // "6.1 Increment the document's throw-on-dynamic-insertion counter."
917 ThrowOnDynamicMarkupInsertionCountIncrementer 900 ThrowOnDynamicMarkupInsertionCountIncrementer
918 throw_on_dynamic_markup_insertions(&document); 901 throw_on_dynamic_markup_insertions(&document);
919 902
920 // "6.2 If the JavaScript execution context stack is empty, 903 // "6.2 If the JavaScript execution context stack is empty,
921 // then perform a microtask checkpoint." 904 // then perform a microtask checkpoint."
922 905
923 // TODO(dominicc): This is the way the Blink HTML parser performs 906 // TODO(dominicc): This is the way the Blink HTML parser performs
924 // checkpoints, but note the spec is different--it talks about the 907 // checkpoints, but note the spec is different--it talks about the
925 // JavaScript stack, not the script nesting level. 908 // JavaScript stack, not the script nesting level.
926 if (0u == reentry_permit_->ScriptNestingLevel()) 909 if (0u == reentry_permit_->ScriptNestingLevel())
927 Microtask::PerformCheckpoint(V8PerIsolateData::MainThreadIsolate()); 910 Microtask::PerformCheckpoint(V8PerIsolateData::MainThreadIsolate());
928 911
929 // "6.3 Push a new element queue onto the custom element 912 // "6.3 Push a new element queue onto the custom element
930 // reactions stack." 913 // reactions stack."
931 CEReactionsScope reactions; 914 CEReactionsScope reactions;
932 915
933 // 7. 916 // 7.
934 QualifiedName element_q_name(g_null_atom, token->GetName(), 917 element = definition->CreateElementSync(document, tag_name);
935 HTMLNames::xhtmlNamespaceURI);
936 element = definition->CreateElementSync(document, element_q_name);
937 918
938 // "8. Append each attribute in the given token to element." We don't use 919 // "8. Append each attribute in the given token to element." We don't use
939 // setAttributes here because the custom element constructor may have 920 // setAttributes here because the custom element constructor may have
940 // manipulated attributes. 921 // manipulated attributes.
941 for (const auto& attribute : token->Attributes()) 922 for (const auto& attribute : token->Attributes())
942 element->setAttribute(attribute.GetName(), attribute.Value()); 923 element->setAttribute(attribute.GetName(), attribute.Value());
943 924
944 // "9. If will execute script is true, then ..." etc. The CEReactionsScope 925 // "9. If will execute script is true, then ..." etc. The CEReactionsScope
945 // and ThrowOnDynamicMarkupInsertionCountIncrementer destructors implement 926 // and ThrowOnDynamicMarkupInsertionCountIncrementer destructors implement
946 // steps 9.1-3. 927 // steps 9.1-3.
947 } else { 928 } else {
948 // FIXME: This can't use HTMLConstructionSite::createElement because we have 929 element = document.createElement(tag_name, GetCreateElementFlags());
949 // to pass the current form element. We should rework form association to
950 // occur after construction to allow better code sharing here.
951 element = HTMLElementFactory::createHTMLElement(token->GetName(), document,
952 GetCreateElementFlags());
953 if (FormAssociated* form_associated_element =
954 element->ToFormAssociatedOrNull()) {
955 form_associated_element->AssociateWith(form);
956 }
957 // Definition for the created element does not exist here and it cannot be 930 // Definition for the created element does not exist here and it cannot be
958 // custom or failed. 931 // custom or failed.
959 DCHECK_NE(element->GetCustomElementState(), CustomElementState::kCustom); 932 DCHECK_NE(element->GetCustomElementState(), CustomElementState::kCustom);
960 DCHECK_NE(element->GetCustomElementState(), CustomElementState::kFailed); 933 DCHECK_NE(element->GetCustomElementState(), CustomElementState::kFailed);
961 934
935 // TODO(dominicc): Move these steps so they happen for custom
936 // elements as well as built-in elements when customized built in
937 // elements are implemented for resettable, listed elements.
938
939 // 10. If element has an xmlns attribute in the XMLNS namespace
940 // whose value is not exactly the same as the element's namespace,
941 // that is a parse error. Similarly, if element has an xmlns:xlink
942 // attribute in the XMLNS namespace whose value is not the XLink
943 // Namespace, that is a parse error.
944
945 // TODO(dominicc): Implement step 10 when the HTML parser does
946 // something useful with parse errors.
kouhei (in TOK) 2017/04/26 04:24:54 FYI: I think we are going to ignore all parse erro
947
948 // 11. If element is a resettable element, invoke its reset
949 // algorithm. (This initializes the element's value and
950 // checkedness based on the element's attributes.)
951 // TODO(dominicc): Implement step 11, resettable elements.
952
953 // 12. If element is a form-associated element, and the form
954 // element pointer is not null, and there is no template element
955 // on the stack of open elements, ...
956 FormAssociated* form_associated_element =
957 element->IsHTMLElement()
958 ? ToHTMLElement(element)->ToFormAssociatedOrNull()
959 : nullptr;
960 if (form_associated_element && document.GetFrame() && form_.Get()) {
961 // ... and element is either not listed or doesn't have a form
962 // attribute, and the intended parent is in the same tree as the
963 // element pointed to by the form element pointer, associate
964 // element with the form element pointed to by the form element
965 // pointer, and suppress the running of the reset the form owner
966 // algorithm when the parser subsequently attempts to insert the
967 // element.
968
969 // TODO(dominicc): There are many differences to the spec here;
970 // some of them are observable:
971 //
972 // - The HTML spec tracks whether there is a template element on
973 // the stack both for manipulating the form element pointer
974 // and using it here.
975 // - FormAssociated::AssociateWith implementations don't do the
976 // "same tree" check; for example
977 // HTMLImageElement::AssociateWith just checks whether the form
978 // is in *a* tree. This check should be done here consistently.
979 // - ListedElement is a mixin; add IsListedElement and skip
980 // setting the form for listed attributes with form=. Instead
981 // we set attributes (step 8) out of order, after this step,
982 // to reset the form association.
983 form_associated_element->AssociateWith(form_.Get());
984 }
962 // "8. Append each attribute in the given token to element." 985 // "8. Append each attribute in the given token to element."
963 SetAttributes(element, token, parser_content_policy_); 986 SetAttributes(element, token, parser_content_policy_);
964 } 987 }
965 988
966 // TODO(dominicc): Implement steps 10-12 when customized built-in elements are
967 // implemented.
968
969 return element; 989 return element;
970 } 990 }
971 991
972 HTMLStackItem* HTMLConstructionSite::CreateElementFromSavedToken( 992 HTMLStackItem* HTMLConstructionSite::CreateElementFromSavedToken(
973 HTMLStackItem* item) { 993 HTMLStackItem* item) {
974 Element* element; 994 Element* element;
975 // NOTE: Moving from item -> token -> item copies the Attribute vector twice! 995 // NOTE: Moving from item -> token -> item copies the Attribute vector twice!
976 AtomicHTMLToken fake_token(HTMLToken::kStartTag, item->LocalName(), 996 AtomicHTMLToken fake_token(HTMLToken::kStartTag, item->LocalName(),
977 item->Attributes()); 997 item->Attributes());
978 if (item->NamespaceURI() == HTMLNames::xhtmlNamespaceURI) 998 element = CreateElement(&fake_token, item->NamespaceURI());
979 element = CreateHTMLElement(&fake_token);
980 else
981 element = CreateElement(&fake_token, item->NamespaceURI());
982 return HTMLStackItem::Create(element, &fake_token, item->NamespaceURI()); 999 return HTMLStackItem::Create(element, &fake_token, item->NamespaceURI());
983 } 1000 }
984 1001
985 bool HTMLConstructionSite::IndexOfFirstUnopenFormattingElement( 1002 bool HTMLConstructionSite::IndexOfFirstUnopenFormattingElement(
986 unsigned& first_unopen_element_index) const { 1003 unsigned& first_unopen_element_index) const {
987 if (active_formatting_elements_.IsEmpty()) 1004 if (active_formatting_elements_.IsEmpty())
988 return false; 1005 return false;
989 unsigned index = active_formatting_elements_.size(); 1006 unsigned index = active_formatting_elements_.size();
990 do { 1007 do {
991 --index; 1008 --index;
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
1084 DCHECK(task.parent); 1101 DCHECK(task.parent);
1085 QueueTask(task); 1102 QueueTask(task);
1086 } 1103 }
1087 1104
1088 DEFINE_TRACE(HTMLConstructionSite::PendingText) { 1105 DEFINE_TRACE(HTMLConstructionSite::PendingText) {
1089 visitor->Trace(parent); 1106 visitor->Trace(parent);
1090 visitor->Trace(next_child); 1107 visitor->Trace(next_child);
1091 } 1108 }
1092 1109
1093 } // namespace blink 1110 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/html/parser/HTMLConstructionSite.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698