#include "core/dom/Comment.h"
#include "core/dom/ContextFeatures.h"
#include "core/dom/DOMImplementation.h"
-#include "core/dom/DOMNamedFlowCollection.h"
#include "core/dom/DocumentFragment.h"
#include "core/dom/DocumentLifecycleNotifier.h"
#include "core/dom/DocumentLifecycleObserver.h"
#include "core/dom/DocumentMarkerController.h"
-#include "core/dom/DocumentSharedObjectPool.h"
#include "core/dom/DocumentType.h"
#include "core/dom/Element.h"
+#include "core/dom/ElementDataCache.h"
#include "core/dom/ElementTraversal.h"
#include "core/dom/ExceptionCode.h"
#include "core/dom/ExecutionContextTask.h"
#include "core/dom/MainThreadTaskRunner.h"
-#include "core/dom/NamedFlowCollection.h"
+#include "core/dom/MutationObserver.h"
#include "core/dom/NodeChildRemovalTracker.h"
#include "core/dom/NodeFilter.h"
#include "core/dom/NodeIterator.h"
#include "core/frame/History.h"
#include "core/frame/PageConsole.h"
#include "core/frame/Settings.h"
-#include "core/frame/animation/AnimationController.h"
#include "core/html/HTMLAllCollection.h"
#include "core/html/HTMLAnchorElement.h"
#include "core/html/HTMLCanvasElement.h"
#include "core/html/HTMLImport.h"
#include "core/html/HTMLInputElement.h"
#include "core/html/HTMLLinkElement.h"
+#include "core/html/HTMLMetaElement.h"
#include "core/html/HTMLNameCollection.h"
#include "core/html/HTMLScriptElement.h"
#include "core/html/HTMLStyleElement.h"
uint64_t Document::s_globalTreeVersion = 0;
-// This class should be passed only to Document::postTask.
-class CheckFocusedElementTask FINAL : public ExecutionContextTask {
-public:
- static PassOwnPtr<CheckFocusedElementTask> create()
- {
- return adoptPtr(new CheckFocusedElementTask());
- }
- virtual ~CheckFocusedElementTask() { }
-
-private:
- CheckFocusedElementTask() { }
- virtual void performTask(ExecutionContext* context) OVERRIDE
- {
- ASSERT(context->isDocument());
- Document* document = toDocument(context);
- document->didRunCheckFocusedElementTask();
- Element* element = document->focusedElement();
- if (!element)
- return;
- if (document->childNeedsStyleRecalc()) {
- document->setNeedsFocusedElementCheck();
- return;
- }
- if (element->renderer() && element->renderer()->needsLayout())
- return;
- if (!element->isFocusable())
- document->setFocusedElement(0);
- }
-};
-
// This class doesn't work with non-Document ExecutionContext.
class AutofocusTask FINAL : public ExecutionContextTask {
public:
}
};
+DocumentVisibilityObserver::DocumentVisibilityObserver(Document& document)
+ : m_document(0)
+{
+ registerObserver(document);
+}
+
+DocumentVisibilityObserver::~DocumentVisibilityObserver()
+{
+ unregisterObserver();
+}
+
+void DocumentVisibilityObserver::unregisterObserver()
+{
+ if (m_document) {
+ m_document->unregisterVisibilityObserver(this);
+ m_document = 0;
+ }
+}
+
+void DocumentVisibilityObserver::registerObserver(Document& document)
+{
+ ASSERT(!m_document);
+ m_document = &document;
+ if (m_document)
+ m_document->registerVisibilityObserver(this);
+}
+
+void DocumentVisibilityObserver::setObservedDocument(Document& document)
+{
+ unregisterObserver();
+ registerObserver(document);
+}
+
Document::Document(const DocumentInit& initializer, DocumentClassFlags documentClasses)
: ContainerNode(0, CreateDocument)
, TreeScope(*this)
, m_paginatedForScreen(false)
, m_compatibilityMode(NoQuirksMode)
, m_compatibilityModeLocked(false)
- , m_didPostCheckFocusedElementTask(false)
, m_hasAutofocused(false)
+ , m_clearFocusedElementTimer(this, &Document::clearFocusedElementTimerFired)
, m_domTreeVersion(++s_globalTreeVersion)
, m_listenerTypes(0)
, m_mutationObserverTypes(0)
, m_visitedLinkState(VisitedLinkState::create(*this))
, m_visuallyOrdered(false)
, m_readyState(Complete)
- , m_bParsing(false)
- , m_styleRecalcTimer(this, &Document::styleRecalcTimerFired)
- , m_inStyleRecalc(false)
+ , m_isParsing(false)
, m_gotoAnchorNeededAfterStylesheetsLoad(false)
, m_containsValidityStyleRules(false)
, m_updateFocusAppearanceRestoresSelection(false)
, m_cssTarget(0)
, m_loadEventProgress(LoadEventNotRun)
, m_startTime(currentTime())
- , m_overMinimumLayoutThreshold(false)
, m_scriptRunner(ScriptRunner::create(this))
, m_xmlVersion("1.0")
, m_xmlStandalone(StandaloneUnspecified)
, m_hasFullscreenElementStack(false)
, m_loadEventDelayCount(0)
, m_loadEventDelayTimer(this, &Document::loadEventDelayTimerFired)
+ , m_pluginLoadingTimer(this, &Document::pluginLoadingTimerFired)
, m_didSetReferrerPolicy(false)
, m_referrerPolicy(ReferrerPolicyDefault)
, m_directionSetOnDocumentElement(false)
, m_lastHandledUserGestureTimestamp(0)
, m_taskRunner(MainThreadTaskRunner::create(this))
, m_registrationContext(initializer.registrationContext(this))
- , m_sharedObjectPoolClearTimer(this, &Document::sharedObjectPoolClearTimerFired)
+ , m_elementDataCacheClearTimer(this, &Document::elementDataCacheClearTimerFired)
#ifndef NDEBUG
, m_didDispatchViewportPropertiesChanged(false)
#endif
ASSERT(m_ranges.isEmpty());
ASSERT(!parentTreeScope());
ASSERT(!hasGuardRefCount());
+ ASSERT(m_visibilityObservers.isEmpty());
if (m_templateDocument)
- m_templateDocument->setTemplateDocumentHost(0); // balanced in templateDocument().
-
- if (Document* ownerDocument = this->ownerDocument())
- ownerDocument->didRemoveEventTargetNode(this);
+ m_templateDocument->m_templateDocumentHost = 0; // balanced in ensureTemplateDocument().
m_scriptRunner.clear();
m_import = 0;
}
+ if (m_timeline) {
+ m_timeline->detachFromDocument();
+ }
+
+ if (m_transitionTimeline) {
+ m_transitionTimeline->detachFromDocument();
+ }
+
m_styleEngine.clear(); // We need to destory CSSFontSelector before destroying m_fetcher.
if (m_elemSheet)
if (isXHTMLDocument() || isHTMLDocument())
return HTMLElementFactory::createHTMLElement(isHTMLDocument() ? name.lower() : name, *this, 0, false);
- return createElement(QualifiedName(nullAtom, name, nullAtom), false);
+ return Element::create(QualifiedName(nullAtom, name, nullAtom), this);
}
PassRefPtr<Element> Document::createElement(const AtomicString& localName, const AtomicString& typeExtension, ExceptionState& exceptionState)
RefPtr<Element> element;
- if (RuntimeEnabledFeatures::customElementsEnabled() && CustomElement::isValidName(localName) && registrationContext()) {
+ if (CustomElement::isValidName(localName) && registrationContext()) {
element = registrationContext()->createCustomTagElement(*this, QualifiedName(nullAtom, localName, xhtmlNamespaceURI));
} else {
element = createElement(localName, exceptionState);
return 0;
}
- if (RuntimeEnabledFeatures::customElementsEnabled() && !typeExtension.isNull() && !typeExtension.isEmpty())
+ if (!typeExtension.isEmpty())
CustomElementRegistrationContext::setIsAttributeAndTypeExtension(element.get(), typeExtension);
return element;
}
-PassRefPtr<Element> Document::createElementNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, const AtomicString& typeExtension, ExceptionState& exceptionState)
+static inline QualifiedName createQualifiedName(const AtomicString& namespaceURI, const AtomicString& qualifiedName, ExceptionState& exceptionState)
{
AtomicString prefix, localName;
- if (!parseQualifiedName(qualifiedName, prefix, localName, exceptionState))
- return 0;
+ if (!Document::parseQualifiedName(qualifiedName, prefix, localName, exceptionState))
+ return nullQName();
QualifiedName qName(prefix, localName, namespaceURI);
- if (!hasValidNamespaceForElements(qName)) {
+ if (!Document::hasValidNamespaceForElements(qName)) {
exceptionState.throwDOMException(NamespaceError, "The namespace URI provided ('" + namespaceURI + "') is not valid for the qualified name provided ('" + qualifiedName + "').");
- return 0;
+ return nullQName();
}
+ return qName;
+}
+
+PassRefPtr<Element> Document::createElementNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, ExceptionState& exceptionState)
+{
+ QualifiedName qName(createQualifiedName(namespaceURI, qualifiedName, exceptionState));
+ if (qName == nullQName())
+ return 0;
+
+ return createElement(qName, false);
+}
+
+PassRefPtr<Element> Document::createElementNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, const AtomicString& typeExtension, ExceptionState& exceptionState)
+{
+ QualifiedName qName(createQualifiedName(namespaceURI, qualifiedName, exceptionState));
+ if (qName == nullQName())
+ return 0;
+
RefPtr<Element> element;
- if (CustomElement::isValidName(qName.localName()) && registrationContext()) {
+ if (CustomElement::isValidName(qName.localName()) && registrationContext())
element = registrationContext()->createCustomTagElement(*this, qName);
- } else {
- element = createElementNS(namespaceURI, qualifiedName, exceptionState);
- if (exceptionState.hadException())
- return 0;
- }
+ else
+ element = createElement(qName, false);
- if (!typeExtension.isNull() && !typeExtension.isEmpty())
+ if (!typeExtension.isEmpty())
CustomElementRegistrationContext::setIsAttributeAndTypeExtension(element.get(), typeExtension);
return element;
bool Document::haveImportsLoaded() const
{
- return !m_import || !m_import->isStateBlockedFromRunningScript();
+ return !m_import || !m_import->state().shouldBlockScriptExecution();
}
DOMWindow* Document::executingWindow()
return settings() && settings()->regionBasedColumnsEnabled();
}
-PassRefPtr<DOMNamedFlowCollection> Document::webkitGetNamedFlows()
-{
- if (!RuntimeEnabledFeatures::cssRegionsEnabled() || !renderView())
- return 0;
-
- updateStyleIfNeeded();
-
- return namedFlows()->createCSSOMSnapshot();
-}
-
-NamedFlowCollection* Document::namedFlows()
-{
- if (!m_namedFlows)
- m_namedFlows = NamedFlowCollection::create(this);
-
- return m_namedFlows.get();
-}
-
-PassRefPtr<Element> Document::createElementNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, ExceptionState& exceptionState)
-{
- AtomicString prefix, localName;
- if (!parseQualifiedName(qualifiedName, prefix, localName, exceptionState))
- return 0;
-
- QualifiedName qName(prefix, localName, namespaceURI);
- if (!hasValidNamespaceForElements(qName)) {
- exceptionState.throwDOMException(NamespaceError, "The namespace URI provided ('" + namespaceURI + "') is not valid for the qualified name provided ('" + qualifiedName + "').");
- return 0;
- }
-
- return createElement(qName, false);
-}
-
String Document::readyState() const
{
DEFINE_STATIC_LOCAL(const String, loading, ("loading"));
case Loading:
if (!m_documentTiming.domLoading) {
m_documentTiming.domLoading = monotonicallyIncreasingTime();
- if (RuntimeEnabledFeatures::webAnimationsCSSEnabled())
- m_timeline->setZeroTime(m_documentTiming.domLoading);
+ m_timeline->setZeroTime(m_documentTiming.domLoading);
}
break;
case Interactive:
m_contentLanguage = language;
// Document's style depends on the content language.
- setNeedsStyleRecalc();
+ setNeedsStyleRecalc(SubtreeStyleChange);
}
void Document::setXMLVersion(const String& version, ExceptionState& exceptionState)
m_titleElement = 0;
else if (!m_titleElement) {
if (HTMLElement* headElement = head()) {
- m_titleElement = createElement(titleTag, false);
+ m_titleElement = HTMLTitleElement::create(*this);
headElement->appendChild(m_titleElement);
}
}
// FIXME: This is broken for SVG.
// Update title based on first title element in the head, if one exists.
if (HTMLElement* headElement = head()) {
- for (Element* element = headElement->firstElementChild(); element; element = element->nextElementSibling()) {
+ for (Element* element = ElementTraversal::firstWithin(*headElement); element; element = ElementTraversal::nextSibling(*element)) {
if (!element->hasTagName(titleTag))
continue;
HTMLTitleElement* title = toHTMLTitleElement(element);
return pageVisibilityState() != PageVisibilityStateVisible;
}
-void Document::dispatchVisibilityStateChangeEvent()
+void Document::didChangeVisibilityState()
{
dispatchEvent(Event::create(EventTypeNames::visibilitychange));
// Also send out the deprecated version until it can be removed.
dispatchEvent(Event::create(EventTypeNames::webkitvisibilitychange));
+
+ PageVisibilityState state = pageVisibilityState();
+ HashSet<DocumentVisibilityObserver*>::const_iterator observerEnd = m_visibilityObservers.end();
+ for (HashSet<DocumentVisibilityObserver*>::const_iterator it = m_visibilityObservers.begin(); it != observerEnd; ++it)
+ (*it)->didChangeVisibilityState(state);
+}
+
+void Document::registerVisibilityObserver(DocumentVisibilityObserver* observer)
+{
+ ASSERT(!m_visibilityObservers.contains(observer));
+ m_visibilityObservers.add(observer);
+}
+
+void Document::unregisterVisibilityObserver(DocumentVisibilityObserver* observer)
+{
+ ASSERT(m_visibilityObservers.contains(observer));
+ m_visibilityObservers.remove(observer);
}
String Document::nodeName() const
bool Document::shouldCallRecalcStyleForDocument()
{
- return needsStyleRecalc() || childNeedsStyleRecalc() || childNeedsDistributionRecalc() || !m_useElementsNeedingUpdate.isEmpty();
+ if (!isActive() || !view())
+ return false;
+ return needsStyleRecalc() || childNeedsStyleRecalc() || childNeedsDistributionRecalc() || !m_useElementsNeedingUpdate.isEmpty() || childNeedsStyleInvalidation();
}
-void Document::scheduleStyleRecalc()
+bool Document::shouldScheduleStyleRecalc()
{
if (!isActive())
- return;
+ return false;
+ if (hasPendingStyleRecalc())
+ return false;
+ if (inStyleRecalc())
+ return false;
+ // InPreLayout will recalc style itself. There's no reason to schedule another recalc.
+ if (m_lifecycle.state() == DocumentLifecycle::InPreLayout)
+ return false;
+ if (!shouldScheduleLayout())
+ return false;
+ return true;
+}
- if (m_styleRecalcTimer.isActive() || !shouldScheduleLayout())
+void Document::scheduleStyleRecalc()
+{
+ if (!shouldScheduleStyleRecalc())
return;
ASSERT(shouldCallRecalcStyleForDocument());
- m_styleRecalcTimer.startOneShot(0);
+ if (!view()->isServicingAnimations())
+ view()->scheduleAnimation();
+ m_lifecycle.advanceTo(DocumentLifecycle::StyleRecalcPending);
InspectorInstrumentation::didScheduleStyleRecalculation(this);
}
-void Document::unscheduleStyleRecalc()
-{
- ASSERT(!isActive() || (!needsStyleRecalc() && !childNeedsStyleRecalc()));
- m_styleRecalcTimer.stop();
-}
-
bool Document::hasPendingForcedStyleRecalc() const
{
- return m_styleRecalcTimer.isActive() && !m_inStyleRecalc && styleChangeType() >= SubtreeStyleChange;
-}
-
-void Document::styleRecalcTimerFired(Timer<Document>*)
-{
- updateStyleIfNeeded();
+ return hasPendingStyleRecalc() && !inStyleRecalc() && styleChangeType() >= SubtreeStyleChange;
}
void Document::updateDistributionIfNeeded()
recalcDistribution();
}
+void Document::updateStyleInvalidationIfNeeded()
+{
+ if (!childNeedsStyleInvalidation())
+ return;
+ TRACE_EVENT0("webkit", "Document::computeNeedsStyleRecalcState");
+ if (!styleResolver()) {
+ clearChildNeedsStyleInvalidation();
+ return;
+ }
+
+ // FIXME: the style resolver can be deleted at present. Either resolve
+ // crbug.com/335964 or move the invalidation data elsewhere.
+ styleResolver()->ensureRuleFeatureSet().computeStyleInvalidation(*this);
+}
+
void Document::updateDistributionForNodeIfNeeded(Node* node)
{
if (node->inDocument()) {
root->recalcDistribution();
}
-void Document::setStyleDependentState(RenderStyle* documentStyle)
+void Document::setupFontBuilder(RenderStyle* documentStyle)
{
- const Pagination& pagination = view()->pagination();
- if (pagination.mode != Pagination::Unpaginated) {
- Pagination::setStylesForPaginationMode(pagination.mode, documentStyle);
- documentStyle->setColumnGap(pagination.gap);
- if (renderView()->hasColumns())
- renderView()->updateColumnInfoFromStyle(documentStyle);
- }
-
FontBuilder fontBuilder;
fontBuilder.initForStyleResolve(*this, documentStyle, isSVGDocument());
RefPtr<CSSFontSelector> selector = m_styleEngine->fontSelector();
WritingMode rootWritingMode = documentElementStyle->writingMode();
TextDirection rootDirection = documentElementStyle->direction();
- HTMLElement* body = this->body();
+ HTMLElement* body = this->body();
+ RefPtr<RenderStyle> bodyStyle;
if (body) {
- RefPtr<RenderStyle> bodyStyle = body->renderStyle();
+ bodyStyle = body->renderStyle();
if (!bodyStyle || body->needsStyleRecalc() || documentElement()->needsStyleRecalc() || change == Force)
bodyStyle = ensureStyleResolver().styleForElement(body, documentElementStyle.get());
if (!writingModeSetOnDocumentElement())
rootDirection = bodyStyle->direction();
}
+ RefPtr<RenderStyle> overflowStyle;
+ if (Element* element = viewportDefiningElement(documentElementStyle.get())) {
+ if (element == body) {
+ overflowStyle = bodyStyle;
+ } else {
+ ASSERT(element == documentElement());
+ overflowStyle = documentElementStyle;
+ }
+ }
+
// Resolved rem units are stored in the matched properties cache so we need to make sure to
// invalidate the cache if the documentElement needed to reattach or the font size changed
// and then trigger a full document recalc. We also need to clear it here since the
// rare and just invalidate the cache for now.
if (styleEngine()->usesRemUnits() && (documentElement()->needsAttach() || documentElement()->computedStyle()->fontSize() != documentElementStyle->fontSize())) {
ensureStyleResolver().invalidateMatchedPropertiesCache();
- documentElement()->setNeedsStyleRecalc();
+ documentElement()->setNeedsStyleRecalc(SubtreeStyleChange);
}
RefPtr<RenderStyle> documentStyle = renderView()->style();
- if (documentStyle->writingMode() != rootWritingMode || documentStyle->direction() != rootDirection) {
+ if (documentStyle->writingMode() != rootWritingMode
+ || documentStyle->direction() != rootDirection
+ || (overflowStyle && (documentStyle->overflowX() != overflowStyle->overflowX() || documentStyle->overflowY() != overflowStyle->overflowY()))) {
RefPtr<RenderStyle> newStyle = RenderStyle::clone(documentStyle.get());
newStyle->setWritingMode(rootWritingMode);
newStyle->setDirection(rootDirection);
+ EOverflow overflowX = OAUTO;
+ EOverflow overflowY = OAUTO;
+ if (overflowStyle) {
+ overflowX = overflowStyle->overflowX();
+ overflowY = overflowStyle->overflowY();
+ // Visible overflow on the viewport is meaningless, and the spec says to treat it as 'auto':
+ if (overflowX == OVISIBLE)
+ overflowX = OAUTO;
+ if (overflowY == OVISIBLE)
+ overflowY = OAUTO;
+
+ // Column-gap is (ab)used by the current paged overflow implementation (in lack of other
+ // ways to specify gaps between pages), so we have to propagate it too.
+ newStyle->setColumnGap(overflowStyle->columnGap());
+ }
+ newStyle->setOverflowX(overflowX);
+ newStyle->setOverflowY(overflowY);
renderView()->setStyle(newStyle);
- setStyleDependentState(newStyle.get());
+ setupFontBuilder(newStyle.get());
}
if (body) {
if (RenderStyle* style = body->renderStyle()) {
if (style->direction() != rootDirection || style->writingMode() != rootWritingMode)
- body->setNeedsStyleRecalc();
+ body->setNeedsStyleRecalc(SubtreeStyleChange);
}
}
if (RenderStyle* style = documentElement()->renderStyle()) {
if (style->direction() != rootDirection || style->writingMode() != rootWritingMode)
- documentElement()->setNeedsStyleRecalc();
+ documentElement()->setNeedsStyleRecalc(SubtreeStyleChange);
}
}
-void Document::recalcStyle(StyleRecalcChange change)
+void Document::updateStyleIfNeeded()
{
- // we should not enter style recalc while painting
- RELEASE_ASSERT(!view() || !view()->isPainting());
+ updateStyle(NoChange);
+}
- // FIXME: We should never enter here without a FrameView or with an inactive document.
- if (!isActive() || !view())
+// FIXME: We need a better name than updateStyleIfNeeded. It's performing style invalidation,
+// style recalc, distribution and <use> shadow tree creation.
+void Document::updateStyle(StyleRecalcChange change)
+{
+ ASSERT(isMainThread());
+
+ if (!shouldCallRecalcStyleForDocument())
return;
- if (m_inStyleRecalc)
+ if (inStyleRecalc())
return;
+ // Entering here from inside layout or paint would be catastrophic since recalcStyle can
+ // tear down the render tree or (unfortunately) run script. Kill the whole renderer if
+ // someone managed to get into here from inside layout or paint.
+ RELEASE_ASSERT(!view()->isInPerformLayout());
+ RELEASE_ASSERT(!view()->isPainting());
+
+ // Script can run below in PostAttachCallbacks or WidgetUpdates, so protect the Frame.
+ RefPtr<Frame> protect(m_frame);
+
TRACE_EVENT0("webkit", "Document::recalcStyle");
TRACE_EVENT_SCOPED_SAMPLING_STATE("Blink", "RecalcStyle");
InspectorInstrumentationCookie cookie = InspectorInstrumentation::willRecalculateStyle(this);
updateDistributionIfNeeded();
- updateUseShadowTrees();
+ updateUseShadowTreesIfNeeded();
+ updateStyleInvalidationIfNeeded();
if (m_evaluateMediaQueriesOnStyleRecalc) {
m_evaluateMediaQueriesOnStyleRecalc = false;
{
PostAttachCallbacks::SuspendScope suspendPostAttachCallbacks;
RenderWidget::UpdateSuspendScope suspendWidgetHierarchyUpdates;
- TemporaryChange<bool> changeInStyleRecalc(m_inStyleRecalc, true);
+ m_lifecycle.advanceTo(DocumentLifecycle::InStyleRecalc);
if (styleChangeType() >= SubtreeStyleChange)
change = Force;
view()->updateCompositingLayersAfterStyleChange();
clearChildNeedsStyleRecalc();
- unscheduleStyleRecalc();
if (m_styleEngine->hasResolver()) {
// Pseudo element removal and similar may only work with these flags still set. Reset them after the style recalc.
m_styleEngine->resetCSSFeatureFlags(resolver.ensureRuleFeatureSet());
resolver.clearStyleSharingList();
}
- }
- InspectorInstrumentation::didRecalculateStyle(cookie);
+ ASSERT(!needsStyleRecalc());
+ ASSERT(!childNeedsStyleRecalc());
+ ASSERT(inStyleRecalc());
+ m_lifecycle.advanceTo(DocumentLifecycle::StyleClean);
+ }
// As a result of the style recalculation, the currently hovered element might have been
// detached (for example, by setting display:none in the :hover style), schedule another mouseMove event
// to check if any other elements ended up under the mouse pointer due to re-layout.
if (hoverNode() && !hoverNode()->renderer() && frame())
frame()->eventHandler().dispatchFakeMouseMoveEventSoon();
-}
-
-void Document::updateStyleIfNeeded()
-{
- ASSERT(isMainThread());
- ASSERT(!view() || (!view()->isInPerformLayout() && !view()->isPainting()));
- if (!shouldCallRecalcStyleForDocument())
- return;
+ if (m_focusedElement && !m_focusedElement->isFocusable())
+ clearFocusedElementSoon();
- RefPtr<Frame> holder(m_frame);
- AnimationUpdateBlock animationUpdateBlock(m_frame ? &m_frame->animation() : 0);
- recalcStyle(NoChange);
DocumentAnimations::serviceAfterStyleRecalc(*this);
+
+ InspectorInstrumentation::didRecalculateStyle(cookie);
}
void Document::updateStyleForNodeIfNeeded(Node* node)
// the path from 'node' to the root needs style recalc.
// Global needed.
- bool needsRecalc = needsStyleRecalc() || childNeedsDistributionRecalc() || !m_useElementsNeedingUpdate.isEmpty();
+ bool needsRecalc = needsStyleRecalc() || childNeedsDistributionRecalc() || !m_useElementsNeedingUpdate.isEmpty() || childNeedsStyleInvalidation();
// On the path.
for (Node* ancestor = node; ancestor && !needsRecalc; ancestor = ancestor->parentOrShadowHostNode())
if (isActive() && frameView)
frameView->partialLayout().reset();
-
- setNeedsFocusedElementCheck();
}
void Document::setNeedsFocusedElementCheck()
{
- // FIXME: Using a Task doesn't look a good idea.
- if (!m_focusedElement || m_didPostCheckFocusedElementTask)
- return;
- m_taskRunner->postTask(CheckFocusedElementTask::create());
- m_didPostCheckFocusedElementTask = true;
+ setNeedsStyleRecalc(LocalStyleChange);
+}
+
+void Document::clearFocusedElementSoon()
+{
+ if (!m_clearFocusedElementTimer.isActive())
+ m_clearFocusedElementTimer.startOneShot(0);
+}
+
+void Document::clearFocusedElementTimerFired(Timer<Document>*)
+{
+ updateStyleIfNeeded();
+ m_clearFocusedElementTimer.stop();
+
+ if (m_focusedElement && !m_focusedElement->isFocusable())
+ setFocusedElement(0);
}
void Document::recalcStyleForLayoutIgnoringPendingStylesheets()
// If new nodes have been added or style recalc has been done with style sheets still
// pending, some nodes may not have had their real style calculated yet. Normally this
// gets cleaned when style sheets arrive but here we need up-to-date style immediately.
- recalcStyle(Force);
+ updateStyle(Force);
}
}
m_useElementsNeedingUpdate.remove(&element);
}
-void Document::updateUseShadowTrees()
+void Document::updateUseShadowTreesIfNeeded()
{
if (m_useElementsNeedingUpdate.isEmpty())
return;
m_renderView->setStyle(StyleResolver::styleForDocument(*this));
view()->updateCompositingLayersAfterStyleChange();
- m_styleEngine->didAttach();
-
ContainerNode::attach(context);
- m_lifecycle.advanceTo(DocumentLifecycle::Active);
+ m_lifecycle.advanceTo(DocumentLifecycle::StyleClean);
}
void Document::detach(const AttachContext& context)
ContainerNode::detach(context);
- unscheduleStyleRecalc();
-
m_styleEngine->didDetach();
if (renderView)
renderView->destroy();
- if (m_touchEventTargets && m_touchEventTargets->size() && parentDocument())
- parentDocument()->didRemoveEventTargetNode(this);
+ if (Document* parentDoc = parentDocument())
+ parentDoc->didClearTouchEventHandlers(this);
// This is required, as our Frame might delete itself as soon as it detaches
// us. However, this violates Node::detach() semantics, as it's never
void Document::removeAllEventListeners()
{
- EventTarget::removeAllEventListeners();
+ ContainerNode::removeAllEventListeners();
if (DOMWindow* domWindow = this->domWindow())
domWindow->removeAllEventListeners();
return 0;
}
+Element* Document::viewportDefiningElement(RenderStyle* rootStyle) const
+{
+ // If a BODY element sets non-visible overflow, it is to be propagated to the viewport, as long
+ // as the following conditions are all met:
+ // (1) The root element is HTML.
+ // (2) It is the primary BODY element (we only assert for this, expecting callers to behave).
+ // (3) The root element has visible overflow.
+ // Otherwise it's the root element's properties that are to be propagated.
+ Element* rootElement = documentElement();
+ Element* bodyElement = body();
+ if (!rootElement)
+ return 0;
+ if (!rootStyle) {
+ rootStyle = rootElement->renderStyle();
+ if (!rootStyle)
+ return 0;
+ }
+ if (bodyElement && rootStyle->isOverflowVisible() && rootElement->hasTagName(htmlTag))
+ return bodyElement;
+ return rootElement;
+}
+
void Document::close()
{
// FIXME: We should follow the specification more closely:
// Just bail out. Before or during the onload we were shifted to another page.
// The old i-Bench suite does this. When this happens don't bother painting or laying out.
m_loadEventProgress = LoadEventCompleted;
- view()->unscheduleRelayout();
return;
}
// We used to force a synchronous display and flush here. This really isn't
// necessary and can in fact be actively harmful if pages are loading at a rate of > 60fps
// (if your platform is syncing flushes and limiting them to 60fps).
- m_overMinimumLayoutThreshold = true;
if (!ownerElement() || (ownerElement()->renderer() && !ownerElement()->renderer()->needsLayout())) {
updateStyleIfNeeded();
void Document::setParsing(bool b)
{
- m_bParsing = b;
+ m_isParsing = b;
- if (m_bParsing && !m_sharedObjectPool)
- m_sharedObjectPool = DocumentSharedObjectPool::create();
-
- if (!m_bParsing && view())
- view()->scheduleRelayout();
+ if (m_isParsing && !m_elementDataCache)
+ m_elementDataCache = ElementDataCache::create();
}
bool Document::shouldScheduleLayout()
bool Document::shouldParserYieldAgressivelyBeforeScriptExecution()
{
- return view() && view()->layoutPending() && !minimumLayoutDelay();
-}
-
-int Document::minimumLayoutDelay()
-{
- if (m_overMinimumLayoutThreshold)
- return 0;
-
- int elapsed = elapsedTime();
- m_overMinimumLayoutThreshold = elapsed > cLayoutScheduleThreshold;
-
- // We'll want to schedule the timer to fire at the minimum layout threshold.
- return max(0, cLayoutScheduleThreshold - elapsed);
+ return view() && view()->layoutPending();
}
int Document::elapsedTime() const
return m_elemSheet.get();
}
-void Document::processHttpEquiv(const AtomicString& equiv, const AtomicString& content)
+void Document::processHttpEquiv(const AtomicString& equiv, const AtomicString& content, bool inDocumentHeadElement)
{
ASSERT(!equiv.isNull() && !content.isNull());
- if (equalIgnoringCase(equiv, "default-style"))
+ if (equalIgnoringCase(equiv, "default-style")) {
processHttpEquivDefaultStyle(content);
- else if (equalIgnoringCase(equiv, "refresh"))
+ } else if (equalIgnoringCase(equiv, "refresh")) {
processHttpEquivRefresh(content);
- else if (equalIgnoringCase(equiv, "set-cookie"))
+ } else if (equalIgnoringCase(equiv, "set-cookie")) {
processHttpEquivSetCookie(content);
- else if (equalIgnoringCase(equiv, "content-language"))
+ } else if (equalIgnoringCase(equiv, "content-language")) {
setContentLanguage(content);
- else if (equalIgnoringCase(equiv, "x-dns-prefetch-control"))
+ } else if (equalIgnoringCase(equiv, "x-dns-prefetch-control")) {
parseDNSPrefetchControlHeader(content);
- else if (equalIgnoringCase(equiv, "x-frame-options"))
+ } else if (equalIgnoringCase(equiv, "x-frame-options")) {
processHttpEquivXFrameOptions(content);
- else if (equalIgnoringCase(equiv, "content-security-policy")
- || equalIgnoringCase(equiv, "content-security-policy-report-only")
- || equalIgnoringCase(equiv, "x-webkit-csp")
- || equalIgnoringCase(equiv, "x-webkit-csp-report-only"))
- processHttpEquivContentSecurityPolicy(equiv, content);
+ } else if (equalIgnoringCase(equiv, "content-security-policy") || equalIgnoringCase(equiv, "content-security-policy-report-only")) {
+ if (inDocumentHeadElement)
+ processHttpEquivContentSecurityPolicy(equiv, content);
+ else
+ contentSecurityPolicy()->reportMetaOutsideHead(content);
+ }
}
void Document::processHttpEquivContentSecurityPolicy(const AtomicString& equiv, const AtomicString& content)
contentSecurityPolicy()->didReceiveHeader(content, ContentSecurityPolicy::Enforce, ContentSecurityPolicy::HeaderSourceMeta);
else if (equalIgnoringCase(equiv, "content-security-policy-report-only"))
contentSecurityPolicy()->didReceiveHeader(content, ContentSecurityPolicy::Report, ContentSecurityPolicy::HeaderSourceMeta);
- // FIXME: Remove deprecation messages after the next release branch.
- else if (equalIgnoringCase(equiv, "x-webkit-csp"))
- UseCounter::countDeprecation(this, UseCounter::PrefixedContentSecurityPolicy);
- else if (equalIgnoringCase(equiv, "x-webkit-csp-report-only"))
- UseCounter::countDeprecation(this, UseCounter::PrefixedContentSecurityPolicyReportOnly);
else
ASSERT_NOT_REACHED();
}
// Stopping the loader isn't enough, as we're already parsing the document; to honor the header's
// intent, we must navigate away from the possibly partially-rendered document to a location that
// doesn't inherit the parent's SecurityOrigin.
- frame->navigationScheduler().scheduleLocationChange(this, SecurityOrigin::urlWithUniqueSecurityOrigin(), String());
+ frame->navigationScheduler().scheduleLocationChange(this, SecurityOrigin::urlWithUniqueSecurityOrigin(), Referrer());
addConsoleMessageWithRequestIdentifier(SecurityMessageSource, ErrorMessageLevel, message, requestIdentifier);
}
}
return;
m_evaluateMediaQueriesOnStyleRecalc = true;
- setNeedsStyleRecalc();
+ setNeedsStyleRecalc(SubtreeStyleChange);
if (updateTime == RecalcStyleImmediately)
updateStyleIfNeeded();
setAnnotatedRegionsDirty(false);
}
-bool Document::setFocusedElement(PassRefPtr<Element> prpNewFocusedElement, FocusDirection direction)
+bool Document::setFocusedElement(PassRefPtr<Element> prpNewFocusedElement, FocusType type)
{
+ m_clearFocusedElementTimer.stop();
+
RefPtr<Element> newFocusedElement = prpNewFocusedElement;
// Make sure newFocusedNode is actually in this document
oldFocusedElement->setFocus(false);
- // Dispatch a change event for text fields or textareas that have been edited
- if (oldFocusedElement->wasChangedSinceLastFormControlChangeEvent())
- oldFocusedElement->dispatchFormControlChangeEvent();
-
// Dispatch the blur event and let the node do any other blur related activities (important for text fields)
// If page lost focus, blur event will have already been dispatched
if (page() && (page()->focusController().isFocused())) {
// Dispatch the focus event and let the node do any other focus related activities (important for text fields)
// If page lost focus, event will be dispatched on page focus, don't duplicate
if (page() && (page()->focusController().isFocused())) {
- m_focusedElement->dispatchFocusEvent(oldFocusedElement.get(), direction);
+ m_focusedElement->dispatchFocusEvent(oldFocusedElement.get(), type);
if (m_focusedElement != newFocusedElement) {
void Document::registerNodeList(LiveNodeListBase* list)
{
- if (list->hasIdNameCache())
- m_nodeListCounts[InvalidateOnIdNameAttrChange]++;
m_nodeListCounts[list->invalidationType()]++;
if (list->isRootedAtDocument())
m_listsInvalidatedAtDocument.add(list);
void Document::unregisterNodeList(LiveNodeListBase* list)
{
- if (list->hasIdNameCache())
- m_nodeListCounts[InvalidateOnIdNameAttrChange]--;
m_nodeListCounts[list->invalidationType()]--;
if (list->isRootedAtDocument()) {
ASSERT(m_listsInvalidatedAtDocument.contains(list));
// FIXME: This should update markers for spelling and grammar checking.
}
-void Document::setWindowAttributeEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, DOMWrapperWorld* isolatedWorld)
+void Document::setWindowAttributeEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener)
{
DOMWindow* domWindow = this->domWindow();
if (!domWindow)
return;
- domWindow->setAttributeEventListener(eventType, listener, isolatedWorld);
+ domWindow->setAttributeEventListener(eventType, listener);
}
-EventListener* Document::getWindowAttributeEventListener(const AtomicString& eventType, DOMWrapperWorld* isolatedWorld)
+EventListener* Document::getWindowAttributeEventListener(const AtomicString& eventType)
{
DOMWindow* domWindow = this->domWindow();
if (!domWindow)
return 0;
- return domWindow->getAttributeEventListener(eventType, isolatedWorld);
+ return domWindow->getAttributeEventListener(eventType);
}
EventQueue* Document::eventQueue() const
return 0;
}
+PassRefPtr<Event> Document::createEvent(ExceptionState& exceptionState)
+{
+ if (!isSVGDocument()) {
+ exceptionState.throwTypeError(ExceptionMessages::notEnoughArguments(1, 0));
+ return 0;
+ }
+
+ UseCounter::count(this, UseCounter::DocumentCreateEventOptionalArgument);
+ // Legacy SVGDocument behavior.
+ return createEvent("undefined", exceptionState);
+}
+
void Document::addMutationEventListenerTypeIfEnabled(ListenerType listenerType)
{
if (ContextFeatures::mutationEventsEnabled(this))
// in the title bar.
if (m_titleElement
&& encoding() != newData.encoding()
- && !m_titleElement->firstElementChild()
+ && !ElementTraversal::firstWithin(*m_titleElement)
&& encoding() == Latin1Encoding()
&& m_titleElement->textContent().containsOnlyLatin1()) {
// FIXME: How is possible to not have a renderer here?
if (renderView())
renderView()->style()->setRTLOrdering(m_visuallyOrdered ? VisualOrder : LogicalOrder);
- setNeedsStyleRecalc();
+ setNeedsStyleRecalc(SubtreeStyleChange);
}
}
bool Document::execCommand(const String& commandName, bool userInterface, const String& value)
{
+ // We don't allow recusrive |execCommand()| to protect against attack code.
+ // Recursive call of |execCommand()| could be happened by moving iframe
+ // with script triggered by insertion, e.g. <iframe src="javascript:...">
+ // <iframe onload="...">. This usage is valid as of the specification
+ // although, it isn't common use case, rather it is used as attack code.
+ static bool inExecCommand = false;
+ if (inExecCommand) {
+ String message = "We don't execute document.execCommand() this time, because it is called recursively.";
+ addConsoleMessage(JSMessageSource, WarningMessageLevel, message);
+ return false;
+ }
+ TemporaryChange<bool> executeScope(inExecCommand, true);
+
+ // Postpone DOM mutation events, which can execute scripts and change
+ // DOM tree against implementation assumption.
+ EventQueueScope eventQueueScope;
return command(this, commandName, userInterface).execute(value);
}
return KURL();
RefPtr<HTMLCollection> children = head()->children();
- for (unsigned i = 0; Node* child = children->item(i); i++) {
+ for (unsigned i = 0; Element* child = children->item(i); i++) {
if (!child->hasTagName(linkTag))
continue;
HTMLLinkElement* linkElement = toHTMLLinkElement(child);
{
m_designMode = value;
for (Frame* frame = m_frame; frame && frame->document(); frame = frame->tree().traverseNext(m_frame))
- frame->document()->setNeedsStyleRecalc();
+ frame->document()->setNeedsStyleRecalc(SubtreeStyleChange);
}
Document::InheritedBool Document::getDesignMode() const
PassRefPtr<Attr> Document::createAttribute(const AtomicString& name, ExceptionState& exceptionState)
{
- return createAttributeNS(nullAtom, name, exceptionState, true);
-}
-
-PassRefPtr<Attr> Document::createAttributeNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, ExceptionState& exceptionState, bool shouldIgnoreNamespaceChecks)
-{
AtomicString prefix, localName;
- if (!parseQualifiedName(qualifiedName, prefix, localName, exceptionState))
+ if (!parseQualifiedName(name, prefix, localName, exceptionState))
return 0;
- QualifiedName qName(prefix, localName, namespaceURI);
-
- if (!shouldIgnoreNamespaceChecks && !hasValidNamespaceForAttributes(qName)) {
- exceptionState.throwDOMException(NamespaceError, "The namespace URI provided ('" + namespaceURI + "') is not valid for the qualified name provided ('" + qualifiedName + "').");
- return 0;
- }
+ QualifiedName qName(prefix, localName, nullAtom);
return Attr::create(*this, qName, emptyAtom);
}
PassRefPtr<HTMLCollection> Document::ensureCachedCollection(CollectionType type)
{
- return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLCollection>(this, type);
+ return ensureRareData().ensureNodeLists().addCache<HTMLCollection>(this, type);
}
PassRefPtr<HTMLCollection> Document::images()
PassRefPtr<HTMLCollection> Document::all()
{
- return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLAllCollection>(this, DocAll);
+ return ensureRareData().ensureNodeLists().addCache<HTMLAllCollection>(this, DocAll);
}
PassRefPtr<HTMLCollection> Document::windowNamedItems(const AtomicString& name)
{
- return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLNameCollection>(this, WindowNamedItems, name);
+ return ensureRareData().ensureNodeLists().addCache<HTMLNameCollection>(this, WindowNamedItems, name);
}
PassRefPtr<HTMLCollection> Document::documentNamedItems(const AtomicString& name)
{
- return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLNameCollection>(this, DocumentNamedItems, name);
+ return ensureRareData().ensureNodeLists().addCache<HTMLNameCollection>(this, DocumentNamedItems, name);
}
void Document::finishedParsing()
InspectorInstrumentation::domContentLoadedEventFired(f.get());
}
- // Schedule dropping of the DocumentSharedObjectPool. We keep it alive for a while after parsing finishes
+ // Schedule dropping of the ElementDataCache. We keep it alive for a while after parsing finishes
// so that dynamically inserted content can also benefit from sharing optimizations.
- // Note that we don't refresh the timer on pool access since that could lead to huge caches being kept
+ // Note that we don't refresh the timer on cache access since that could lead to huge caches being kept
// alive indefinitely by something innocuous like JS setting .innerHTML repeatedly on a timer.
- static const int timeToKeepSharedObjectPoolAliveAfterParsingFinishedInSeconds = 10;
- m_sharedObjectPoolClearTimer.startOneShot(timeToKeepSharedObjectPoolAliveAfterParsingFinishedInSeconds);
+ m_elementDataCacheClearTimer.startOneShot(10);
// Parser should have picked up all preloads by now
m_fetcher->clearPreloads();
m_import->didFinishParsing();
}
-void Document::sharedObjectPoolClearTimerFired(Timer<Document>*)
+void Document::elementDataCacheClearTimerFired(Timer<Document>*)
{
- m_sharedObjectPool.clear();
+ m_elementDataCache.clear();
}
Vector<IconURL> Document::iconURLs(int iconTypesMask)
RefPtr<HTMLCollection> children = head() ? head()->children() : 0;
unsigned length = children ? children->length() : 0;
for (unsigned i = 0; i < length; i++) {
- Node* child = children->item(i);
+ Element* child = children->item(i);
if (!child->hasTagName(linkTag))
continue;
HTMLLinkElement* linkElement = toHTMLLinkElement(child);
HTMLCanvasElement* Document::getCSSCanvasElement(const String& name)
{
- RefPtr<HTMLCanvasElement>& element = m_cssCanvasElements.add(name, 0).iterator->value;
+ RefPtr<HTMLCanvasElement>& element = m_cssCanvasElements.add(name, 0).storedValue->value;
if (!element) {
element = HTMLCanvasElement::create(*this);
element->setAccelerationDisabled(true);
m_parser->resumeScheduledTasks();
if (m_scriptedAnimationController)
m_scriptedAnimationController->resume();
+
+ MutationObserver::resumeSuspendedObservers();
}
// FIXME: suspendScheduledTasks(), resumeScheduledTasks(), tasksNeedSuspension()
frame()->loader().checkCompleted();
}
+void Document::loadPluginsSoon()
+{
+ // FIXME: Remove this timer once we don't need to compute layout to load plugins.
+ if (!m_pluginLoadingTimer.isActive())
+ m_pluginLoadingTimer.startOneShot(0);
+}
+
+void Document::pluginLoadingTimerFired(Timer<Document>*)
+{
+ updateLayout();
+}
+
ScriptedAnimationController& Document::ensureScriptedAnimationController()
{
if (!m_scriptedAnimationController) {
void Document::didAddTouchEventHandler(Node* handler)
{
+ // The node should either be in this document, or be the Document node of a child
+ // of this document.
+ ASSERT(&handler->document() == this
+ || (handler->isDocumentNode() && toDocument(handler)->parentDocument() == this));
if (!m_touchEventTargets.get())
m_touchEventTargets = adoptPtr(new TouchEventTargetSet);
- m_touchEventTargets->add(handler);
- if (Document* parent = parentDocument()) {
- parent->didAddTouchEventHandler(this);
+ bool isFirstHandler = m_touchEventTargets->isEmpty();
+
+ if (!m_touchEventTargets->add(handler).isNewEntry) {
+ // Just incremented refcount, no real change.
+ // If this is a child document node, then the count should never go above 1.
+ ASSERT(!handler->isDocumentNode() || &handler->document() == this);
return;
}
- if (Page* page = this->page()) {
- if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
- scrollingCoordinator->touchEventTargetRectsDidChange(this);
- if (m_touchEventTargets->size() == 1)
- frameHost()->chrome().client().needTouchEvents(true);
+
+ if (isFirstHandler) {
+ if (Document* parent = parentDocument()) {
+ parent->didAddTouchEventHandler(this);
+ } else {
+ // This is the first touch handler on the whole page.
+ if (FrameHost* frameHost = this->frameHost())
+ frameHost->chrome().client().needTouchEvents(true);
+ }
+ }
+
+ // When we're all done with all frames, ensure touch hit rects are marked as dirty.
+ if (!handler->isDocumentNode() || handler == this) {
+ if (Page* page = this->page()) {
+ if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
+ scrollingCoordinator->touchEventTargetRectsDidChange();
+ }
}
}
-void Document::didRemoveTouchEventHandler(Node* handler)
+void Document::didRemoveTouchEventHandler(Node* handler, bool clearAll)
{
+ // Note that we can't assert that |handler| is in this document because it might be in
+ // the process of moving out of it.
+ ASSERT(clearAll || m_touchEventTargets->contains(handler));
if (!m_touchEventTargets.get())
return;
- ASSERT(m_touchEventTargets->contains(handler));
- m_touchEventTargets->remove(handler);
- if (Document* parent = parentDocument()) {
- parent->didRemoveTouchEventHandler(this);
- return;
- }
- Page* page = this->page();
- if (!page)
- return;
- if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
- scrollingCoordinator->touchEventTargetRectsDidChange(this);
- if (m_touchEventTargets->size())
- return;
- for (const Frame* frame = page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
- if (frame->document() && frame->document()->hasTouchEventHandlers())
+ if (clearAll) {
+ if (!m_touchEventTargets->contains(handler))
+ return;
+ m_touchEventTargets->removeAll(handler);
+ } else {
+ if (!m_touchEventTargets->remove(handler))
+ // Just decremented refcount, no real update.
return;
}
- frameHost()->chrome().client().needTouchEvents(false);
-}
-void Document::didRemoveEventTargetNode(Node* handler)
-{
- if (m_touchEventTargets && !m_touchEventTargets->isEmpty()) {
- if (handler == this)
- m_touchEventTargets->clear();
- else
- m_touchEventTargets->removeAll(handler);
- if (m_touchEventTargets->isEmpty() && parentDocument())
- parentDocument()->didRemoveEventTargetNode(this);
+ if (m_touchEventTargets->isEmpty()) {
+ if (Document* parent = parentDocument()) {
+ // This was the last handler in this document, update the parent document too.
+ parent->didRemoveTouchEventHandler(this, clearAll);
+ } else {
+ // We just removed the last touch handler on the whole page.
+ if (FrameHost* frameHost = this->frameHost())
+ frameHost->chrome().client().needTouchEvents(false);
+ }
+ }
+
+ // When we're all done with all frames, ensure touch hit rects are marked as dirty.
+ if (!handler->isDocumentNode() || handler == this) {
+ if (Page* page = this->page()) {
+ if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
+ scrollingCoordinator->touchEventTargetRectsDidChange();
+ }
}
}
return Locale::defaultLocale();
LocaleIdentifierToLocaleMap::AddResult result = m_localeCache.add(localeKey, nullptr);
if (result.isNewEntry)
- result.iterator->value = Locale::create(localeKey);
- return *(result.iterator->value);
+ result.storedValue->value = Locale::create(localeKey);
+ return *(result.storedValue->value);
}
Document& Document::ensureTemplateDocument()
{
- if (const Document* document = templateDocument())
- return *const_cast<Document*>(document);
+ if (isTemplateDocument())
+ return *this;
+
+ if (m_templateDocument)
+ return *m_templateDocument;
if (isHTMLDocument()) {
- DocumentInit init = DocumentInit::fromContext(contextDocument(), blankURL());
+ DocumentInit init = DocumentInit::fromContext(contextDocument(), blankURL()).withNewRegistrationContext();
m_templateDocument = HTMLDocument::create(init);
} else {
m_templateDocument = Document::create(DocumentInit(blankURL()));
}
- m_templateDocument->setTemplateDocumentHost(this); // balanced in dtor.
+ m_templateDocument->m_templateDocumentHost = this; // balanced in dtor.
return *m_templateDocument.get();
}
return false;
}
+// FIXME: Remove this code once we have input routing in the browser
+// process. See http://crbug.com/339659.
+void Document::defaultEventHandler(Event* event)
+{
+ if (frame() && frame()->remotePlatformLayer()) {
+ frame()->chromeClient().forwardInputEvent(this, event);
+ return;
+ }
+ Node::defaultEventHandler(event);
+}
+
} // namespace WebCore