diff options
Diffstat (limited to 'Source/WebCore/html/HTMLBodyElement.cpp')
-rw-r--r-- | Source/WebCore/html/HTMLBodyElement.cpp | 306 |
1 files changed, 185 insertions, 121 deletions
diff --git a/Source/WebCore/html/HTMLBodyElement.cpp b/Source/WebCore/html/HTMLBodyElement.cpp index 9da1410fe..b1ee9c4c2 100644 --- a/Source/WebCore/html/HTMLBodyElement.cpp +++ b/Source/WebCore/html/HTMLBodyElement.cpp @@ -3,7 +3,7 @@ * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2000 Simon Hausmann (hausmann@kde.org) * (C) 2001 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2004, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2004-2017 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -24,18 +24,20 @@ #include "config.h" #include "HTMLBodyElement.h" -#include "Attribute.h" #include "CSSImageValue.h" #include "CSSParser.h" #include "CSSValueKeywords.h" +#include "DOMWindow.h" +#include "DOMWrapperWorld.h" #include "EventNames.h" #include "Frame.h" #include "FrameView.h" -#include "HTMLFrameElementBase.h" +#include "HTMLFrameElement.h" +#include "HTMLIFrameElement.h" #include "HTMLNames.h" #include "HTMLParserIdioms.h" -#include "Page.h" #include "StyleProperties.h" +#include <wtf/NeverDestroyed.h> namespace WebCore { @@ -47,14 +49,21 @@ HTMLBodyElement::HTMLBodyElement(const QualifiedName& tagName, Document& documen ASSERT(hasTagName(bodyTag)); } -PassRefPtr<HTMLBodyElement> HTMLBodyElement::create(Document& document) +bool HTMLBodyElement::isFirstBodyElementOfDocument() const { - return adoptRef(new HTMLBodyElement(bodyTag, document)); + // By spec http://dev.w3.org/csswg/cssom-view/#the-html-body-element + // "The HTML body element is the first body HTML element child of the root HTML element html." + return document().body() == this; } -PassRefPtr<HTMLBodyElement> HTMLBodyElement::create(const QualifiedName& tagName, Document& document) +Ref<HTMLBodyElement> HTMLBodyElement::create(Document& document) { - return adoptRef(new HTMLBodyElement(tagName, document)); + return adoptRef(*new HTMLBodyElement(bodyTag, document)); +} + +Ref<HTMLBodyElement> HTMLBodyElement::create(const QualifiedName& tagName, Document& document) +{ + return adoptRef(*new HTMLBodyElement(tagName, document)); } HTMLBodyElement::~HTMLBodyElement() @@ -73,9 +82,9 @@ void HTMLBodyElement::collectStyleForPresentationAttribute(const QualifiedName& if (name == backgroundAttr) { String url = stripLeadingAndTrailingHTMLSpaces(value); if (!url.isEmpty()) { - auto imageValue = CSSImageValue::create(document().completeURL(url).string()); + auto imageValue = CSSImageValue::create(document().completeURL(url)); imageValue.get().setInitiator(localName()); - style.setProperty(CSSProperty(CSSPropertyBackgroundImage, std::move(imageValue))); + style.setProperty(CSSProperty(CSSPropertyBackgroundImage, WTFMove(imageValue))); } } else if (name == marginwidthAttr || name == leftmarginAttr) { addHTMLLengthToStyle(style, CSSPropertyMarginRight, value); @@ -88,12 +97,56 @@ void HTMLBodyElement::collectStyleForPresentationAttribute(const QualifiedName& } else if (name == textAttr) { addHTMLColorToStyle(style, CSSPropertyColor, value); } else if (name == bgpropertiesAttr) { - if (equalIgnoringCase(value, "fixed")) + if (equalLettersIgnoringASCIICase(value, "fixed")) addPropertyToPresentationAttributeStyle(style, CSSPropertyBackgroundAttachment, CSSValueFixed); } else HTMLElement::collectStyleForPresentationAttribute(name, value, style); } +HTMLElement::EventHandlerNameMap HTMLBodyElement::createWindowEventHandlerNameMap() +{ + static const QualifiedName* const table[] = { + &onbeforeunloadAttr, + &onblurAttr, + &onerrorAttr, + &onfocusAttr, + &onfocusinAttr, + &onfocusoutAttr, + &onhashchangeAttr, + &onlanguagechangeAttr, + &onloadAttr, + &onmessageAttr, + &onofflineAttr, + &ononlineAttr, + &onorientationchangeAttr, + &onpagehideAttr, + &onpageshowAttr, + &onpopstateAttr, + &onresizeAttr, + &onscrollAttr, + &onstorageAttr, + &onunloadAttr, + &onwebkitmouseforcechangedAttr, + &onwebkitmouseforcedownAttr, + &onwebkitmouseforceupAttr, + &onwebkitmouseforcewillbeginAttr, + &onwebkitwillrevealbottomAttr, + &onwebkitwillrevealleftAttr, + &onwebkitwillrevealrightAttr, + &onwebkitwillrevealtopAttr, + }; + + EventHandlerNameMap map; + populateEventHandlerNameMap(map, table); + return map; +} + +const AtomicString& HTMLBodyElement::eventNameForWindowEventHandlerAttribute(const QualifiedName& attributeName) +{ + static NeverDestroyed<EventHandlerNameMap> map = createWindowEventHandlerNameMap(); + return eventNameForEventHandlerAttribute(attributeName, map.get()); +} + void HTMLBodyElement::parseAttribute(const QualifiedName& name, const AtomicString& value) { if (name == vlinkAttr || name == alinkAttr || name == linkAttr) { @@ -105,8 +158,8 @@ void HTMLBodyElement::parseAttribute(const QualifiedName& name, const AtomicStri else document().resetActiveLinkColor(); } else { - RGBA32 color; - if (CSSParser::parseColor(color, value, !document().inQuirksMode())) { + Color color = CSSParser::parseColor(value, !document().inQuirksMode()); + if (color.isValid()) { if (name == linkAttr) document().setLinkColor(color); else if (name == vlinkAttr) @@ -116,64 +169,48 @@ void HTMLBodyElement::parseAttribute(const QualifiedName& name, const AtomicStri } } - setNeedsStyleRecalc(); - } else if (name == onloadAttr) - document().setWindowAttributeEventListener(eventNames().loadEvent, name, value); - else if (name == onbeforeunloadAttr) - document().setWindowAttributeEventListener(eventNames().beforeunloadEvent, name, value); - else if (name == onunloadAttr) - document().setWindowAttributeEventListener(eventNames().unloadEvent, name, value); - else if (name == onpagehideAttr) - document().setWindowAttributeEventListener(eventNames().pagehideEvent, name, value); - else if (name == onpageshowAttr) - document().setWindowAttributeEventListener(eventNames().pageshowEvent, name, value); - else if (name == onpopstateAttr) - document().setWindowAttributeEventListener(eventNames().popstateEvent, name, value); - else if (name == onblurAttr) - document().setWindowAttributeEventListener(eventNames().blurEvent, name, value); - else if (name == onfocusAttr) - document().setWindowAttributeEventListener(eventNames().focusEvent, name, value); -#if ENABLE(ORIENTATION_EVENTS) - else if (name == onorientationchangeAttr) - document().setWindowAttributeEventListener(eventNames().orientationchangeEvent, name, value); -#endif - else if (name == onhashchangeAttr) - document().setWindowAttributeEventListener(eventNames().hashchangeEvent, name, value); - else if (name == onresizeAttr) - document().setWindowAttributeEventListener(eventNames().resizeEvent, name, value); - else if (name == onscrollAttr) - document().setWindowAttributeEventListener(eventNames().scrollEvent, name, value); - else if (name == onselectionchangeAttr) - document().setAttributeEventListener(eventNames().selectionchangeEvent, name, value); - else if (name == onstorageAttr) - document().setWindowAttributeEventListener(eventNames().storageEvent, name, value); - else if (name == ononlineAttr) - document().setWindowAttributeEventListener(eventNames().onlineEvent, name, value); - else if (name == onofflineAttr) - document().setWindowAttributeEventListener(eventNames().offlineEvent, name, value); - else - HTMLElement::parseAttribute(name, value); + invalidateStyleForSubtree(); + return; + } + + if (name == onselectionchangeAttr) { + document().setAttributeEventListener(eventNames().selectionchangeEvent, name, value, mainThreadNormalWorld()); + return; + } + + auto& eventName = eventNameForWindowEventHandlerAttribute(name); + if (!eventName.isNull()) { + document().setWindowAttributeEventListener(eventName, name, value, mainThreadNormalWorld()); + return; + } + + HTMLElement::parseAttribute(name, value); } Node::InsertionNotificationRequest HTMLBodyElement::insertedInto(ContainerNode& insertionPoint) { HTMLElement::insertedInto(insertionPoint); - if (!insertionPoint.inDocument()) + if (!insertionPoint.isConnected()) return InsertionDone; // FIXME: It's surprising this is web compatible since it means a marginwidth and marginheight attribute can // magically appear on the <body> of all documents embedded through <iframe> or <frame>. // FIXME: Perhaps this code should be in attach() instead of here. - Element* ownerElement = document().ownerElement(); - if (ownerElement && isHTMLFrameElementBase(*ownerElement)) { - HTMLFrameElementBase& ownerFrameElement = toHTMLFrameElementBase(*ownerElement); - int marginWidth = ownerFrameElement.marginWidth(); - if (marginWidth != -1) - setIntegralAttribute(marginwidthAttr, marginWidth); - int marginHeight = ownerFrameElement.marginHeight(); - if (marginHeight != -1) - setIntegralAttribute(marginheightAttr, marginHeight); - } + auto* ownerElement = document().ownerElement(); + if (!is<HTMLFrameElementBase>(ownerElement)) + return InsertionDone; + + auto& ownerFrameElement = downcast<HTMLFrameElementBase>(*ownerElement); + + // Read values from the owner before setting any attributes, since setting an attribute can run arbitrary + // JavaScript, which might delete the owner element. + int marginWidth = ownerFrameElement.marginWidth(); + int marginHeight = ownerFrameElement.marginHeight(); + + if (marginWidth != -1) + setIntegralAttribute(marginwidthAttr, marginWidth); + if (marginHeight != -1) + setIntegralAttribute(marginheightAttr, marginHeight); return InsertionDone; } @@ -188,9 +225,9 @@ bool HTMLBodyElement::supportsFocus() const return hasEditableStyle() || HTMLElement::supportsFocus(); } -static int adjustForZoom(int value, Frame& frame) +static int adjustForZoom(int value, const Frame& frame) { - float zoomFactor = frame.pageZoomFactor() * frame.frameScaleFactor(); + double zoomFactor = frame.pageZoomFactor() * frame.frameScaleFactor(); if (zoomFactor == 1) return value; // Needed because of truncation (rather than rounding) when scaling up. @@ -201,91 +238,118 @@ static int adjustForZoom(int value, Frame& frame) int HTMLBodyElement::scrollLeft() { - document().updateLayoutIgnorePendingStylesheets(); - Frame* frame = document().frame(); - if (!frame) - return 0; - FrameView* view = frame->view(); - if (!view) - return 0; -#if PLATFORM(IOS) - return adjustForZoom(view->actualScrollX(), *frame); -#else - return adjustForZoom(view->scrollX(), *frame); -#endif + if (isFirstBodyElementOfDocument()) { + document().updateLayoutIgnorePendingStylesheets(); + Frame* frame = document().frame(); + if (!frame) + return 0; + FrameView* view = frame->view(); + if (!view) + return 0; + return adjustForZoom(view->contentsScrollPosition().x(), *frame); + } + return HTMLElement::scrollLeft(); } void HTMLBodyElement::setScrollLeft(int scrollLeft) { - document().updateLayoutIgnorePendingStylesheets(); - Frame* frame = document().frame(); - if (!frame) - return; - FrameView* view = frame->view(); - if (!view) - return; - view->setScrollPosition(IntPoint(static_cast<int>(scrollLeft * frame->pageZoomFactor() * frame->frameScaleFactor()), view->scrollY())); + if (isFirstBodyElementOfDocument()) { + document().updateLayoutIgnorePendingStylesheets(); + Frame* frame = document().frame(); + if (!frame) + return; + FrameView* view = frame->view(); + if (!view) + return; + view->setScrollPosition(IntPoint(static_cast<int>(scrollLeft * frame->pageZoomFactor() * frame->frameScaleFactor()), view->scrollY())); + } + HTMLElement::setScrollLeft(scrollLeft); } int HTMLBodyElement::scrollTop() { - document().updateLayoutIgnorePendingStylesheets(); - Frame* frame = document().frame(); - if (!frame) - return 0; - FrameView* view = frame->view(); - if (!view) - return 0; -#if PLATFORM(IOS) - return adjustForZoom(view->actualScrollY(), *frame); -#else - return adjustForZoom(view->scrollY(), *frame); -#endif + if (isFirstBodyElementOfDocument()) { + document().updateLayoutIgnorePendingStylesheets(); + Frame* frame = document().frame(); + if (!frame) + return 0; + FrameView* view = frame->view(); + if (!view) + return 0; + return adjustForZoom(view->contentsScrollPosition().y(), *frame); + } + return HTMLElement::scrollTop(); } void HTMLBodyElement::setScrollTop(int scrollTop) { - document().updateLayoutIgnorePendingStylesheets(); - Frame* frame = document().frame(); - if (!frame) - return; - FrameView* view = frame->view(); - if (!view) + if (isFirstBodyElementOfDocument()) { + document().updateLayoutIgnorePendingStylesheets(); + Frame* frame = document().frame(); + if (!frame) + return; + FrameView* view = frame->view(); + if (!view) + return; + view->setScrollPosition(IntPoint(view->scrollX(), static_cast<int>(scrollTop * frame->pageZoomFactor() * frame->frameScaleFactor()))); + } + return HTMLElement::setScrollTop(scrollTop); +} + +void HTMLBodyElement::scrollTo(const ScrollToOptions& options) +{ + if (isFirstBodyElementOfDocument()) { + // If the element is the HTML body element, document is in quirks mode, and the element is not potentially scrollable, + // invoke scroll() on window with options as the only argument, and terminate these steps. + // Note that WebKit always uses quirks mode document scrolling behavior. See Document::scrollingElement(). + // FIXME: Scrolling an independently scrollable body is broken: webkit.org/b/161612. + auto* window = document().domWindow(); + if (!window) + return; + + window->scrollTo(options); return; - view->setScrollPosition(IntPoint(view->scrollX(), static_cast<int>(scrollTop * frame->pageZoomFactor() * frame->frameScaleFactor()))); + } + return HTMLElement::scrollTo(options); } int HTMLBodyElement::scrollHeight() { - // Update the document's layout. - document().updateLayoutIgnorePendingStylesheets(); - Frame* frame = document().frame(); - if (!frame) - return 0; - FrameView* view = frame->view(); - if (!view) - return 0; - return adjustForZoom(view->contentsHeight(), *frame); + if (isFirstBodyElementOfDocument()) { + // Update the document's layout. + document().updateLayoutIgnorePendingStylesheets(); + Frame* frame = document().frame(); + if (!frame) + return 0; + FrameView* view = frame->view(); + if (!view) + return 0; + return adjustForZoom(view->contentsHeight(), *frame); + } + return HTMLElement::scrollHeight(); } int HTMLBodyElement::scrollWidth() { - // Update the document's layout. - document().updateLayoutIgnorePendingStylesheets(); - Frame* frame = document().frame(); - if (!frame) - return 0; - FrameView* view = frame->view(); - if (!view) - return 0; - return adjustForZoom(view->contentsWidth(), *frame); + if (isFirstBodyElementOfDocument()) { + // Update the document's layout. + document().updateLayoutIgnorePendingStylesheets(); + Frame* frame = document().frame(); + if (!frame) + return 0; + FrameView* view = frame->view(); + if (!view) + return 0; + return adjustForZoom(view->contentsWidth(), *frame); + } + return HTMLElement::scrollWidth(); } void HTMLBodyElement::addSubresourceAttributeURLs(ListHashSet<URL>& urls) const { HTMLElement::addSubresourceAttributeURLs(urls); - addSubresourceURL(urls, document().completeURL(getAttribute(backgroundAttr))); + addSubresourceURL(urls, document().completeURL(attributeWithoutSynchronization(backgroundAttr))); } } // namespace WebCore |