blob: 60d6a66e7544bb7709218739cc6d80467d80bda4 [file] [log] [blame]
// Copyright 2016 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_REENTRY_PERMIT_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_PARSER_HTML_PARSER_REENTRY_PERMIT_H_
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "third_party/blink/renderer/platform/wtf/ref_counted.h"
namespace blink {
// The HTML spec for parsing controls reentering the parser from
// script with the "parser pause flag" and "script nesting level."
//
// The parser pause flag puts a brake on whether the tokenizer will
// produce more tokens. When the parser is paused, nested invocations
// of the tokenizer unwind.
//
// The script nesting level is incremented and decremented any time
// the parser causes script to run. The script nesting level:
//
// - May prevent document.open from blowing away the document.
//
// - Governs whether a script element becomes the "pending
// parsing-blocking script." The pending parsing-blocking script in
// turn affects whether document.write reenters the parser.
//
// Clearing the parser pause flag is simple: Whenever the script
// nesting level hits zero, the parser pause flag is cleared. However
// setting the parser pause flag is subtle.
//
// Processing a typical script end tag, or running a chain of pending
// parser-blocking scripts after that, does not set the parser pause
// flag. However recursively parsing end script tags, or running
// custom element constructors, does set the parser pause flag.
class HTMLParserReentryPermit final
: public RefCounted<HTMLParserReentryPermit> {
public:
static scoped_refptr<HTMLParserReentryPermit> Create();
~HTMLParserReentryPermit() = default;
unsigned ScriptNestingLevel() const { return script_nesting_level_; }
bool ParserPauseFlag() const { return parser_pause_flag_; }
void Pause() {
CHECK(script_nesting_level_);
parser_pause_flag_ = true;
}
class ScriptNestingLevelIncrementer final {
STACK_ALLOCATED();
public:
explicit ScriptNestingLevelIncrementer(HTMLParserReentryPermit* permit)
: permit_(permit) {
permit_->script_nesting_level_++;
}
ScriptNestingLevelIncrementer(ScriptNestingLevelIncrementer&&) = default;
~ScriptNestingLevelIncrementer() {
permit_->script_nesting_level_--;
if (!permit_->script_nesting_level_)
permit_->parser_pause_flag_ = false;
}
private:
HTMLParserReentryPermit* permit_;
DISALLOW_COPY_AND_ASSIGN(ScriptNestingLevelIncrementer);
};
ScriptNestingLevelIncrementer IncrementScriptNestingLevel() {
return ScriptNestingLevelIncrementer(this);
}
private:
HTMLParserReentryPermit();
// https://html.spec.whatwg.org/C/#script-nesting-level
unsigned script_nesting_level_;
// https://html.spec.whatwg.org/C/#parser-pause-flag
bool parser_pause_flag_;
DISALLOW_COPY_AND_ASSIGN(HTMLParserReentryPermit);
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_PARSER_HTML_PARSER_REENTRY_PERMIT_H_