summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/dom/Document.cpp
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@nokia.com>2012-05-07 11:21:11 +0200
committerSimon Hausmann <simon.hausmann@nokia.com>2012-05-07 11:21:11 +0200
commit2cf6c8816a73e0132bd8fa3b509d62d7c51b6e47 (patch)
tree988e8c5b116dd0466244ae2fe5af8ee9be926d76 /Source/WebCore/dom/Document.cpp
parentdd91e772430dc294e3bf478c119ef8d43c0a3358 (diff)
Imported WebKit commit 7e538425aa020340619e927792f3d895061fb54b (http://svn.webkit.org/repository/webkit/trunk@116286)
Diffstat (limited to 'Source/WebCore/dom/Document.cpp')
-rw-r--r--Source/WebCore/dom/Document.cpp993
1 files changed, 768 insertions, 225 deletions
diff --git a/Source/WebCore/dom/Document.cpp b/Source/WebCore/dom/Document.cpp
index 809f99041..014c2536a 100644
--- a/Source/WebCore/dom/Document.cpp
+++ b/Source/WebCore/dom/Document.cpp
@@ -3,7 +3,7 @@
* (C) 1999 Antti Koivisto (koivisto@kde.org)
* (C) 2001 Dirk Mueller (mueller@kde.org)
* (C) 2006 Alexey Proskuryakov (ap@webkit.org)
- * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2011, 2012 Apple Inc. All rights reserved.
* Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
* Copyright (C) 2008, 2009, 2011 Google Inc. All rights reserved.
* Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
@@ -35,10 +35,8 @@
#include "CDATASection.h"
#include "CSSParser.h"
#include "CSSStyleDeclaration.h"
-#include "CSSStyleSelector.h"
#include "CSSStyleSheet.h"
#include "CSSValueKeywords.h"
-#include "CSSValuePool.h"
#include "CachedCSSStyleSheet.h"
#include "CachedResourceLoader.h"
#include "Chrome.h"
@@ -62,6 +60,7 @@
#include "EditingText.h"
#include "Editor.h"
#include "Element.h"
+#include "ElementShadow.h"
#include "EntityReference.h"
#include "Event.h"
#include "EventFactory.h"
@@ -69,6 +68,7 @@
#include "EventListener.h"
#include "EventNames.h"
#include "ExceptionCode.h"
+#include "FlowThreadController.h"
#include "FocusController.h"
#include "FormAssociatedElement.h"
#include "Frame.h"
@@ -119,13 +119,12 @@
#include "PageGroup.h"
#include "PageTransitionEvent.h"
#include "PlatformKeyboardEvent.h"
+#include "PluginDocument.h"
#include "PopStateEvent.h"
#include "ProcessingInstruction.h"
#include "RegisteredEventListener.h"
#include "RenderArena.h"
-#include "RenderFlowThread.h"
-#include "RenderLayer.h"
-#include "RenderLayerBacking.h"
+#include "RenderNamedFlowThread.h"
#include "RenderTextControl.h"
#include "RenderView.h"
#include "RenderWidget.h"
@@ -142,8 +141,8 @@
#include "SegmentedString.h"
#include "Settings.h"
#include "ShadowRoot.h"
-#include "ShadowTree.h"
#include "StaticHashSetNodeList.h"
+#include "StyleResolver.h"
#include "StyleSheetList.h"
#include "TextResourceDecoder.h"
#include "Timer.h"
@@ -304,10 +303,10 @@ static bool shouldInheritSecurityOriginFromOwner(const KURL& url)
// If a Document has the address "about:blank"
// The origin of the Document is the origin it was assigned when its browsing context was created.
//
- // Note: We generalize this to all "about" URLs and invalid URLs because we
+ // Note: We generalize this to all "blank" URLs and invalid URLs because we
// treat all of these URLs as about:blank.
//
- return !url.isValid() || url.protocolIs("about");
+ return !url.isValid() || url.isBlankURL();
}
static Widget* widgetForNode(Node* focusedNode)
@@ -346,6 +345,44 @@ static bool disableRangeMutation(Page* page)
#endif
}
+static bool canAccessAncestor(const SecurityOrigin* activeSecurityOrigin, Frame* targetFrame)
+{
+ // targetFrame can be 0 when we're trying to navigate a top-level frame
+ // that has a 0 opener.
+ if (!targetFrame)
+ return false;
+
+ const bool isLocalActiveOrigin = activeSecurityOrigin->isLocal();
+ for (Frame* ancestorFrame = targetFrame; ancestorFrame; ancestorFrame = ancestorFrame->tree()->parent()) {
+ Document* ancestorDocument = ancestorFrame->document();
+ // FIXME: Should be an ASSERT? Frames should alway have documents.
+ if (!ancestorDocument)
+ return true;
+
+ const SecurityOrigin* ancestorSecurityOrigin = ancestorDocument->securityOrigin();
+ if (activeSecurityOrigin->canAccess(ancestorSecurityOrigin))
+ return true;
+
+ // Allow file URL descendant navigation even when allowFileAccessFromFileURLs is false.
+ // FIXME: It's a bit strange to special-case local origins here. Should we be doing
+ // something more general instead?
+ if (isLocalActiveOrigin && ancestorSecurityOrigin->isLocal())
+ return true;
+ }
+
+ return false;
+}
+
+static void printNavigationErrorMessage(Frame* frame, const KURL& activeURL)
+{
+ // FIXME: this error message should contain more specifics of why the navigation change is not allowed.
+ String message = "Unsafe JavaScript attempt to initiate a navigation change for frame with URL " +
+ frame->document()->url().string() + " from frame with URL " + activeURL.string() + ".\n";
+
+ // FIXME: should we print to the console of the document performing the navigation instead?
+ frame->domWindow()->printErrorMessage(message);
+}
+
static HashSet<Document*>* documentsThatNeedStyleRecalc = 0;
class DocumentWeakReference : public ThreadSafeRefCounted<DocumentWeakReference> {
@@ -405,7 +442,8 @@ Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML)
, m_overMinimumLayoutThreshold(false)
, m_scriptRunner(ScriptRunner::create(this))
, m_xmlVersion("1.0")
- , m_xmlStandalone(false)
+ , m_xmlStandalone(StandaloneUnspecified)
+ , m_hasXMLDeclaration(0)
, m_savedRenderer(0)
, m_designMode(inherit)
#if ENABLE(DASHBOARD_SUPPORT)
@@ -420,6 +458,7 @@ Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML)
, m_isHTML(isHTML)
, m_isViewSource(false)
, m_sawElementsInKnownNamespaces(false)
+ , m_isSrcdocDocument(false)
, m_eventQueue(DocumentEventQueue::create(this))
, m_weakReference(DocumentWeakReference::create(this))
, m_idAttributeName(idAttr)
@@ -431,7 +470,7 @@ Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML)
#endif
, m_loadEventDelayCount(0)
, m_loadEventDelayTimer(this, &Document::loadEventDelayTimerFired)
- , m_referrerPolicy(SecurityPolicy::ReferrerPolicyDefault)
+ , m_referrerPolicy(ReferrerPolicyDefault)
, m_directionSetOnDocumentElement(false)
, m_writingModeSetOnDocumentElement(false)
, m_writeRecursionIsTooDeep(false)
@@ -439,6 +478,12 @@ Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML)
, m_wheelEventHandlerCount(0)
, m_touchEventHandlerCount(0)
, m_pendingTasksTimer(this, &Document::pendingTasksTimerFired)
+ , m_scheduledTasksAreSuspended(false)
+ , m_visualUpdatesAllowed(true)
+ , m_visualUpdatesSuppressionTimer(this, &Document::visualUpdatesSuppressionTimerFired)
+#ifndef NDEBUG
+ , m_didDispatchViewportPropertiesChanged(false)
+#endif
{
m_document = this;
@@ -485,8 +530,8 @@ Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML)
m_gotoAnchorNeededAfterStylesheetsLoad = false;
- m_didCalculateStyleSelector = false;
- m_hasDirtyStyleSelector = false;
+ m_didCalculateStyleResolver = false;
+ m_hasDirtyStyleResolver = false;
m_pendingStylesheets = 0;
m_ignorePendingStylesheets = false;
m_hasNodesWithPlaceholderStyle = false;
@@ -556,8 +601,6 @@ Document::~Document()
if (m_elemSheet)
m_elemSheet->clearOwnerNode();
- if (m_mappedElementSheet)
- m_mappedElementSheet->clearOwnerNode();
if (m_pageUserSheet)
m_pageUserSheet->clearOwnerNode();
if (m_pageGroupUserSheets) {
@@ -576,7 +619,7 @@ Document::~Document()
if (m_mediaQueryMatcher)
m_mediaQueryMatcher->documentDestroyed();
- clearStyleSelector(); // We need to destory CSSFontSelector before destroying m_cachedResourceLoader.
+ clearStyleResolver(); // We need to destory CSSFontSelector before destroying m_cachedResourceLoader.
m_cachedResourceLoader.clear();
// We must call clearRareData() here since a Document class inherits TreeScope
@@ -607,6 +650,7 @@ void Document::removedLastRef()
m_documentElement = 0;
#if ENABLE(FULLSCREEN_API)
m_fullScreenElement = 0;
+ m_fullScreenElementStack.clear();
#endif
// removeAllChildren() doesn't always unregister IDs,
@@ -669,7 +713,7 @@ void Document::buildAccessKeyMap(TreeScope* scope)
m_elementsByAccessKey.set(accessKey.impl(), element);
if (element->hasShadowRoot()) {
- for (ShadowRoot* root = element->shadowTree()->youngestShadowRoot(); root; root = root->olderShadowRoot())
+ for (ShadowRoot* root = element->shadow()->youngestShadowRoot(); root; root = root->olderShadowRoot())
buildAccessKeyMap(root);
}
}
@@ -730,7 +774,7 @@ void Document::setDocType(PassRefPtr<DocumentType> docType)
if (m_docType)
this->adoptIfNeeded(m_docType.get());
// Doctype affects the interpretation of the stylesheets.
- clearStyleSelector();
+ clearStyleResolver();
}
DOMImplementation* Document::implementation()
@@ -749,7 +793,7 @@ void Document::childrenChanged(bool changedByParser, Node* beforeChange, Node* a
return;
m_documentElement = newDocumentElement;
// The root style used for media query matching depends on the document element.
- clearStyleSelector();
+ clearStyleResolver();
}
PassRefPtr<Element> Document::createElement(const AtomicString& name, ExceptionCode& ec)
@@ -874,7 +918,7 @@ PassRefPtr<Node> Document::importNode(Node* importedNode, bool deep, ExceptionCo
return newElement.release();
}
case ATTRIBUTE_NODE:
- return Attr::create(0, this, static_cast<Attr*>(importedNode)->attr()->clone());
+ return Attr::create(this, QualifiedName(nullAtom, static_cast<Attr*>(importedNode)->name(), nullAtom), static_cast<Attr*>(importedNode)->value());
case DOCUMENT_FRAGMENT_NODE: {
if (importedNode->isShadowRoot()) {
// ShadowRoot nodes should not be explicitly importable.
@@ -940,15 +984,20 @@ PassRefPtr<Node> Document::adoptNode(PassRefPtr<Node> source, ExceptionCode& ec)
break;
}
default:
+ if (source->isShadowRoot()) {
+ // ShadowRoot cannot disconnect itself from the host node.
+ ec = HIERARCHY_REQUEST_ERR;
+ return 0;
+ }
+
+ // FIXME: What about <frame> and <object>?
if (source->hasTagName(iframeTag)) {
HTMLIFrameElement* iframe = static_cast<HTMLIFrameElement*>(source.get());
if (frame() && frame()->tree()->isDescendantOf(iframe->contentFrame())) {
ec = HIERARCHY_REQUEST_ERR;
return 0;
}
- iframe->setRemainsAliveOnRemovalFromTree(attached() && source->attached() && iframe->canRemainAliveOnRemovalFromTree());
}
-
if (source->parentNode())
source->parentNode()->removeChild(source.get(), ec);
}
@@ -1015,6 +1064,11 @@ PassRefPtr<Element> Document::createElement(const QualifiedName& qName, bool cre
return e.release();
}
+bool Document::regionBasedColumnsEnabled() const
+{
+ return settings() && settings()->regionBasedColumnsEnabled();
+}
+
bool Document::cssRegionsEnabled() const
{
return settings() && settings()->cssRegionsEnabled();
@@ -1033,16 +1087,26 @@ static bool validFlowName(const String& flowName)
PassRefPtr<WebKitNamedFlow> Document::webkitGetFlowByName(const String& flowName)
{
- if (!cssRegionsEnabled() || flowName.isEmpty() || !validFlowName(flowName) || !renderer())
- return 0;
+ return webkitGetFlowByName(flowName, CheckFlowNameForInvalidValues);
+}
- // Make a slower check for invalid flow name
- CSSParser p(true);
- if (!p.parseFlowThread(flowName, this))
+PassRefPtr<WebKitNamedFlow> Document::webkitGetFlowByName(const String& flowName, FlowNameCheck flowNameCheck)
+{
+ if (!cssRegionsEnabled() || !renderer())
return 0;
+ if (flowNameCheck == CheckFlowNameForInvalidValues) {
+ if (flowName.isEmpty() || !validFlowName(flowName))
+ return 0;
+
+ // Make a slower check for invalid flow name.
+ CSSParser parser(document());
+ if (!parser.parseFlowThread(flowName))
+ return 0;
+ }
+
if (RenderView* view = renderer()->view())
- return view->ensureRenderFlowThreadWithName(flowName)->ensureNamedFlow();
+ return view->flowThreadController()->ensureRenderFlowThreadWithName(flowName)->ensureNamedFlow();
return 0;
}
@@ -1102,6 +1166,58 @@ void Document::setReadyState(ReadyState readyState)
m_readyState = readyState;
dispatchEvent(Event::create(eventNames().readystatechangeEvent, false, false));
+
+ if (settings() && settings()->suppressesIncrementalRendering())
+ setVisualUpdatesAllowed(readyState);
+}
+
+void Document::setVisualUpdatesAllowed(ReadyState readyState)
+{
+ ASSERT(settings() && settings()->suppressesIncrementalRendering());
+ switch (readyState) {
+ case Loading:
+ ASSERT(!m_visualUpdatesSuppressionTimer.isActive());
+ ASSERT(m_visualUpdatesAllowed);
+ m_visualUpdatesSuppressionTimer.startOneShot(settings()->incrementalRenderingSuppressionTimeoutInSeconds());
+ setVisualUpdatesAllowed(false);
+ break;
+ case Interactive:
+ ASSERT(m_visualUpdatesSuppressionTimer.isActive() || m_visualUpdatesAllowed);
+ break;
+ case Complete:
+ if (m_visualUpdatesSuppressionTimer.isActive()) {
+ ASSERT(!m_visualUpdatesAllowed);
+ m_visualUpdatesSuppressionTimer.stop();
+ setVisualUpdatesAllowed(true);
+ } else
+ ASSERT(m_visualUpdatesAllowed);
+ break;
+ }
+}
+
+void Document::setVisualUpdatesAllowed(bool visualUpdatesAllowed)
+{
+ if (m_visualUpdatesAllowed == visualUpdatesAllowed)
+ return;
+
+ m_visualUpdatesAllowed = visualUpdatesAllowed;
+
+ if (!visualUpdatesAllowed)
+ return;
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (view())
+ view()->updateCompositingLayersAfterLayout();
+#endif
+
+ if (renderer())
+ renderer()->repaint();
+}
+
+void Document::visualUpdatesSuppressionTimerFired(Timer<Document>*)
+{
+ ASSERT(!m_visualUpdatesAllowed);
+ setVisualUpdatesAllowed(true);
}
String Document::encoding() const
@@ -1132,7 +1248,7 @@ void Document::setContentLanguage(const String& language)
m_contentLanguage = language;
// Recalculate style so language is used when selecting the initial font.
- styleSelectorChanged(DeferRecalcStyle);
+ styleResolverChanged(DeferRecalcStyle);
}
void Document::setXMLVersion(const String& version, ExceptionCode& ec)
@@ -1157,7 +1273,7 @@ void Document::setXMLStandalone(bool standalone, ExceptionCode& ec)
return;
}
- m_xmlStandalone = standalone;
+ m_xmlStandalone = standalone ? Standalone : NotStandalone;
}
void Document::setDocumentURI(const String& uri)
@@ -1198,7 +1314,7 @@ String Document::suggestedMIMEType() const
// * making it receive a rect as parameter, i.e. nodesFromRect(x, y, w, h);
// * making it receive the expading size of each direction separately,
// i.e. nodesFromRect(x, y, topSize, rightSize, bottomSize, leftSize);
-PassRefPtr<NodeList> Document::nodesFromRect(int centerX, int centerY, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding, bool ignoreClipping) const
+PassRefPtr<NodeList> Document::nodesFromRect(int centerX, int centerY, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding, bool ignoreClipping, bool allowShadowContent) const
{
// FIXME: Share code between this, elementFromPoint and caretRangeFromPoint.
if (!renderer())
@@ -1230,15 +1346,16 @@ PassRefPtr<NodeList> Document::nodesFromRect(int centerX, int centerY, unsigned
return handleZeroPadding(request, result);
}
- HitTestResult result(point, topPadding, rightPadding, bottomPadding, leftPadding);
- renderView()->layer()->hitTest(request, result);
+ enum ShadowContentFilterPolicy shadowContentFilterPolicy = allowShadowContent ? AllowShadowContent : DoNotAllowShadowContent;
+ HitTestResult result(point, topPadding, rightPadding, bottomPadding, leftPadding, shadowContentFilterPolicy);
+ renderView()->hitTest(request, result);
return StaticHashSetNodeList::adopt(result.rectBasedTestResult());
}
PassRefPtr<NodeList> Document::handleZeroPadding(const HitTestRequest& request, HitTestResult& result) const
{
- renderView()->layer()->hitTest(request, result);
+ renderView()->hitTest(request, result);
Node* node = result.innerNode();
if (!node)
@@ -1266,7 +1383,7 @@ static Node* nodeFromPoint(Frame* frame, RenderView* renderView, int x, int y, L
HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
HitTestResult result(point);
- renderView->layer()->hitTest(request, result);
+ renderView->hitTest(request, result);
if (localPoint)
*localPoint = result.localPoint();
@@ -1582,11 +1699,14 @@ void Document::recalcStyle(StyleChange change)
if (m_inStyleRecalc)
return; // Guard against re-entrancy. -dwh
- if (m_hasDirtyStyleSelector)
+ if (m_hasDirtyStyleResolver)
updateActiveStylesheets(RecalcStyleImmediately);
InspectorInstrumentationCookie cookie = InspectorInstrumentation::willRecalculateStyle(this);
+ if (m_elemSheet && m_elemSheet->internal()->usesRemUnits())
+ m_usesRemUnits = true;
+
m_inStyleRecalc = true;
suspendPostAttachCallbacks();
RenderWidget::suspendWidgetHierarchyUpdates();
@@ -1608,8 +1728,8 @@ void Document::recalcStyle(StyleChange change)
// style selector may set this again during recalc
m_hasNodesWithPlaceholderStyle = false;
- RefPtr<RenderStyle> documentStyle = CSSStyleSelector::styleForDocument(this, m_styleSelector ? m_styleSelector->fontSelector() : 0);
- StyleChange ch = diff(documentStyle.get(), renderer()->style());
+ RefPtr<RenderStyle> documentStyle = StyleResolver::styleForDocument(this, m_styleResolver ? m_styleResolver->fontSelector() : 0);
+ StyleChange ch = Node::diff(documentStyle.get(), renderer()->style(), this);
if (ch != NoChange)
renderer()->setStyle(documentStyle.release());
}
@@ -1627,7 +1747,7 @@ void Document::recalcStyle(StyleChange change)
bool layoutPending = view()->layoutPending() || renderer()->needsLayout();
// If we didn't update compositing layers because of layout(), we need to do so here.
if (!layoutPending)
- view()->updateCompositingLayers();
+ view()->updateCompositingLayersAfterStyleChange();
}
#endif
@@ -1639,7 +1759,7 @@ bail_out:
m_inStyleRecalc = false;
// Pseudo element removal and similar may only work with these flags still set. Reset them after the style recalc.
- if (m_styleSelector)
+ if (m_styleResolver)
resetCSSFeatureFlags();
if (frameView) {
@@ -1725,7 +1845,7 @@ void Document::updateLayoutIgnorePendingStylesheets()
HTMLElement* bodyElement = body();
if (bodyElement && !bodyElement->renderer() && m_pendingSheetLayout == NoLayoutWithPendingSheets) {
m_pendingSheetLayout = DidLayoutWithPendingSheets;
- styleSelectorChanged(RecalcStyleImmediately);
+ styleResolverChanged(RecalcStyleImmediately);
} else if (m_hasNodesWithPlaceholderStyle)
// 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
@@ -1744,14 +1864,14 @@ PassRefPtr<RenderStyle> Document::styleForElementIgnoringPendingStylesheets(Elem
bool oldIgnore = m_ignorePendingStylesheets;
m_ignorePendingStylesheets = true;
- RefPtr<RenderStyle> style = styleSelector()->styleForElement(element, element->parentNode() ? element->parentNode()->computedStyle() : 0);
+ RefPtr<RenderStyle> style = styleResolver()->styleForElement(element, element->parentNode() ? element->parentNode()->computedStyle() : 0);
m_ignorePendingStylesheets = oldIgnore;
return style.release();
}
PassRefPtr<RenderStyle> Document::styleForPage(int pageIndex)
{
- RefPtr<RenderStyle> style = styleSelector()->styleForPage(pageIndex);
+ RefPtr<RenderStyle> style = styleResolver()->styleForPage(pageIndex);
return style.release();
}
@@ -1778,6 +1898,7 @@ bool Document::isPageBoxVisible(int pageIndex)
void Document::pageSizeAndMarginsInPixels(int pageIndex, IntSize& pageSize, int& marginTop, int& marginRight, int& marginBottom, int& marginLeft)
{
RefPtr<RenderStyle> style = styleForPage(pageIndex);
+ RenderView* view = renderView();
int width = pageSize.width();
int height = pageSize.height();
@@ -1796,8 +1917,8 @@ void Document::pageSizeAndMarginsInPixels(int pageIndex, IntSize& pageSize, int&
LengthSize size = style->pageSize();
ASSERT(size.width().isFixed());
ASSERT(size.height().isFixed());
- width = size.width().calcValue(0);
- height = size.height().calcValue(0);
+ width = valueForLength(size.width(), 0, view);
+ height = valueForLength(size.height(), 0, view);
break;
}
default:
@@ -1807,17 +1928,10 @@ void Document::pageSizeAndMarginsInPixels(int pageIndex, IntSize& pageSize, int&
// The percentage is calculated with respect to the width even for margin top and bottom.
// http://www.w3.org/TR/CSS2/box.html#margin-properties
- marginTop = style->marginTop().isAuto() ? marginTop : style->marginTop().calcValue(width);
- marginRight = style->marginRight().isAuto() ? marginRight : style->marginRight().calcValue(width);
- marginBottom = style->marginBottom().isAuto() ? marginBottom : style->marginBottom().calcValue(width);
- marginLeft = style->marginLeft().isAuto() ? marginLeft : style->marginLeft().calcValue(width);
-}
-
-PassRefPtr<CSSValuePool> Document::cssValuePool() const
-{
- if (!m_cssValuePool)
- m_cssValuePool = CSSValuePool::create();
- return m_cssValuePool;
+ marginTop = style->marginTop().isAuto() ? marginTop : intValueForLength(style->marginTop(), width, view);
+ marginRight = style->marginRight().isAuto() ? marginRight : intValueForLength(style->marginRight(), width, view);
+ marginBottom = style->marginBottom().isAuto() ? marginBottom : intValueForLength(style->marginBottom(), width, view);
+ marginLeft = style->marginLeft().isAuto() ? marginLeft : intValueForLength(style->marginLeft(), width, view);
}
void Document::setIsViewSource(bool isViewSource)
@@ -1832,33 +1946,32 @@ void Document::setIsViewSource(bool isViewSource)
void Document::combineCSSFeatureFlags()
{
// Delay resetting the flags until after next style recalc since unapplying the style may not work without these set (this is true at least with before/after).
- m_usesSiblingRules = m_usesSiblingRules || m_styleSelector->usesSiblingRules();
- m_usesFirstLineRules = m_usesFirstLineRules || m_styleSelector->usesFirstLineRules();
- m_usesBeforeAfterRules = m_usesBeforeAfterRules || m_styleSelector->usesBeforeAfterRules();
- m_usesLinkRules = m_usesLinkRules || m_styleSelector->usesLinkRules();
+ m_usesSiblingRules = m_usesSiblingRules || m_styleResolver->usesSiblingRules();
+ m_usesFirstLineRules = m_usesFirstLineRules || m_styleResolver->usesFirstLineRules();
+ m_usesBeforeAfterRules = m_usesBeforeAfterRules || m_styleResolver->usesBeforeAfterRules();
+ m_usesLinkRules = m_usesLinkRules || m_styleResolver->usesLinkRules();
}
void Document::resetCSSFeatureFlags()
{
- m_usesSiblingRules = m_styleSelector->usesSiblingRules();
- m_usesFirstLineRules = m_styleSelector->usesFirstLineRules();
- m_usesBeforeAfterRules = m_styleSelector->usesBeforeAfterRules();
- m_usesLinkRules = m_styleSelector->usesLinkRules();
+ m_usesSiblingRules = m_styleResolver->usesSiblingRules();
+ m_usesFirstLineRules = m_styleResolver->usesFirstLineRules();
+ m_usesBeforeAfterRules = m_styleResolver->usesBeforeAfterRules();
+ m_usesLinkRules = m_styleResolver->usesLinkRules();
}
-void Document::createStyleSelector()
+void Document::createStyleResolver()
{
bool matchAuthorAndUserStyles = true;
if (Settings* docSettings = settings())
matchAuthorAndUserStyles = docSettings->authorAndUserStylesEnabled();
- m_styleSelector = adoptPtr(new CSSStyleSelector(this, m_styleSheets.get(), m_mappedElementSheet.get(), pageUserSheet(), pageGroupUserSheets(), m_userSheets.get(),
- !inQuirksMode(), matchAuthorAndUserStyles));
+ m_styleResolver = adoptPtr(new StyleResolver(this, matchAuthorAndUserStyles));
combineCSSFeatureFlags();
}
-
-inline void Document::clearStyleSelector()
+
+inline void Document::clearStyleResolver()
{
- m_styleSelector.clear();
+ m_styleResolver.clear();
}
void Document::attach()
@@ -2284,6 +2397,7 @@ void Document::implicitClose()
ImageLoader::dispatchPendingBeforeLoadEvents();
ImageLoader::dispatchPendingLoadEvents();
+ ImageLoader::dispatchPendingErrorEvents();
HTMLLinkElement::dispatchPendingLoadEvents();
HTMLStyleElement::dispatchPendingLoadEvents();
@@ -2307,11 +2421,11 @@ void Document::implicitClose()
printf("onload fired at %d\n", elapsedTime());
#endif
- m_processingLoadEvent = false;
-
// An event handler may have removed the frame
- if (!frame())
+ if (!frame()) {
+ m_processingLoadEvent = false;
return;
+ }
// Make sure both the initial layout and reflow happen after the onload
// fires. This will improve onload scores, and other browsers do it.
@@ -2320,6 +2434,7 @@ void Document::implicitClose()
if (frame()->navigationScheduler()->locationChangePending() && elapsedTime() < cLayoutScheduleThreshold) {
// 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_processingLoadEvent = false;
view()->unscheduleRelayout();
return;
}
@@ -2339,13 +2454,7 @@ void Document::implicitClose()
view()->layout();
}
- // If painting and compositing layer updates were suppressed pending the load event, do these actions now.
- if (renderer() && settings() && settings()->suppressesIncrementalRendering()) {
-#if USE(ACCELERATED_COMPOSITING)
- view()->updateCompositingLayers();
-#endif
- renderer()->repaint();
- }
+ m_processingLoadEvent = false;
#if PLATFORM(MAC) || PLATFORM(CHROMIUM)
if (f && renderObject && AXObjectCache::accessibilityEnabled()) {
@@ -2516,11 +2625,15 @@ void Document::updateBaseURL()
if (!m_baseURL.isValid())
m_baseURL = KURL();
- if (m_elemSheet)
- m_elemSheet->setFinalURL(m_baseURL);
- if (m_mappedElementSheet)
- m_mappedElementSheet->setFinalURL(m_baseURL);
-
+ if (m_elemSheet) {
+ // Element sheet is silly. It never contains anything.
+ ASSERT(!m_elemSheet->internal()->ruleCount());
+ bool usesRemUnits = m_elemSheet->internal()->usesRemUnits();
+ m_elemSheet = CSSStyleSheet::createInline(this, m_baseURL);
+ // FIXME: So we are not really the parser. The right fix is to eliminate the element sheet completely.
+ m_elemSheet->internal()->parserSetUsesRemUnits(usesRemUnits);
+ }
+
if (!equalIgnoringFragmentIdentifier(oldBaseURL, m_baseURL)) {
// Base URL change changes any relative visited links.
// FIXME: There are other URLs in the tree that would need to be re-evaluated on dynamic base URL change. Style should be invalidated too.
@@ -2585,6 +2698,76 @@ void Document::disableEval()
frame()->script()->disableEval();
}
+bool Document::canNavigate(Frame* targetFrame)
+{
+ if (!m_frame)
+ return false;
+
+ // FIXME: We shouldn't call this function without a target frame, but
+ // fast/forms/submit-to-blank-multiple-times.html depends on this function
+ // returning true when supplied with a 0 targetFrame.
+ if (!targetFrame)
+ return true;
+
+ // Frame-busting is generally allowed (unless we're sandboxed and prevent from frame-busting).
+ if (!isSandboxed(SandboxTopNavigation) && targetFrame == m_frame->tree()->top())
+ return true;
+
+ if (isSandboxed(SandboxNavigation)) {
+ if (targetFrame->tree()->isDescendantOf(m_frame))
+ return true;
+
+ printNavigationErrorMessage(targetFrame, url());
+ return false;
+ }
+
+ // This is the normal case. A document can navigate its decendant frames,
+ // or, more generally, a document can navigate a frame if the document is
+ // in the same origin as any of that frame's ancestors (in the frame
+ // hierarchy).
+ //
+ // See http://www.adambarth.com/papers/2008/barth-jackson-mitchell.pdf for
+ // historical information about this security check.
+ if (canAccessAncestor(securityOrigin(), targetFrame))
+ return true;
+
+ // Top-level frames are easier to navigate than other frames because they
+ // display their URLs in the address bar (in most browsers). However, there
+ // are still some restrictions on navigation to avoid nuisance attacks.
+ // Specifically, a document can navigate a top-level frame if that frame
+ // opened the document or if the document is the same-origin with any of
+ // the top-level frame's opener's ancestors (in the frame hierarchy).
+ //
+ // In both of these cases, the document performing the navigation is in
+ // some way related to the frame being navigate (e.g., by the "opener"
+ // and/or "parent" relation). Requiring some sort of relation prevents a
+ // document from navigating arbitrary, unrelated top-level frames.
+ if (!targetFrame->tree()->parent()) {
+ if (targetFrame == m_frame->loader()->opener())
+ return true;
+
+ if (canAccessAncestor(securityOrigin(), targetFrame->loader()->opener()))
+ return true;
+ }
+
+ printNavigationErrorMessage(targetFrame, url());
+ return false;
+}
+
+Frame* Document::findUnsafeParentScrollPropagationBoundary()
+{
+ Frame* currentFrame = m_frame;
+ Frame* ancestorFrame = currentFrame->tree()->parent();
+
+ while (ancestorFrame) {
+ if (!ancestorFrame->document()->securityOrigin()->canAccess(securityOrigin()))
+ return currentFrame;
+ currentFrame = ancestorFrame;
+ ancestorFrame = ancestorFrame->tree()->parent();
+ }
+ return 0;
+}
+
CSSStyleSheet* Document::pageUserSheet()
{
if (m_pageUserSheet)
@@ -2600,8 +2783,8 @@ CSSStyleSheet* Document::pageUserSheet()
// Parse the sheet and cache it.
m_pageUserSheet = CSSStyleSheet::createInline(this, settings()->userStyleSheetLocation());
- m_pageUserSheet->setIsUserStyleSheet(true);
- m_pageUserSheet->parseString(userSheetText, !inQuirksMode());
+ m_pageUserSheet->internal()->setIsUserStyleSheet(true);
+ m_pageUserSheet->internal()->parseString(userSheetText);
return m_pageUserSheet.get();
}
@@ -2609,7 +2792,7 @@ void Document::clearPageUserSheet()
{
if (m_pageUserSheet) {
m_pageUserSheet = 0;
- styleSelectorChanged(DeferRecalcStyle);
+ styleResolverChanged(DeferRecalcStyle);
}
}
@@ -2617,7 +2800,7 @@ void Document::updatePageUserSheet()
{
clearPageUserSheet();
if (pageUserSheet())
- styleSelectorChanged(RecalcStyleImmediately);
+ styleResolverChanged(RecalcStyleImmediately);
}
const Vector<RefPtr<CSSStyleSheet> >* Document::pageGroupUserSheets() const
@@ -2645,12 +2828,12 @@ const Vector<RefPtr<CSSStyleSheet> >* Document::pageGroupUserSheets() const
continue;
if (!UserContentURLPattern::matchesPatterns(url(), sheet->whitelist(), sheet->blacklist()))
continue;
- RefPtr<CSSStyleSheet> parsedSheet = CSSStyleSheet::createInline(const_cast<Document*>(this), sheet->url());
- parsedSheet->setIsUserStyleSheet(sheet->level() == UserStyleUserLevel);
- parsedSheet->parseString(sheet->source(), !inQuirksMode());
+ RefPtr<CSSStyleSheet> groupSheet = CSSStyleSheet::createInline(const_cast<Document*>(this), sheet->url());
if (!m_pageGroupUserSheets)
m_pageGroupUserSheets = adoptPtr(new Vector<RefPtr<CSSStyleSheet> >);
- m_pageGroupUserSheets->append(parsedSheet.release());
+ m_pageGroupUserSheets->append(groupSheet);
+ groupSheet->internal()->setIsUserStyleSheet(sheet->level() == UserStyleUserLevel);
+ groupSheet->internal()->parseString(sheet->source());
}
}
@@ -2662,7 +2845,7 @@ void Document::clearPageGroupUserSheets()
m_pageGroupUserSheetCacheValid = false;
if (m_pageGroupUserSheets && m_pageGroupUserSheets->size()) {
m_pageGroupUserSheets->clear();
- styleSelectorChanged(DeferRecalcStyle);
+ styleResolverChanged(DeferRecalcStyle);
}
}
@@ -2670,15 +2853,15 @@ void Document::updatePageGroupUserSheets()
{
clearPageGroupUserSheets();
if (pageGroupUserSheets() && pageGroupUserSheets()->size())
- styleSelectorChanged(RecalcStyleImmediately);
+ styleResolverChanged(RecalcStyleImmediately);
}
-void Document::addUserSheet(PassRefPtr<CSSStyleSheet> userSheet)
+void Document::addUserSheet(PassRefPtr<StyleSheetInternal> userSheet)
{
if (!m_userSheets)
m_userSheets = adoptPtr(new Vector<RefPtr<CSSStyleSheet> >);
- m_userSheets->append(userSheet);
- styleSelectorChanged(RecalcStyleImmediately);
+ m_userSheets->append(CSSStyleSheet::create(userSheet, this));
+ styleResolverChanged(RecalcStyleImmediately);
}
CSSStyleSheet* Document::elementSheet()
@@ -2688,13 +2871,6 @@ CSSStyleSheet* Document::elementSheet()
return m_elemSheet.get();
}
-CSSStyleSheet* Document::mappedElementSheet()
-{
- if (!m_mappedElementSheet)
- m_mappedElementSheet = CSSStyleSheet::createInline(this, m_baseURL);
- return m_mappedElementSheet.get();
-}
-
int Document::nodeAbsIndex(Node *node)
{
ASSERT(node->document() == this);
@@ -2728,7 +2904,7 @@ void Document::processHttpEquiv(const String& equiv, const String& content)
// -dwh
m_selectedStylesheetSet = content;
m_preferredStylesheetSet = content;
- styleSelectorChanged(DeferRecalcStyle);
+ styleResolverChanged(DeferRecalcStyle);
} else if (equalIgnoringCase(equiv, "refresh")) {
double delay;
String url;
@@ -2835,22 +3011,26 @@ void Document::processViewport(const String& features)
void Document::updateViewportArguments()
{
- if (page() && page()->mainFrame() == frame())
+ if (page() && page()->mainFrame() == frame()) {
+#ifndef NDEBUG
+ m_didDispatchViewportPropertiesChanged = true;
+#endif
page()->chrome()->dispatchViewportPropertiesDidChange(m_viewportArguments);
+ }
}
void Document::processReferrerPolicy(const String& policy)
{
ASSERT(!policy.isNull());
- m_referrerPolicy = SecurityPolicy::ReferrerPolicyDefault;
+ m_referrerPolicy = ReferrerPolicyDefault;
if (equalIgnoringCase(policy, "never"))
- m_referrerPolicy = SecurityPolicy::ReferrerPolicyNever;
+ m_referrerPolicy = ReferrerPolicyNever;
else if (equalIgnoringCase(policy, "always"))
- m_referrerPolicy = SecurityPolicy::ReferrerPolicyAlways;
+ m_referrerPolicy = ReferrerPolicyAlways;
else if (equalIgnoringCase(policy, "origin"))
- m_referrerPolicy = SecurityPolicy::ReferrerPolicyOrigin;
+ m_referrerPolicy = ReferrerPolicyOrigin;
}
MouseEventWithHitTestResults Document::prepareMouseEvent(const HitTestRequest& request, const LayoutPoint& documentPoint, const PlatformMouseEvent& event)
@@ -2861,7 +3041,7 @@ MouseEventWithHitTestResults Document::prepareMouseEvent(const HitTestRequest& r
return MouseEventWithHitTestResults(event, HitTestResult(LayoutPoint()));
HitTestResult result(documentPoint);
- renderView()->layer()->hitTest(request, result);
+ renderView()->hitTest(request, result);
if (!request.readOnly())
updateStyleIfNeeded();
@@ -3008,7 +3188,7 @@ String Document::selectedStylesheetSet() const
void Document::setSelectedStylesheetSet(const String& aString)
{
m_selectedStylesheetSet = aString;
- styleSelectorChanged(DeferRecalcStyle);
+ styleResolverChanged(DeferRecalcStyle);
}
// This method is called whenever a top-level stylesheet has finished loading.
@@ -3027,7 +3207,7 @@ void Document::removePendingSheet()
if (m_pendingStylesheets)
return;
- styleSelectorChanged(RecalcStyleIfNeeded);
+ styleResolverChanged(RecalcStyleIfNeeded);
if (ScriptableDocumentParser* parser = scriptableDocumentParser())
parser->executeScriptsWaitingForStylesheets();
@@ -3036,12 +3216,18 @@ void Document::removePendingSheet()
view()->scrollToFragment(m_url);
}
-void Document::styleSelectorChanged(StyleSelectorUpdateFlag updateFlag)
+void Document::evaluateMediaQueryList()
+{
+ if (m_mediaQueryMatcher)
+ m_mediaQueryMatcher->styleResolverChanged();
+}
+
+void Document::styleResolverChanged(StyleResolverUpdateFlag updateFlag)
{
// Don't bother updating, since we haven't loaded all our style info yet
// and haven't calculated the style selector for the first time.
- if (!attached() || (!m_didCalculateStyleSelector && !haveStylesheetsLoaded())) {
- m_styleSelector.clear();
+ if (!attached() || (!m_didCalculateStyleResolver && !haveStylesheetsLoaded())) {
+ m_styleResolver.clear();
return;
}
@@ -3085,8 +3271,7 @@ void Document::styleSelectorChanged(StyleSelectorUpdateFlag updateFlag)
view()->scheduleRelayout();
}
- if (m_mediaQueryMatcher)
- m_mediaQueryMatcher->styleSelectorChanged();
+ evaluateMediaQueryList();
}
void Document::addStyleSheetCandidateNode(Node* node, bool createdByParser)
@@ -3126,7 +3311,7 @@ void Document::removeStyleSheetCandidateNode(Node* node)
{
m_styleSheetCandidateNodes.remove(node);
}
-
+
void Document::collectActiveStylesheets(Vector<RefPtr<StyleSheet> >& sheets)
{
bool matchAuthorAndUserStyles = true;
@@ -3197,6 +3382,7 @@ void Document::collectActiveStylesheets(Vector<RefPtr<StyleSheet> >& sheets)
// Check to see if this sheet belongs to a styleset
// (thus making it PREFERRED or ALTERNATE rather than
// PERSISTENT).
+ AtomicString rel = e->getAttribute(relAttr);
if (!enabledViaScript && !title.isEmpty()) {
// Yes, we have a title.
if (m_preferredStylesheetSet.isEmpty()) {
@@ -3204,58 +3390,51 @@ void Document::collectActiveStylesheets(Vector<RefPtr<StyleSheet> >& sheets)
// we are NOT an alternate sheet, then establish
// us as the preferred set. Otherwise, just ignore
// this sheet.
- AtomicString rel = e->getAttribute(relAttr);
if (e->hasLocalName(styleTag) || !rel.contains("alternate"))
m_preferredStylesheetSet = m_selectedStylesheetSet = title;
}
if (title != m_preferredStylesheetSet)
sheet = 0;
}
+
+ if (rel.contains("alternate") && title.isEmpty())
+ sheet = 0;
}
if (sheet)
sheets.append(sheet);
}
}
-bool Document::testAddedStylesheetRequiresStyleRecalc(CSSStyleSheet* stylesheet)
+bool Document::testAddedStylesheetRequiresStyleRecalc(StyleSheetInternal* stylesheet)
{
- if (stylesheet->disabled())
- return false;
// See if all rules on the sheet are scoped to some specific ids or classes.
// Then test if we actually have any of those in the tree at the moment.
- // FIXME: Even we if we find some, we could just invalidate those subtrees instead of invalidating the entire style.
HashSet<AtomicStringImpl*> idScopes;
HashSet<AtomicStringImpl*> classScopes;
- if (!CSSStyleSelector::determineStylesheetSelectorScopes(stylesheet, idScopes, classScopes))
- return true;
- // Testing for classes is not particularly fast so bail out if there are more than a few.
- static const int maximumClassScopesToTest = 4;
- if (classScopes.size() > maximumClassScopesToTest)
+ if (!StyleResolver::determineStylesheetSelectorScopes(stylesheet, idScopes, classScopes))
return true;
- HashSet<AtomicStringImpl*>::iterator end = idScopes.end();
- for (HashSet<AtomicStringImpl*>::iterator it = idScopes.begin(); it != end; ++it) {
- AtomicStringImpl* id = *it;
- Element* idElement = getElementById(id);
- if (!idElement)
+ // Invalidate the subtrees that match the scopes.
+ Node* node = firstChild();
+ while (node) {
+ if (!node->isStyledElement()) {
+ node = node->traverseNextNode();
continue;
- if (containsMultipleElementsWithId(id))
- return true;
- idElement->setNeedsStyleRecalc();
- }
- end = classScopes.end();
- for (HashSet<AtomicStringImpl*>::iterator it = classScopes.begin(); it != end; ++it) {
- // FIXME: getElementsByClassName is not optimal for this. We should handle all classes in a single pass.
- RefPtr<NodeList> classElements = getElementsByClassName(*it);
- unsigned elementCount = classElements->length();
- for (unsigned i = 0; i < elementCount; ++i)
- classElements->item(i)->setNeedsStyleRecalc();
+ }
+ StyledElement* element = static_cast<StyledElement*>(node);
+ if (SelectorChecker::elementMatchesSelectorScopes(element, idScopes, classScopes)) {
+ element->setNeedsStyleRecalc();
+ // The whole subtree is now invalidated, we can skip to the next sibling.
+ node = node->traverseNextSibling();
+ continue;
+ }
+ node = node->traverseNextNode();
}
return false;
}
-
-void Document::analyzeStylesheetChange(StyleSelectorUpdateFlag updateFlag, const Vector<RefPtr<StyleSheet> >& newStylesheets, bool& requiresStyleSelectorReset, bool& requiresFullStyleRecalc)
+
+void Document::analyzeStylesheetChange(StyleResolverUpdateFlag updateFlag, const Vector<RefPtr<StyleSheet> >& newStylesheets, bool& requiresStyleResolverReset, bool& requiresFullStyleRecalc)
{
- requiresStyleSelectorReset = true;
+ requiresStyleResolverReset = true;
requiresFullStyleRecalc = true;
// Stylesheets of <style> elements that @import stylesheets are active but loading. We need to trigger a full recalc when such loads are done.
@@ -3273,7 +3452,7 @@ void Document::analyzeStylesheetChange(StyleSelectorUpdateFlag updateFlag, const
if (updateFlag != RecalcStyleIfNeeded)
return;
- if (!m_styleSelector)
+ if (!m_styleResolver)
return;
// See if we are just adding stylesheets.
@@ -3284,7 +3463,7 @@ void Document::analyzeStylesheetChange(StyleSelectorUpdateFlag updateFlag, const
if (m_styleSheets->item(i) != newStylesheets[i])
return;
}
- requiresStyleSelectorReset = false;
+ requiresStyleResolverReset = false;
// If we are already parsing the body and so may have significant amount of elements, put some effort into trying to avoid style recalcs.
if (!body() || m_hasNodesWithPlaceholderStyle)
@@ -3292,19 +3471,32 @@ void Document::analyzeStylesheetChange(StyleSelectorUpdateFlag updateFlag, const
for (unsigned i = oldStylesheetCount; i < newStylesheetCount; ++i) {
if (!newStylesheets[i]->isCSSStyleSheet())
return;
- if (testAddedStylesheetRequiresStyleRecalc(static_cast<CSSStyleSheet*>(newStylesheets[i].get())))
+ if (newStylesheets[i]->disabled())
+ continue;
+ if (testAddedStylesheetRequiresStyleRecalc(static_cast<CSSStyleSheet*>(newStylesheets[i].get())->internal()))
return;
}
requiresFullStyleRecalc = false;
}
-bool Document::updateActiveStylesheets(StyleSelectorUpdateFlag updateFlag)
+static bool styleSheetsUseRemUnits(const Vector<RefPtr<StyleSheet> >& sheets)
+{
+ for (unsigned i = 0; i < sheets.size(); ++i) {
+ if (!sheets[i]->isCSSStyleSheet())
+ continue;
+ if (static_cast<CSSStyleSheet*>(sheets[i].get())->internal()->usesRemUnits())
+ return true;
+ }
+ return false;
+}
+
+bool Document::updateActiveStylesheets(StyleResolverUpdateFlag updateFlag)
{
if (m_inStyleRecalc) {
// SVG <use> element may manage to invalidate style selector in the middle of a style recalc.
// https://bugs.webkit.org/show_bug.cgi?id=54344
// FIXME: This should be fixed in SVG and this code replaced with ASSERT(!m_inStyleRecalc).
- m_hasDirtyStyleSelector = true;
+ m_hasDirtyStyleResolver = true;
scheduleForcedStyleRecalc();
return false;
}
@@ -3314,20 +3506,21 @@ bool Document::updateActiveStylesheets(StyleSelectorUpdateFlag updateFlag)
StyleSheetVector newStylesheets;
collectActiveStylesheets(newStylesheets);
- bool requiresStyleSelectorReset;
+ bool requiresStyleResolverReset;
bool requiresFullStyleRecalc;
- analyzeStylesheetChange(updateFlag, newStylesheets, requiresStyleSelectorReset, requiresFullStyleRecalc);
+ analyzeStylesheetChange(updateFlag, newStylesheets, requiresStyleResolverReset, requiresFullStyleRecalc);
- if (requiresStyleSelectorReset)
- clearStyleSelector();
+ if (requiresStyleResolverReset)
+ clearStyleResolver();
else {
- m_styleSelector->appendAuthorStylesheets(m_styleSheets->length(), newStylesheets);
+ m_styleResolver->appendAuthorStylesheets(m_styleSheets->length(), newStylesheets);
resetCSSFeatureFlags();
}
m_styleSheets->swap(newStylesheets);
- m_didCalculateStyleSelector = true;
- m_hasDirtyStyleSelector = false;
+ m_usesRemUnits = styleSheetsUseRemUnits(m_styleSheets->vector());
+ m_didCalculateStyleResolver = true;
+ m_hasDirtyStyleResolver = false;
return requiresFullStyleRecalc;
}
@@ -3796,6 +3989,8 @@ void Document::addListenerTypeIfNeeded(const AtomicString& eventType)
#endif
else if (eventType == eventNames().scrollEvent)
addListenerType(SCROLL_LISTENER);
+ else if (eventType == eventNames().webkitRegionLayoutUpdateEvent)
+ addListenerType(REGIONLAYOUTUPDATE_LISTENER);
}
CSSStyleDeclaration* Document::getOverrideStyle(Element*, const String&)
@@ -4119,6 +4314,12 @@ void Document::documentWillSuspendForPageCache()
HashSet<Element*>::iterator end = m_documentSuspensionCallbackElements.end();
for (HashSet<Element*>::iterator i = m_documentSuspensionCallbackElements.begin(); i != end; ++i)
(*i)->documentWillSuspendForPageCache();
+
+#ifndef NDEBUG
+ // Clear the update flag to be able to check if the viewport arguments update
+ // is dispatched, after the document is restored from the page cache.
+ m_didDispatchViewportPropertiesChanged = false;
+#endif
}
void Document::documentDidResumeFromPageCache()
@@ -4139,8 +4340,6 @@ void Document::documentDidResumeFromPageCache()
ASSERT(m_frame);
m_frame->loader()->client()->dispatchDidBecomeFrameset(isFrameSet());
-
- updateViewportArguments();
}
void Document::registerForPageCacheSuspensionCallbacks(Element* e)
@@ -4353,7 +4552,7 @@ PassRefPtr<Attr> Document::createAttributeNS(const String& namespaceURI, const S
return 0;
}
- return Attr::create(0, this, Attribute::create(qName, StringImpl::empty()));
+ return Attr::create(this, qName, emptyString());
}
#if ENABLE(SVG)
@@ -4438,7 +4637,7 @@ HTMLAllCollection* Document::all()
HTMLCollection* Document::windowNamedItems(const AtomicString& name)
{
- OwnPtr<HTMLNameCollection>& collection = m_windowNamedItemCollections.add(name.impl(), nullptr).first->second;
+ OwnPtr<HTMLNameCollection>& collection = m_windowNamedItemCollections.add(name.impl(), nullptr).iterator->second;
if (!collection)
collection = HTMLNameCollection::create(this, WindowNamedItems, name);
return collection.get();
@@ -4446,7 +4645,7 @@ HTMLCollection* Document::windowNamedItems(const AtomicString& name)
HTMLCollection* Document::documentNamedItems(const AtomicString& name)
{
- OwnPtr<HTMLNameCollection>& collection = m_documentNamedItemCollections.add(name.impl(), nullptr).first->second;
+ OwnPtr<HTMLNameCollection>& collection = m_documentNamedItemCollections.add(name.impl(), nullptr).iterator->second;
if (!collection)
collection = HTMLNameCollection::create(this, DocumentNamedItems, name);
return collection.get();
@@ -4671,6 +4870,20 @@ bool Document::useSecureKeyboardEntryWhenActive() const
return m_useSecureKeyboardEntryWhenActive;
}
+static bool isEligibleForSeamless(Document* parent, Document* child)
+{
+ // It should not matter what we return for the top-most document.
+ if (!parent)
+ return false;
+ if (parent->isSandboxed(SandboxSeamlessIframes))
+ return false;
+ if (child->isSrcdocDocument())
+ return true;
+ if (parent->securityOrigin()->canAccess(child->securityOrigin()))
+ return true;
+ return parent->securityOrigin()->canRequest(child->url());
+}
+
void Document::initSecurityContext()
{
if (haveInitializedSecurityOrigin()) {
@@ -4707,22 +4920,33 @@ void Document::initSecurityContext()
if (Settings* settings = this->settings()) {
if (!settings->isWebSecurityEnabled()) {
- // Web security is turned off. We should let this document access every
- // other document. This is used primary by testing harnesses for web
- // sites.
- securityOrigin()->grantUniversalAccess();
-
+ // Web security is turned off. We should let this document access every
+ // other document. This is used primary by testing harnesses for web
+ // sites.
+ securityOrigin()->grantUniversalAccess();
} else if (settings->allowUniversalAccessFromFileURLs() && securityOrigin()->isLocal()) {
- // Some clients want file:// URLs to have universal access, but that
- // setting is dangerous for other clients.
- securityOrigin()->grantUniversalAccess();
+ // Some clients want file:// URLs to have universal access, but that
+ // setting is dangerous for other clients.
+ securityOrigin()->grantUniversalAccess();
} else if (!settings->allowFileAccessFromFileURLs() && securityOrigin()->isLocal()) {
- // Some clients want file:// URLs to have even tighter restrictions by
- // default, and not be able to access other local files.
- securityOrigin()->enforceFilePathSeparation();
+ // Some clients want file:// URLs to have even tighter restrictions by
+ // default, and not be able to access other local files.
+ // FIXME 81578: The naming of this is confusing. Files with restricted access to other local files
+ // still can have other privileges that can be remembered, thereby not making them unique origins.
+ securityOrigin()->enforceFilePathSeparation();
}
}
+ Document* parentDocument = ownerElement() ? ownerElement()->document() : 0;
+ if (parentDocument && m_frame->loader()->shouldTreatURLAsSrcdocDocument(url())) {
+ m_isSrcdocDocument = true;
+ setBaseURLOverride(parentDocument->baseURL());
+ }
+
+ // FIXME: What happens if we inherit the security origin? This check may need to be later.
+ // <iframe seamless src="about:blank"> likely won't work as-is.
+ m_mayDisplaySeamlessWithParent = isEligibleForSeamless(parentDocument, this);
+
if (!shouldInheritSecurityOriginFromOwner(m_url))
return;
@@ -4738,11 +4962,27 @@ void Document::initSecurityContext()
return;
}
+ if (isSandboxed(SandboxOrigin)) {
+ // If we're supposed to inherit our security origin from our owner,
+ // but we're also sandboxed, the only thing we inherit is the ability
+ // to load local resources. This lets about:blank iframes in file://
+ // URL documents load images and other resources from the file system.
+ if (ownerFrame->document()->securityOrigin()->canLoadLocalResources())
+ securityOrigin()->grantLoadLocalResources();
+ return;
+ }
+
m_cookieURL = ownerFrame->document()->cookieURL();
// We alias the SecurityOrigins to match Firefox, see Bug 15313
// https://bugs.webkit.org/show_bug.cgi?id=15313
setSecurityOrigin(ownerFrame->document()->securityOrigin());
- setContentSecurityPolicy(ownerFrame->document()->contentSecurityPolicy());
+}
+
+void Document::initContentSecurityPolicy()
+{
+ if (!m_frame->tree()->parent() || !shouldInheritSecurityOriginFromOwner(m_url))
+ return;
+ contentSecurityPolicy()->copyStateFrom(m_frame->tree()->parent()->document()->contentSecurityPolicy());
}
void Document::setSecurityOrigin(PassRefPtr<SecurityOrigin> origin)
@@ -4838,7 +5078,7 @@ CanvasRenderingContext* Document::getCSSCanvasContext(const String& type, const
HTMLCanvasElement* Document::getCSSCanvasElement(const String& name)
{
- RefPtr<HTMLCanvasElement>& element = m_cssCanvasElements.add(name, 0).first->second;
+ RefPtr<HTMLCanvasElement>& element = m_cssCanvasElements.add(name, 0).iterator->second;
if (!element)
element = HTMLCanvasElement::create(this);
return element.get();
@@ -4927,18 +5167,24 @@ void Document::pendingTasksTimerFired(Timer<Document>*)
}
}
-void Document::suspendScheduledTasks()
+void Document::suspendScheduledTasks(ActiveDOMObject::ReasonForSuspension reason)
{
+ ASSERT(!m_scheduledTasksAreSuspended);
+
suspendScriptedAnimationControllerCallbacks();
- suspendActiveDOMObjects(ActiveDOMObject::WillShowDialog);
+ suspendActiveDOMObjects(reason);
scriptRunner()->suspend();
m_pendingTasksTimer.stop();
if (m_parser)
m_parser->suspendScheduledTasks();
+
+ m_scheduledTasksAreSuspended = true;
}
void Document::resumeScheduledTasks()
{
+ ASSERT(m_scheduledTasksAreSuspended);
+
if (m_parser)
m_parser->resumeScheduledTasks();
if (!m_pendingTasks.isEmpty())
@@ -4946,6 +5192,8 @@ void Document::resumeScheduledTasks()
scriptRunner()->resume();
resumeActiveDOMObjects();
resumeScriptedAnimationControllerCallbacks();
+
+ m_scheduledTasksAreSuspended = false;
}
void Document::suspendScriptedAnimationControllerCallbacks()
@@ -5051,49 +5299,248 @@ bool Document::fullScreenIsAllowedForElement(Element* element) const
void Document::requestFullScreenForElement(Element* element, unsigned short flags, FullScreenCheckType checkType)
{
- do {
- if (!page() || !page()->settings()->fullScreenEnabled())
- break;
+ // The Mozilla Full Screen API <https://wiki.mozilla.org/Gecko:FullScreenAPI> has different requirements
+ // for full screen mode, and do not have the concept of a full screen element stack.
+ bool inLegacyMozillaMode = (flags & Element::LEGACY_MOZILLA_REQUEST);
+ do {
if (!element)
element = documentElement();
-
+
+ // 1. If any of the following conditions are true, terminate these steps and queue a task to fire
+ // an event named fullscreenerror with its bubbles attribute set to true on the context object's
+ // node document:
+
+ // The context object is not in a document.
+ if (!element->inDocument())
+ break;
+
+ // The context object's node document, or an ancestor browsing context's document does not have
+ // the fullscreen enabled flag set.
if (checkType == EnforceIFrameAllowFulScreenRequirement && !fullScreenIsAllowedForElement(element))
break;
-
+
+ // The context object's node document fullscreen element stack is not empty and its top element
+ // is not an ancestor of the context object. (NOTE: Ignore this requirement if the request was
+ // made via the legacy Mozilla-style API.)
+ if (!m_fullScreenElementStack.isEmpty() && !m_fullScreenElementStack.first()->contains(element) && !inLegacyMozillaMode)
+ break;
+
+ // A descendant browsing context's document has a non-empty fullscreen element stack.
+ bool descendentHasNonEmptyStack = false;
+ for (Frame* descendant = frame() ? frame()->tree()->traverseNext() : 0; descendant; descendant = descendant->tree()->traverseNext()) {
+ if (descendant->document()->webkitFullscreenElement()) {
+ descendentHasNonEmptyStack = true;
+ break;
+ }
+ }
+ if (descendentHasNonEmptyStack && !inLegacyMozillaMode)
+ break;
+
+ // This algorithm is not allowed to show a pop-up:
+ // An algorithm is allowed to show a pop-up if, in the task in which the algorithm is running, either:
+ // - an activation behavior is currently being processed whose click event was trusted, or
+ // - the event listener for a trusted click event is being handled.
if (!ScriptController::processingUserGesture())
break;
+
+ // There is a previously-established user preference, security risk, or platform limitation.
+ if (!page() || !page()->settings()->fullScreenEnabled())
+ break;
if (!page()->chrome()->client()->supportsFullScreenForElement(element, flags & Element::ALLOW_KEYBOARD_INPUT))
break;
-
+
+ // 2. Let doc be element's node document. (i.e. "this")
+ Document* currentDoc = this;
+
+ // 3. Let docs be all doc's ancestor browsing context's documents (if any) and doc.
+ Deque<Document*> docs;
+
+ do {
+ docs.prepend(currentDoc);
+ currentDoc = currentDoc->ownerElement() ? currentDoc->ownerElement()->document() : 0;
+ } while (currentDoc);
+
+ // 4. For each document in docs, run these substeps:
+ Deque<Document*>::iterator current = docs.begin(), following = docs.begin();
+
+ do {
+ ++following;
+
+ // 1. Let following document be the document after document in docs, or null if there is no
+ // such document.
+ Document* currentDoc = *current;
+ Document* followingDoc = following != docs.end() ? *following : 0;
+
+ // 2. If following document is null, push context object on document's fullscreen element
+ // stack, and queue a task to fire an event named fullscreenchange with its bubbles attribute
+ // set to true on the document.
+ if (!followingDoc) {
+ currentDoc->pushFullscreenElementStack(element);
+ addDocumentToFullScreenChangeEventQueue(currentDoc);
+ continue;
+ }
+
+ // 3. Otherwise, if document's fullscreen element stack is either empty or its top element
+ // is not following document's browsing context container,
+ Element* topElement = currentDoc->webkitFullscreenElement();
+ if (!topElement || topElement != followingDoc->ownerElement()) {
+ // ...push following document's browsing context container on document's fullscreen element
+ // stack, and queue a task to fire an event named fullscreenchange with its bubbles attribute
+ // set to true on document.
+ currentDoc->pushFullscreenElementStack(followingDoc->ownerElement());
+ addDocumentToFullScreenChangeEventQueue(currentDoc);
+ continue;
+ }
+
+ // 4. Otherwise, do nothing for this document. It stays the same.
+ } while (++current != docs.end());
+
+ // 5. Return, and run the remaining steps asynchronously.
+ // 6. Optionally, perform some animation.
m_areKeysEnabledInFullScreen = flags & Element::ALLOW_KEYBOARD_INPUT;
page()->chrome()->client()->enterFullScreenForElement(element);
+
+ // 7. Optionally, display a message indicating how the user can exit displaying the context object fullscreen.
return;
} while (0);
-
+
m_fullScreenErrorEventTargetQueue.append(element ? element : documentElement());
m_fullScreenChangeDelayTimer.startOneShot(0);
}
void Document::webkitCancelFullScreen()
{
- if (!page() || !m_fullScreenElement)
+ // The Mozilla "cancelFullScreen()" API behaves like the W3C "fully exit fullscreen" behavior, which
+ // is defined as:
+ // "To fully exit fullscreen act as if the exitFullscreen() method was invoked on the top-level browsing
+ // context's document and subsequently empty that document's fullscreen element stack."
+ if (!topDocument()->webkitFullscreenElement())
return;
+
+ // To achieve that aim, remove all the elements from the top document's stack except for the first before
+ // calling webkitExitFullscreen():
+ Deque<RefPtr<Element> > replacementFullscreenElementStack;
+ replacementFullscreenElementStack.prepend(topDocument()->webkitFullscreenElement());
+ topDocument()->m_fullScreenElementStack.swap(replacementFullscreenElementStack);
+
+ topDocument()->webkitExitFullscreen();
+}
+
+void Document::webkitExitFullscreen()
+{
+ // The exitFullscreen() method must run these steps:
- page()->chrome()->client()->exitFullScreenForElement(m_fullScreenElement.get());
+ // 1. Let doc be the context object. (i.e. "this")
+ Document* currentDoc = this;
+
+ // 2. If doc's fullscreen element stack is empty, terminate these steps.
+ if (m_fullScreenElementStack.isEmpty())
+ return;
+
+ // 3. Let descendants be all the doc's descendant browsing context's documents with a non-empty fullscreen
+ // element stack (if any), ordered so that the child of the doc is last and the document furthest
+ // away from the doc is first.
+ Deque<RefPtr<Document> > descendants;
+ for (Frame* descendant = frame() ? frame()->tree()->traverseNext() : 0; descendant; descendant = descendant->tree()->traverseNext()) {
+ if (descendant->document()->webkitFullscreenElement())
+ descendants.prepend(descendant->document());
+ }
+
+ // 4. For each descendant in descendants, empty descendant's fullscreen element stack, and queue a
+ // task to fire an event named fullscreenchange with its bubbles attribute set to true on descendant.
+ for (Deque<RefPtr<Document> >::iterator i = descendants.begin(); i != descendants.end(); ++i) {
+ (*i)->clearFullscreenElementStack();
+ addDocumentToFullScreenChangeEventQueue(i->get());
+ }
+
+ // 5. While doc is not null, run these substeps:
+ Element* newTop = 0;
+ while (currentDoc) {
+ // 1. Pop the top element of doc's fullscreen element stack.
+ currentDoc->popFullscreenElementStack();
+
+ // If doc's fullscreen element stack is non-empty and the element now at the top is either
+ // not in a document or its node document is not doc, repeat this substep.
+ newTop = currentDoc->webkitFullscreenElement();
+ if (newTop && (!newTop->inDocument() || newTop->document() != currentDoc))
+ continue;
+
+ // 2. Queue a task to fire an event named fullscreenchange with its bubbles attribute set to true
+ // on doc.
+ Node* target = currentDoc->m_fullScreenElement.get();
+ if (!target)
+ target = currentDoc;
+ addDocumentToFullScreenChangeEventQueue(currentDoc);
+
+ // 3. If doc's fullscreen element stack is empty and doc's browsing context has a browsing context
+ // container, set doc to that browsing context container's node document.
+ if (!newTop && currentDoc->ownerElement())
+ currentDoc = currentDoc->ownerElement()->document();
+
+ // 4. Otherwise, set doc to null.
+ currentDoc = 0;
+ }
+
+ // 6. Return, and run the remaining steps asynchronously.
+ // 7. Optionally, perform some animation.
+
+ // Only exit out of full screen window mode if there are no remaining elements in the
+ // full screen stack.
+ if (!newTop) {
+ page()->chrome()->client()->exitFullScreenForElement(m_fullScreenElement.get());
+ return;
+ }
+
+ // Otherwise, notify the chrome of the new full screen element.
+ page()->chrome()->client()->enterFullScreenForElement(newTop);
+}
+
+bool Document::webkitFullscreenEnabled() const
+{
+ // 4. The fullscreenEnabled attribute must return true if the context object and all ancestor
+ // browsing context's documents have their fullscreen enabled flag set, or false otherwise.
+
+ // Top-level browsing contexts are implied to have their allowFullScreen attribute set.
+ HTMLFrameOwnerElement* owner = ownerElement();
+ if (!owner)
+ return true;
+
+ do {
+ if (!owner->isFrameElementBase())
+ continue;
+
+ if (!static_cast<HTMLFrameElementBase*>(owner)->allowFullScreen())
+ return false;
+ } while ((owner = owner->document()->ownerElement()));
+
+ return true;
}
void Document::webkitWillEnterFullScreenForElement(Element* element)
{
+ if (!attached() || inPageCache())
+ return;
+
ASSERT(element);
- ASSERT(page() && page()->settings()->fullScreenEnabled());
+
+ // Protect against being called after the document has been removed from the page.
+ if (!page())
+ return;
+
+ ASSERT(page()->settings()->fullScreenEnabled());
if (m_fullScreenRenderer)
m_fullScreenRenderer->unwrapRenderer();
m_fullScreenElement = element;
+#if USE(NATIVE_FULLSCREEN_VIDEO)
+ if (element && element->isMediaElement())
+ return;
+#endif
+
// Create a placeholder block for a the full-screen element, to keep the page from reflowing
// when the element is removed from the normal flow. Only do this for a RenderBox, as only
// a box will have a frameRect. The placeholder will be created in setFullScreenRenderer()
@@ -5112,30 +5559,47 @@ void Document::webkitWillEnterFullScreenForElement(Element* element)
recalcStyle(Force);
}
-
+
void Document::webkitDidEnterFullScreenForElement(Element*)
{
+ if (!m_fullScreenElement)
+ return;
+
+ if (!attached() || inPageCache())
+ return;
+
m_fullScreenElement->didBecomeFullscreenElement();
- m_fullScreenChangeEventTargetQueue.append(m_fullScreenElement);
m_fullScreenChangeDelayTimer.startOneShot(0);
}
void Document::webkitWillExitFullScreenForElement(Element*)
{
- m_fullScreenElement->setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(false);
-
+ if (!m_fullScreenElement)
+ return;
+
+ if (!attached() || inPageCache())
+ return;
+
m_fullScreenElement->willStopBeingFullscreenElement();
}
void Document::webkitDidExitFullScreenForElement(Element*)
{
+ if (!m_fullScreenElement)
+ return;
+
+ if (!attached() || inPageCache())
+ return;
+
+ m_fullScreenElement->setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(false);
+
m_areKeysEnabledInFullScreen = false;
if (m_fullScreenRenderer)
m_fullScreenRenderer->unwrapRenderer();
- m_fullScreenChangeEventTargetQueue.append(m_fullScreenElement.release());
+ m_fullScreenElement = 0;
scheduleForcedStyleRecalc();
m_fullScreenChangeDelayTimer.startOneShot(0);
@@ -5201,28 +5665,34 @@ void Document::setFullScreenRendererBackgroundColor(Color backgroundColor)
void Document::fullScreenChangeDelayTimerFired(Timer<Document>*)
{
- while (!m_fullScreenChangeEventTargetQueue.isEmpty()) {
- RefPtr<Element> element = m_fullScreenChangeEventTargetQueue.takeFirst();
- if (!element)
- element = documentElement();
+ Deque<RefPtr<Node> > changeQueue;
+ m_fullScreenChangeEventTargetQueue.swap(changeQueue);
+
+ while (!changeQueue.isEmpty()) {
+ RefPtr<Node> node = changeQueue.takeFirst();
+ if (!node)
+ node = documentElement();
// If the element was removed from our tree, also message the documentElement.
- if (!contains(element.get()))
- m_fullScreenChangeEventTargetQueue.append(documentElement());
+ if (!contains(node.get()))
+ changeQueue.append(documentElement());
- element->dispatchEvent(Event::create(eventNames().webkitfullscreenchangeEvent, true, false));
+ node->dispatchEvent(Event::create(eventNames().webkitfullscreenchangeEvent, true, false));
}
- while (!m_fullScreenErrorEventTargetQueue.isEmpty()) {
- RefPtr<Element> element = m_fullScreenErrorEventTargetQueue.takeFirst();
- if (!element)
- element = documentElement();
+ Deque<RefPtr<Node> > errorQueue;
+ m_fullScreenErrorEventTargetQueue.swap(errorQueue);
+
+ while (!errorQueue.isEmpty()) {
+ RefPtr<Node> node = errorQueue.takeFirst();
+ if (!node)
+ node = documentElement();
- // If the element was removed from our tree, also message the documentElement.
- if (!contains(element.get()))
- m_fullScreenErrorEventTargetQueue.append(documentElement());
+ // If the node was removed from our tree, also message the documentElement.
+ if (!contains(node.get()))
+ errorQueue.append(documentElement());
- element->dispatchEvent(Event::create(eventNames().webkitfullscreenerrorEvent, true, false));
+ node->dispatchEvent(Event::create(eventNames().webkitfullscreenerrorEvent, true, false));
}
}
@@ -5263,6 +5733,35 @@ void Document::setAnimatingFullScreen(bool flag)
scheduleForcedStyleRecalc();
}
}
+
+void Document::clearFullscreenElementStack()
+{
+ m_fullScreenElementStack.clear();
+}
+
+void Document::popFullscreenElementStack()
+{
+ if (m_fullScreenElementStack.isEmpty())
+ return;
+
+ m_fullScreenElementStack.removeFirst();
+}
+
+void Document::pushFullscreenElementStack(Element* element)
+{
+ m_fullScreenElementStack.prepend(element);
+}
+
+void Document::addDocumentToFullScreenChangeEventQueue(Document* doc)
+{
+ ASSERT(doc);
+ Node* target = doc->webkitFullscreenElement();
+ if (!target)
+ target = doc->webkitCurrentFullScreenElement();
+ if (!target)
+ target = doc;
+ m_fullScreenChangeEventTargetQueue.append(target);
+}
#endif
void Document::decrementLoadEventDelayCount()
@@ -5281,12 +5780,22 @@ void Document::loadEventDelayTimerFired(Timer<Document>*)
}
#if ENABLE(REQUEST_ANIMATION_FRAME)
-int Document::webkitRequestAnimationFrame(PassRefPtr<RequestAnimationFrameCallback> callback, Element* animationElement)
+int Document::webkitRequestAnimationFrame(PassRefPtr<RequestAnimationFrameCallback> callback)
{
- if (!m_scriptedAnimationController)
- m_scriptedAnimationController = ScriptedAnimationController::create(this, page()->displayID());
+ if (!m_scriptedAnimationController) {
+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+ m_scriptedAnimationController = ScriptedAnimationController::create(this, page() ? page()->displayID() : 0);
+#else
+ m_scriptedAnimationController = ScriptedAnimationController::create(this, 0);
+#endif
+ // It's possible that the Page may have suspended scripted animations before
+ // we were created. We need to make sure that we don't start up the animation
+ // controller on a background tab, for example.
+ if (!page() || page()->scriptedAnimationsSuspended())
+ m_scriptedAnimationController->suspend();
+ }
- return m_scriptedAnimationController->registerCallback(callback, animationElement);
+ return m_scriptedAnimationController->registerCallback(callback);
}
void Document::webkitCancelAnimationFrame(int id)
@@ -5296,11 +5805,11 @@ void Document::webkitCancelAnimationFrame(int id)
m_scriptedAnimationController->cancelCallback(id);
}
-void Document::serviceScriptedAnimations(DOMTimeStamp time)
+void Document::serviceScriptedAnimations(double monotonicAnimationStartTime)
{
if (!m_scriptedAnimationController)
return;
- m_scriptedAnimationController->serviceScriptedAnimations(time);
+ m_scriptedAnimationController->serviceScriptedAnimations(monotonicAnimationStartTime);
}
#endif
@@ -5377,11 +5886,22 @@ void Document::didRemoveTouchEventHandler()
mainFrame->notifyChromeClientTouchEventHandlerCountChanged();
}
-bool Document::visualUpdatesAllowed() const
+HTMLIFrameElement* Document::seamlessParentIFrame() const
+{
+ if (!shouldDisplaySeamlesslyWithParent())
+ return 0;
+
+ HTMLFrameOwnerElement* ownerElement = this->ownerElement();
+ ASSERT(ownerElement->hasTagName(iframeTag));
+ return static_cast<HTMLIFrameElement*>(ownerElement);
+}
+
+bool Document::shouldDisplaySeamlesslyWithParent() const
{
- return !settings()
- || !settings()->suppressesIncrementalRendering()
- || loadEventFinished();
+ HTMLFrameOwnerElement* ownerElement = this->ownerElement();
+ if (!ownerElement)
+ return false;
+ return m_mayDisplaySeamlessWithParent && ownerElement->hasTagName(iframeTag) && ownerElement->fastHasAttribute(seamlessAttr);
}
DocumentLoader* Document::loader() const
@@ -5408,12 +5928,12 @@ PassRefPtr<NodeList> Document::getItems(const String& typeNames)
// In this case we need to create an unique string identifier to map such request in the cache.
String localTypeNames = typeNames.isNull() ? String("http://webkit.org/microdata/undefinedItemType") : typeNames;
- pair<NodeListsNodeData::MicroDataItemListCache::iterator, bool> result = nodeLists->m_microDataItemListCache.add(localTypeNames, 0);
- if (!result.second)
- return PassRefPtr<NodeList>(result.first->second);
+ NodeListsNodeData::MicroDataItemListCache::AddResult result = nodeLists->m_microDataItemListCache.add(localTypeNames, 0);
+ if (!result.isNewEntry)
+ return PassRefPtr<NodeList>(result.iterator->second);
RefPtr<MicroDataItemList> list = MicroDataItemList::create(this, typeNames);
- result.first->second = list.get();
+ result.iterator->second = list.get();
return list.release();
}
@@ -5430,4 +5950,27 @@ void Document::removeCachedMicroDataItemList(MicroDataItemList* list, const Stri
}
#endif
+IntSize Document::viewportSize() const
+{
+ if (!view())
+ return IntSize();
+ return view()->visibleContentRect(/* includeScrollbars */ true).size();
+}
+
+Node* eventTargetNodeForDocument(Document* doc)
+{
+ if (!doc)
+ return 0;
+ Node* node = doc->focusedNode();
+ if (!node && doc->isPluginDocument()) {
+ PluginDocument* pluginDocument = static_cast<PluginDocument*>(doc);
+ node = pluginDocument->pluginNode();
+ }
+ if (!node && doc->isHTMLDocument())
+ node = doc->body();
+ if (!node)
+ node = doc->documentElement();
+ return node;
+}
+
} // namespace WebCore