一、本文以一个简单的 HTML 表单,包罗两个文本输入框和一个提交按钮:
- <form action="demo_form.php">
- First name: <input type="text" name="fname"><br>
- Last name: <input type="text" name="lname"><br>
- <input type="submit" value="提交">
- </form>
复制代码 测试时候可以打开菜鸟教程在线编辑器 (runoob.com)运行以上代码
二、看下c++form表单接口定义:
2.1)、form接口定义文件:
third_party\blink\renderer\core\html\forms\html_form_element.idl
method="get|post|dialog"
- // https://html.spec.whatwg.org/C/#the-form-element
- [
- Exposed=Window,
- HTMLConstructor,
- LegacyOverrideBuiltIns
- ] interface HTMLFormElement : HTMLElement {
- [CEReactions, Reflect=accept_charset] attribute DOMString acceptCharset;
- [CEReactions, URL] attribute USVString action;
- [CEReactions, Reflect, ReflectOnly=("on","off"), ReflectMissing="on", ReflectInvalid="on"] attribute DOMString autocomplete;
- [CEReactions] attribute DOMString enctype;
- [CEReactions] attribute DOMString encoding;
- [CEReactions] attribute DOMString method;
- [CEReactions, Reflect] attribute DOMString name;
- [CEReactions, Reflect] attribute boolean noValidate;
- [CEReactions, Reflect] attribute DOMString target;
- [CEReactions, Reflect] attribute DOMString rel;
- [SameObject, PutForwards=value] readonly attribute DOMTokenList relList;
- readonly attribute HTMLFormControlsCollection elements;
- readonly attribute long length;
- [ImplementedAs=item] getter Element (unsigned long index);
- // FIXME: This getter should not have [NotEnumerable].
- [NotEnumerable] getter (RadioNodeList or Element) (DOMString name);
- [ImplementedAs=submitFromJavaScript] void submit();
- [RaisesException] void requestSubmit(optional HTMLElement? submitter = null);
- [CEReactions] void reset();
- boolean checkValidity();
- boolean reportValidity();
- };
复制代码 2.2)、blink下form接口实现:
third_party\blink\renderer\core\html\forms\html_form_element.h
third_party\blink\renderer\core\html\forms\html_form_element.cc
用于查找和遍历form元素
- #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_HTML_FORM_ELEMENT_H_
- #define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_HTML_FORM_ELEMENT_H_
- #include "third_party/blink/renderer/core/core_export.h"
- #include "third_party/blink/renderer/core/html/forms/html_form_control_element.h"
- #include "third_party/blink/renderer/core/html/forms/radio_button_group_scope.h"
- #include "third_party/blink/renderer/core/html/html_element.h"
- #include "third_party/blink/renderer/core/loader/form_submission.h"
- #include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
- namespace blink {
- class DOMTokenList;
- class Event;
- class HTMLFormControlElement;
- class HTMLFormControlsCollection;
- class HTMLImageElement;
- class ListedElement;
- class RelList;
- class V8UnionElementOrRadioNodeList;
- class CORE_EXPORT HTMLFormElement final : public HTMLElement {
- DEFINE_WRAPPERTYPEINFO();
- public:
- enum RelAttribute {
- kNone = 0,
- kNoReferrer = 1 << 0,
- kNoOpener = 1 << 1,
- kOpener = 1 << 2,
- };
- explicit HTMLFormElement(Document&);
- ~HTMLFormElement() override;
- void Trace(Visitor*) const override;
- HTMLFormControlsCollection* elements();
- void GetNamedElements(const AtomicString&, HeapVector<Member<Element>>&);
- unsigned length() const;
- HTMLElement* item(unsigned index);
- String action() const;
- void setAction(const AtomicString&);
- String enctype() const { return attributes_.EncodingType(); }
- void setEnctype(const AtomicString&);
- String encoding() const { return attributes_.EncodingType(); }
- void setEncoding(const AtomicString& value) { setEnctype(value); }
- DOMTokenList& relList() const;
- bool HasRel(RelAttribute relation) const;
- bool ShouldAutocomplete() const;
- void Associate(ListedElement&);
- void Disassociate(ListedElement&);
- void Associate(HTMLImageElement&);
- void Disassociate(HTMLImageElement&);
- void DidAssociateByParser();
- void PrepareForSubmission(const Event*,
- HTMLFormControlElement* submit_button);
- void submitFromJavaScript();
- void requestSubmit(ExceptionState& exception_state);
- void requestSubmit(HTMLElement* submitter, ExceptionState& exception_state);
- void reset();
- void AttachLayoutTree(AttachContext& context) override;
- void DetachLayoutTree(bool performing_reattach) override;
- void SubmitImplicitly(const Event&, bool from_implicit_submission_trigger);
- String GetName() const;
- bool NoValidate() const;
- const AtomicString& Action() const;
- String method() const;
- void setMethod(const AtomicString&);
- FormSubmission::SubmitMethod Method() const { return attributes_.Method(); }
- // Find the 'default button.'
- // https://html.spec.whatwg.org/C/#default-button
- HTMLFormControlElement* FindDefaultButton() const;
- bool checkValidity();
- bool reportValidity();
- bool MatchesValidityPseudoClasses() const final;
- bool IsValidElement() final;
- RadioButtonGroupScope& GetRadioButtonGroupScope() {
- return radio_button_group_scope_;
- }
- const ListedElement::List& ListedElements(
- bool include_shadow_trees = false) const;
- const HeapVector<Member<HTMLImageElement>>& ImageElements();
- V8UnionElementOrRadioNodeList* AnonymousNamedGetter(const AtomicString& name);
- void InvalidateDefaultButtonStyle() const;
- // 'construct the entry list'
- // https://html.spec.whatwg.org/C/#constructing-the-form-data-set
- // Returns nullptr if this form is already running this function.
- FormData* ConstructEntryList(HTMLFormControlElement* submit_button,
- const WTF::TextEncoding& encoding);
- uint64_t UniqueRendererFormId() const { return unique_renderer_form_id_; }
- void InvalidateListedElementsIncludingShadowTrees();
- private:
- InsertionNotificationRequest InsertedInto(ContainerNode&) override;
- void RemovedFrom(ContainerNode&) override;
- void FinishParsingChildren() override;
- void HandleLocalEvents(Event&) override;
- void ParseAttribute(const AttributeModificationParams&) override;
- bool IsURLAttribute(const Attribute&) const override;
- bool HasLegalLinkAttribute(const QualifiedName&) const override;
- NamedItemType GetNamedItemType() const override {
- return NamedItemType::kName;
- }
- void SubmitDialog(FormSubmission*);
- void ScheduleFormSubmission(const Event*,
- HTMLFormControlElement* submit_button);
- void CollectListedElements(
- const Node& root,
- ListedElement::List& elements,
- ListedElement::List* elements_including_shadow_trees = nullptr,
- bool in_shadow_tree = false) const;
- void CollectImageElements(Node& root, HeapVector<Member<HTMLImageElement>>&);
- // Returns true if the submission should proceed.
- bool ValidateInteractively();
- // Validates each of the controls, and stores controls of which 'invalid'
- // event was not canceled to the specified vector. Returns true if there
- // are any invalid controls in this form.
- bool CheckInvalidControlsAndCollectUnhandled(ListedElement::List*);
- Element* ElementFromPastNamesMap(const AtomicString&);
- void AddToPastNamesMap(Element*, const AtomicString& past_name);
- void RemoveFromPastNamesMap(HTMLElement&);
- typedef HeapHashMap<AtomicString, Member<Element>> PastNamesMap;
- FormSubmission::Attributes attributes_;
- Member<PastNamesMap> past_names_map_;
- RadioButtonGroupScope radio_button_group_scope_;
- // Do not access listed_elements_ directly. Use ListedElements() instead.
- ListedElement::List listed_elements_;
- // Do not access listed_elements_including_shadow_trees_ directly. Use
- // ListedElements(true) instead.
- ListedElement::List listed_elements_including_shadow_trees_;
- // Do not access image_elements_ directly. Use ImageElements() instead.
- HeapVector<Member<HTMLImageElement>> image_elements_;
- uint64_t unique_renderer_form_id_;
- base::OnceClosure cancel_last_submission_;
- bool is_submitting_ = false;
- bool in_user_js_submit_event_ = false;
- bool is_constructing_entry_list_ = false;
- bool listed_elements_are_dirty_ : 1;
- bool listed_elements_including_shadow_trees_are_dirty_ : 1;
- bool image_elements_are_dirty_ : 1;
- bool has_elements_associated_by_parser_ : 1;
- bool has_elements_associated_by_form_attribute_ : 1;
- bool did_finish_parsing_children_ : 1;
- bool is_in_reset_function_ : 1;
- Member<RelList> rel_list_;
- unsigned rel_attribute_ = 0;
- };
- } // namespace blink
- #endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_HTML_FORM_ELEMENT_H_
复制代码 2.3)、v8下form接口实现:
out\Debug\gen\third_party\blink\renderer\bindings\core\v8\v8_html_form_element.h
out\Debug\gen\third_party\blink\renderer\bindings\core\v8\v8_html_form_element.cc
截取部分定义:
- void MethodAttributeGetCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
-
- RUNTIME_CALL_TIMER_SCOPE_DISABLED_BY_DEFAULT(info.GetIsolate(), "Blink_HTMLFormElement_method_Getter");
- BLINK_BINDINGS_TRACE_EVENT("HTMLFormElement.method.get");
- v8::Isolate* isolate = info.GetIsolate();
- v8::Local<v8::Object> v8_receiver = info.This();
- HTMLFormElement* blink_receiver = V8HTMLFormElement::ToWrappableUnsafe(isolate, v8_receiver);
- auto&& return_value = blink_receiver->method();
- bindings::V8SetReturnValue(info, return_value, isolate, bindings::V8ReturnValue::kNonNullable);
- }
- void MethodAttributeSetCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
-
- RUNTIME_CALL_TIMER_SCOPE_DISABLED_BY_DEFAULT(info.GetIsolate(), "Blink_HTMLFormElement_method_Setter");
- BLINK_BINDINGS_TRACE_EVENT("HTMLFormElement.method.set");
- v8::Isolate* isolate = info.GetIsolate();
- const ExceptionContextType exception_context_type = ExceptionContextType::kAttributeSet;
- const char* const class_like_name = "HTMLFormElement";
- const char* const property_name = "method";
- ExceptionState exception_state(isolate, exception_context_type, class_like_name, property_name);
- // [CEReactions]
- CEReactionsScope ce_reactions_scope;
- v8::Local<v8::Object> v8_receiver = info.This();
- HTMLFormElement* blink_receiver = V8HTMLFormElement::ToWrappableUnsafe(isolate, v8_receiver);
- v8::Local<v8::Value> v8_property_value = info[0];
- auto&& arg1_value = NativeValueTraits<IDLString>::NativeValue(isolate, v8_property_value, exception_state);
- if (UNLIKELY(exception_state.HadException())) {
- return;
- }
- blink_receiver->setMethod(arg1_value);
- }
复制代码 2.4)、form_datat数据填充接口:
FormData用来构建FormSubmission对象重要存储form表单内的元素参数:
比方:
First name: <input type="text" name="fname"><br>
Last name: <input type="text" name="lname"><br>
会转换成FirstName=Mickey&LastName=Mouse,末了放到url请求参数内里。
结果:
https://www.runoob.com/try/demo_source/demo-form.php?FirstName=Mickey&LastName=Mouse
hird_party\blink\renderer\core\html\forms\form_data.idl
- // https://xhr.spec.whatwg.org/#interface-formdata
- typedef (File or USVString) FormDataEntryValue;
- [
- Exposed=(Window,Worker)
- ] interface FormData {
- [RaisesException] constructor(optional HTMLFormElement form, optional HTMLElement? submitter = null);
- void append(USVString name, USVString value);
- [CallWith=ScriptState] void append(USVString name, Blob value, optional USVString filename);
- [ImplementedAs=deleteEntry] void delete(USVString name);
- FormDataEntryValue? get(USVString name);
- sequence<FormDataEntryValue> getAll(USVString name);
- boolean has(USVString name);
- void set(USVString name, USVString value);
- void set(USVString name, Blob value, optional USVString filename);
- iterable<USVString, FormDataEntryValue>;
- };
复制代码 blink和v8定义:
third_party\blink\renderer\core\html\forms\form_data.h
third_party\blink\renderer\core\html\forms\form_data.cc
- #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_FORM_DATA_H_
- #define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_FORM_DATA_H_
- #include "third_party/blink/renderer/bindings/core/v8/iterable.h"
- #include "third_party/blink/renderer/bindings/core/v8/v8_sync_iterator_form_data.h"
- #include "third_party/blink/renderer/bindings/core/v8/v8_typedefs.h"
- #include "third_party/blink/renderer/core/core_export.h"
- #include "third_party/blink/renderer/core/html/html_element.h"
- #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
- #include "third_party/blink/renderer/platform/network/encoded_form_data.h"
- #include "third_party/blink/renderer/platform/wtf/forward.h"
- #include "third_party/blink/renderer/platform/wtf/text/text_encoding.h"
- namespace blink {
- class Blob;
- class File;
- class FormControlState;
- class HTMLFormElement;
- class ScriptState;
- class ExecutionContext;
- class CORE_EXPORT FormData final : public ScriptWrappable,
- public PairSyncIterable<FormData> {
- DEFINE_WRAPPERTYPEINFO();
- public:
- static FormData* Create(ExceptionState& exception_state) {
- return MakeGarbageCollected<FormData>();
- }
- static FormData* Create(HTMLFormElement* form,
- ExceptionState& exception_state);
- static FormData* Create(HTMLFormElement* form,
- HTMLElement* submitter,
- ExceptionState& exception_state);
- explicit FormData(const WTF::TextEncoding&);
- // Clones form_data. This clones |form_data.entries_| Vector, but
- // doesn't clone entries in it because they are immutable.
- FormData(const FormData& form_data);
- FormData();
- void Trace(Visitor*) const override;
- // FormData IDL interface.
- void append(const String& name, const String& value);
- void append(ScriptState*,
- const String& name,
- Blob*,
- const String& filename = String());
- void deleteEntry(const String& name);
- V8FormDataEntryValue* get(const String& name);
- HeapVector<Member<V8FormDataEntryValue>> getAll(const String& name);
- bool has(const String& name);
- void set(const String& name, const String& value);
- void set(const String& name, Blob*, const String& filename = String());
- // Internal functions.
- const WTF::TextEncoding& Encoding() const { return encoding_; }
- std::string Encode(const String& key) const;
- class Entry;
- const HeapVector<Member<const Entry>>& Entries() const { return entries_; }
- size_t size() const { return entries_.size(); }
- void append(const String& name, Blob*, const String& filename = String());
- void AppendFromElement(const String& name, int value);
- void AppendFromElement(const String& name, File* file);
- void AppendFromElement(const String& name, const String& value);
- // This flag is true if this FormData is created with a <form>, and its
- // associated elements contain a non-empty password field.
- bool ContainsPasswordData() const { return contains_password_data_; }
- void SetContainsPasswordData(bool flag) { contains_password_data_ = flag; }
- scoped_refptr<EncodedFormData> EncodeFormData(
- EncodedFormData::EncodingType = EncodedFormData::kFormURLEncoded);
- scoped_refptr<EncodedFormData> EncodeMultiPartFormData();
- void AppendToControlState(FormControlState& state) const;
- static FormData* CreateFromControlState(ExecutionContext& execution_context,
- const FormControlState& state,
- wtf_size_t& index);
- private:
- void SetEntry(const Entry*);
- IterationSource* CreateIterationSource(ScriptState*,
- ExceptionState&) override;
- WTF::TextEncoding encoding_;
- // Entry pointers in entries_ never be nullptr.
- HeapVector<Member<const Entry>> entries_;
- bool contains_password_data_ = false;
- };
- // Represents entry, which is a pair of a name and a value.
- // https://xhr.spec.whatwg.org/#concept-formdata-entry
- // Entry objects are immutable.
- class FormData::Entry final : public GarbageCollected<FormData::Entry> {
- public:
- Entry(const String& name, const String& value);
- Entry(const String& name, Blob* blob, const String& filename);
- void Trace(Visitor*) const;
- bool IsString() const { return !blob_; }
- bool isFile() const { return blob_ != nullptr; }
- const String& name() const { return name_; }
- const String& Value() const { return value_; }
- Blob* GetBlob() const { return blob_.Get(); }
- CORE_EXPORT File* GetFile() const;
- const String& Filename() const { return filename_; }
- private:
- const String name_;
- const String value_;
- const Member<Blob> blob_;
- const String filename_;
- };
- } // namespace blink
- #endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_FORM_DATA_H_
复制代码 out\Debug\gen\third_party\blink\renderer\bindings\core\v8\v8_form_data.h
out\Debug\gen\third_party\blink\renderer\bindings\core\v8\v8_form_data.cc
截图部分实现:
- void KeysOperationCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
- RUNTIME_CALL_TIMER_SCOPE_DISABLED_BY_DEFAULT(info.GetIsolate(), "Blink_FormData_keys");
- BLINK_BINDINGS_TRACE_EVENT("FormData.keys");
- v8::Isolate* isolate = info.GetIsolate();
- v8::Local<v8::Object> v8_receiver = info.This();
- FormData* blink_receiver = V8FormData::ToWrappableUnsafe(isolate, v8_receiver);
- v8::Local<v8::Context> receiver_context = v8_receiver->GetCreationContextChecked();
- ScriptState* receiver_script_state = ScriptState::From(receiver_context);
- ScriptState* script_state = receiver_script_state;
- const ExceptionContextType exception_context_type = ExceptionContextType::kOperationInvoke;
- const char* const class_like_name = "FormData";
- const char* const property_name = "keys";
- ExceptionState exception_state(isolate, exception_context_type, class_like_name, property_name);
- auto&& return_value = blink_receiver->keysForBinding(script_state, exception_state);
- if (UNLIKELY(exception_state.HadException())) {
- return;
- }
- bindings::V8SetReturnValue(info, return_value, blink_receiver);
- }
- void ValuesOperationCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
- RUNTIME_CALL_TIMER_SCOPE_DISABLED_BY_DEFAULT(info.GetIsolate(), "Blink_FormData_values");
- BLINK_BINDINGS_TRACE_EVENT("FormData.values");
- v8::Isolate* isolate = info.GetIsolate();
- v8::Local<v8::Object> v8_receiver = info.This();
- FormData* blink_receiver = V8FormData::ToWrappableUnsafe(isolate, v8_receiver);
- v8::Local<v8::Context> receiver_context = v8_receiver->GetCreationContextChecked();
- ScriptState* receiver_script_state = ScriptState::From(receiver_context);
- ScriptState* script_state = receiver_script_state;
- const ExceptionContextType exception_context_type = ExceptionContextType::kOperationInvoke;
- const char* const class_like_name = "FormData";
- const char* const property_name = "values";
- ExceptionState exception_state(isolate, exception_context_type, class_like_name, property_name);
- auto&& return_value = blink_receiver->valuesForBinding(script_state, exception_state);
- if (UNLIKELY(exception_state.HadException())) {
- return;
- }
- bindings::V8SetReturnValue(info, return_value, blink_receiver);
- }
复制代码 2.5)、form submit 管理类FormSubmission
网页点击submit会调用到FormSubmission。
third_party\blink\renderer\core\loader\form_submission.h
third_party\blink\renderer\core\loader\form_submission.cc
- #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_FORM_SUBMISSION_H_
- #define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_FORM_SUBMISSION_H_
- #include "third_party/blink/public/common/tokens/tokens.h"
- #include "third_party/blink/public/mojom/frame/policy_container.mojom-blink.h"
- #include "third_party/blink/public/mojom/frame/triggering_event_info.mojom-blink-forward.h"
- #include "third_party/blink/public/web/web_frame_load_type.h"
- #include "third_party/blink/renderer/core/loader/frame_loader_types.h"
- #include "third_party/blink/renderer/core/loader/navigation_policy.h"
- #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
- #include "third_party/blink/renderer/platform/weborigin/kurl.h"
- #include "third_party/blink/renderer/platform/heap/member.h"
- #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
- namespace blink {
- class Element;
- class EncodedFormData;
- class Event;
- class Frame;
- class HTMLFormControlElement;
- class HTMLFormElement;
- class LocalDOMWindow;
- class ResourceRequest;
- class SourceLocation;
- class FormSubmission final : public GarbageCollected<FormSubmission> {
- public:
- enum SubmitMethod { kGetMethod, kPostMethod, kDialogMethod };
- class Attributes {
- DISALLOW_NEW();
- public:
- Attributes()
- : method_(kGetMethod),
- is_multi_part_form_(false),
- encoding_type_("application/x-www-form-urlencoded") {}
- Attributes(const Attributes&) = delete;
- Attributes& operator=(const Attributes&) = delete;
- SubmitMethod Method() const { return method_; }
- static SubmitMethod ParseMethodType(const String&);
- void UpdateMethodType(const String&);
- static String MethodString(SubmitMethod);
- const String& Action() const { return action_; }
- void ParseAction(const String&);
- const AtomicString& Target() const { return target_; }
- void SetTarget(const AtomicString& target) { target_ = target; }
- const AtomicString& EncodingType() const { return encoding_type_; }
- static AtomicString ParseEncodingType(const String&);
- void UpdateEncodingType(const String&);
- bool IsMultiPartForm() const { return is_multi_part_form_; }
- const String& AcceptCharset() const { return accept_charset_; }
- void SetAcceptCharset(const String& value) { accept_charset_ = value; }
- void CopyFrom(const Attributes&);
- private:
- SubmitMethod method_;
- bool is_multi_part_form_;
- String action_;
- AtomicString target_;
- AtomicString encoding_type_;
- String accept_charset_;
- };
- // Create FormSubmission
- //
- // This returns nullptr if form submission is not allowed for the given
- // arguments. For example, if navigation policy for the event is
- // `kNavigationPolicyLinkPreview`.
- static FormSubmission* Create(HTMLFormElement*,
- const Attributes&,
- const Event*,
- HTMLFormControlElement* submit_button);
- FormSubmission(
- SubmitMethod,
- const KURL& action,
- const AtomicString& target,
- const AtomicString& content_type,
- Element* submitter,
- scoped_refptr<EncodedFormData>,
- const Event*,
- NavigationPolicy navigation_policy,
- mojom::blink::TriggeringEventInfo triggering_event_info,
- ClientNavigationReason reason,
- std::unique_ptr<ResourceRequest> resource_request,
- Frame* target_frame,
- WebFrameLoadType load_type,
- LocalDOMWindow* origin_window,
- const LocalFrameToken& initiator_frame_token,
- std::unique_ptr<SourceLocation> source_location,
- mojo::PendingRemote<mojom::blink::PolicyContainerHostKeepAliveHandle>
- initiator_policy_container_keep_alive_handle);
- // FormSubmission for DialogMethod
- explicit FormSubmission(const String& result);
- void Trace(Visitor*) const;
- void Navigate();
- KURL RequestURL() const;
- SubmitMethod Method() const { return method_; }
- const KURL& Action() const { return action_; }
- EncodedFormData* Data() const { return form_data_.get(); }
- const String& Result() const { return result_; }
- Frame* TargetFrame() const { return target_frame_.Get(); }
- private:
- // FIXME: Hold an instance of Attributes instead of individual members.
- SubmitMethod method_;
- KURL action_;
- AtomicString target_;
- AtomicString content_type_;
- Member<Element> submitter_;
- scoped_refptr<EncodedFormData> form_data_;
- NavigationPolicy navigation_policy_;
- mojom::blink::TriggeringEventInfo triggering_event_info_;
- String result_;
- ClientNavigationReason reason_;
- std::unique_ptr<ResourceRequest> resource_request_;
- Member<Frame> target_frame_;
- WebFrameLoadType load_type_;
- Member<LocalDOMWindow> origin_window_;
- LocalFrameToken initiator_frame_token_;
- // Since form submissions are scheduled asynchronously, we need to store the
- // source location when we create the form submission and then pass it over to
- // the `FrameLoadRequest`. Capturing the source location later when creating
- // the `FrameLoadRequest` will not return the correct location.
- std::unique_ptr<SourceLocation> source_location_;
- // Since form submissions are scheduled asynchronously, we need to keep a
- // handle to the initiator PolicyContainerHost. This ensures that it remains
- // available in the browser until we create the NavigationRequest.
- mojo::PendingRemote<mojom::blink::PolicyContainerHostKeepAliveHandle>
- initiator_policy_container_keep_alive_handle_;
- };
- } // namespace blink
- #endif // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_FORM_SUBMISSION_H_
复制代码 2.6)、submit_input类对应前端<input type="submit":
third_party\blink\renderer\core\html\forms\submit_input_type.h
third_party\blink\renderer\core\html\forms\submit_input_type.cc
- #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_SUBMIT_INPUT_TYPE_H_
- #define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_SUBMIT_INPUT_TYPE_H_
- #include "third_party/blink/renderer/core/html/forms/base_button_input_type.h"
- namespace blink {
- class SubmitInputType final : public BaseButtonInputType {
- public:
- explicit SubmitInputType(HTMLInputElement& element);
- private:
- void AppendToFormData(FormData&) const override;
- bool SupportsRequired() const override;
- void HandleDOMActivateEvent(Event&) override;
- bool CanBeSuccessfulSubmitButton() override;
- String DefaultLabel() const override;
- bool IsTextButton() const override;
- void ValueAttributeChanged() override;
- };
- template <>
- struct DowncastTraits<SubmitInputType> {
- static bool AllowFrom(const InputType& type) {
- return type.IsSubmitInputType();
- }
- };
- } // namespace blink
- #endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_SUBMIT_INPUT_TYPE_H_
复制代码 三、看下form表单提交过程:
form表单提交过程:
1、render历程点击提交<input type="submit" value="提交">
2、render历程在HTMLFormElement类中构建 FormSubmission并剖析<input>内容、从而构建出请求参数:FirstName=Mickey&LastName=Mouse 以及
获取method="get"
/*
First name: <input type="text" name="FirstName" value="Mickey"><br>
Last name: <input type="text" name="LastName" value="Mouse"><br>
*/
末了拼接出请求URL
https://www.runoob.com/try/demo_source/demo-form.php?FirstName=Mickey&LastName=Mouse
3、给主历程发送message.set_method_name("CreateNewWindow");
在新标签中打开https://www.runoob.com/try/demo_source/demo-form.php?FirstName=Mickey&LastName=Mouse。
============================优雅的分割线===================================
1、render历程点击提交<input type="submit" value="提交">
SubmitInputType::HandleDOMActivateEvent(Event& event)
- void SubmitInputType::HandleDOMActivateEvent(Event& event) {
- if (GetElement().IsDisabledFormControl() || !GetElement().Form())
- return;
- // Event handlers can run.
- GetElement().Form()->PrepareForSubmission(&event, &GetElement());
- event.SetDefaultHandled();
- }
复制代码
2、HTMLFormElement::ScheduleFormSubmission 函数
调用 FormSubmission* form_submission =
FormSubmission::Create(this, attributes_, event, submit_button);
- void HTMLFormElement::ScheduleFormSubmission(
- const Event* event,
- HTMLFormControlElement* submit_button) {
- LocalFrameView* view = GetDocument().View();
- LocalFrame* frame = GetDocument().GetFrame();
- if (!view || !frame || !frame->GetPage())
- return;
- // https://html.spec.whatwg.org/C/#form-submission-algorithm
- // 2. If form document is not connected, has no associated browsing context,
- // or its active sandboxing flag set has its sandboxed forms browsing
- // context flag set, then abort these steps without doing anything.
- if (!isConnected()) {
- GetDocument().AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
- mojom::ConsoleMessageSource::kJavaScript,
- mojom::ConsoleMessageLevel::kWarning,
- "Form submission canceled because the form is not connected"));
- return;
- }
- if (is_constructing_entry_list_) {
- GetDocument().AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
- mojom::ConsoleMessageSource::kJavaScript,
- mojom::ConsoleMessageLevel::kWarning,
- "Form submission canceled because the form is "
- "constructing entry list"));
- return;
- }
- if (is_submitting_)
- return;
- // Delay dispatching 'close' to dialog until done submitting.
- EventQueueScope scope_for_dialog_close;
- base::AutoReset<bool> submit_scope(&is_submitting_, true);
- if (event && !submit_button) {
- // In a case of implicit submission without a submit button, 'submit'
- // event handler might add a submit button. We search for a submit
- // button again.
- // TODO(tkent): Do we really need to activate such submit button?
- for (ListedElement* listed_element : ListedElements()) {
- auto* control = DynamicTo<HTMLFormControlElement>(listed_element);
- if (!control)
- continue;
- DCHECK(!control->IsActivatedSubmit());
- if (control->IsSuccessfulSubmitButton()) {
- submit_button = control;
- break;
- }
- }
- }
- FormSubmission* form_submission =
- FormSubmission::Create(this, attributes_, event, submit_button);
- if (!form_submission) {
- // Form submission is not allowed for some NavigationPolicies, e.g. Link
- // Preview. If an user triggered such user event for form submission, just
- // ignores it.
- return;
- }
- Frame* target_frame = form_submission->TargetFrame();
- // 'formdata' event handlers might disconnect the form.
- if (!isConnected()) {
- GetDocument().AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
- mojom::ConsoleMessageSource::kJavaScript,
- mojom::ConsoleMessageLevel::kWarning,
- "Form submission canceled because the form is not connected"));
- return;
- }
- if (form_submission->Method() == FormSubmission::kDialogMethod) {
- SubmitDialog(form_submission);
- return;
- }
- DCHECK(form_submission->Method() == FormSubmission::kPostMethod ||
- form_submission->Method() == FormSubmission::kGetMethod);
- DCHECK(form_submission->Data());
- if (form_submission->Action().IsEmpty())
- return;
- if (GetExecutionContext()->IsSandboxed(
- network::mojom::blink::WebSandboxFlags::kForms)) {
- // FIXME: This message should be moved off the console once a solution to
- // https://bugs.webkit.org/show_bug.cgi?id=103274 exists.
- GetExecutionContext()->AddConsoleMessage(
- MakeGarbageCollected<ConsoleMessage>(
- mojom::blink::ConsoleMessageSource::kSecurity,
- mojom::blink::ConsoleMessageLevel::kError,
- "Blocked form submission to '" +
- form_submission->Action().ElidedString() +
- "' because the form's frame is sandboxed and the 'allow-forms' "
- "permission is not set."));
- return;
- }
- if (form_submission->Action().ProtocolIsJavaScript()) {
- // For javascript URLs we need to do the CSP check for 'form-action' here.
- // All other schemes are checked in the browser.
- //
- // TODO(antoniosartori): Should we keep the 'form-action' check for
- // javascript: URLs? For 'frame-src' and 'navigate-to', we do not check
- // javascript: URLs. Reading the specification, it looks like 'form-action'
- // should not apply to javascript: URLs.
- if (!GetExecutionContext()->GetContentSecurityPolicy()->AllowFormAction(
- form_submission->Action())) {
- return;
- }
- }
- UseCounter::Count(GetDocument(), WebFeature::kFormsSubmitted);
- if (MixedContentChecker::IsMixedFormAction(GetDocument().GetFrame(),
- form_submission->Action())) {
- UseCounter::Count(GetDocument(), WebFeature::kMixedContentFormsSubmitted);
- }
- if (FastHasAttribute(html_names::kDisabledAttr)) {
- UseCounter::Count(GetDocument(),
- WebFeature::kFormDisabledAttributePresentAndSubmit);
- }
- if (!target_frame)
- return;
- if (form_submission->Action().ProtocolIsJavaScript()) {
- // For javascript urls, don't post a task to execute the form submission
- // because we already get another task posted for it in
- // Document::ProcessJavascriptUrl. If we post two tasks, the javascript will
- // be run too late according to some tests.
- form_submission->Navigate();
- return;
- }
- FrameScheduler* scheduler = GetDocument().GetFrame()->GetFrameScheduler();
- if (auto* target_local_frame = DynamicTo<LocalFrame>(target_frame)) {
- if (!target_local_frame->IsNavigationAllowed())
- return;
- // Cancel parsing if the form submission is targeted at this frame.
- if (target_local_frame == GetDocument().GetFrame() &&
- !form_submission->Action().ProtocolIsJavaScript()) {
- target_local_frame->GetDocument()->CancelParsing();
- }
- // Use the target frame's frame scheduler. If we can't due to targeting a
- // RemoteFrame, then use the frame scheduler from the frame this form is in.
- scheduler = target_local_frame->GetFrameScheduler();
- // Cancel pending javascript url navigations for the target frame. This new
- // form submission should take precedence over them.
- target_local_frame->GetDocument()->CancelPendingJavaScriptUrls();
- // Cancel any pre-existing attempt to navigate the target frame which was
- // already sent to the browser process so this form submission will take
- // precedence over it.
- target_local_frame->Loader().CancelClientNavigation();
- }
- cancel_last_submission_ =
- target_frame->ScheduleFormSubmission(scheduler, form_submission);
- }
复制代码 3、FormSubmission::Create()函数构建FirstName=Mickey&LastName=Mouse,以及打开提交页面方式:
- FormSubmission* FormSubmission::Create(HTMLFormElement* form,
- const Attributes& attributes,
- const Event* event,
- HTMLFormControlElement* submit_button) {
- DCHECK(form);
- FormSubmission::Attributes copied_attributes;
- copied_attributes.CopyFrom(attributes);
- if (submit_button) {
- AtomicString attribute_value;
- if (!(attribute_value =
- submit_button->FastGetAttribute(html_names::kFormactionAttr))
- .IsNull())
- copied_attributes.ParseAction(attribute_value);
- if (!(attribute_value =
- submit_button->FastGetAttribute(html_names::kFormenctypeAttr))
- .IsNull())
- copied_attributes.UpdateEncodingType(attribute_value);
- if (!(attribute_value =
- submit_button->FastGetAttribute(html_names::kFormmethodAttr))
- .IsNull())
- copied_attributes.UpdateMethodType(attribute_value);
- if (!(attribute_value =
- submit_button->FastGetAttribute(html_names::kFormtargetAttr))
- .IsNull())
- copied_attributes.SetTarget(attribute_value);
- }
- if (copied_attributes.Method() == kDialogMethod) {
- if (submit_button) {
- return MakeGarbageCollected<FormSubmission>(
- submit_button->ResultForDialogSubmit());
- }
- return MakeGarbageCollected<FormSubmission>("");
- }
- Document& document = form->GetDocument();
- KURL action_url = document.CompleteURL(copied_attributes.Action().empty()
- ? document.Url().GetString()
- : copied_attributes.Action());
- if ((document.domWindow()->GetSecurityContext().GetInsecureRequestPolicy() &
- mojom::blink::InsecureRequestPolicy::kUpgradeInsecureRequests) !=
- mojom::blink::InsecureRequestPolicy::kLeaveInsecureRequestsAlone &&
- action_url.ProtocolIs("http") &&
- !network::IsUrlPotentiallyTrustworthy(GURL(action_url))) {
- UseCounter::Count(document,
- WebFeature::kUpgradeInsecureRequestsUpgradedRequestForm);
- action_url.SetProtocol("https");
- if (action_url.Port() == 80)
- action_url.SetPort(443);
- }
- bool is_mailto_form = action_url.ProtocolIs("mailto");
- bool is_multi_part_form = false;
- AtomicString encoding_type = copied_attributes.EncodingType();
- if (copied_attributes.Method() == kPostMethod) {
- is_multi_part_form = copied_attributes.IsMultiPartForm();
- if (is_multi_part_form && is_mailto_form) {
- encoding_type = AtomicString("application/x-www-form-urlencoded");
- is_multi_part_form = false;
- }
- }
- WTF::TextEncoding data_encoding =
- is_mailto_form
- ? UTF8Encoding()
- : FormDataEncoder::EncodingFromAcceptCharset(
- copied_attributes.AcceptCharset(), document.Encoding());
- //解析<input>构建请求参数FirstName=Mickey&LastName=Mouse
- FormData* dom_form_data = form->ConstructEntryList(
- submit_button, data_encoding.EncodingForFormSubmission());
- DCHECK(dom_form_data);
- scoped_refptr<EncodedFormData> form_data;
- String boundary;
- if (is_multi_part_form) {
- form_data = dom_form_data->EncodeMultiPartFormData();
- boundary = form_data->Boundary().data();
- } else {
- form_data = dom_form_data->EncodeFormData(
- attributes.Method() == kGetMethod
- ? EncodedFormData::kFormURLEncoded
- : EncodedFormData::ParseEncodingType(encoding_type));
- if (copied_attributes.Method() == kPostMethod && is_mailto_form) {
- // Convert the form data into a string that we put into the URL.
- AppendMailtoPostFormDataToURL(action_url, *form_data, encoding_type);
- form_data = EncodedFormData::Create();
- }
- }
- form_data->SetIdentifier(GenerateFormDataIdentifier());
- form_data->SetContainsPasswordData(dom_form_data->ContainsPasswordData());
- if (copied_attributes.Method() != FormSubmission::kPostMethod &&
- !action_url.ProtocolIsJavaScript()) {
- action_url.SetQuery(form_data->FlattenToString());
- }
- std::unique_ptr<ResourceRequest> resource_request =
- std::make_unique<ResourceRequest>(action_url);
- ClientNavigationReason reason = ClientNavigationReason::kFormSubmissionGet;
- if (copied_attributes.Method() == FormSubmission::kPostMethod) {
- reason = ClientNavigationReason::kFormSubmissionPost;
- resource_request->SetHttpMethod(http_names::kPOST);
- resource_request->SetHttpBody(form_data);
- // construct some user headers if necessary
- if (boundary.empty()) {
- resource_request->SetHTTPContentType(encoding_type);
- } else {
- resource_request->SetHTTPContentType(encoding_type +
- "; boundary=" + boundary);
- }
- }
- resource_request->SetHasUserGesture(
- LocalFrame::HasTransientUserActivation(form->GetDocument().GetFrame()));
- resource_request->SetFormSubmission(true);
- mojom::blink::TriggeringEventInfo triggering_event_info;
- if (event) {
- triggering_event_info =
- event->isTrusted()
- ? mojom::blink::TriggeringEventInfo::kFromTrustedEvent
- : mojom::blink::TriggeringEventInfo::kFromUntrustedEvent;
- if (event->UnderlyingEvent())
- event = event->UnderlyingEvent();
- } else {
- triggering_event_info = mojom::blink::TriggeringEventInfo::kNotFromEvent;
- }
- FrameLoadRequest frame_request(form->GetDocument().domWindow(),
- *resource_request);
- //设置submit打开策略
- NavigationPolicy navigation_policy = NavigationPolicyFromEvent(event);
- if (navigation_policy == kNavigationPolicyLinkPreview) {
- return nullptr;
- }
- frame_request.SetNavigationPolicy(navigation_policy);
- frame_request.SetClientRedirectReason(reason);
- if (submit_button) {
- frame_request.SetSourceElement(submit_button);
- } else {
- frame_request.SetSourceElement(form);
- }
- frame_request.SetTriggeringEventInfo(triggering_event_info);
- AtomicString target_or_base_target = frame_request.CleanNavigationTarget(
- copied_attributes.Target().empty() ? document.BaseTarget()
- : copied_attributes.Target());
- if (form->HasRel(HTMLFormElement::kNoReferrer)) {
- frame_request.SetNoReferrer();
- frame_request.SetNoOpener();
- }
- if (form->HasRel(HTMLFormElement::kNoOpener) ||
- (EqualIgnoringASCIICase(target_or_base_target, "_blank") &&
- !form->HasRel(HTMLFormElement::kOpener) &&
- form->GetDocument()
- .domWindow()
- ->GetFrame()
- ->GetSettings()
- ->GetTargetBlankImpliesNoOpenerEnabledWillBeRemoved())) {
- frame_request.SetNoOpener();
- }
- //给主进程发送message.set_method_name("CreateNewWindow");
- Frame* target_frame =
- form->GetDocument()
- .GetFrame()
- ->Tree()
- .FindOrCreateFrameForNavigation(frame_request, target_or_base_target)
- .frame;
- // Apply replacement now, before any async steps, as the result may change.
- WebFrameLoadType load_type = WebFrameLoadType::kStandard;
- LocalFrame* target_local_frame = DynamicTo<LocalFrame>(target_frame);
- if (target_local_frame &&
- target_local_frame->NavigationShouldReplaceCurrentHistoryEntry(
- frame_request, load_type)) {
- load_type = WebFrameLoadType::kReplaceCurrentItem;
- }
- return MakeGarbageCollected<FormSubmission>(
- copied_attributes.Method(), action_url, target_or_base_target,
- encoding_type, frame_request.GetSourceElement(), std::move(form_data),
- event, frame_request.GetNavigationPolicy(), triggering_event_info, reason,
- std::move(resource_request), target_frame, load_type,
- form->GetDocument().domWindow(),
- form->GetDocument().GetFrame()->GetLocalFrameToken(),
- CaptureSourceLocation(form->GetDocument().domWindow()),
- form->GetDocument()
- .domWindow()
- ->GetPolicyContainer()
- ->IssueKeepAliveHandle());
- }
复制代码 3.1)、构建FirstName=Mickey&LastName=Mouse 参数
/ /ConstructEntryList函数遍历form表单位素
FormData* dom_form_data = form->ConstructEntryList(
submit_button, data_encoding.EncodingForFormSubmission());
DCHECK(dom_form_data);
3.2)、FormSubmission::Create调用FindOrCreateFrameForNavigation
用来打开提交新页面。
Frame* target_frame =
form->GetDocument()
.GetFrame()
->Tree()
.FindOrCreateFrameForNavigation(frame_request, target_or_base_target)
.frame;
3.3)、FindOrCreateFrameForNavigation调用RenderFrameImpl::CreateNewWindow 函数
RenderFrameImpl::CreateNewWindow函数定义(content\renderer\render_frame_impl.cc):
- WebView* RenderFrameImpl::CreateNewWindow(
- const WebURLRequest& request,
- const blink::WebWindowFeatures& features,
- const WebString& frame_name,
- WebNavigationPolicy policy,
- network::mojom::WebSandboxFlags sandbox_flags,
- const blink::SessionStorageNamespaceId& session_storage_namespace_id,
- bool& consumed_user_gesture,
- const absl::optional<blink::Impression>& impression,
- const absl::optional<blink::WebPictureInPictureWindowOptions>& pip_options,
- const blink::WebURL& base_url) {
- consumed_user_gesture = false;
- mojom::CreateNewWindowParamsPtr params = mojom::CreateNewWindowParams::New();
- // The user activation check is done at the browser process through
- // |frame_host->CreateNewWindow()| call below. But the extensions case
- // handled through the following |if| is an exception.
- params->allow_popup = false;
- if (GetContentClient()->renderer()->AllowPopup())
- params->allow_popup = true;
- params->window_container_type = WindowFeaturesToContainerType(features);
- params->session_storage_namespace_id = session_storage_namespace_id;
- if (!features.noopener) {
- params->clone_from_session_storage_namespace_id =
- GetWebView()->GetSessionStorageNamespaceId();
- }
- const std::string& frame_name_utf8 = frame_name.Utf8(
- WebString::UTF8ConversionMode::kStrictReplacingErrorsWithFFFD);
- params->frame_name = frame_name_utf8;
- params->opener_suppressed = features.noopener;
- params->disposition = NavigationPolicyToDisposition(policy);
- if (!request.IsNull()) {
- params->target_url = request.Url();
- // The browser process does not consider empty URLs as valid (partly due to
- // a risk of treating them as a navigation to the privileged NTP in some
- // cases), so treat an attempt to create a window with an empty URL as
- // opening about:blank.
- //
- // Similarly, javascript: URLs should not be sent to the browser process,
- // since they are either handled within the renderer process (if a window is
- // created within the same browsing context group) or ignored (in the
- // noopener case). Use about:blank for the URL in that case as well, to
- // reduce the risk of running them incorrectly.
- if (params->target_url.is_empty() ||
- params->target_url.SchemeIs(url::kJavaScriptScheme)) {
- params->target_url = GURL(url::kAboutBlankURL);
- }
- params->referrer = blink::mojom::Referrer::New(
- blink::WebStringToGURL(request.ReferrerString()),
- request.GetReferrerPolicy());
- }
- params->features = ConvertWebWindowFeaturesToMojoWindowFeatures(features);
- params->is_form_submission = request.IsFormSubmission();
- params->form_submission_post_data =
- blink::GetRequestBodyForWebURLRequest(request);
- params->form_submission_post_content_type = request.HttpContentType().Utf8();
- params->impression = impression;
- if (pip_options) {
- CHECK_EQ(policy, blink::kWebNavigationPolicyPictureInPicture);
- auto pip_mojom_opts = blink::mojom::PictureInPictureWindowOptions::New();
- pip_mojom_opts->width = pip_options->width;
- pip_mojom_opts->height = pip_options->height;
- // TODO(crbug.com/1444658): Remove this from mojom and the browser side.
- pip_mojom_opts->initial_aspect_ratio = 0.0;
- // TODO(crbug.com/1410379): Remove this from mojom and the browser side.
- pip_mojom_opts->lock_aspect_ratio = false;
- params->pip_options = std::move(pip_mojom_opts);
- }
- params->download_policy.ApplyDownloadFramePolicy(
- /*is_opener_navigation=*/false, request.HasUserGesture(),
- // `openee_can_access_opener_origin` only matters for opener navigations,
- // so its value here is irrelevant.
- /*openee_can_access_opener_origin=*/true,
- !GetWebFrame()->IsAllowedToDownload(), GetWebFrame()->IsAdFrame());
- params->initiator_activation_and_ad_status =
- blink::GetNavigationInitiatorActivationAndAdStatus(
- request.HasUserGesture(), GetWebFrame()->IsAdFrame(),
- GetWebFrame()->IsAdScriptInStack());
- // We preserve this information before sending the message since |params| is
- // moved on send.
- bool is_background_tab =
- params->disposition == WindowOpenDisposition::NEW_BACKGROUND_TAB;
- mojom::CreateNewWindowStatus status;
- mojom::CreateNewWindowReplyPtr reply;
- auto* frame_host = GetFrameHost();
- if (!frame_host->CreateNewWindow(std::move(params), &status, &reply)) {
- // The sync IPC failed, e.g. maybe the render process is in the middle of
- // shutting down. Can't create a new window without the browser process,
- // so just bail out.
- return nullptr;
- }
- // If creation of the window was blocked (e.g. because this frame doesn't
- // have user activation), return before consuming user activation. A frame
- // that isn't allowed to open a window shouldn't be able to consume the
- // activation for the rest of the frame tree.
- if (status == mojom::CreateNewWindowStatus::kBlocked)
- return nullptr;
- // For Android WebView, we support a pop-up like behavior for window.open()
- // even if the embedding app doesn't support multiple windows. In this case,
- // window.open() will return "window" and navigate it to whatever URL was
- // passed. We also don't need to consume user gestures to protect against
- // multiple windows being opened, because, well, the app doesn't support
- // multiple windows.
- // TODO(dcheng): It's awkward that this is plumbed into Blink but not really
- // used much in Blink, except to enable web testing... perhaps this should
- // be checked directly in the browser side.
- if (status == mojom::CreateNewWindowStatus::kReuse) {
- // In this case, treat javascript: URLs as blocked rather than running them
- // in a reused main frame in Android WebView. See https://crbug.com/1083819.
- if (!request.IsNull() && request.Url().ProtocolIs(url::kJavaScriptScheme)) {
- return nullptr;
- }
- return GetWebView();
- }
- // Consume the transient user activation in the current renderer.
- consumed_user_gesture = GetWebFrame()->ConsumeTransientUserActivation(
- blink::UserActivationUpdateSource::kBrowser);
- // If we should ignore the new window (e.g. because of `noopener`), return
- // now that user activation was consumed.
- if (status == mojom::CreateNewWindowStatus::kIgnore)
- return nullptr;
- DCHECK(reply);
- DCHECK_NE(MSG_ROUTING_NONE, reply->main_frame_route_id);
- DCHECK_NE(MSG_ROUTING_NONE, reply->widget_params->routing_id);
- // While this view may be a background extension page, it can spawn a visible
- // render view. So we just assume that the new one is not another background
- // page instead of passing on our own value.
- // TODO(vangelis): Can we tell if the new view will be a background page?
- bool never_composited = false;
- // The initial hidden state for the RenderViewImpl here has to match what the
- // browser will eventually decide for the given disposition. Since we have to
- // return from this call synchronously, we just have to make our best guess
- // and rely on the browser sending a WasHidden / WasShown message if it
- // disagrees.
- mojom::CreateViewParamsPtr view_params = mojom::CreateViewParams::New();
- view_params->opener_frame_token = GetWebFrame()->GetFrameToken();
- view_params->window_was_opened_by_another_window = true;
- view_params->renderer_preferences = GetWebView()->GetRendererPreferences();
- view_params->web_preferences = GetWebView()->GetWebPreferences();
- view_params->replication_state = blink::mojom::FrameReplicationState::New();
- view_params->replication_state->frame_policy.sandbox_flags = sandbox_flags;
- view_params->replication_state->name = frame_name_utf8;
- view_params->devtools_main_frame_token = reply->devtools_main_frame_token;
- view_params->browsing_context_group_info = reply->browsing_context_group_info;
- view_params->color_provider_colors = reply->color_provider_colors;
- auto main_frame_params = mojom::CreateLocalMainFrameParams::New();
- main_frame_params->frame_token = reply->main_frame_token;
- main_frame_params->routing_id = reply->main_frame_route_id;
- main_frame_params->frame = std::move(reply->frame);
- main_frame_params->interface_broker =
- std::move(reply->main_frame_interface_broker);
- main_frame_params->document_token = reply->document_token;
- main_frame_params->policy_container = std::move(reply->policy_container);
- main_frame_params->associated_interface_provider_remote =
- std::move(reply->associated_interface_provider);
- main_frame_params->widget_params = std::move(reply->widget_params);
- main_frame_params->subresource_loader_factories =
- base::WrapUnique(static_cast<blink::PendingURLLoaderFactoryBundle*>(
- CloneLoaderFactories()->Clone().release()));
- view_params->main_frame =
- mojom::CreateMainFrameUnion::NewLocalParams(std::move(main_frame_params));
- view_params->blink_page_broadcast = std::move(reply->page_broadcast);
- view_params->session_storage_namespace_id =
- reply->cloned_session_storage_namespace_id;
- DCHECK(!view_params->session_storage_namespace_id.empty())
- << "Session storage namespace must be populated.";
- view_params->hidden = is_background_tab;
- view_params->never_composited = never_composited;
- WebView* web_view = agent_scheduling_group_->CreateWebView(
- std::move(view_params),
- /*was_created_by_renderer=*/true, base_url);
- if (reply->wait_for_debugger) {
- blink::WebFrameWidget* frame_widget =
- web_view->MainFrame()->ToWebLocalFrame()->LocalRoot()->FrameWidget();
- frame_widget->WaitForDebuggerWhenShown();
- }
- return web_view;
- }
复制代码 堆栈图:

- @3 content.dll!content::RenderFrameImpl::CreateNewWindow(const blink::WebURLRequest & request, const blink::WebWindowFeatures & features, const blink::WebString & frame_name, blink::WebNavigationPolicy policy, network::mojom::WebSandboxFlags sandbox_flags, const std::__Cr::basic_string<char,std::__Cr::char_traits<char>,std::__Cr::allocator<char>> & session_storage_namespace_id, bool & consumed_user_gesture, const std::__Cr::optional<blink::Impression> & impression, const std::__Cr::optional<blink::WebPictureInPictureWindowOptions> & pip_options, const blink::WebURL & base_url) 行 6562 C++ 已加载符号。
- @2 blink_core.dll!blink::ChromeClientImpl::CreateWindowDelegate(blink::LocalFrame * frame, const blink::FrameLoadRequest & r, const WTF::AtomicString & name, const blink::WebWindowFeatures & features, network::mojom::WebSandboxFlags sandbox_flags, const std::__Cr::basic_string<char,std::__Cr::char_traits<char>,std::__Cr::allocator<char>> & session_storage_namespace_id, bool & consumed_user_gesture) 行 342 C++ 已加载符号。
- @1 blink_core.dll!blink::ChromeClient::CreateWindow(blink::LocalFrame * frame, const blink::FrameLoadRequest & r, const WTF::AtomicString & frame_name, const blink::WebWindowFeatures & features, network::mojom::WebSandboxFlags sandbox_flags, const std::__Cr::basic_string<char,std::__Cr::char_traits<char>,std::__Cr::allocator<char>> & session_storage_namespace_id, bool & consumed_user_gesture) 行 88 C++ 已加载符号。
- @0 blink_core.dll!blink::CreateNewWindow(blink::LocalFrame & opener_frame, blink::FrameLoadRequest & request, const WTF::AtomicString & frame_name) 行 355 C++ 已加载符号。
- > blink_core.dll!blink::FrameTree::FindOrCreateFrameForNavigation(blink::FrameLoadRequest & request, const WTF::AtomicString & name) 行 217 C++ 已加载符号。
复制代码 3.4)、RenderFrameImpl::CreateNewWindow 调用frame_host->CreateNewWindow 给主历程发送CreateNewWindow的mojom消息。
mojom::CreateNewWindowStatus status;
mojom::CreateNewWindowReplyPtr reply;
auto* frame_host = GetFrameHost();
//给主历程发送CreateNewWindow mojom消息
if (!frame_host->CreateNewWindow(std::move(params), &status, &reply)) {
// The sync IPC failed, e.g. maybe the render process is in the middle of
// shutting down. Can't create a new window without the browser process,
// so just bail out.
return nullptr;
}
4、主历程收到子历程发送的mojom CreateNewWindow消息:
在RenderFrameHostImpl::CreateNewWindow函数内里处理打开 submit提交URL="https://www.runoob.com/try/demo_source/demo-form.php?FirstName=Mickey&LastName=Mouse"
src\content\browser\renderer_host\render_frame_host_impl.cc
浏览器打开了一个submit提交的新标签,至此form提交完成。
- void RenderFrameHostImpl::CreateNewWindow(
- mojom::CreateNewWindowParamsPtr params,
- CreateNewWindowCallback callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- TRACE_EVENT2("navigation", "RenderFrameHostImpl::CreateNewWindow",
- "render_frame_host", this, "url", params->target_url);
- // Only top-most frames can open picture-in-picture windows.
- if (params->disposition == WindowOpenDisposition::NEW_PICTURE_IN_PICTURE &&
- GetParentOrOuterDocumentOrEmbedder()) {
- frame_host_associated_receiver_.ReportBadMessage(
- "Only top-most frames can open picture-in-picture windows.");
- return;
- }
- bool no_javascript_access = false;
- // Filter out URLs to which navigation is disallowed from this context.
- GetProcess()->FilterURL(false, ¶ms->target_url);
- bool effective_transient_activation_state =
- params->allow_popup || HasTransientUserActivation() ||
- (transient_allow_popup_.IsActive() &&
- params->disposition == WindowOpenDisposition::NEW_POPUP);
- // Ignore window creation when sent from a frame that's not active or
- // created.
- bool can_create_window =
- IsActive() && is_render_frame_created() &&
- GetContentClient()->browser()->CanCreateWindow(
- this, GetLastCommittedURL(),
- GetOutermostMainFrame()->GetLastCommittedURL(),
- last_committed_origin_, params->window_container_type,
- params->target_url, params->referrer.To<Referrer>(),
- params->frame_name, params->disposition, *params->features,
- effective_transient_activation_state, params->opener_suppressed,
- &no_javascript_access);
- // If this frame isn't allowed to create a window, return early (before we
- // consume transient user activation).
- if (!can_create_window) {
- std::move(callback).Run(mojom::CreateNewWindowStatus::kBlocked, nullptr);
- return;
- }
- // Otherwise, consume user activation before we proceed. In particular, it is
- // important to do this before we return from the |opener_suppressed| case
- // below.
- // NB: This call will consume activations in the browser and the remote frame
- // proxies for this frame. The initiating renderer will consume its view of
- // the activations after we return.
- // See `owner_` invariants about `IsActive()`, which is implied by
- // `can_create_window`.
- CHECK(owner_);
- bool was_consumed = owner_->UpdateUserActivationState(
- blink::mojom::UserActivationUpdateType::kConsumeTransientActivation,
- blink::mojom::UserActivationNotificationType::kNone);
- // For Android WebView, we support a pop-up like behavior for window.open()
- // even if the embedding app doesn't support multiple windows. In this case,
- // window.open() will return "window" and navigate it to whatever URL was
- // passed.
- if (!GetOrCreateWebPreferences().supports_multiple_windows) {
- std::move(callback).Run(mojom::CreateNewWindowStatus::kReuse, nullptr);
- return;
- }
- // This will clone the sessionStorage for namespace_id_to_clone.
- StoragePartition* storage_partition = GetStoragePartition();
- DOMStorageContextWrapper* dom_storage_context =
- static_cast<DOMStorageContextWrapper*>(
- storage_partition->GetDOMStorageContext());
- scoped_refptr<SessionStorageNamespaceImpl> cloned_namespace;
- if (!params->clone_from_session_storage_namespace_id.empty()) {
- cloned_namespace = SessionStorageNamespaceImpl::CloneFrom(
- dom_storage_context, params->session_storage_namespace_id,
- params->clone_from_session_storage_namespace_id);
- } else {
- cloned_namespace = SessionStorageNamespaceImpl::Create(
- dom_storage_context, params->session_storage_namespace_id);
- }
- if (IsCredentialless() || IsNestedWithinFencedFrame() ||
- CoopSuppressOpener(/*opener=*/this)) {
- params->opener_suppressed = true;
- // TODO(https://crbug.com/1060691) This should be applied to all
- // popups opened with noopener.
- params->frame_name.clear();
- }
- RenderFrameHostImpl* top_level_opener = GetMainFrame();
- int popup_virtual_browsing_context_group =
- params->opener_suppressed
- ? CrossOriginOpenerPolicyAccessReportManager::
- GetNewVirtualBrowsingContextGroup()
- : top_level_opener->virtual_browsing_context_group();
- int popup_soap_by_default_virtual_browsing_context_group =
- params->opener_suppressed
- ? CrossOriginOpenerPolicyAccessReportManager::
- GetNewVirtualBrowsingContextGroup()
- : top_level_opener->soap_by_default_virtual_browsing_context_group();
- // If the opener is suppressed or script access is disallowed, we should
- // open the window in a new BrowsingInstance, and thus a new process. That
- // means the current renderer process will not be able to route messages to
- // it. Because of this, we will immediately show and navigate the window
- // in OnCreateNewWindowOnUI, using the params provided here.
- bool is_new_browsing_instance =
- params->opener_suppressed || no_javascript_access;
- DCHECK(IsRenderFrameLive());
- // The non-owning pointer |new_frame_tree| is valid in this stack frame since
- // nothing can delete it until this thread is freed up again.
- FrameTree* new_frame_tree =
- delegate_->CreateNewWindow(this, *params, is_new_browsing_instance,
- was_consumed, cloned_namespace.get());
- transient_allow_popup_.Deactivate();
- MaybeRecordAdClickMainFrameNavigationUseCounter(
- /*initiator_frame=*/this, params->initiator_activation_and_ad_status);
- if (is_new_browsing_instance || !new_frame_tree) {
- // Opener suppressed, Javascript access disabled, or delegate did not
- // provide a handle to any windows it created. In these cases, never tell
- // the renderer about the new window.
- std::move(callback).Run(mojom::CreateNewWindowStatus::kIgnore, nullptr);
- return;
- }
- DCHECK(!params->opener_suppressed);
- RenderFrameHostImpl* new_main_rfh =
- new_frame_tree->root()->current_frame_host();
- new_main_rfh->virtual_browsing_context_group_ =
- popup_virtual_browsing_context_group;
- new_main_rfh->soap_by_default_virtual_browsing_context_group_ =
- popup_soap_by_default_virtual_browsing_context_group;
- // COOP and COOP reporter are inherited from the opener to the popup's initial
- // empty document.
- if (IsOpenerSameOriginFrame(/*opener=*/this) &&
- GetMainFrame()->coop_access_report_manager()->coop_reporter()) {
- new_main_rfh->SetCrossOriginOpenerPolicyReporter(
- std::make_unique<CrossOriginOpenerPolicyReporter>(
- GetProcess()->GetStoragePartition(), GetLastCommittedURL(),
- params->referrer->url,
- // TODO(https://crbug.com/1385827): See if we need to send the
- // origin to reporters as well.
- new_main_rfh->cross_origin_opener_policy(), GetReportingSource(),
- isolation_info_.network_anonymization_key()));
- }
- mojo::PendingAssociatedRemote<mojom::Frame> pending_frame_remote;
- mojo::PendingAssociatedReceiver<mojom::Frame> pending_frame_receiver =
- pending_frame_remote.InitWithNewEndpointAndPassReceiver();
- new_main_rfh->SetMojomFrameRemote(std::move(pending_frame_remote));
- mojo::PendingRemote<blink::mojom::BrowserInterfaceBroker>
- browser_interface_broker;
- new_main_rfh->BindBrowserInterfaceBrokerReceiver(
- browser_interface_broker.InitWithNewPipeAndPassReceiver());
- mojo::PendingAssociatedRemote<blink::mojom::AssociatedInterfaceProvider>
- pending_associated_interface_provider;
- new_main_rfh->BindAssociatedInterfaceProviderReceiver(
- pending_associated_interface_provider
- .InitWithNewEndpointAndPassReceiver());
- // With this path, RenderViewHostImpl::CreateRenderView is never called
- // because `blink::WebView` is already created on the renderer side. Thus we
- // need to establish the connection here.
- mojo::PendingAssociatedRemote<blink::mojom::PageBroadcast> page_broadcast;
- mojo::PendingAssociatedReceiver<blink::mojom::PageBroadcast>
- page_broadcast_receiver =
- page_broadcast.InitWithNewEndpointAndPassReceiver();
- auto widget_params =
- new_main_rfh->GetLocalRenderWidgetHost()
- ->BindAndGenerateCreateFrameWidgetParamsForNewWindow();
- new_main_rfh->render_view_host()->BindPageBroadcast(
- std::move(page_broadcast));
- bool wait_for_debugger =
- devtools_instrumentation::ShouldWaitForDebuggerInWindowOpen();
- mojom::CreateNewWindowReplyPtr reply = mojom::CreateNewWindowReply::New(
- new_main_rfh->GetFrameToken(), new_main_rfh->GetRoutingID(),
- std::move(pending_frame_receiver), std::move(widget_params),
- std::move(page_broadcast_receiver), std::move(browser_interface_broker),
- std::move(pending_associated_interface_provider), cloned_namespace->id(),
- new_main_rfh->GetDevToolsFrameToken(), wait_for_debugger,
- new_main_rfh->GetDocumentToken(),
- new_main_rfh->policy_container_host()->CreatePolicyContainerForBlink(),
- blink::BrowsingContextGroupInfo(
- new_main_rfh->GetSiteInstance()->browsing_instance_token(),
- new_main_rfh->GetSiteInstance()->coop_related_group_token()),
- delegate_->GetColorProviderColorMaps());
- std::move(callback).Run(mojom::CreateNewWindowStatus::kSuccess,
- std::move(reply));
- // The mojom reply callback with kSuccess causes the renderer to create the
- // renderer-side objects.
- new_main_rfh->render_view_host()->RenderViewCreated(new_main_rfh);
- }
复制代码 子历程发送消息定义在
F:\code\google\src\out\Debug\gen\content\common\frame.mojom.cc
message.set_method_name("CreateNewWindow");
- FrameHostProxy::FrameHostProxy(mojo::MessageReceiverWithResponder* receiver)
- : receiver_(receiver) {
- }
- bool FrameHostProxy::CreateNewWindow(
- CreateNewWindowParamsPtr param_params, CreateNewWindowStatus* out_param_status, CreateNewWindowReplyPtr* out_param_reply) {
- #if BUILDFLAG(MOJO_TRACE_ENABLED)
- TRACE_EVENT_BEGIN1(
- "mojom", "Call content::mojom::FrameHost::CreateNewWindow (sync)", "input_parameters",
- [&](perfetto::TracedValue context){
- auto dict = std::move(context).WriteDictionary();
- perfetto::WriteIntoTracedValueWithFallback(
- dict.AddItem("params"), param_params,
- "<value of type CreateNewWindowParamsPtr>");
- });
- #else
- TRACE_EVENT0("mojom", "FrameHost::CreateNewWindow");
- #endif
-
- const bool kExpectsResponse = true;
- const bool kIsSync = true;
- const bool kAllowInterrupt =
- true;
- const bool is_urgent = false;
-
- const uint32_t kFlags =
- ((kExpectsResponse) ? mojo::Message::kFlagExpectsResponse : 0) |
- ((kIsSync) ? mojo::Message::kFlagIsSync : 0) |
- ((kAllowInterrupt) ? 0 : mojo::Message::kFlagNoInterrupt) |
- ((is_urgent) ? mojo::Message::kFlagIsUrgent : 0);
-
- mojo::Message message(
- internal::kFrameHost_CreateNewWindow_Name, kFlags, 0, 0, nullptr);
- mojo::internal::MessageFragment<
- ::content::mojom::internal::FrameHost_CreateNewWindow_Params_Data> params(
- message);
- params.Allocate();
- mojo::internal::MessageFragment<
- typename decltype(params->params)::BaseType> params_fragment(
- params.message());
- mojo::internal::Serialize<::content::mojom::CreateNewWindowParamsDataView>(
- param_params, params_fragment);
- params->params.Set(
- params_fragment.is_null() ? nullptr : params_fragment.data());
- MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
- params->params.is_null(),
- mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
- "null params in FrameHost.CreateNewWindow request");
- #if defined(ENABLE_IPC_FUZZER)
- message.set_interface_name(FrameHost::Name_);
- message.set_method_name("CreateNewWindow");
- #endif
- bool result = false;
- std::unique_ptr<mojo::MessageReceiver> responder(
- new FrameHost_CreateNewWindow_HandleSyncResponse(
- &result, out_param_status, out_param_reply));
- ::mojo::internal::SendMojoMessage(*receiver_, message, std::move(responder));
- #if BUILDFLAG(MOJO_TRACE_ENABLED)
- TRACE_EVENT_END1(
- "mojom", "FrameHost::CreateNewWindow", "sync_response_parameters",
- [&](perfetto::TracedValue context){
- auto dict = std::move(context).WriteDictionary();
- perfetto::WriteIntoTracedValueWithFallback(
- dict.AddItem("status"), out_param_status,
- "<value of type CreateNewWindowStatus>");
- perfetto::WriteIntoTracedValueWithFallback(
- dict.AddItem("reply"), out_param_reply,
- "<value of type CreateNewWindowReplyPtr>");
- });
- #endif
- return result;
- }
复制代码 总结:至此分析完毕。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |