一、本文以一个简单的 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-buttonHTMLFormControlElement* 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-formdatatypedef (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 DialogMethodexplicit 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=MouseFormData* 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 necessaryif (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 参数
FormData* dom_form_data = form->ConstructEntryList(
submit_button, data_encoding.EncodingForFormSubmission());
DCHECK(dom_form_data);
3.2)、FindOrCreateFrameForNavigation给主进程发送mojom消息CreateNewWindow
用来打开提交新页面。
Frame* target_frame =
form->GetDocument()
.GetFrame()
->Tree()
.FindOrCreateFrameForNavigation(frame_request, target_or_base_target)
.frame;
4、主进程收到子进程发送的mojom CreateNewWindow消息:
在F:\code\google\src\content\browser\renderer_host\render_frame_host_impl.cc里面处理:
RenderFrameHostImpl::CreateNewWindow打开https://www.runoob.com/try/demo_source/demo-form.php?FirstName=Mickey&LastName=Mouse
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() &¶ms->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>");});
#elseTRACE_EVENT0("mojom", "FrameHost::CreateNewWindow");
#endifconst 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");
#endifbool 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>");});
#endifreturn result;
}