diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-07-16 11:45:35 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-07-17 08:59:23 +0000 |
commit | 552906b0f222c5d5dd11b9fd73829d510980461a (patch) | |
tree | 3a11e6ed0538a81dd83b20cf3a4783e297f26d91 /chromium/third_party/blink/renderer/core/html/parser | |
parent | 1b05827804eaf047779b597718c03e7d38344261 (diff) | |
download | qtwebengine-chromium-552906b0f222c5d5dd11b9fd73829d510980461a.tar.gz |
BASELINE: Update Chromium to 83.0.4103.122
Change-Id: Ie3a82f5bb0076eec2a7c6a6162326b4301ee291e
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/third_party/blink/renderer/core/html/parser')
36 files changed, 889 insertions, 253 deletions
diff --git a/chromium/third_party/blink/renderer/core/html/parser/BUILD.gn b/chromium/third_party/blink/renderer/core/html/parser/BUILD.gn index 83e917e1e90..43eb9f797d7 100644 --- a/chromium/third_party/blink/renderer/core/html/parser/BUILD.gn +++ b/chromium/third_party/blink/renderer/core/html/parser/BUILD.gn @@ -35,6 +35,8 @@ blink_core_sources("parser") { "html_meta_charset_parser.h", "html_parser_idioms.cc", "html_parser_idioms.h", + "html_parser_metrics.cc", + "html_parser_metrics.h", "html_parser_options.cc", "html_parser_options.h", "html_parser_reentry_permit.cc", @@ -62,6 +64,7 @@ blink_core_sources("parser") { "input_stream_preprocessor.h", "markup_tokenizer_inlines.h", "nesting_level_incrementer.h", + "parser_scripting_flag_policy.h", "parser_synchronization_policy.h", "preload_request.cc", "preload_request.h", @@ -85,9 +88,7 @@ blink_core_sources("parser") { } fuzzer_test("blink_html_tokenizer_fuzzer") { - sources = [ - "html_tokenizer_fuzzer.cc", - ] + sources = [ "html_tokenizer_fuzzer.cc" ] deps = [ "../../:core", "../../../platform:blink_fuzzer_test_support", diff --git a/chromium/third_party/blink/renderer/core/html/parser/OWNERS b/chromium/third_party/blink/renderer/core/html/parser/OWNERS index 23b641cfa1f..2812e39384d 100644 --- a/chromium/third_party/blink/renderer/core/html/parser/OWNERS +++ b/chromium/third_party/blink/renderer/core/html/parser/OWNERS @@ -1,6 +1,7 @@ +csharrison@chromium.org kouhei@chromium.org +masonfreed@chromium.org yoavweiss@chromium.org -csharrison@chromium.org # TEAM: loading-dev@chromium.org # COMPONENT: Blink>HTML>Parser diff --git a/chromium/third_party/blink/renderer/core/html/parser/background_html_parser.cc b/chromium/third_party/blink/renderer/core/html/parser/background_html_parser.cc index 83c6e31cef2..6bc906f027b 100644 --- a/chromium/third_party/blink/renderer/core/html/parser/background_html_parser.cc +++ b/chromium/third_party/blink/renderer/core/html/parser/background_html_parser.cc @@ -33,7 +33,6 @@ #include "third_party/blink/renderer/core/html/parser/html_document_parser.h" #include "third_party/blink/renderer/core/html/parser/text_resource_decoder.h" #include "third_party/blink/renderer/core/html_names.h" -#include "third_party/blink/renderer/platform/instrumentation/histogram.h" #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h" #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h" #include "third_party/blink/renderer/platform/wtf/functional.h" @@ -164,6 +163,7 @@ void BackgroundHTMLParser::Finish() { } void BackgroundHTMLParser::Stop() { + ClearParser(); delete this; } @@ -175,6 +175,10 @@ void BackgroundHTMLParser::ForcePlaintextForTextDocument() { tokenizer_->SetState(HTMLTokenizer::kPLAINTEXTState); } +void BackgroundHTMLParser::ClearParser() { + parser_.Clear(); +} + void BackgroundHTMLParser::MarkEndOfFile() { DCHECK(!input_.Current().IsClosed()); input_.Append(String(&kEndOfFileMarker, 1)); diff --git a/chromium/third_party/blink/renderer/core/html/parser/background_html_parser.h b/chromium/third_party/blink/renderer/core/html/parser/background_html_parser.h index 5b94d6ebf6a..de2b5d96511 100644 --- a/chromium/third_party/blink/renderer/core/html/parser/background_html_parser.h +++ b/chromium/third_party/blink/renderer/core/html/parser/background_html_parser.h @@ -56,7 +56,7 @@ class BackgroundHTMLParser { public: Configuration(); HTMLParserOptions options; - base::WeakPtr<HTMLDocumentParser> parser; + WeakPersistent<HTMLDocumentParser> parser; std::unique_ptr<TextResourceDecoder> decoder; }; @@ -74,7 +74,7 @@ class BackgroundHTMLParser { USING_FAST_MALLOC(Checkpoint); public: - base::WeakPtr<HTMLDocumentParser> parser; + WeakPersistent<HTMLDocumentParser> parser; std::unique_ptr<HTMLToken> token; std::unique_ptr<HTMLTokenizer> tokenizer; HTMLTreeBuilderSimulator::State tree_builder_state; @@ -93,6 +93,8 @@ class BackgroundHTMLParser { void ForcePlaintextForTextDocument(); + void ClearParser(); + private: BackgroundHTMLParser(std::unique_ptr<Configuration>, scoped_refptr<base::SingleThreadTaskRunner>); @@ -111,7 +113,7 @@ class BackgroundHTMLParser { std::unique_ptr<HTMLTokenizer> tokenizer_; HTMLTreeBuilderSimulator tree_builder_simulator_; HTMLParserOptions options_; - base::WeakPtr<HTMLDocumentParser> parser_; + WeakPersistent<HTMLDocumentParser> parser_; CompactHTMLTokenStream pending_tokens_; PreloadRequestStream pending_preloads_; diff --git a/chromium/third_party/blink/renderer/core/html/parser/css_preload_scanner.cc b/chromium/third_party/blink/renderer/core/html/parser/css_preload_scanner.cc index 1dd67036707..279776cb0b0 100644 --- a/chromium/third_party/blink/renderer/core/html/parser/css_preload_scanner.cc +++ b/chromium/third_party/blink/renderer/core/html/parser/css_preload_scanner.cc @@ -236,7 +236,7 @@ static String ParseCSSStringOrURL(const String& string) { } void CSSPreloadScanner::EmitRule(const SegmentedString& source) { - if (DeprecatedEqualIgnoringCase(rule_, "import")) { + if (EqualIgnoringASCIICase(rule_, "import")) { String url = ParseCSSStringOrURL(rule_value_.ToString()); TextPosition position = TextPosition(source.CurrentLine(), source.CurrentColumn()); @@ -250,7 +250,7 @@ void CSSPreloadScanner::EmitRule(const SegmentedString& source) { requests_->push_back(std::move(request)); } state_ = kInitial; - } else if (DeprecatedEqualIgnoringCase(rule_, "charset")) + } else if (EqualIgnoringASCIICase(rule_, "charset")) state_ = kInitial; else state_ = kDoneParsingImportRules; diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_construction_site.cc b/chromium/third_party/blink/renderer/core/html/parser/html_construction_site.cc index e5b8596cb60..88bf8c170a1 100644 --- a/chromium/third_party/blink/renderer/core/html/parser/html_construction_site.cc +++ b/chromium/third_party/blink/renderer/core/html/parser/html_construction_site.cc @@ -300,7 +300,7 @@ void HTMLConstructionSite::AttachLater(ContainerNode* parent, DCHECK(ScriptingContentIsAllowed(parser_content_policy_) || !element || !element->IsScriptElement()); DCHECK(PluginContentIsAllowed(parser_content_policy_) || - !IsHTMLPlugInElement(child)); + !IsA<HTMLPlugInElement>(child)); HTMLConstructionSiteTask task(HTMLConstructionSiteTask::kInsert); task.parent = parent; @@ -572,16 +572,15 @@ void HTMLConstructionSite::SetCompatibilityModeFromDoctype( "-//W3C//DTD HTML Experimental 970421//") || public_id.StartsWithIgnoringASCIICase("-//W3C//DTD W3 HTML//") || public_id.StartsWithIgnoringASCIICase("-//W3O//DTD W3 HTML 3.0//") || - DeprecatedEqualIgnoringCase(public_id, - "-//W3O//DTD W3 HTML Strict 3.0//EN//") || + EqualIgnoringASCIICase(public_id, + "-//W3O//DTD W3 HTML Strict 3.0//EN//") || public_id.StartsWithIgnoringASCIICase( "-//WebTechs//DTD Mozilla HTML 2.0//") || public_id.StartsWithIgnoringASCIICase( "-//WebTechs//DTD Mozilla HTML//") || - DeprecatedEqualIgnoringCase(public_id, - "-/W3C/DTD HTML 4.0 Transitional/EN") || - DeprecatedEqualIgnoringCase(public_id, "HTML") || - DeprecatedEqualIgnoringCase( + EqualIgnoringASCIICase(public_id, "-/W3C/DTD HTML 4.0 Transitional/EN") || + EqualIgnoringASCIICase(public_id, "HTML") || + EqualIgnoringASCIICase( system_id, "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd") || (system_id.IsEmpty() && public_id.StartsWithIgnoringASCIICase( @@ -844,7 +843,7 @@ CreateElementFlags HTMLConstructionSite::GetCreateElementFlags() const { : CreateElementFlags::ByParser(); } -inline Document& HTMLConstructionSite::OwnerDocumentForCurrentNode() { +Document& HTMLConstructionSite::OwnerDocumentForCurrentNode() { if (auto* template_element = DynamicTo<HTMLTemplateElement>(*CurrentNode())) return template_element->content()->GetDocument(); return CurrentNode()->GetDocument(); @@ -919,8 +918,15 @@ Element* HTMLConstructionSite::CreateElement( // reactions stack." CEReactionsScope reactions; - // 7. - element = definition->CreateAutonomousCustomElementSync(document, tag_name); + // "7. Let element be the result of creating an element given document, + // localName, given namespace, null, and is. If will execute script is true, + // set the synchronous custom elements flag; otherwise, leave it unset." + // TODO(crbug.com/1080673): We clear the CreatedbyParser flag here, so that + // elements get fully constructed. Some elements (e.g. HTMLInputElement) + // only partially construct themselves when created by the parser, but since + // this is a custom element, we need a fully-constructed element here. + element = definition->CreateElement( + document, tag_name, GetCreateElementFlags().SetCreatedByParser(false)); // "8. Append each attribute in the given token to element." We don't use // setAttributes here because the custom element constructor may have diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_document_parser.cc b/chromium/third_party/blink/renderer/core/html/parser/html_document_parser.cc index 81914e59108..eb81ef312c7 100644 --- a/chromium/third_party/blink/renderer/core/html/parser/html_document_parser.cc +++ b/chromium/third_party/blink/renderer/core/html/parser/html_document_parser.cc @@ -43,6 +43,7 @@ #include "third_party/blink/renderer/core/html/html_document.h" #include "third_party/blink/renderer/core/html/parser/atomic_html_token.h" #include "third_party/blink/renderer/core/html/parser/background_html_parser.h" +#include "third_party/blink/renderer/core/html/parser/html_parser_metrics.h" #include "third_party/blink/renderer/core/html/parser/html_parser_scheduler.h" #include "third_party/blink/renderer/core/html/parser/html_resource_preloader.h" #include "third_party/blink/renderer/core/html/parser/html_tree_builder.h" @@ -58,7 +59,6 @@ #include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h" #include "third_party/blink/renderer/platform/heap/handle.h" #include "third_party/blink/renderer/platform/heap/heap.h" -#include "third_party/blink/renderer/platform/instrumentation/histogram.h" #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h" #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" @@ -70,6 +70,16 @@ namespace blink { +static size_t g_discarded_token_count_for_testing = 0; + +void ResetDiscardedTokenCountForTesting() { + g_discarded_token_count_for_testing = 0; +} + +size_t GetDiscardedTokenCountForTesting() { + return g_discarded_token_count_for_testing; +} + // This is a direct transcription of step 4 from: // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#fragment-case static HTMLTokenizer::State TokenizerStateForContextElement( @@ -89,7 +99,7 @@ static HTMLTokenizer::State TokenizerStateForContextElement( context_tag.Matches(html_names::kIFrameTag) || context_tag.Matches(html_names::kNoembedTag) || (context_tag.Matches(html_names::kNoscriptTag) && - options.script_enabled) || + options.scripting_flag) || context_tag.Matches(html_names::kNoframesTag)) return report_errors ? HTMLTokenizer::kRAWTEXTState : HTMLTokenizer::kPLAINTEXTState; @@ -101,6 +111,32 @@ static HTMLTokenizer::State TokenizerStateForContextElement( return HTMLTokenizer::kDataState; } +class ScopedYieldTimer { + public: + // This object is created at the start of a block of parsing, and will + // report the time since the last block yielded if known. + ScopedYieldTimer(std::unique_ptr<base::ElapsedTimer>* timer, + HTMLParserMetrics* metrics_reporter) + : timer_(timer), reporting_metrics_(metrics_reporter) { + if (!reporting_metrics_ || !(*timer_)) + return; + + metrics_reporter->AddYieldInterval((*timer_)->Elapsed()); + timer_->reset(); + } + + // The destructor creates a new timer, which will keep track of time until + // the next block starts. + ~ScopedYieldTimer() { + if (reporting_metrics_) + *timer_ = std::make_unique<base::ElapsedTimer>(); + } + + private: + std::unique_ptr<base::ElapsedTimer>* timer_; + bool reporting_metrics_; +}; + HTMLDocumentParser::HTMLDocumentParser(HTMLDocument& document, ParserSynchronizationPolicy sync_policy) : HTMLDocumentParser(document, kAllowScriptingContent, sync_policy) { @@ -131,7 +167,6 @@ HTMLDocumentParser::HTMLDocumentParser(Document& document, ParserContentPolicy content_policy, ParserSynchronizationPolicy sync_policy) : ScriptableDocumentParser(document, content_policy), - ContextLifecycleStateObserver(&document), options_(&document), reentry_permit_(HTMLParserReentryPermit::Create()), token_(sync_policy == kForceSynchronousParsing @@ -160,7 +195,15 @@ HTMLDocumentParser::HTMLDocumentParser(Document& document, // Threading is not allowed in prefetch mode. DCHECK(!document.IsPrefetchOnly() || !ShouldUseThreading()); - UpdateStateIfNeeded(); + // Report metrics for async document parsing only. The document + // must be main frame to meet UKM requirements, and must have a high + // resolution clock for high quality data. + if (sync_policy == kAllowAsynchronousParsing && document.GetFrame() && + document.GetFrame()->IsMainFrame() && + base::TimeTicks::IsHighResolution()) { + metrics_reporter_ = std::make_unique<HTMLParserMetrics>( + document.UkmSourceID(), document.UkmRecorder()); + } // Don't create preloader for parsing clipboard content. if (content_policy == kDisallowScriptingAndPluginContent) @@ -194,7 +237,6 @@ void HTMLDocumentParser::Trace(Visitor* visitor) { visitor->Trace(script_runner_); visitor->Trace(preloader_); ScriptableDocumentParser::Trace(visitor); - ContextLifecycleStateObserver::Trace(visitor); HTMLParserScriptRunnerHost::Trace(visitor); } @@ -269,7 +311,7 @@ bool HTMLDocumentParser::IsParsingFragment() const { } void HTMLDocumentParser::PumpTokenizerIfPossible() { - CheckIfBodyStylesheetAdded(); + CheckIfBlockingStylesheetAdded(); if (IsStopped() || IsPaused()) return; @@ -285,7 +327,9 @@ void HTMLDocumentParser::ResumeParsingAfterYield() { DCHECK(ShouldUseThreading()); DCHECK(have_background_parser_); - CheckIfBodyStylesheetAdded(); + ScopedYieldTimer(&yield_timer_, metrics_reporter_.get()); + + CheckIfBlockingStylesheetAdded(); if (IsStopped() || IsPaused()) return; @@ -301,7 +345,7 @@ void HTMLDocumentParser::RunScriptsForPausedTreeBuilder() { // We will not have a scriptRunner when parsing a DocumentFragment. if (script_runner_) script_runner_->ProcessScriptElement(script_element, script_start_position); - CheckIfBodyStylesheetAdded(); + CheckIfBlockingStylesheetAdded(); } bool HTMLDocumentParser::CanTakeNextToken() { @@ -335,7 +379,8 @@ void HTMLDocumentParser::EnqueueTokenizedChunk( // Note that on commit, the loader dispatched preloads for all the non-media // links. GetDocument()->Loader()->DispatchLinkHeaderPreloads( - chunk->viewport, PreloadHelper::kOnlyLoadMedia); + base::OptionalOrNullptr(chunk->viewport), + PreloadHelper::kOnlyLoadMedia); tried_loading_link_headers_ = true; if (GetDocument()->Loader()->GetPrefetchedSignedExchangeManager()) { // Link header preloads for prefetched signed exchanges won't be started @@ -390,12 +435,8 @@ void HTMLDocumentParser::EnqueueTokenizedChunk( speculations_.push_back(std::move(chunk)); - if (!IsPaused() && !IsScheduledForUnpause()) { - if (GetDocument()->IsContextPaused()) - parser_scheduler_->ForceUnpauseAfterYield(); - else - parser_scheduler_->ScheduleForUnpause(); - } + if (!IsPaused() && !IsScheduledForUnpause()) + parser_scheduler_->ScheduleForUnpause(); } void HTMLDocumentParser::DidReceiveEncodingDataFromBackgroundParser( @@ -453,16 +494,14 @@ void HTMLDocumentParser::DiscardSpeculationsAndResumeFrom( std::unique_ptr<TokenizedChunk> last_chunk_before_script, std::unique_ptr<HTMLToken> token, std::unique_ptr<HTMLTokenizer> tokenizer) { - weak_factory_.InvalidateWeakPtrs(); + // Clear back ref. + background_parser_->ClearParser(); size_t discarded_token_count = 0; for (const auto& speculation : speculations_) { discarded_token_count += speculation->tokens.size(); } - DEFINE_STATIC_LOCAL(CustomCountHistogram, discarded_token_count_histogram, - ("Parser.DiscardedTokenCount", 1, 100000, 50)); - discarded_token_count_histogram.Count( - base::saturated_cast<base::Histogram::Sample>(discarded_token_count)); + g_discarded_token_count_for_testing += discarded_token_count; speculations_.clear(); pending_csp_meta_token_ = nullptr; @@ -470,7 +509,7 @@ void HTMLDocumentParser::DiscardSpeculationsAndResumeFrom( std::unique_ptr<BackgroundHTMLParser::Checkpoint> checkpoint = std::make_unique<BackgroundHTMLParser::Checkpoint>(); - checkpoint->parser = weak_factory_.GetWeakPtr(); + checkpoint->parser = this; checkpoint->token = std::move(token); checkpoint->tokenizer = std::move(tokenizer); checkpoint->tree_builder_state = @@ -490,7 +529,8 @@ void HTMLDocumentParser::DiscardSpeculationsAndResumeFrom( } size_t HTMLDocumentParser::ProcessTokenizedChunkFromBackgroundParser( - std::unique_ptr<TokenizedChunk> pop_chunk) { + std::unique_ptr<TokenizedChunk> pop_chunk, + bool* reached_end_of_file) { TRACE_EVENT_WITH_FLOW0( "blink,loading", "HTMLDocumentParser::processTokenizedChunkFromBackgroundParser", @@ -551,6 +591,7 @@ size_t HTMLDocumentParser::ProcessTokenizedChunkFromBackgroundParser( // There should never be any chunks after the EOF. DCHECK(speculations_.IsEmpty()); PrepareToStopParsing(); + *reached_end_of_file = true; break; } @@ -595,17 +636,18 @@ void HTMLDocumentParser::PumpPendingSpeculations() { probe::ParseHTML probe(GetDocument(), this); SpeculationsPumpSession session(pump_speculations_session_nesting_level_); + bool reached_end_of_file = false; while (!speculations_.IsEmpty()) { DCHECK(!IsScheduledForUnpause()); - size_t element_token_count = - ProcessTokenizedChunkFromBackgroundParser(speculations_.TakeFirst()); + size_t element_token_count = ProcessTokenizedChunkFromBackgroundParser( + speculations_.TakeFirst(), &reached_end_of_file); session.AddedElementTokens(element_token_count); // Always check IsParsing first as document_ may be null. Surprisingly, // IsScheduledForUnpause() may be set here as a result of // ProcessTokenizedChunkFromBackgroundParser running arbitrary javascript // which invokes nested event loops. (e.g. inspector breakpoints) - CheckIfBodyStylesheetAdded(); + CheckIfBlockingStylesheetAdded(); if (!IsParsing() || IsPaused() || IsScheduledForUnpause()) break; @@ -614,6 +656,13 @@ void HTMLDocumentParser::PumpPendingSpeculations() { session, speculations_.front()->starting_script)) break; } + + if (metrics_reporter_) { + metrics_reporter_->AddChunk(session.ElapsedTime(), + session.ProcessedElementTokens()); + if (reached_end_of_file) + metrics_reporter_->ReportMetricsAtParseEnd(); + } } void HTMLDocumentParser::ForcePlaintextForTextDocument() { @@ -697,7 +746,7 @@ void HTMLDocumentParser::ConstructTreeFromHTMLToken() { Token().Clear(); tree_builder_->ConstructTree(&atomic_token); - CheckIfBodyStylesheetAdded(); + CheckIfBlockingStylesheetAdded(); // FIXME: ConstructTree may synchronously cause Document to be detached. if (!token_) @@ -714,7 +763,7 @@ void HTMLDocumentParser::ConstructTreeFromCompactHTMLToken( DCHECK(!GetDocument()->IsPrefetchOnly()); AtomicHTMLToken token(compact_token); tree_builder_->ConstructTree(&token); - CheckIfBodyStylesheetAdded(); + CheckIfBlockingStylesheetAdded(); } bool HTMLDocumentParser::HasInsertionPoint() { @@ -775,7 +824,7 @@ void HTMLDocumentParser::StartBackgroundParser() { std::unique_ptr<BackgroundHTMLParser::Configuration> config = std::make_unique<BackgroundHTMLParser::Configuration>(); config->options = options_; - config->parser = weak_factory_.GetWeakPtr(); + config->parser = this; config->decoder = TakeDecoder(); // The background parser is created on the main thread, but may otherwise @@ -808,7 +857,6 @@ void HTMLDocumentParser::StopBackgroundParser() { // Make this sync, as lsan triggers on some unittests if the task runner is // used. background_parser_->Stop(); - weak_factory_.InvalidateWeakPtrs(); } void HTMLDocumentParser::Append(const String& input_source) { @@ -1010,7 +1058,7 @@ void HTMLDocumentParser::ResumeParsingAfterPause() { DCHECK(!IsExecutingScript()); DCHECK(!IsPaused()); - CheckIfBodyStylesheetAdded(); + CheckIfBlockingStylesheetAdded(); if (IsStopped() || IsPaused()) return; @@ -1099,7 +1147,7 @@ void HTMLDocumentParser::DidLoadAllPendingParserBlockingStylesheets() { added_pending_parser_blocking_stylesheet_ = false; } -void HTMLDocumentParser::CheckIfBodyStylesheetAdded() { +void HTMLDocumentParser::CheckIfBlockingStylesheetAdded() { if (added_pending_parser_blocking_stylesheet_) { added_pending_parser_blocking_stylesheet_ = false; is_waiting_for_stylesheets_ = true; @@ -1119,16 +1167,6 @@ void HTMLDocumentParser::ParseDocumentFragment( parser->Detach(); } -void HTMLDocumentParser::ContextLifecycleStateChanged( - mojom::FrameLifecycleState state) { - if (!parser_scheduler_) - return; - if (state == mojom::FrameLifecycleState::kRunning) - parser_scheduler_->Unpause(); - else - parser_scheduler_->Pause(); -} - void HTMLDocumentParser::AppendBytes(const char* data, size_t length) { if (!length || IsStopped()) return; diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_document_parser.h b/chromium/third_party/blink/renderer/core/html/parser/html_document_parser.h index 9e98f0fe52f..ac73abc6eeb 100644 --- a/chromium/third_party/blink/renderer/core/html/parser/html_document_parser.h +++ b/chromium/third_party/blink/renderer/core/html/parser/html_document_parser.h @@ -32,7 +32,6 @@ #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/dom/parser_content_policy.h" #include "third_party/blink/renderer/core/dom/scriptable_document_parser.h" -#include "third_party/blink/renderer/core/execution_context/context_lifecycle_state_observer.h" #include "third_party/blink/renderer/core/html/parser/background_html_input_stream.h" #include "third_party/blink/renderer/core/html/parser/html_input_stream.h" #include "third_party/blink/renderer/core/html/parser/html_parser_options.h" @@ -59,14 +58,20 @@ class DocumentEncodingData; class DocumentFragment; class Element; class HTMLDocument; +class HTMLParserMetrics; class HTMLParserScheduler; class HTMLParserScriptRunner; class HTMLPreloadScanner; class HTMLResourcePreloader; class HTMLTreeBuilder; +// TODO(https://crbug.com/1049898): These are only exposed to make it possible +// to delete an expired histogram. The test should be rewritten to test at a +// different level, so it won't have to make assertions about internal state. +void CORE_EXPORT ResetDiscardedTokenCountForTesting(); +size_t CORE_EXPORT GetDiscardedTokenCountForTesting(); + class CORE_EXPORT HTMLDocumentParser : public ScriptableDocumentParser, - public ContextLifecycleStateObserver, private HTMLParserScriptRunnerHost { USING_GARBAGE_COLLECTED_MIXIN(HTMLDocumentParser); USING_PRE_FINALIZER(HTMLDocumentParser, Dispose); @@ -102,8 +107,6 @@ class CORE_EXPORT HTMLDocumentParser : public ScriptableDocumentParser, bool IsParsingAtLineNumber() const final; OrdinalNumber LineNumber() const final; - void ContextLifecycleStateChanged(mojom::FrameLifecycleState) final; - HTMLParserReentryPermit* ReentryPermit() { return reentry_permit_.get(); } struct TokenizedChunk { @@ -159,7 +162,7 @@ class CORE_EXPORT HTMLDocumentParser : public ScriptableDocumentParser, void ExecuteScriptsWaitingForResources() final; void DidAddPendingParserBlockingStylesheet() final; void DidLoadAllPendingParserBlockingStylesheets() final; - void CheckIfBodyStylesheetAdded(); + void CheckIfBlockingStylesheetAdded(); void DocumentElementAvailable() override; // HTMLParserScriptRunnerHost @@ -178,7 +181,8 @@ class CORE_EXPORT HTMLDocumentParser : public ScriptableDocumentParser, std::unique_ptr<HTMLToken>, std::unique_ptr<HTMLTokenizer>); size_t ProcessTokenizedChunkFromBackgroundParser( - std::unique_ptr<TokenizedChunk>); + std::unique_ptr<TokenizedChunk>, + bool*); void PumpPendingSpeculations(); bool CanTakeNextToken(); @@ -245,6 +249,11 @@ class CORE_EXPORT HTMLDocumentParser : public ScriptableDocumentParser, Member<HTMLResourcePreloader> preloader_; PreloadRequestStream queued_preloads_; + // Metrics gathering and reporting + std::unique_ptr<HTMLParserMetrics> metrics_reporter_; + // A timer for how long we are inactive after yielding + std::unique_ptr<base::ElapsedTimer> yield_timer_; + // If this is non-null, then there is a meta CSP token somewhere in the // speculation buffer. Preloads will be deferred until a token matching this // pointer is parsed and the CSP policy is applied. Note that this pointer @@ -264,8 +273,6 @@ class CORE_EXPORT HTMLDocumentParser : public ScriptableDocumentParser, bool tried_loading_link_headers_; bool added_pending_parser_blocking_stylesheet_; bool is_waiting_for_stylesheets_; - - base::WeakPtrFactory<HTMLDocumentParser> weak_factory_{this}; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_document_parser_loading_test.cc b/chromium/third_party/blink/renderer/core/html/parser/html_document_parser_loading_test.cc index cf1a4f2c9a9..54ec8d65eb3 100644 --- a/chromium/third_party/blink/renderer/core/html/parser/html_document_parser_loading_test.cc +++ b/chromium/third_party/blink/renderer/core/html/parser/html_document_parser_loading_test.cc @@ -8,7 +8,6 @@ #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/testing/sim/sim_request.h" #include "third_party/blink/renderer/core/testing/sim/sim_test.h" -#include "third_party/blink/renderer/platform/testing/histogram_tester.h" #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" namespace blink { @@ -16,9 +15,9 @@ namespace blink { class HTMLDocumentParserSimTest : public SimTest { protected: HTMLDocumentParserSimTest() { + ResetDiscardedTokenCountForTesting(); Document::SetThreadedParsingEnabledForTesting(true); } - HistogramTester histogram_; }; class HTMLDocumentParserLoadingTest : public HTMLDocumentParserSimTest, @@ -432,7 +431,7 @@ TEST_F(HTMLDocumentParserSimTest, NoRewindNoDocWrite) { )HTML"); test::RunPendingTasks(); - histogram_.ExpectTotalCount("Parser.DiscardedTokenCount", 0); + EXPECT_EQ(0U, GetDiscardedTokenCountForTesting()); } TEST_F(HTMLDocumentParserSimTest, RewindBrokenToken) { @@ -447,7 +446,7 @@ TEST_F(HTMLDocumentParserSimTest, RewindBrokenToken) { )HTML"); test::RunPendingTasks(); - histogram_.ExpectTotalCount("Parser.DiscardedTokenCount", 1); + EXPECT_EQ(2U, GetDiscardedTokenCountForTesting()); } TEST_F(HTMLDocumentParserSimTest, RewindDifferentNamespace) { @@ -462,7 +461,7 @@ TEST_F(HTMLDocumentParserSimTest, RewindDifferentNamespace) { )HTML"); test::RunPendingTasks(); - histogram_.ExpectTotalCount("Parser.DiscardedTokenCount", 1); + EXPECT_EQ(2U, GetDiscardedTokenCountForTesting()); } TEST_F(HTMLDocumentParserSimTest, NoRewindSaneDocWrite1) { @@ -476,7 +475,7 @@ TEST_F(HTMLDocumentParserSimTest, NoRewindSaneDocWrite1) { "</script>"); test::RunPendingTasks(); - histogram_.ExpectTotalCount("Parser.DiscardedTokenCount", 0); + EXPECT_EQ(0U, GetDiscardedTokenCountForTesting()); } TEST_F(HTMLDocumentParserSimTest, NoRewindSaneDocWrite2) { @@ -491,7 +490,7 @@ TEST_F(HTMLDocumentParserSimTest, NoRewindSaneDocWrite2) { )HTML"); test::RunPendingTasks(); - histogram_.ExpectTotalCount("Parser.DiscardedTokenCount", 0); + EXPECT_EQ(0U, GetDiscardedTokenCountForTesting()); } TEST_F(HTMLDocumentParserSimTest, NoRewindSaneDocWriteWithTitle) { @@ -511,7 +510,7 @@ TEST_F(HTMLDocumentParserSimTest, NoRewindSaneDocWriteWithTitle) { )HTML"); test::RunPendingTasks(); - histogram_.ExpectTotalCount("Parser.DiscardedTokenCount", 0); + EXPECT_EQ(0U, GetDiscardedTokenCountForTesting()); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_document_parser_test.cc b/chromium/third_party/blink/renderer/core/html/parser/html_document_parser_test.cc index 33750cefc73..d74f07df6a4 100644 --- a/chromium/third_party/blink/renderer/core/html/parser/html_document_parser_test.cc +++ b/chromium/third_party/blink/renderer/core/html/parser/html_document_parser_test.cc @@ -6,7 +6,6 @@ #include <memory> #include "testing/gtest/include/gtest/gtest.h" -#include "third_party/blink/public/platform/web_prerendering_support.h" #include "third_party/blink/renderer/core/html/html_document.h" #include "third_party/blink/renderer/core/html/parser/text_resource_decoder.h" #include "third_party/blink/renderer/core/loader/prerenderer_client.h" @@ -24,27 +23,11 @@ class MockPrerendererClient : public PrerendererClient { : PrerendererClient(page, nullptr), is_prefetch_only_(is_prefetch_only) {} private: - void WillAddPrerender(Prerender*) override {} bool IsPrefetchOnly() override { return is_prefetch_only_; } bool is_prefetch_only_; }; -class MockWebPrerenderingSupport : public WebPrerenderingSupport { - public: - MockWebPrerenderingSupport() { Initialize(this); } - - void Add(const WebPrerender&) override {} - void Cancel(const WebPrerender&) override {} - void Abandon(const WebPrerender&) override {} - void PrefetchFinished() override { prefetch_finished_ = true; } - - bool IsPrefetchFinished() const { return prefetch_finished_; } - - private: - bool prefetch_finished_ = false; -}; - class HTMLDocumentParserTest : public PageTestBase { protected: void SetUp() override { @@ -60,19 +43,12 @@ class HTMLDocumentParserTest : public PageTestBase { parser->SetDecoder(std::move(decoder)); return parser; } - - bool PrefetchFinishedCleanly() { - return prerendering_support_.IsPrefetchFinished(); - } - - private: - MockWebPrerenderingSupport prerendering_support_; }; } // namespace TEST_F(HTMLDocumentParserTest, AppendPrefetch) { - HTMLDocument& document = ToHTMLDocument(GetDocument()); + auto& document = To<HTMLDocument>(GetDocument()); ProvidePrerendererClientTo( *document.GetPage(), MakeGarbageCollected<MockPrerendererClient>(*document.GetPage(), true)); @@ -90,11 +66,10 @@ TEST_F(HTMLDocumentParserTest, AppendPrefetch) { // DCHECK). static_cast<DocumentParser*>(parser)->Finish(); EXPECT_EQ(HTMLTokenizer::kDataState, parser->Tokenizer()->GetState()); - EXPECT_TRUE(PrefetchFinishedCleanly()); } TEST_F(HTMLDocumentParserTest, AppendNoPrefetch) { - HTMLDocument& document = ToHTMLDocument(GetDocument()); + auto& document = To<HTMLDocument>(GetDocument()); EXPECT_FALSE(document.IsPrefetchOnly()); // Use ForceSynchronousParsing to allow calling append(). HTMLDocumentParser* parser = CreateParser(document); diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_element_stack.cc b/chromium/third_party/blink/renderer/core/html/parser/html_element_stack.cc index 598ed12a677..a4a13996c81 100644 --- a/chromium/third_party/blink/renderer/core/html/parser/html_element_stack.cc +++ b/chromium/third_party/blink/renderer/core/html/parser/html_element_stack.cc @@ -134,8 +134,6 @@ HTMLElementStack::HTMLElementStack() body_element_(nullptr), stack_depth_(0) {} -HTMLElementStack::~HTMLElementStack() = default; - bool HTMLElementStack::HasOnlyOneElement() const { return !TopRecord()->Next(); } @@ -251,8 +249,8 @@ bool HTMLElementStack::IsHTMLIntegrationPoint(HTMLStackItem* item) { item->GetAttributeItem(mathml_names::kEncodingAttr); if (encoding_attr) { const String& encoding = encoding_attr->Value(); - return DeprecatedEqualIgnoringCase(encoding, "text/html") || - DeprecatedEqualIgnoringCase(encoding, "application/xhtml+xml"); + return EqualIgnoringASCIICase(encoding, "text/html") || + EqualIgnoringASCIICase(encoding, "application/xhtml+xml"); } return false; } diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_element_stack.h b/chromium/third_party/blink/renderer/core/html/parser/html_element_stack.h index bafb57a8d25..a433c82874c 100644 --- a/chromium/third_party/blink/renderer/core/html/parser/html_element_stack.h +++ b/chromium/third_party/blink/renderer/core/html/parser/html_element_stack.h @@ -45,7 +45,6 @@ class HTMLElementStack { public: HTMLElementStack(); - ~HTMLElementStack(); class ElementRecord final : public GarbageCollected<ElementRecord> { public: diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_formatting_element_list.cc b/chromium/third_party/blink/renderer/core/html/parser/html_formatting_element_list.cc index 9741293150a..8ade3c166af 100644 --- a/chromium/third_party/blink/renderer/core/html/parser/html_formatting_element_list.cc +++ b/chromium/third_party/blink/renderer/core/html/parser/html_formatting_element_list.cc @@ -39,8 +39,6 @@ static const size_t kNoahsArkCapacity = 3; HTMLFormattingElementList::HTMLFormattingElementList() = default; -HTMLFormattingElementList::~HTMLFormattingElementList() = default; - Element* HTMLFormattingElementList::ClosestElementInScopeWithName( const AtomicString& target_name) { for (wtf_size_t i = 1; i <= entries_.size(); ++i) { diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_formatting_element_list.h b/chromium/third_party/blink/renderer/core/html/parser/html_formatting_element_list.h index 7d8e16b883e..f9c4f2a13cb 100644 --- a/chromium/third_party/blink/renderer/core/html/parser/html_formatting_element_list.h +++ b/chromium/third_party/blink/renderer/core/html/parser/html_formatting_element_list.h @@ -42,7 +42,6 @@ class HTMLFormattingElementList { public: HTMLFormattingElementList(); - ~HTMLFormattingElementList(); // Ideally Entry would be private, but HTMLTreeBuilder has to coordinate // between the HTMLFormattingElementList and HTMLElementStack and needs access diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_parser_idioms.cc b/chromium/third_party/blink/renderer/core/html/parser/html_parser_idioms.cc index fed483dae45..85a7b67b3c4 100644 --- a/chromium/third_party/blink/renderer/core/html/parser/html_parser_idioms.cc +++ b/chromium/third_party/blink/renderer/core/html/parser/html_parser_idioms.cc @@ -379,7 +379,7 @@ WTF::TextEncoding EncodingFromMetaAttributes( const AtomicString& attribute_value = AtomicString(html_attribute.second); if (ThreadSafeMatch(attribute_name, html_names::kHttpEquivAttr)) { - if (DeprecatedEqualIgnoringCase(attribute_value, "content-type")) + if (EqualIgnoringASCIICase(attribute_value, "content-type")) got_pragma = true; } else if (ThreadSafeMatch(attribute_name, html_names::kCharsetAttr)) { has_charset = true; diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_parser_metrics.cc b/chromium/third_party/blink/renderer/core/html/parser/html_parser_metrics.cc new file mode 100644 index 00000000000..997ff68addd --- /dev/null +++ b/chromium/third_party/blink/renderer/core/html/parser/html_parser_metrics.cc @@ -0,0 +1,104 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/core/html/parser/html_parser_metrics.h" + +#include "base/metrics/histogram_macros.h" +#include "services/metrics/public/cpp/ukm_builders.h" + +namespace blink { + +HTMLParserMetrics::HTMLParserMetrics(int64_t source_id, + ukm::UkmRecorder* recorder) + : source_id_(source_id), recorder_(recorder) {} + +void HTMLParserMetrics::AddChunk(base::TimeDelta elapsed_time, + unsigned tokens_parsed) { + DCHECK(base::TimeTicks::IsHighResolution()); + + ++chunk_count_; + + accumulated_parsing_time_ += elapsed_time; + if (elapsed_time < min_parsing_time_) + min_parsing_time_ = elapsed_time; + if (elapsed_time > max_parsing_time_) + max_parsing_time_ = elapsed_time; + + total_tokens_parsed_ += tokens_parsed; + if (tokens_parsed < min_tokens_parsed_) + min_tokens_parsed_ = tokens_parsed; + if (tokens_parsed > max_tokens_parsed_) + max_tokens_parsed_ = tokens_parsed; +} + +void HTMLParserMetrics::AddYieldInterval(base::TimeDelta elapsed_time) { + DCHECK(base::TimeTicks::IsHighResolution()); + + yield_count_++; + + accumulated_yield_intervals_ += elapsed_time; + if (elapsed_time < min_yield_interval_) + min_yield_interval_ = elapsed_time; + if (elapsed_time > max_yield_interval_) + max_yield_interval_ = elapsed_time; +} + +void HTMLParserMetrics::ReportMetricsAtParseEnd() { + // The various histogram limits were chosen based on initial UKM data. + UMA_HISTOGRAM_COUNTS_1000("Blink.HTMLParsing.ChunkCount", chunk_count_); + UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES( + "Blink.HTMLParsing.ParsingTimeMax", max_parsing_time_, + base::TimeDelta::FromMicroseconds(1), base::TimeDelta::FromSeconds(100), + 1000); + UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES("Blink.HTMLParsing.ParsingTimeMin", + min_parsing_time_, + base::TimeDelta::FromMicroseconds(1), + base::TimeDelta::FromSeconds(1), 100); + UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES( + "Blink.HTMLParsing.ParsingTimeTotal", accumulated_parsing_time_, + base::TimeDelta::FromMicroseconds(1), base::TimeDelta::FromSeconds(100), + 1000); + UMA_HISTOGRAM_COUNTS_1M("Blink.HTMLParsing.TokensParsedMax", + max_tokens_parsed_); + UMA_HISTOGRAM_COUNTS_10000("Blink.HTMLParsing.TokensParsedMin", + min_tokens_parsed_); + UMA_HISTOGRAM_COUNTS_1M("Blink.HTMLParsing.TokensParsedAverage", + total_tokens_parsed_ / chunk_count_); + + // Only report yield data if we actually yielded. + if (max_yield_interval_ != base::TimeDelta()) { + UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES( + "Blink.HTMLParsing.YieldedTimeMax", max_yield_interval_, + base::TimeDelta::FromMicroseconds(1), base::TimeDelta::FromSeconds(100), + 1000); + UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES( + "Blink.HTMLParsing.YieldedTimeMin", min_yield_interval_, + base::TimeDelta::FromMicroseconds(1), base::TimeDelta::FromSeconds(10), + 100); + UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES( + "Blink.HTMLParsing.YieldedTimeAverage", + accumulated_yield_intervals_ / yield_count_, + base::TimeDelta::FromMicroseconds(1), base::TimeDelta::FromSeconds(10), + 100); + } + + // Build and report UKM + ukm::builders::Blink_HTMLParsing builder(source_id_); + builder.SetChunkCount(chunk_count_); + builder.SetParsingTimeMax(max_parsing_time_.InMicroseconds()); + builder.SetParsingTimeMin(min_parsing_time_.InMicroseconds()); + builder.SetParsingTimeTotal(accumulated_parsing_time_.InMicroseconds()); + builder.SetTokensParsedMax(max_tokens_parsed_); + builder.SetTokensParsedMin(min_tokens_parsed_); + builder.SetTokensParsedAverage(total_tokens_parsed_ / chunk_count_); + if (accumulated_yield_intervals_ != base::TimeDelta()) { + builder.SetYieldedTimeMax(max_yield_interval_.InMicroseconds()); + builder.SetYieldedTimeMin(min_yield_interval_.InMicroseconds()); + builder.SetYieldedTimeAverage( + accumulated_yield_intervals_.InMicroseconds() / yield_count_); + } + builder.Record(recorder_); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_parser_metrics.h b/chromium/third_party/blink/renderer/core/html/parser/html_parser_metrics.h new file mode 100644 index 00000000000..e6c84aa70e7 --- /dev/null +++ b/chromium/third_party/blink/renderer/core/html/parser/html_parser_metrics.h @@ -0,0 +1,56 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_PARSER_HTML_PARSER_METRICS_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_PARSER_HTML_PARSER_METRICS_H_ + +#include "base/time/time.h" +#include "third_party/blink/renderer/core/core_export.h" +#include "third_party/blink/renderer/platform/instrumentation/histogram.h" + +namespace ukm { +class UkmRecorder; +} + +namespace blink { + +// Store and report metrics data for the HTMLDocumentParser. +class CORE_EXPORT HTMLParserMetrics { + public: + HTMLParserMetrics(int64_t source_id, ukm::UkmRecorder*); + ~HTMLParserMetrics() = default; + + void AddChunk(base::TimeDelta elapsed_time, unsigned tokens_parsed); + + void AddYieldInterval(base::TimeDelta elapsed_time); + + void ReportMetricsAtParseEnd(); + + private: + // UKM System data. + const int64_t source_id_; + ukm::UkmRecorder* const recorder_; + + // Metrics data. + unsigned chunk_count_ = 0; // For computing averages. + base::TimeDelta accumulated_parsing_time_; // Constructed with 0 value + base::TimeDelta min_parsing_time_ = base::TimeDelta::Max(); + base::TimeDelta max_parsing_time_; // Constructed with 0 value + unsigned total_tokens_parsed_ = 0; + unsigned min_tokens_parsed_ = UINT_MAX; + unsigned max_tokens_parsed_ = 0; + + // Yield count may not equal chunk count - 1. That is, there is not + // always one yield between every pair of chunks. + unsigned yield_count_ = 0; + base::TimeDelta accumulated_yield_intervals_; // Constructed with 0 value + base::TimeDelta min_yield_interval_ = base::TimeDelta::Max(); + base::TimeDelta max_yield_interval_; // Constructed with 0 value + + DISALLOW_COPY_AND_ASSIGN(HTMLParserMetrics); +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_PARSER_HTML_PARSER_METRICS_H_ diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_parser_metrics_test.cc b/chromium/third_party/blink/renderer/core/html/parser/html_parser_metrics_test.cc new file mode 100644 index 00000000000..7f797d2b3f9 --- /dev/null +++ b/chromium/third_party/blink/renderer/core/html/parser/html_parser_metrics_test.cc @@ -0,0 +1,256 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/core/html/parser/html_parser_metrics.h" + +#include "base/test/metrics/histogram_tester.h" +#include "base/test/test_mock_time_task_runner.h" +#include "components/ukm/test_ukm_recorder.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/renderer/core/frame/frame_test_helpers.h" +#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h" +#include "third_party/blink/renderer/platform/testing/url_test_helpers.h" + +namespace blink { + +class HTMLParserMetricsTest : public testing::Test { + public: + HTMLParserMetricsTest() { + helper_.Initialize(nullptr, nullptr, nullptr, nullptr); + } + + ~HTMLParserMetricsTest() override = default; + + void SetUp() override {} + + void TearDown() override {} + + void LoadHTML(const std::string& html) { + frame_test_helpers::LoadHTMLString(helper_.GetWebView()->MainFrameImpl(), + html, + url_test_helpers::ToKURL("about:blank")); + } + + protected: + frame_test_helpers::WebViewHelper helper_; +}; + +TEST_F(HTMLParserMetricsTest, ReportSingleChunk) { + // Although the tests use a mock clock, the metrics recorder checks if the + // system has a high resolution clock before recording results. As a result, + // the tests will fail if the system does not have a high resolution clock. + if (!base::TimeTicks::IsHighResolution()) + return; + + base::HistogramTester histogram_tester; + LoadHTML(R"HTML( + <div></div> + )HTML"); + + // Should have one of each metric, except the yield times because with + // a single chunk they should not report. + histogram_tester.ExpectTotalCount("Blink.HTMLParsing.ChunkCount", 1); + histogram_tester.ExpectTotalCount("Blink.HTMLParsing.ParsingTimeMax", 1); + histogram_tester.ExpectTotalCount("Blink.HTMLParsing.ParsingTimeMin", 1); + histogram_tester.ExpectTotalCount("Blink.HTMLParsing.ParsingTimeTotal", 1); + histogram_tester.ExpectTotalCount("Blink.HTMLParsing.TokensParsedMax", 1); + histogram_tester.ExpectTotalCount("Blink.HTMLParsing.TokensParsedMin", 1); + histogram_tester.ExpectTotalCount("Blink.HTMLParsing.TokensParsedAverage", 1); + histogram_tester.ExpectTotalCount("Blink.HTMLParsing.YieldedTimeMax", 0); + histogram_tester.ExpectTotalCount("Blink.HTMLParsing.YieldedTimeMin", 0); + histogram_tester.ExpectTotalCount("Blink.HTMLParsing.YieldedTimeAverage", 0); + + // Expect specific values for the chunks and tokens counts + histogram_tester.ExpectUniqueSample("Blink.HTMLParsing.ChunkCount", 1, 1); + histogram_tester.ExpectUniqueSample("Blink.HTMLParsing.TokensParsedMax", 2, + 1); + histogram_tester.ExpectUniqueSample("Blink.HTMLParsing.TokensParsedMin", 2, + 1); + histogram_tester.ExpectUniqueSample("Blink.HTMLParsing.TokensParsedAverage", + 2, 1); + + // Expect that the times have moved from the default and the max and min + // and total are all the same (within the same bucket) + std::vector<base::Bucket> parsing_time_max_buckets = + histogram_tester.GetAllSamples("Blink.HTMLParsing.ParsingTimeMax"); + std::vector<base::Bucket> parsing_time_min_buckets = + histogram_tester.GetAllSamples("Blink.HTMLParsing.ParsingTimeMin"); + std::vector<base::Bucket> parsing_time_total_buckets = + histogram_tester.GetAllSamples("Blink.HTMLParsing.ParsingTimeTotal"); + EXPECT_EQ(parsing_time_max_buckets.size(), 1u); + EXPECT_EQ(parsing_time_min_buckets.size(), 1u); + EXPECT_EQ(parsing_time_total_buckets.size(), 1u); + EXPECT_GT(parsing_time_max_buckets[0].min, 0); + EXPECT_GT(parsing_time_min_buckets[0].min, 0); + EXPECT_GT(parsing_time_total_buckets[0].min, 0); +} + +TEST_F(HTMLParserMetricsTest, HistogramReportsTwoChunks) { + // Although the tests use a mock clock, the metrics recorder checks if the + // system has a high resolution clock before recording results. As a result, + // the tests will fail if the system does not have a high resolution clock. + if (!base::TimeTicks::IsHighResolution()) + return; + + base::HistogramTester histogram_tester; + + // This content exceeds the number of tokens before a script tag used as + // the yield threshold. If the yield threshold changes, this test will fail + // and/or need changing. See the HTMLParserScheduler::ShouldYield method for + // the current value of the constant. + LoadHTML(R"HTML( + <head></head> + <div></div><div></div><div></div><div></div><div></div><div></div> + <div></div><div></div><div></div><div></div><div></div><div></div> + <div></div><div></div><div></div><div></div><div></div><div></div> + <div></div><div></div><div></div><div></div><div></div><div></div> + <div></div><div></div><div></div><div></div><div></div><div></div> + <div></div><div></div><div></div><div></div><div></div><div></div> + <div></div><div></div><div></div><div></div><div></div><div></div> + <div></div><div></div><div></div><div></div><div></div><div></div> + <div></div><div></div><div></div><div></div><div></div><div></div> + <script>document.offsetTop</script> + )HTML"); + + // Should have one of each metric. + histogram_tester.ExpectTotalCount("Blink.HTMLParsing.ChunkCount", 1); + histogram_tester.ExpectTotalCount("Blink.HTMLParsing.ParsingTimeMax", 1); + histogram_tester.ExpectTotalCount("Blink.HTMLParsing.ParsingTimeMin", 1); + histogram_tester.ExpectTotalCount("Blink.HTMLParsing.ParsingTimeTotal", 1); + histogram_tester.ExpectTotalCount("Blink.HTMLParsing.TokensParsedMax", 1); + histogram_tester.ExpectTotalCount("Blink.HTMLParsing.TokensParsedMin", 1); + histogram_tester.ExpectTotalCount("Blink.HTMLParsing.TokensParsedAverage", 1); + histogram_tester.ExpectTotalCount("Blink.HTMLParsing.YieldedTimeMax", 1); + histogram_tester.ExpectTotalCount("Blink.HTMLParsing.YieldedTimeMin", 1); + histogram_tester.ExpectTotalCount("Blink.HTMLParsing.YieldedTimeAverage", 1); + + // Expect specific values for the chunks and tokens counts + histogram_tester.ExpectUniqueSample("Blink.HTMLParsing.ChunkCount", 2, 1); + histogram_tester.ExpectUniqueSample("Blink.HTMLParsing.TokensParsedMax", 110, + 1); + histogram_tester.ExpectUniqueSample("Blink.HTMLParsing.TokensParsedMin", 0, + 1); + histogram_tester.ExpectUniqueSample("Blink.HTMLParsing.TokensParsedAverage", + 55, 1); + + // For parse times, expect that the times have moved from the default. + std::vector<base::Bucket> parsing_time_max_buckets = + histogram_tester.GetAllSamples("Blink.HTMLParsing.ParsingTimeMax"); + std::vector<base::Bucket> parsing_time_min_buckets = + histogram_tester.GetAllSamples("Blink.HTMLParsing.ParsingTimeMin"); + std::vector<base::Bucket> parsing_time_total_buckets = + histogram_tester.GetAllSamples("Blink.HTMLParsing.ParsingTimeTotal"); + EXPECT_EQ(parsing_time_max_buckets.size(), 1u); + EXPECT_EQ(parsing_time_min_buckets.size(), 1u); + EXPECT_EQ(parsing_time_total_buckets.size(), 1u); + EXPECT_GT(parsing_time_max_buckets[0].min, 0); + EXPECT_GT(parsing_time_min_buckets[0].min, 0); + EXPECT_GT(parsing_time_total_buckets[0].min, 0); + + // For yields, the values should be the same because there was only one yield, + // but due to different histogram sizes we can't directly compare them. + std::vector<base::Bucket> yield_time_max_buckets = + histogram_tester.GetAllSamples("Blink.HTMLParsing.YieldedTimeMax"); + std::vector<base::Bucket> yield_time_min_buckets = + histogram_tester.GetAllSamples("Blink.HTMLParsing.YieldedTimeMin"); + std::vector<base::Bucket> yield_time_average_buckets = + histogram_tester.GetAllSamples("Blink.HTMLParsing.YieldedTimeAverage"); + EXPECT_EQ(yield_time_max_buckets.size(), 1u); + EXPECT_EQ(yield_time_min_buckets.size(), 1u); + EXPECT_EQ(yield_time_average_buckets.size(), 1u); + EXPECT_GT(yield_time_max_buckets[0].min, 0); + EXPECT_GT(yield_time_min_buckets[0].min, 0); + EXPECT_GT(yield_time_average_buckets[0].min, 0); +} + +TEST_F(HTMLParserMetricsTest, UkmStoresValuesCorrectly) { + // Although the tests use a mock clock, the metrics recorder checks if the + // system has a high resolution clock before recording results. As a result, + // the tests will fail if the system does not have a high resolution clock. + if (!base::TimeTicks::IsHighResolution()) + return; + + ukm::TestUkmRecorder recorder; + HTMLParserMetrics reporter(ukm::UkmRecorder::GetNewSourceID(), &recorder); + + // Start with empty metrics + auto entries = recorder.GetEntriesByName("Blink.HTMLParsing"); + EXPECT_EQ(entries.size(), 0u); + + // Run a fictional sequence of calls + base::TimeDelta first_parse_time = base::TimeDelta::FromMicroseconds(20); + base::TimeDelta second_parse_time = base::TimeDelta::FromMicroseconds(10); + base::TimeDelta third_parse_time = base::TimeDelta::FromMicroseconds(30); + unsigned first_tokens_parsed = 50u; + unsigned second_tokens_parsed = 40u; + unsigned third_tokens_parsed = 60u; + base::TimeDelta first_yield_time = base::TimeDelta::FromMicroseconds(80); + base::TimeDelta second_yield_time = base::TimeDelta::FromMicroseconds(70); + + reporter.AddChunk(first_parse_time, first_tokens_parsed); + reporter.AddYieldInterval(first_yield_time); + reporter.AddChunk(second_parse_time, second_tokens_parsed); + reporter.AddYieldInterval(second_yield_time); + reporter.AddChunk(third_parse_time, third_tokens_parsed); + reporter.ReportMetricsAtParseEnd(); + + // Check we have a single entry + entries = recorder.GetEntriesByName("Blink.HTMLParsing"); + EXPECT_EQ(entries.size(), 1u); + auto* entry = entries[0]; + + // Verify all the values + EXPECT_TRUE(ukm::TestUkmRecorder::EntryHasMetric(entry, "ChunkCount")); + const int64_t* metric_value = + ukm::TestUkmRecorder::GetEntryMetric(entry, "ChunkCount"); + EXPECT_EQ(*metric_value, 3); + + EXPECT_TRUE(ukm::TestUkmRecorder::EntryHasMetric(entry, "ParsingTimeMax")); + metric_value = ukm::TestUkmRecorder::GetEntryMetric(entry, "ParsingTimeMax"); + EXPECT_EQ(*metric_value, third_parse_time.InMicroseconds()); + + EXPECT_TRUE(ukm::TestUkmRecorder::EntryHasMetric(entry, "ParsingTimeMin")); + metric_value = ukm::TestUkmRecorder::GetEntryMetric(entry, "ParsingTimeMin"); + EXPECT_EQ(*metric_value, second_parse_time.InMicroseconds()); + + EXPECT_TRUE(ukm::TestUkmRecorder::EntryHasMetric(entry, "ParsingTimeTotal")); + metric_value = + ukm::TestUkmRecorder::GetEntryMetric(entry, "ParsingTimeTotal"); + EXPECT_EQ(*metric_value, + (first_parse_time + second_parse_time + third_parse_time) + .InMicroseconds()); + + EXPECT_TRUE(ukm::TestUkmRecorder::EntryHasMetric(entry, "TokensParsedMax")); + metric_value = ukm::TestUkmRecorder::GetEntryMetric(entry, "TokensParsedMax"); + EXPECT_EQ(*metric_value, third_tokens_parsed); + + EXPECT_TRUE(ukm::TestUkmRecorder::EntryHasMetric(entry, "TokensParsedMin")); + metric_value = ukm::TestUkmRecorder::GetEntryMetric(entry, "TokensParsedMin"); + EXPECT_EQ(*metric_value, second_tokens_parsed); + + EXPECT_TRUE( + ukm::TestUkmRecorder::EntryHasMetric(entry, "TokensParsedAverage")); + metric_value = + ukm::TestUkmRecorder::GetEntryMetric(entry, "TokensParsedAverage"); + EXPECT_EQ( + *metric_value, + (first_tokens_parsed + second_tokens_parsed + third_tokens_parsed) / 3); + + EXPECT_TRUE(ukm::TestUkmRecorder::EntryHasMetric(entry, "YieldedTimeMax")); + metric_value = ukm::TestUkmRecorder::GetEntryMetric(entry, "YieldedTimeMax"); + EXPECT_EQ(*metric_value, first_yield_time.InMicroseconds()); + + EXPECT_TRUE(ukm::TestUkmRecorder::EntryHasMetric(entry, "YieldedTimeMin")); + metric_value = ukm::TestUkmRecorder::GetEntryMetric(entry, "YieldedTimeMin"); + EXPECT_EQ(*metric_value, second_yield_time.InMicroseconds()); + + EXPECT_TRUE( + ukm::TestUkmRecorder::EntryHasMetric(entry, "YieldedTimeAverage")); + metric_value = + ukm::TestUkmRecorder::GetEntryMetric(entry, "YieldedTimeAverage"); + EXPECT_EQ(*metric_value, + ((first_yield_time + second_yield_time) / 2).InMicroseconds()); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_parser_options.cc b/chromium/third_party/blink/renderer/core/html/parser/html_parser_options.cc index 494d91f99cf..a5c4119348f 100644 --- a/chromium/third_party/blink/renderer/core/html/parser/html_parser_options.cc +++ b/chromium/third_party/blink/renderer/core/html/parser/html_parser_options.cc @@ -26,19 +26,20 @@ #include "third_party/blink/renderer/core/html/parser/html_parser_options.h" #include "third_party/blink/renderer/core/dom/document.h" +#include "third_party/blink/renderer/core/frame/settings.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" namespace blink { HTMLParserOptions::HTMLParserOptions(Document* document) { - if (!document) + if (!document || !document->GetFrame()) return; - if (document->GetFrame()) { - script_enabled = document->CanExecuteScripts(kNotAboutToExecuteScript); - priority_hints_origin_trial_enabled = - RuntimeEnabledFeatures::PriorityHintsEnabled(document); - } + scripting_flag = (document->GetSettings()->GetParserScriptingFlagPolicy() == + ParserScriptingFlagPolicy::kEnabled) || + document->CanExecuteScripts(kNotAboutToExecuteScript); + priority_hints_origin_trial_enabled = + RuntimeEnabledFeatures::PriorityHintsEnabled(document); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_parser_options.h b/chromium/third_party/blink/renderer/core/html/parser/html_parser_options.h index 50011d16d10..267d50f5383 100644 --- a/chromium/third_party/blink/renderer/core/html/parser/html_parser_options.h +++ b/chromium/third_party/blink/renderer/core/html/parser/html_parser_options.h @@ -37,7 +37,8 @@ class CORE_EXPORT HTMLParserOptions { DISALLOW_NEW(); public: - bool script_enabled = false; + // https://html.spec.whatwg.org/#scripting-flag + bool scripting_flag = false; // TODO(domfarolino): Remove this when Priority Hints is no longer in an // Origin Trial. See https://crbug.com/821464. diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_parser_scheduler.cc b/chromium/third_party/blink/renderer/core/html/parser/html_parser_scheduler.cc index 601f0eb325c..1559a1624ba 100644 --- a/chromium/third_party/blink/renderer/core/html/parser/html_parser_scheduler.cc +++ b/chromium/third_party/blink/renderer/core/html/parser/html_parser_scheduler.cc @@ -40,10 +40,6 @@ SpeculationsPumpSession::SpeculationsPumpSession(unsigned& nesting_level) SpeculationsPumpSession::~SpeculationsPumpSession() = default; -inline base::TimeDelta SpeculationsPumpSession::ElapsedTime() const { - return start_time_.Elapsed(); -} - void SpeculationsPumpSession::AddedElementTokens(size_t count) { processed_element_tokens_ += count; } @@ -51,9 +47,7 @@ void SpeculationsPumpSession::AddedElementTokens(size_t count) { HTMLParserScheduler::HTMLParserScheduler( HTMLDocumentParser* parser, scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner) - : parser_(parser), - loading_task_runner_(std::move(loading_task_runner)), - is_paused_with_active_timer_(false) {} + : parser_(parser), loading_task_runner_(std::move(loading_task_runner)) {} HTMLParserScheduler::~HTMLParserScheduler() = default; @@ -62,37 +56,18 @@ void HTMLParserScheduler::Trace(Visitor* visitor) { } bool HTMLParserScheduler::IsScheduledForUnpause() const { - return is_paused_with_active_timer_ || - cancellable_continue_parse_task_handle_.IsActive(); + return cancellable_continue_parse_task_handle_.IsActive(); } void HTMLParserScheduler::ScheduleForUnpause() { - DCHECK(!is_paused_with_active_timer_); cancellable_continue_parse_task_handle_ = PostCancellableTask(*loading_task_runner_, FROM_HERE, WTF::Bind(&HTMLParserScheduler::ContinueParsing, WrapWeakPersistent(this))); } -void HTMLParserScheduler::Pause() { - DCHECK(!is_paused_with_active_timer_); - if (!cancellable_continue_parse_task_handle_.IsActive()) - return; - is_paused_with_active_timer_ = true; - cancellable_continue_parse_task_handle_.Cancel(); -} - -void HTMLParserScheduler::Unpause() { - DCHECK(!cancellable_continue_parse_task_handle_.IsActive()); - if (!is_paused_with_active_timer_) - return; - is_paused_with_active_timer_ = false; - ScheduleForUnpause(); -} - void HTMLParserScheduler::Detach() { cancellable_continue_parse_task_handle_.Cancel(); - is_paused_with_active_timer_ = false; } inline bool HTMLParserScheduler::ShouldYield( @@ -131,11 +106,6 @@ bool HTMLParserScheduler::YieldIfNeeded(const SpeculationsPumpSession& session, return false; } -void HTMLParserScheduler::ForceUnpauseAfterYield() { - DCHECK(!cancellable_continue_parse_task_handle_.IsActive()); - is_paused_with_active_timer_ = true; -} - void HTMLParserScheduler::ContinueParsing() { parser_->ResumeParsingAfterYield(); } diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_parser_scheduler.h b/chromium/third_party/blink/renderer/core/html/parser/html_parser_scheduler.h index 9c63198537a..87d35d4a9f8 100644 --- a/chromium/third_party/blink/renderer/core/html/parser/html_parser_scheduler.h +++ b/chromium/third_party/blink/renderer/core/html/parser/html_parser_scheduler.h @@ -42,10 +42,10 @@ class SpeculationsPumpSession : public NestingLevelIncrementer { STACK_ALLOCATED(); public: - SpeculationsPumpSession(unsigned& nesting_level); + explicit SpeculationsPumpSession(unsigned& nesting_level); ~SpeculationsPumpSession(); - base::TimeDelta ElapsedTime() const; + base::TimeDelta ElapsedTime() const { return start_time_.Elapsed(); } void AddedElementTokens(size_t count); size_t ProcessedElementTokens() const { return processed_element_tokens_; } @@ -64,18 +64,6 @@ class HTMLParserScheduler final : public GarbageCollected<HTMLParserScheduler> { void ScheduleForUnpause(); bool YieldIfNeeded(const SpeculationsPumpSession&, bool starting_script); - /** - * Can only be called if this scheduler is paused. If this is called, - * then after the scheduler is resumed by calling resume(), this call - * ensures that HTMLDocumentParser::resumeAfterYield will be called. Used to - * signal this scheduler that the background html parser sent chunks to - * HTMLDocumentParser while it was paused. - */ - void ForceUnpauseAfterYield(); - - void Pause(); - void Unpause(); - void Detach(); // Clear active tasks if any. void Trace(Visitor*); @@ -88,7 +76,6 @@ class HTMLParserScheduler final : public GarbageCollected<HTMLParserScheduler> { scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner_; TaskHandle cancellable_continue_parse_task_handle_; - bool is_paused_with_active_timer_; DISALLOW_COPY_AND_ASSIGN(HTMLParserScheduler); }; diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc b/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc index 0d4a5339a14..c2410ab5a27 100644 --- a/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc +++ b/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc @@ -58,7 +58,6 @@ #include "third_party/blink/renderer/core/loader/subresource_integrity_helper.h" #include "third_party/blink/renderer/core/origin_trials/origin_trials.h" #include "third_party/blink/renderer/core/script/script_loader.h" -#include "third_party/blink/renderer/platform/instrumentation/histogram.h" #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h" #include "third_party/blink/renderer/platform/loader/fetch/integrity_metadata.h" #include "third_party/blink/renderer/platform/loader/fetch/resource.h" @@ -114,8 +113,10 @@ static String InitiatorFor(const StringImpl* tag_impl) { static bool MediaAttributeMatches(const MediaValuesCached& media_values, const String& attribute_value) { + // Since this is for preload scanning only, ExecutionContext-based origin + // trials for media queries are not needed. scoped_refptr<MediaQuerySet> media_queries = - MediaQuerySet::Create(attribute_value); + MediaQuerySet::Create(attribute_value, nullptr); MediaQueryEvaluator media_query_evaluator(media_values); return media_query_evaluator.Eval(*media_queries); } @@ -162,7 +163,8 @@ class TokenPreloadScanner::StartTagScanner { if (Match(tag_impl_, html_names::kImgTag) || Match(tag_impl_, html_names::kSourceTag) || Match(tag_impl_, html_names::kLinkTag)) { - source_size_ = SizesAttributeParser(media_values_, String()).length(); + source_size_ = + SizesAttributeParser(media_values_, String(), nullptr).length(); return; } if (!Match(tag_impl_, html_names::kInputTag) && @@ -470,9 +472,10 @@ class TokenPreloadScanner::StartTagScanner { img_src_url_ = attribute_value; } else if (Match(attribute_name, html_names::kRelAttr)) { LinkRelAttribute rel(attribute_value); - link_is_style_sheet_ = rel.IsStyleSheet() && !rel.IsAlternate() && - rel.GetIconType() == kInvalidIcon && - !rel.IsDNSPrefetch(); + link_is_style_sheet_ = + rel.IsStyleSheet() && !rel.IsAlternate() && + rel.GetIconType() == mojom::blink::FaviconIconType::kInvalid && + !rel.IsDNSPrefetch(); link_is_preconnect_ = rel.IsPreconnect(); link_is_preload_ = rel.IsLinkPreload(); link_is_modulepreload_ = rel.IsModulePreload(); @@ -517,8 +520,8 @@ class TokenPreloadScanner::StartTagScanner { if (Match(attribute_name, html_names::kSrcAttr)) { SetUrlToLoad(attribute_value, kDisallowURLReplacement); } else if (Match(attribute_name, html_names::kTypeAttr)) { - input_is_image_ = DeprecatedEqualIgnoringCase(attribute_value, - input_type_names::kImage); + input_is_image_ = + EqualIgnoringASCIICase(attribute_value, input_type_names::kImage); } } @@ -693,7 +696,7 @@ class TokenPreloadScanner::StartTagScanner { void ParseSourceSize(const String& attribute_value) { source_size_ = - SizesAttributeParser(media_values_, attribute_value).length(); + SizesAttributeParser(media_values_, attribute_value, nullptr).length(); source_size_set_ = true; } @@ -745,7 +748,7 @@ class TokenPreloadScanner::StartTagScanner { mojom::FetchImportanceMode importance_; bool importance_mode_set_; String nonce_; - Member<MediaValuesCached> media_values_; + MediaValuesCached* media_values_; bool referrer_policy_set_; network::mojom::ReferrerPolicy referrer_policy_; bool integrity_attr_set_; @@ -878,13 +881,13 @@ static void HandleMetaNameAttribute( return; String content_attribute_value(content_attribute->Value()); - if (DeprecatedEqualIgnoringCase(name_attribute_value, "viewport")) { + if (EqualIgnoringASCIICase(name_attribute_value, "viewport")) { HandleMetaViewport(content_attribute_value, document_parameters, media_values, viewport); return; } - if (DeprecatedEqualIgnoringCase(name_attribute_value, "referrer")) { + if (EqualIgnoringASCIICase(name_attribute_value, "referrer")) { HandleMetaReferrer(content_attribute_value, document_parameters, css_scanner); } @@ -960,11 +963,11 @@ void TokenPreloadScanner::ScanCommon( token.GetAttributeItem(html_names::kHttpEquivAttr); if (equiv_attribute) { String equiv_attribute_value(equiv_attribute->Value()); - if (DeprecatedEqualIgnoringCase(equiv_attribute_value, - "content-security-policy")) { + if (EqualIgnoringASCIICase(equiv_attribute_value, + "content-security-policy")) { *is_csp_meta_tag = true; - } else if (DeprecatedEqualIgnoringCase(equiv_attribute_value, - "accept-ch")) { + } else if (EqualIgnoringASCIICase(equiv_attribute_value, + "accept-ch")) { const typename Token::Attribute* content_attribute = token.GetAttributeItem(html_names::kContentAttr); if (content_attribute) { @@ -1097,7 +1100,8 @@ CachedDocumentParameters::CachedDocumentParameters(Document* document) { viewport_meta_enabled = document->GetSettings() && document->GetSettings()->GetViewportMetaEnabled(); referrer_policy = document->GetReferrerPolicy(); - integrity_features = SubresourceIntegrityHelper::GetFeatures(document); + integrity_features = + SubresourceIntegrityHelper::GetFeatures(document->GetExecutionContext()); lazyload_policy_enforced = document->IsLazyLoadPolicyEnforced(); if (document->Loader() && document->Loader()->GetFrame()) { lazy_load_image_setting = diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner_fuzzer.cc b/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner_fuzzer.cc index 7247ddc7857..1929b81aacd 100644 --- a/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner_fuzzer.cc +++ b/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner_fuzzer.cc @@ -40,7 +40,7 @@ int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { FuzzedDataProvider fuzzed_data(data, size); HTMLParserOptions options; - options.script_enabled = fuzzed_data.ConsumeBool(); + options.scripting_flag = fuzzed_data.ConsumeBool(); std::unique_ptr<CachedDocumentParameters> document_parameters = CachedDocumentParametersForFuzzing(fuzzed_data); diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner_test.cc b/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner_test.cc index b4699156f62..9ac9b6412bf 100644 --- a/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner_test.cc +++ b/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner_test.cc @@ -146,7 +146,8 @@ class HTMLMockHTMLResourcePreloader : public ResourcePreloader { PreloadRequestVerification(type, url, base_url, width, referrer_policy); Resource* resource = preload_request_->Start(document); ASSERT_TRUE(resource); - EXPECT_EQ(expected_referrer, resource->GetResourceRequest().HttpReferrer()); + EXPECT_EQ(expected_referrer, + resource->GetResourceRequest().ReferrerString()); } void PreconnectRequestVerification(const String& host, @@ -633,11 +634,11 @@ TEST_F(HTMLPreloadScannerTest, testMetaAcceptCH) { "640w'>", "blabla.gif", "http://example.test/", ResourceType::kImage, 0}, {"http://example.test", - "<meta http-equiv='accept-ch' content='dpr \t'><img srcset='bla.gif " + "<meta http-equiv='accept-ch' content='dpr '><img srcset='bla.gif " "320w, blabla.gif 640w'>", "blabla.gif", "http://example.test/", ResourceType::kImage, 0, dpr}, {"http://example.test", - "<meta http-equiv='accept-ch' content='bla,dpr \t'><img srcset='bla.gif " + "<meta http-equiv='accept-ch' content='bla,dpr '><img srcset='bla.gif " "320w, blabla.gif 640w'>", "blabla.gif", "http://example.test/", ResourceType::kImage, 0, dpr}, {"http://example.test", @@ -662,7 +663,7 @@ TEST_F(HTMLPreloadScannerTest, testMetaAcceptCH) { viewport_width}, {"http://example.test", "<meta http-equiv='accept-ch' content=' viewport-width ,width, " - "wutever, dpr \t'><img sizes='90vw' srcset='bla.gif 320w, blabla.gif " + "wutever, dpr '><img sizes='90vw' srcset='bla.gif 320w, blabla.gif " "640w'>", "blabla.gif", "http://example.test/", ResourceType::kImage, 450, all}, }; @@ -684,7 +685,7 @@ TEST_F(HTMLPreloadScannerTest, testMetaAcceptCHInsecureDocument) { const PreloadScannerTestCase expect_no_client_hint = { "http://example.test", "<meta http-equiv='accept-ch' content=' viewport-width ,width, " - "wutever, dpr \t'><img sizes='90vw' srcset='bla.gif 320w, blabla.gif " + "wutever, dpr '><img sizes='90vw' srcset='bla.gif 320w, blabla.gif " "640w'>", "blabla.gif", "http://example.test/", @@ -694,7 +695,7 @@ TEST_F(HTMLPreloadScannerTest, testMetaAcceptCHInsecureDocument) { const PreloadScannerTestCase expect_client_hint = { "http://example.test", "<meta http-equiv='accept-ch' content=' viewport-width ,width, " - "wutever, dpr \t'><img sizes='90vw' srcset='bla.gif 320w, blabla.gif " + "wutever, dpr '><img sizes='90vw' srcset='bla.gif 320w, blabla.gif " "640w'>", "blabla.gif", "http://example.test/", @@ -871,9 +872,7 @@ TEST_F(HTMLPreloadScannerTest, testReferrerPolicy) { "referrerpolicy='strict-origin-when-cross-origin' " "href='bla.gif'/>", "bla.gif", "http://example.test/", ResourceType::kImage, 0, - network::mojom::ReferrerPolicy:: - kNoReferrerWhenDowngradeOriginWhenCrossOrigin, - nullptr}, + network::mojom::ReferrerPolicy::kStrictOriginWhenCrossOrigin, nullptr}, {"http://example.test", "<link rel='stylesheet' href='sheet.css' type='text/css'>", "sheet.css", "http://example.test/", ResourceType::kCSSStyleSheet, 0, diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_srcset_parser.cc b/chromium/third_party/blink/renderer/core/html/parser/html_srcset_parser.cc index 4a040fb80b0..7d3025bbee5 100644 --- a/chromium/third_party/blink/renderer/core/html/parser/html_srcset_parser.cc +++ b/chromium/third_party/blink/renderer/core/html/parser/html_srcset_parser.cc @@ -32,12 +32,16 @@ #include "third_party/blink/renderer/core/html/parser/html_srcset_parser.h" #include <algorithm> + +#include "third_party/blink/public/common/features.h" +#include "third_party/blink/public/platform/web_network_state_notifier.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/frame/frame_console.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/web_feature.h" #include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h" #include "third_party/blink/renderer/core/inspector/console_message.h" +#include "third_party/blink/renderer/platform/heap/heap.h" #include "third_party/blink/renderer/platform/instrumentation/use_counter.h" #include "third_party/blink/renderer/platform/json/json_values.h" #include "third_party/blink/renderer/platform/loader/fetch/memory_cache.h" @@ -197,9 +201,10 @@ static void SrcsetError(Document* document, String message) { StringBuilder error_message; error_message.Append("Failed parsing 'srcset' attribute value since "); error_message.Append(message); - document->GetFrame()->Console().AddMessage(ConsoleMessage::Create( - mojom::ConsoleMessageSource::kOther, mojom::ConsoleMessageLevel::kError, - error_message.ToString())); + document->GetFrame()->Console().AddMessage( + MakeGarbageCollected<ConsoleMessage>( + mojom::ConsoleMessageSource::kOther, + mojom::ConsoleMessageLevel::kError, error_message.ToString())); } } @@ -328,14 +333,15 @@ static void ParseImageCandidatesFromSrcsetAttribute( if (document) { UseCounter::Count(document, WebFeature::kSrcsetDroppedCandidate); if (document->GetFrame()) { - document->GetFrame()->Console().AddMessage(ConsoleMessage::Create( - mojom::ConsoleMessageSource::kOther, - mojom::ConsoleMessageLevel::kError, - String("Dropped srcset candidate ") + - JSONValue::QuoteString( - String(image_url_start, - static_cast<wtf_size_t>(image_url_end - - image_url_start))))); + document->GetFrame()->Console().AddMessage( + MakeGarbageCollected<ConsoleMessage>( + mojom::ConsoleMessageSource::kOther, + mojom::ConsoleMessageLevel::kError, + String("Dropped srcset candidate ") + + JSONValue::QuoteString( + String(image_url_start, + static_cast<wtf_size_t>(image_url_end - + image_url_start))))); } } continue; @@ -444,8 +450,12 @@ static ImageCandidate PickBestImageCandidate( de_duped_image_candidates.push_back(&image); prev_density = image.Density(); } + unsigned winner = - SelectionLogic(de_duped_image_candidates, device_scale_factor); + blink::WebNetworkStateNotifier::SaveDataEnabled() && + base::FeatureList::IsEnabled(blink::features::kSaveDataImgSrcset) + ? 0 + : SelectionLogic(de_duped_image_candidates, device_scale_factor); DCHECK_LT(winner, de_duped_image_candidates.size()); winner = AvoidDownloadIfHigherDensityResourceIsInCache( de_duped_image_candidates, winner, document); diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_srcset_parser.h b/chromium/third_party/blink/renderer/core/html/parser/html_srcset_parser.h index 1270664c288..9af275482ca 100644 --- a/chromium/third_party/blink/renderer/core/html/parser/html_srcset_parser.h +++ b/chromium/third_party/blink/renderer/core/html/parser/html_srcset_parser.h @@ -41,7 +41,7 @@ namespace blink { class Document; -enum { kUninitializedDescriptor = -1 }; +constexpr int kUninitializedDescriptor = -1; class DescriptorParsingResult { STACK_ALLOCATED(); diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_srcset_parser_test.cc b/chromium/third_party/blink/renderer/core/html/parser/html_srcset_parser_test.cc index cc3aed6a9fe..9b8791ad9db 100644 --- a/chromium/third_party/blink/renderer/core/html/parser/html_srcset_parser_test.cc +++ b/chromium/third_party/blink/renderer/core/html/parser/html_srcset_parser_test.cc @@ -4,9 +4,13 @@ #include "third_party/blink/renderer/core/html/parser/html_srcset_parser.h" -#include "testing/gtest/include/gtest/gtest.h" #include <limits.h> +#include "base/test/scoped_feature_list.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/common/features.h" +#include "third_party/blink/public/platform/web_network_state_notifier.h" + namespace blink { typedef struct { @@ -173,4 +177,150 @@ TEST(HTMLSrcsetParserTest, Basic) { } } +TEST(HTMLSrcsetParserTest, SaveDataEnabledBasic) { + SrcsetParserTestCase test_cases[] = { + // 0 + {2.0, 0.5, "", "data:,a 1w, data:,b 2x", "data:,a", 2.0, 1}, + {2.0, 1, "", "data:,a 2w, data:,b 2x", "data:,a", 2.0, 2}, + {2.0, -1, "", "1x.gif 1x, 2x.gif 2x", "1x.gif", 1.0, -1}, + {2.0, -1, "", "1x.gif 1q, 2x.gif 2x", "2x.gif", 2.0, -1}, + {1.0, -1, "", "1x.gif 1q, 2x.gif 2x", "2x.gif", 2.0, -1}, + {1.0, -1, "", "1x.gif 1x 100h, 2x.gif 2x", "2x.gif", 2.0, -1}, // 5 + {1.0, -1, "", "1x.gif 1x 100w, 2x.gif 2x", "2x.gif", 2.0, -1}, + {1.0, -1, "", "1x.gif 1x 100h 100w, 2x.gif 2x", "2x.gif", 2.0, -1}, + {2.0, -1, "", "1x.gif 1x, 2x.gif -2x", "1x.gif", 1.0, -1}, + {2.0, -1, "", "0x.gif 0x", "0x.gif", 0.0, -1}, + {2.0, -1, "", "0x.gif -0x", "0x.gif", 0.0, -1}, // 10 + {2.0, -1, "", "neg.gif -2x", "", 1.0, -1}, + {2.0, -1, "", "1x.gif 1x, 2x.gif 2q", "1x.gif", 1.0, -1}, + {2.0, -1, "", "1x.gif, 2x.gif 2q", "1x.gif", 1.0, -1}, + {2.0, -1, "", "1x.gif , 2x.gif 2q", "1x.gif", 1.0, -1}, + {2.0, -1, "1x.gif 1x, 2x.gif 2x", "1x.gif 1x, 2x.gif 2x", "1x.gif", 1.0, + -1}, // 15 + {1.0, -1, "1x.gif 1x, 2x.gif 2x", "1x.gif 1x, 2x.gif 2x", "1x.gif", 1.0, + -1}, + {1.0, -1, "1x.gif 1x, 2x.gif 2x", "", "1x.gif 1x, 2x.gif 2x", 1.0, -1}, + {2.0, -1, "src.gif", "1x.gif 1x, 2x.gif 2x", "1x.gif", 1.0, -1}, + {1.0, -1, "src.gif", "1x.gif 1x, 2x.gif 2x", "1x.gif", 1.0, -1}, + {1.0, -1, "src.gif", "2x.gif 2x", "src.gif", 1.0, -1}, // 20 + {2.0, -1, "src.gif", "2x.gif 2x", "src.gif", 1.0, -1}, + {2.0, -1, "src.gif", "2x.gif 2px", "src.gif", 1.0, -1}, + {2.0, -1, "src.gif", "2x.gif 2ex", "src.gif", 1.0, -1}, + {10.0, -1, "src.gif", "2x.gif 2e1x", "src.gif", 1.0, -1}, + {2.0, -1, "src.gif", "2x.gif 2e1x", "src.gif", 1.0, -1}, // 25 + {2.0, -1, "src.gif", "2x.gif +2x", "src.gif", 1.0, -1}, + {1.5, -1, "src.gif", "2x.gif 2x", "src.gif", 1.0, -1}, + {2.5, -1, "src.gif", "2x.gif 2x", "src.gif", 1.0, -1}, + {2.5, -1, "src.gif", "2x.gif 2x, 3x.gif 3x", "src.gif", 1.0, -1}, + {2.0, -1, "", "1x,, , x ,2x ", "1x", 1.0, -1}, // 30 + {2.0, -1, "", "1x,, , x ,2x ", "1x", 1.0, -1}, + {2.0, -1, "", ",,1x,, , x ,2x ", "1x", 1.0, -1}, + {2.0, -1, "", ",,1x,,", "1x", 1.0, -1}, + {2.0, -1, "", ",1x,", "1x", 1.0, -1}, + {2.0, -1, "", + "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg 1x, 2x.gif 2x", + "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg", 1.0, -1}, // 35 + {2.0, -1, "", + "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg 2x, 1x.gif 1x", "1x.gif", + 1.0, -1}, + {2.0, -1, "", + "1x,, , x ,2x , 1x.gif, 3x, 4x.gif 4x 100z, 5x.gif 5, dx.gif dx, " + "2x.gif 2x ,", + "1x", 1.0, -1}, + {4.0, -1, "", + "1x,, , x ,2x , 1x.gif, 3x, 4x.gif 4x 100h, 5x.gif 5, dx.gif dx, " + "2x.gif 2x ,", + "1x", 1.0, -1}, + {4.0, -1, "", + "1x,, , x ,2x , 1x.gif, 3x, 4x.gif 4x 100z, 5x.gif 5, dx.gif dx, " + "2x.gif 2x ,", + "1x", 1.0, -1}, + {1.0, -1, "", + "1x,, , x ,2x , 1x.gif, 3x, 4x.gif 4x 100z, 5x.gif 5, dx.gif dx, " + "2x.gif 2x ,", + "1x", 1.0, -1}, // 40 + {5.0, -1, "", + "1x,, , x ,2x , 1x.gif, 3x, 4x.gif 4x 100z, 5x.gif 5, dx.gif dx, " + "2x.gif 2x ,", + "1x", 1.0, -1}, + {2.0, -1, "", + "1x.gif 1x, " + "data:image/" + "svg+xml;base64," + "PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGh" + "laWdodD0iMTAwIj4KCTxyZWN0IHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIiBmaWxsPSJncm" + "VlbiIvPgo8L3N2Zz4K 2x", + "1x.gif", 1.0, -1}, + {2.0, -1, "1x.gif", + "data:image/" + "svg+xml;base64," + "PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGh" + "laWdodD0iMTAwIj4KCTxyZWN0IHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIiBmaWxsPSJncm" + "VlbiIvPgo8L3N2Zz4K 2x", + "1x.gif", 1.0, -1}, + {2.0, -1, "1x.svg#red", "1x.svg#green 2x", "1x.svg#red", 1.0, -1}, + {2.0, -1, "", "1x.svg#red 1x, 1x.svg#green 2x", "1x.svg#red", 1.0, + -1}, // 45 + {1.0, 400, "", "400.gif 400w, 6000.gif 6000w", "400.gif", 1.0, 400}, + {1.0, 400, "", "400.gif 400pw, 6000.gif 6000w", "6000.gif", 15.0, 6000}, + {1.0, 400, "fallback.gif", "400.gif 400pw", "fallback.gif", 1.0, -1}, + {1.0, 400, "fallback.gif", "400.gif +400w", "fallback.gif", 1.0, -1}, + {1.0, 400, "", "400.gif 400w 400h, 6000.gif 6000w", "400.gif", 1.0, + 400}, // 50 + {4.0, 400, "", "400.gif 400w, 6000.gif 6000w", "400.gif", 1.0, 400}, + {3.8, 400, "", "400.gif 400w, 6000.gif 6000w", "400.gif", 1.0, 400}, + {0.9, 800, "src.gif", "400.gif 400w", "400.gif", 0.5, 400}, + {0.9, 800, "src.gif", "1x.gif 1x, 400.gif 400w", "400.gif", 0.5, 400}, + {0.9, 800, "src.gif", "1x.gif 0.6x, 400.gif 400w", "400.gif", 0.5, + 400}, // 55 + {0.9, 800, "src.gif", "1x.gif 1x, 400.gif 720w", "400.gif", 0.9, 720}, + {0.9, 800, "src.gif", "1x.gif 1x, 400.gif 719w", "400.gif", 719.0 / 800.0, + 719}, + {2.0, 800, "src.gif", "400.gif 400w", "400.gif", 0.5, 400}, + {1.0, 400, "src.gif", "800.gif 800w", "800.gif", 2.0, 800}, + {1.0, 400, "src.gif", "0.gif 0w, 800.gif 800w", "800.gif", 2.0, + 800}, // 60 + {1.0, 400, "src.gif", "0.gif 0w, 2x.gif 2x", "src.gif", 1.0, -1}, + {1.0, 400, "src.gif", "800.gif 2x, 1600.gif 1600w", "800.gif", 2.0, -1}, + {1.0, 400, "", "400.gif 400w, 2x.gif 2x", "400.gif", 1.0, 400}, + {2.0, 400, "", "400.gif 400w, 2x.gif 2x", "400.gif", 1.0, 400}, + {1.0, 0, "", "400.gif 400w, 6000.gif 6000w", "400.gif", + std::numeric_limits<float>::infinity(), 400}, // 65 + {2.0, -1, "", ", 1x.gif 1x, 2x.gif 2x", "1x.gif", 1.0, -1}, + {1.0, -1, "", ",1x.gif 1x, 2x.gif 2x", "1x.gif", 1.0, -1}, + {1.0, -1, "", ",1x.gif 1.x , 2x.gif 2x", "2x.gif", 2.0, -1}, + {1.2, -1, "", ",1x.gif 1x, 1.4x.gif 1.4x, 2x.gif 2x", "1x.gif", 1.0, -1}, + {1.0, -1, "", "inf.gif 0.00000000001x", "inf.gif", 1e-11, -1}, // 70 + {1.0, -1, "", "data:,a ( , data:,b 1x, ), data:,c", "data:,c", 1.0, -1}, + {1.0, 1, "", "data:,a 1w 1h", "data:,a", 1.0, 1}, + {1.0, -1, "", ",1x.gif 1x future-descriptor(3x, 4h, whatever), 2x.gif 2x", + "2x.gif", 2.0, -1}, + {2.0, -1, "", ",1x.gif 1x future-descriptor(3x, 4h, whatever), 2x.gif 2x", + "2x.gif", 2.0, -1}, + {1.0, -1, "", "data:,a 1 w", "", 1.0, -1}, // 75 + {1.0, -1, "", "data:,a 1 w", "", 1.0, -1}, + {1.0, -1, "", "data:,a +1x", "", 1.0, -1}, + {1.0, -1, "", "data:,a +1x", "", 1.0, -1}, + {1.0, -1, "", "data:,a 1.0x", "data:,a", 1.0, -1}, + {1.0, -1, "", "1%20and%202.gif 1x", "1%20and%202.gif", 1.0, -1}, // 80 + {1.0, 700, "", "data:,a 0.5x, data:,b 1400w", "data:,a", 0.5, -1}, + {0, 0, nullptr, nullptr, nullptr, + 0} // Do not remove the terminator line. + }; + + blink::WebNetworkStateNotifier::SetSaveDataEnabled(true); + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitWithFeatures({blink::features::kSaveDataImgSrcset}, + {}); + for (unsigned i = 0; test_cases[i].src_input; ++i) { + SrcsetParserTestCase test = test_cases[i]; + ImageCandidate candidate = BestFitSourceForImageAttributes( + test.device_scale_factor, test.effective_size, test.src_input, + test.srcset_input); + ASSERT_EQ(test.output_density, candidate.Density()); + ASSERT_EQ(test.output_resource_width, candidate.GetResourceWidth()); + ASSERT_EQ(test.output_url, candidate.ToString().Ascii()); + } +} + } // namespace blink diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_tokenizer.cc b/chromium/third_party/blink/renderer/core/html/parser/html_tokenizer.cc index 5340cb22bab..241efc1df37 100644 --- a/chromium/third_party/blink/renderer/core/html/parser/html_tokenizer.cc +++ b/chromium/third_party/blink/renderer/core/html/parser/html_tokenizer.cc @@ -1465,7 +1465,7 @@ void HTMLTokenizer::UpdateStateFor(const String& tag_name) { ThreadSafeMatch(tag_name, html_names::kNoembedTag) || ThreadSafeMatch(tag_name, html_names::kNoframesTag) || (ThreadSafeMatch(tag_name, html_names::kNoscriptTag) && - options_.script_enabled)) + options_.scripting_flag)) SetState(HTMLTokenizer::kRAWTEXTState); } diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_tokenizer_fuzzer.cc b/chromium/third_party/blink/renderer/core/html/parser/html_tokenizer_fuzzer.cc index e0fb488daa7..a21c158d304 100644 --- a/chromium/third_party/blink/renderer/core/html/parser/html_tokenizer_fuzzer.cc +++ b/chromium/third_party/blink/renderer/core/html/parser/html_tokenizer_fuzzer.cc @@ -20,7 +20,7 @@ int FuzzTokenizer(const uint8_t* data, size_t size) { // Use the first byte of fuzz data to randomize the tokenizer options. HTMLParserOptions options; - options.script_enabled = fuzzed_data_provider.ConsumeBool(); + options.scripting_flag = fuzzed_data_provider.ConsumeBool(); std::unique_ptr<HTMLTokenizer> tokenizer = std::make_unique<HTMLTokenizer>(options); diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_tree_builder.cc b/chromium/third_party/blink/renderer/core/html/parser/html_tree_builder.cc index a33e0b6aca0..24f19c4dc6e 100644 --- a/chromium/third_party/blink/renderer/core/html/parser/html_tree_builder.cc +++ b/chromium/third_party/blink/renderer/core/html/parser/html_tree_builder.cc @@ -32,6 +32,7 @@ #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/dom/document_fragment.h" #include "third_party/blink/renderer/core/dom/element_traversal.h" +#include "third_party/blink/renderer/core/dom/shadow_root.h" #include "third_party/blink/renderer/core/frame/web_feature.h" #include "third_party/blink/renderer/core/html/forms/html_form_control_element.h" #include "third_party/blink/renderer/core/html/forms/html_form_element.h" @@ -43,6 +44,7 @@ #include "third_party/blink/renderer/core/html/parser/html_token.h" #include "third_party/blink/renderer/core/html/parser/html_tokenizer.h" #include "third_party/blink/renderer/core/html_names.h" +#include "third_party/blink/renderer/core/inspector/console_message.h" #include "third_party/blink/renderer/core/mathml_names.h" #include "third_party/blink/renderer/core/svg_names.h" #include "third_party/blink/renderer/core/xlink_names.h" @@ -765,7 +767,7 @@ void HTMLTreeBuilder::ProcessStartTagForInBody(AtomicHTMLToken* token) { Attribute* type_attribute = token->GetAttributeItem(html_names::kTypeAttr); bool disable_frameset = !type_attribute || - !DeprecatedEqualIgnoringCase(type_attribute->Value(), "hidden"); + !EqualIgnoringASCIICase(type_attribute->Value(), "hidden"); tree_.ReconstructTheActiveFormattingElements(); tree_.InsertSelfClosingHTMLElementDestroyingToken(token); @@ -812,7 +814,7 @@ void HTMLTreeBuilder::ProcessStartTagForInBody(AtomicHTMLToken* token) { ProcessGenericRawTextStartTag(token); return; } - if (token->GetName() == html_names::kNoscriptTag && options_.script_enabled) { + if (token->GetName() == html_names::kNoscriptTag && options_.scripting_flag) { ProcessGenericRawTextStartTag(token); return; } @@ -909,10 +911,50 @@ bool HTMLTreeBuilder::ProcessTemplateEndTag(AtomicHTMLToken* token) { tree_.GenerateImpliedEndTags(); if (!tree_.CurrentStackItem()->HasTagName(html_names::kTemplateTag)) ParseError(token); - tree_.OpenElements()->PopUntilPopped(html_names::kTemplateTag); + tree_.OpenElements()->PopUntil(html_names::kTemplateTag.LocalName()); + HTMLStackItem* template_stack_item = + tree_.OpenElements()->TopRecord()->StackItem(); + tree_.OpenElements()->Pop(); + HTMLStackItem* shadow_host_stack_item = + tree_.OpenElements()->TopRecord()->StackItem(); tree_.ActiveFormattingElements()->ClearToLastMarker(); template_insertion_modes_.pop_back(); ResetInsertionModeAppropriately(); + // Check for a declarative shadow root. + if (RuntimeEnabledFeatures::DeclarativeShadowDOMEnabled() && + template_stack_item) { + if (Attribute* type_attribute = template_stack_item->GetAttributeItem( + html_names::kShadowrootAttr)) { + String shadow_mode = type_attribute->Value(); + bool is_open = EqualIgnoringASCIICase(shadow_mode, "open"); + if (is_open || EqualIgnoringASCIICase(shadow_mode, "closed")) { + DCHECK(template_stack_item->IsElementNode()); + DCHECK(shadow_host_stack_item); + DCHECK(shadow_host_stack_item->IsElementNode()); + UseCounter::Count(shadow_host_stack_item->GetElement()->GetDocument(), + WebFeature::kDeclarativeShadowRoot); + bool delegates_focus = template_stack_item->GetAttributeItem( + html_names::kShadowrootdelegatesfocusAttr); + // TODO(1063157): Add an attribute for imperative slot assignment. + bool manual_slotting = false; + shadow_host_stack_item->GetElement()->AttachDeclarativeShadowRoot( + DynamicTo<HTMLTemplateElement>(template_stack_item->GetElement()), + is_open ? ShadowRootType::kOpen : ShadowRootType::kClosed, + delegates_focus ? FocusDelegation::kDelegateFocus + : FocusDelegation::kNone, + manual_slotting ? SlotAssignmentMode::kManual + : SlotAssignmentMode::kAuto); + } else { + tree_.OwnerDocumentForCurrentNode().AddConsoleMessage( + MakeGarbageCollected<ConsoleMessage>( + mojom::blink::ConsoleMessageSource::kOther, + mojom::blink::ConsoleMessageLevel::kWarning, + "Invalid declarative shadowroot attribute value \"" + + shadow_mode + + "\". Valid values include \"open\" and \"closed\".")); + } + } + } return true; } @@ -1012,7 +1054,7 @@ void HTMLTreeBuilder::ProcessStartTagForInTable(AtomicHTMLToken* token) { if (token->GetName() == html_names::kInputTag) { Attribute* type_attribute = token->GetAttributeItem(html_names::kTypeAttr); if (type_attribute && - DeprecatedEqualIgnoringCase(type_attribute->Value(), "hidden")) { + EqualIgnoringASCIICase(type_attribute->Value(), "hidden")) { ParseError(token); tree_.InsertSelfClosingHTMLElementDestroyingToken(token); return; @@ -2628,7 +2670,7 @@ bool HTMLTreeBuilder::ProcessStartTagForInHead(AtomicHTMLToken* token) { return true; } if (token->GetName() == html_names::kNoscriptTag) { - if (options_.script_enabled) { + if (options_.scripting_flag) { ProcessGenericRawTextStartTag(token); return true; } diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_tree_builder_simulator.cc b/chromium/third_party/blink/renderer/core/html/parser/html_tree_builder_simulator.cc index 3da53b045b1..ea11a426b6c 100644 --- a/chromium/third_party/blink/renderer/core/html/parser/html_tree_builder_simulator.cc +++ b/chromium/third_party/blink/renderer/core/html/parser/html_tree_builder_simulator.cc @@ -191,7 +191,7 @@ HTMLTreeBuilderSimulator::SimulatedToken HTMLTreeBuilderSimulator::Simulate( ThreadSafeMatch(tag_name, html_names::kNoembedTag) || ThreadSafeMatch(tag_name, html_names::kNoframesTag) || (ThreadSafeMatch(tag_name, html_names::kNoscriptTag) && - options_.script_enabled)) { + options_.scripting_flag)) { tokenizer->SetState(HTMLTokenizer::kRAWTEXTState); } } @@ -270,9 +270,9 @@ bool HTMLTreeBuilderSimulator::IsHTMLIntegrationPointForStartTag( } } else if (tokens_ns == SVG) { // FIXME: It's very fragile that we special case foreignObject here to be - // case-insensitive. - if (DeprecatedEqualIgnoringCase(tag_name, - svg_names::kForeignObjectTag.LocalName())) + // ASCII case-insensitive. + if (EqualIgnoringASCIICase(tag_name, + svg_names::kForeignObjectTag.LocalName())) return true; return ThreadSafeMatch(tag_name, svg_names::kDescTag) || ThreadSafeMatch(tag_name, svg_names::kTitleTag); @@ -299,9 +299,9 @@ bool HTMLTreeBuilderSimulator::IsHTMLIntegrationPointForEndTag( return ThreadSafeMatch(tag_name, mathml_names::kAnnotationXmlTag); if (tokens_ns == SVG) { // FIXME: It's very fragile that we special case foreignObject here to be - // case-insensitive. - if (DeprecatedEqualIgnoringCase(tag_name, - svg_names::kForeignObjectTag.LocalName())) + // ASCII case-insensitive. + if (EqualIgnoringASCIICase(tag_name, + svg_names::kForeignObjectTag.LocalName())) return true; return ThreadSafeMatch(tag_name, svg_names::kDescTag) || ThreadSafeMatch(tag_name, svg_names::kTitleTag); diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_view_source_parser_test.cc b/chromium/third_party/blink/renderer/core/html/parser/html_view_source_parser_test.cc index 2e98f7e4ad8..3bd21514f75 100644 --- a/chromium/third_party/blink/renderer/core/html/parser/html_view_source_parser_test.cc +++ b/chromium/third_party/blink/renderer/core/html/parser/html_view_source_parser_test.cc @@ -17,7 +17,7 @@ namespace blink { TEST(HTMLViewSourceParserTest, DetachThenFinish_ShouldNotCrash) { String mime_type("text/html"); auto* document = MakeGarbageCollected<HTMLViewSourceDocument>( - DocumentInit::Create(), mime_type); + DocumentInit::Create().WithTypeFrom(mime_type)); auto* parser = MakeGarbageCollected<HTMLViewSourceParser>(*document, mime_type); // A client may detach the parser from the document. diff --git a/chromium/third_party/blink/renderer/core/html/parser/parser_scripting_flag_policy.h b/chromium/third_party/blink/renderer/core/html/parser/parser_scripting_flag_policy.h new file mode 100644 index 00000000000..48d44e856e0 --- /dev/null +++ b/chromium/third_party/blink/renderer/core/html/parser/parser_scripting_flag_policy.h @@ -0,0 +1,16 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_PARSER_PARSER_SCRIPTING_FLAG_POLICY_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_PARSER_PARSER_SCRIPTING_FLAG_POLICY_H_ + +namespace blink { + +// Decides whether the scripting flag of the parser should be set to enabled. +// https://html.spec.whatwg.org/#scripting-flag +enum class ParserScriptingFlagPolicy { kOnlyIfScriptIsEnabled, kEnabled }; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_PARSER_PARSER_SCRIPTING_FLAG_POLICY_H_ diff --git a/chromium/third_party/blink/renderer/core/html/parser/preload_request.cc b/chromium/third_party/blink/renderer/core/html/parser/preload_request.cc index b90b9f0936b..a355cb13d0b 100644 --- a/chromium/third_party/blink/renderer/core/html/parser/preload_request.cc +++ b/chromium/third_party/blink/renderer/core/html/parser/preload_request.cc @@ -28,6 +28,33 @@ KURL PreloadRequest::CompleteURL(Document* document) { return document->CompleteURL(resource_url_); } +// static +std::unique_ptr<PreloadRequest> PreloadRequest::CreateIfNeeded( + const String& initiator_name, + const TextPosition& initiator_position, + const String& resource_url, + const KURL& base_url, + ResourceType resource_type, + const network::mojom::ReferrerPolicy referrer_policy, + ReferrerSource referrer_source, + ResourceFetcher::IsImageSet is_image_set, + const FetchParameters::ResourceWidth& resource_width, + const ClientHintsPreferences& client_hints_preferences, + RequestType request_type) { + // Never preload data URLs. We also disallow relative ref URLs which become + // data URLs if the document's URL is a data URL. We don't want to create + // extra resource requests with data URLs to avoid copy / initialization + // overhead, which can be significant for large URLs. + if (resource_url.IsEmpty() || resource_url.StartsWith("#") || + ProtocolIs(resource_url, "data")) { + return nullptr; + } + return base::WrapUnique(new PreloadRequest( + initiator_name, initiator_position, resource_url, base_url, resource_type, + resource_width, client_hints_preferences, request_type, referrer_policy, + referrer_source, is_image_set)); +} + Resource* PreloadRequest::Start(Document* document) { DCHECK(IsMainThread()); @@ -47,6 +74,8 @@ Resource* PreloadRequest::Start(Document* document) { resource_request.SetRequestContext( ResourceFetcher::DetermineRequestContext(resource_type_, is_image_set_)); + resource_request.SetRequestDestination( + ResourceFetcher::DetermineRequestDestination(resource_type_)); resource_request.SetFetchImportanceMode(importance_); @@ -59,7 +88,7 @@ Resource* PreloadRequest::Start(Document* document) { ResourceLoaderOptions options; options.initiator_info = initiator_info; - FetchParameters params(resource_request, options); + FetchParameters params(std::move(resource_request), options); if (resource_type_ == ResourceType::kImportResource) { const SecurityOrigin* security_origin = @@ -116,8 +145,7 @@ Resource* PreloadRequest::Start(Document* document) { params.SetLazyImagePlaceholder(); } - return PreloadHelper::StartPreload(resource_type_, params, - document->Fetcher()); + return PreloadHelper::StartPreload(resource_type_, params, *document); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/core/html/parser/preload_request.h b/chromium/third_party/blink/renderer/core/html/parser/preload_request.h index afb88f92b21..761f071fa3f 100644 --- a/chromium/third_party/blink/renderer/core/html/parser/preload_request.h +++ b/chromium/third_party/blink/renderer/core/html/parser/preload_request.h @@ -39,8 +39,6 @@ class CORE_EXPORT PreloadRequest { enum ReferrerSource { kDocumentIsReferrer, kBaseUrlIsReferrer }; - // TODO(csharrison): Move the implementation to the cpp file when core/html - // gets its own testing source set in html/BUILD.gn. static std::unique_ptr<PreloadRequest> CreateIfNeeded( const String& initiator_name, const TextPosition& initiator_position, @@ -54,20 +52,7 @@ class CORE_EXPORT PreloadRequest { FetchParameters::ResourceWidth(), const ClientHintsPreferences& client_hints_preferences = ClientHintsPreferences(), - RequestType request_type = kRequestTypePreload) { - // Never preload data URLs. We also disallow relative ref URLs which become - // data URLs if the document's URL is a data URL. We don't want to create - // extra resource requests with data URLs to avoid copy / initialization - // overhead, which can be significant for large URLs. - if (resource_url.IsEmpty() || resource_url.StartsWith("#") || - ProtocolIs(resource_url, "data")) { - return nullptr; - } - return base::WrapUnique(new PreloadRequest( - initiator_name, initiator_position, resource_url, base_url, - resource_type, resource_width, client_hints_preferences, request_type, - referrer_policy, referrer_source, is_image_set)); - } + RequestType request_type = kRequestTypePreload); Resource* Start(Document*); @@ -167,25 +152,25 @@ class CORE_EXPORT PreloadRequest { KURL CompleteURL(Document*); - String initiator_name_; - TextPosition initiator_position_; - String resource_url_; - KURL base_url_; + const String initiator_name_; + const TextPosition initiator_position_; + const String resource_url_; + const KURL base_url_; String charset_; - ResourceType resource_type_; + const ResourceType resource_type_; mojom::ScriptType script_type_; CrossOriginAttributeValue cross_origin_; mojom::FetchImportanceMode importance_; String nonce_; FetchParameters::DeferOption defer_; - FetchParameters::ResourceWidth resource_width_; - ClientHintsPreferences client_hints_preferences_; - RequestType request_type_; - network::mojom::ReferrerPolicy referrer_policy_; - ReferrerSource referrer_source_; + const FetchParameters::ResourceWidth resource_width_; + const ClientHintsPreferences client_hints_preferences_; + const RequestType request_type_; + const network::mojom::ReferrerPolicy referrer_policy_; + const ReferrerSource referrer_source_; IntegrityMetadataSet integrity_metadata_; bool from_insertion_scanner_; - ResourceFetcher::IsImageSet is_image_set_; + const ResourceFetcher::IsImageSet is_image_set_; bool is_lazy_load_image_enabled_; }; |