diff options
| author | Allan Sandfeld Jensen <allan.jensen@digia.com> | 2013-09-13 12:51:20 +0200 |
|---|---|---|
| committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-09-19 20:50:05 +0200 |
| commit | d441d6f39bb846989d95bcf5caf387b42414718d (patch) | |
| tree | e367e64a75991c554930278175d403c072de6bb8 /Source/WebCore/page | |
| parent | 0060b2994c07842f4c59de64b5e3e430525c4b90 (diff) | |
| download | qtwebkit-d441d6f39bb846989d95bcf5caf387b42414718d.tar.gz | |
Import Qt5x2 branch of QtWebkit for Qt 5.2
Importing a new snapshot of webkit.
Change-Id: I2d01ad12cdc8af8cb015387641120a9d7ea5f10c
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@digia.com>
Diffstat (limited to 'Source/WebCore/page')
212 files changed, 10387 insertions, 8155 deletions
diff --git a/Source/WebCore/page/AbstractView.idl b/Source/WebCore/page/AbstractView.idl index c57aaeaba..4c39566ea 100644 --- a/Source/WebCore/page/AbstractView.idl +++ b/Source/WebCore/page/AbstractView.idl @@ -26,8 +26,8 @@ // Introduced in DOM Level 2: [ + NoInterfaceObject, ObjCCustomImplementation, - OmitConstructor ] interface AbstractView { readonly attribute Document document; readonly attribute StyleMedia styleMedia; diff --git a/Source/WebCore/page/AlternativeTextClient.h b/Source/WebCore/page/AlternativeTextClient.h index a81358994..54477b60c 100644 --- a/Source/WebCore/page/AlternativeTextClient.h +++ b/Source/WebCore/page/AlternativeTextClient.h @@ -68,7 +68,6 @@ public: #endif #if USE(DICTATION_ALTERNATIVES) virtual void showDictationAlternativeUI(const WebCore::FloatRect& boundingBoxOfDictatedText, uint64_t dictationContext) = 0; - virtual void dismissDictationAlternativeUI() = 0; virtual void removeDictationAlternatives(uint64_t dictationContext) = 0; virtual Vector<String> dictationAlternatives(uint64_t dictationContext) = 0; #endif diff --git a/Source/WebCore/page/AutoscrollController.cpp b/Source/WebCore/page/AutoscrollController.cpp new file mode 100644 index 000000000..7257ed49b --- /dev/null +++ b/Source/WebCore/page/AutoscrollController.cpp @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. + * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) + * Copyright (C) 2012 Digia Plc. and/or its subsidiary(-ies) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "AutoscrollController.h" + +#include "Chrome.h" +#include "ChromeClient.h" +#include "EventHandler.h" +#include "Frame.h" +#include "FrameView.h" +#include "HitTestResult.h" +#include "Page.h" +#include "RenderBox.h" +#include "ScrollView.h" +#include <wtf/CurrentTime.h> + +namespace WebCore { + +// Delay time in second for start autoscroll if pointer is in border edge of scrollable element. +static double autoscrollDelay = 0.2; + +// When the autoscroll or the panScroll is triggered when do the scroll every 0.05s to make it smooth +static const double autoscrollInterval = 0.05; + +#if ENABLE(PAN_SCROLLING) +static Frame* getMainFrame(Frame* frame) +{ + Page* page = frame->page(); + return page ? page->mainFrame() : 0; +} +#endif + +AutoscrollController::AutoscrollController() + : m_autoscrollTimer(this, &AutoscrollController::autoscrollTimerFired) + , m_autoscrollRenderer(0) + , m_autoscrollType(NoAutoscroll) + , m_dragAndDropAutoscrollStartTime(0) +{ +} + +RenderBox* AutoscrollController::autoscrollRenderer() const +{ + return m_autoscrollRenderer; +} + +bool AutoscrollController::autoscrollInProgress() const +{ + return m_autoscrollType == AutoscrollForSelection; +} + +void AutoscrollController::startAutoscrollForSelection(RenderObject* renderer) +{ + // We don't want to trigger the autoscroll or the panScroll if it's already active + if (m_autoscrollTimer.isActive()) + return; + RenderBox* scrollable = RenderBox::findAutoscrollable(renderer); + if (!scrollable) + return; + m_autoscrollType = AutoscrollForSelection; + m_autoscrollRenderer = scrollable; + startAutoscrollTimer(); +} + +void AutoscrollController::stopAutoscrollTimer(bool rendererIsBeingDestroyed) +{ + RenderBox* scrollable = m_autoscrollRenderer; + m_autoscrollTimer.stop(); + m_autoscrollRenderer = 0; + + if (!scrollable) + return; + + Frame* frame = scrollable->frame(); + EventHandler* eventHandler = frame->eventHandler(); + if (autoscrollInProgress() && eventHandler->mouseDownWasInSubframe()) { + if (Frame* subframe = eventHandler->subframeForTargetNode(eventHandler->mousePressNode())) + subframe->eventHandler()->stopAutoscrollTimer(rendererIsBeingDestroyed); + return; + } + + if (!rendererIsBeingDestroyed) + scrollable->stopAutoscroll(); +#if ENABLE(PAN_SCROLLING) + if (panScrollInProgress()) { + if (FrameView* view = frame->view()) { + view->removePanScrollIcon(); + view->setCursor(pointerCursor()); + } + } +#endif + + m_autoscrollType = NoAutoscroll; + +#if ENABLE(PAN_SCROLLING) + // If we're not in the top frame we notify it that we are not doing a panScroll any more. + if (Frame* mainFrame = getMainFrame(frame)) { + if (frame != mainFrame) + mainFrame->eventHandler()->didPanScrollStop(); + } +#endif +} + +void AutoscrollController::updateAutoscrollRenderer() +{ + if (!m_autoscrollRenderer) + return; + + RenderObject* renderer = m_autoscrollRenderer; + +#if ENABLE(PAN_SCROLLING) + HitTestResult hitTest = m_autoscrollRenderer->frame()->eventHandler()->hitTestResultAtPoint(m_panScrollStartPos, HitTestRequest::ReadOnly | HitTestRequest::Active); + + if (Node* nodeAtPoint = hitTest.innerNode()) + renderer = nodeAtPoint->renderer(); +#endif + + while (renderer && !(renderer->isBox() && toRenderBox(renderer)->canAutoscroll())) + renderer = renderer->parent(); + m_autoscrollRenderer = renderer && renderer->isBox() ? toRenderBox(renderer) : 0; +} + +void AutoscrollController::updateDragAndDrop(Node* dropTargetNode, const IntPoint& eventPosition, double eventTime) +{ + if (!dropTargetNode) { + stopAutoscrollTimer(); + return; + } + + RenderBox* scrollable = RenderBox::findAutoscrollable(dropTargetNode->renderer()); + if (!scrollable) { + stopAutoscrollTimer(); + return; + } + + Frame* frame = scrollable->frame(); + if (!frame) { + stopAutoscrollTimer(); + return; + } + + Page* page = frame->page(); + if (!page || !page->chrome().client()->shouldAutoscrollForDragAndDrop(scrollable)) { + stopAutoscrollTimer(); + return; + } + + IntSize offset = scrollable->calculateAutoscrollDirection(eventPosition); + if (offset.isZero()) { + stopAutoscrollTimer(); + return; + } + + m_dragAndDropAutoscrollReferencePosition = eventPosition + offset; + + if (m_autoscrollType == NoAutoscroll) { + m_autoscrollType = AutoscrollForDragAndDrop; + m_autoscrollRenderer = scrollable; + m_dragAndDropAutoscrollStartTime = eventTime; + startAutoscrollTimer(); + } else if (m_autoscrollRenderer != scrollable) { + m_dragAndDropAutoscrollStartTime = eventTime; + m_autoscrollRenderer = scrollable; + } +} + +#if ENABLE(PAN_SCROLLING) +void AutoscrollController::didPanScrollStart() +{ + m_autoscrollType = AutoscrollForPan; +} + +void AutoscrollController::didPanScrollStop() +{ + m_autoscrollType = NoAutoscroll; +} + +void AutoscrollController::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent) +{ + switch (m_autoscrollType) { + case AutoscrollForPan: + if (mouseEvent.button() == MiddleButton) + m_autoscrollType = AutoscrollForPanCanStop; + break; + case AutoscrollForPanCanStop: + stopAutoscrollTimer(); + break; + } +} + +bool AutoscrollController::panScrollInProgress() const +{ + return m_autoscrollType == AutoscrollForPan || m_autoscrollType == AutoscrollForPanCanStop; +} + +void AutoscrollController::startPanScrolling(RenderBox* scrollable, const IntPoint& lastKnownMousePosition) +{ + // We don't want to trigger the autoscroll or the panScroll if it's already active + if (m_autoscrollTimer.isActive()) + return; + + m_autoscrollType = AutoscrollForPan; + m_autoscrollRenderer = scrollable; + m_panScrollStartPos = lastKnownMousePosition; + + if (FrameView* view = scrollable->frame()->view()) + view->addPanScrollIcon(lastKnownMousePosition); + scrollable->frame()->eventHandler()->didPanScrollStart(); + startAutoscrollTimer(); +} +#else +bool AutoscrollController::panScrollInProgress() const +{ + return false; +} +#endif + +void AutoscrollController::autoscrollTimerFired(Timer<AutoscrollController>*) +{ + if (!m_autoscrollRenderer) { + stopAutoscrollTimer(); + return; + } + + Frame* frame = m_autoscrollRenderer->frame(); + switch (m_autoscrollType) { + case AutoscrollForDragAndDrop: + if (WTF::currentTime() - m_dragAndDropAutoscrollStartTime > autoscrollDelay) + m_autoscrollRenderer->autoscroll(m_dragAndDropAutoscrollReferencePosition); + break; + case AutoscrollForSelection: { + EventHandler* eventHandler = frame->eventHandler(); + if (!eventHandler->mousePressed()) { + stopAutoscrollTimer(); + return; + } +#if ENABLE(DRAG_SUPPORT) + eventHandler->updateSelectionForMouseDrag(); +#endif + m_autoscrollRenderer->autoscroll(eventHandler->lastKnownMousePosition()); + break; + } + case NoAutoscroll: + break; +#if ENABLE(PAN_SCROLLING) + case AutoscrollForPanCanStop: + case AutoscrollForPan: + // we verify that the main frame hasn't received the order to stop the panScroll + if (Frame* mainFrame = getMainFrame(frame)) { + if (!mainFrame->eventHandler()->panScrollInProgress()) { + stopAutoscrollTimer(); + return; + } + } + if (FrameView* view = frame->view()) + updatePanScrollState(view, frame->eventHandler()->lastKnownMousePosition()); + m_autoscrollRenderer->panScroll(m_panScrollStartPos); + break; +#endif + } +} + +void AutoscrollController::startAutoscrollTimer() +{ + m_autoscrollTimer.startRepeating(autoscrollInterval); +} + +#if ENABLE(PAN_SCROLLING) +void AutoscrollController::updatePanScrollState(FrameView* view, const IntPoint& lastKnownMousePosition) +{ + // At the original click location we draw a 4 arrowed icon. Over this icon there won't be any scroll + // So we don't want to change the cursor over this area + bool east = m_panScrollStartPos.x() < (lastKnownMousePosition.x() - ScrollView::noPanScrollRadius); + bool west = m_panScrollStartPos.x() > (lastKnownMousePosition.x() + ScrollView::noPanScrollRadius); + bool north = m_panScrollStartPos.y() > (lastKnownMousePosition.y() + ScrollView::noPanScrollRadius); + bool south = m_panScrollStartPos.y() < (lastKnownMousePosition.y() - ScrollView::noPanScrollRadius); + + if (m_autoscrollType == AutoscrollForPan && (east || west || north || south)) + m_autoscrollType = AutoscrollForPanCanStop; + + if (north) { + if (east) + view->setCursor(northEastPanningCursor()); + else if (west) + view->setCursor(northWestPanningCursor()); + else + view->setCursor(northPanningCursor()); + } else if (south) { + if (east) + view->setCursor(southEastPanningCursor()); + else if (west) + view->setCursor(southWestPanningCursor()); + else + view->setCursor(southPanningCursor()); + } else if (east) + view->setCursor(eastPanningCursor()); + else if (west) + view->setCursor(westPanningCursor()); + else + view->setCursor(middlePanningCursor()); +} +#endif + +} // namespace WebCore diff --git a/Source/WebCore/page/AutoscrollController.h b/Source/WebCore/page/AutoscrollController.h new file mode 100644 index 000000000..f5d4bf09a --- /dev/null +++ b/Source/WebCore/page/AutoscrollController.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2006, 2007, 2009, 2010, 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef AutoscrollController_h +#define AutoscrollController_h + +#include "IntPoint.h" +#include "Timer.h" + +namespace WebCore { + +class EventHandler; +class Frame; +class FrameView; +class Node; +class PlatformMouseEvent; +class RenderBox; +class RenderObject; + +enum AutoscrollType { + NoAutoscroll, + AutoscrollForDragAndDrop, + AutoscrollForSelection, +#if ENABLE(PAN_SCROLLING) + AutoscrollForPanCanStop, + AutoscrollForPan, +#endif +}; + +// AutscrollController handels autoscroll and pan scroll for EventHandler. +class AutoscrollController { +public: + AutoscrollController(); + RenderBox* autoscrollRenderer() const; + bool autoscrollInProgress() const; + bool panScrollInProgress() const; + void startAutoscrollForSelection(RenderObject*); + void stopAutoscrollTimer(bool rendererIsBeingDestroyed = false); + void updateAutoscrollRenderer(); + void updateDragAndDrop(Node* targetNode, const IntPoint& eventPosition, double eventTime); +#if ENABLE(PAN_SCROLLING) + void didPanScrollStart(); + void didPanScrollStop(); + void handleMouseReleaseEvent(const PlatformMouseEvent&); + void setPanScrollInProgress(bool); + void startPanScrolling(RenderBox*, const IntPoint&); +#endif + +private: + void autoscrollTimerFired(Timer<AutoscrollController>*); + void startAutoscrollTimer(); +#if ENABLE(PAN_SCROLLING) + void updatePanScrollState(FrameView*, const IntPoint&); +#endif + + Timer<AutoscrollController> m_autoscrollTimer; + RenderBox* m_autoscrollRenderer; + AutoscrollType m_autoscrollType; + IntPoint m_dragAndDropAutoscrollReferencePosition; + double m_dragAndDropAutoscrollStartTime; +#if ENABLE(PAN_SCROLLING) + IntPoint m_panScrollStartPos; +#endif +}; + +} // namespace WebCore + +#endif // AutoscrollController_h diff --git a/Source/WebCore/page/BarInfo.cpp b/Source/WebCore/page/BarProp.cpp index 36b2ad6a7..3be4fb397 100644 --- a/Source/WebCore/page/BarInfo.cpp +++ b/Source/WebCore/page/BarProp.cpp @@ -27,7 +27,7 @@ */ #include "config.h" -#include "BarInfo.h" +#include "BarProp.h" #include "Chrome.h" #include "Frame.h" @@ -35,18 +35,18 @@ namespace WebCore { -BarInfo::BarInfo(Frame* frame, Type type) +BarProp::BarProp(Frame* frame, Type type) : DOMWindowProperty(frame) , m_type(type) { } -BarInfo::Type BarInfo::type() const +BarProp::Type BarProp::type() const { return m_type; } -bool BarInfo::visible() const +bool BarProp::visible() const { if (!m_frame) return false; @@ -58,13 +58,13 @@ bool BarInfo::visible() const case Locationbar: case Personalbar: case Toolbar: - return page->chrome()->toolbarsVisible(); + return page->chrome().toolbarsVisible(); case Menubar: - return page->chrome()->menubarVisible(); + return page->chrome().menubarVisible(); case Scrollbars: - return page->chrome()->scrollbarsVisible(); + return page->chrome().scrollbarsVisible(); case Statusbar: - return page->chrome()->statusbarVisible(); + return page->chrome().statusbarVisible(); } ASSERT_NOT_REACHED(); diff --git a/Source/WebCore/page/BarInfo.h b/Source/WebCore/page/BarProp.h index 4f09a45b2..36830ea6a 100644 --- a/Source/WebCore/page/BarInfo.h +++ b/Source/WebCore/page/BarProp.h @@ -26,8 +26,8 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef BarInfo_h -#define BarInfo_h +#ifndef BarProp_h +#define BarProp_h #include "DOMWindowProperty.h" #include "ScriptWrappable.h" @@ -36,22 +36,22 @@ namespace WebCore { - class Frame; +class Frame; - class BarInfo : public ScriptWrappable, public RefCounted<BarInfo>, public DOMWindowProperty { - public: - enum Type { Locationbar, Menubar, Personalbar, Scrollbars, Statusbar, Toolbar }; +class BarProp : public ScriptWrappable, public RefCounted<BarProp>, public DOMWindowProperty { +public: + enum Type { Locationbar, Menubar, Personalbar, Scrollbars, Statusbar, Toolbar }; - static PassRefPtr<BarInfo> create(Frame* frame, Type type) { return adoptRef(new BarInfo(frame, type)); } + static PassRefPtr<BarProp> create(Frame* frame, Type type) { return adoptRef(new BarProp(frame, type)); } - Type type() const; - bool visible() const; + Type type() const; + bool visible() const; - private: - BarInfo(Frame*, Type); - Type m_type; - }; +private: + BarProp(Frame*, Type); + Type m_type; +}; } // namespace WebCore -#endif // BarInfo_h +#endif // BarProp_h diff --git a/Source/WebCore/page/BarInfo.idl b/Source/WebCore/page/BarProp.idl index a7dc091f6..188a24f70 100644 --- a/Source/WebCore/page/BarInfo.idl +++ b/Source/WebCore/page/BarProp.idl @@ -27,9 +27,8 @@ */ [ - JSGenerateIsReachable=ImplFrame, - OmitConstructor -] interface BarInfo { + GenerateIsReachable=ImplFrame, +] interface BarProp { readonly attribute boolean visible; }; diff --git a/Source/WebCore/page/CaptionUserPreferences.cpp b/Source/WebCore/page/CaptionUserPreferences.cpp new file mode 100644 index 000000000..5b1590f6f --- /dev/null +++ b/Source/WebCore/page/CaptionUserPreferences.cpp @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2013 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(VIDEO_TRACK) + +#include "CaptionUserPreferences.h" +#include "DOMWrapperWorld.h" +#include "Page.h" +#include "PageGroup.h" +#include "Settings.h" +#include "TextTrackList.h" +#include "UserStyleSheetTypes.h" +#include <wtf/NonCopyingSort.h> + +namespace WebCore { + +CaptionUserPreferences::CaptionUserPreferences(PageGroup* group) + : m_pageGroup(group) + , m_displayMode(ForcedOnly) + , m_timer(this, &CaptionUserPreferences::timerFired) + , m_testingMode(false) + , m_havePreferences(false) +{ +} + +CaptionUserPreferences::~CaptionUserPreferences() +{ +} + +void CaptionUserPreferences::timerFired(Timer<CaptionUserPreferences>*) +{ + captionPreferencesChanged(); +} + +void CaptionUserPreferences::notify() +{ + m_havePreferences = true; + if (!m_timer.isActive()) + m_timer.startOneShot(0); +} + +CaptionUserPreferences::CaptionDisplayMode CaptionUserPreferences::captionDisplayMode() const +{ + return m_displayMode; +} + +void CaptionUserPreferences::setCaptionDisplayMode(CaptionUserPreferences::CaptionDisplayMode mode) +{ + m_displayMode = mode; + if (m_testingMode && mode != AlwaysOn) { + setUserPrefersCaptions(false); + setUserPrefersSubtitles(false); + } + notify(); +} + +bool CaptionUserPreferences::userPrefersCaptions() const +{ + Page* page = *(pageGroup()->pages().begin()); + if (!page) + return false; + + return page->settings()->shouldDisplayCaptions(); +} + +void CaptionUserPreferences::setUserPrefersCaptions(bool preference) +{ + Page* page = *(pageGroup()->pages().begin()); + if (!page) + return; + + page->settings()->setShouldDisplayCaptions(preference); + notify(); +} + +bool CaptionUserPreferences::userPrefersSubtitles() const +{ + Page* page = *(pageGroup()->pages().begin()); + if (!page) + return false; + + return page->settings()->shouldDisplaySubtitles(); +} + +void CaptionUserPreferences::setUserPrefersSubtitles(bool preference) +{ + Page* page = *(pageGroup()->pages().begin()); + if (!page) + return; + + page->settings()->setShouldDisplaySubtitles(preference); + notify(); +} + +bool CaptionUserPreferences::userPrefersTextDescriptions() const +{ + Page* page = *(pageGroup()->pages().begin()); + if (!page) + return false; + + return page->settings()->shouldDisplayTextDescriptions(); +} + +void CaptionUserPreferences::setUserPrefersTextDescriptions(bool preference) +{ + Page* page = *(pageGroup()->pages().begin()); + if (!page) + return; + + page->settings()->setShouldDisplayTextDescriptions(preference); + notify(); +} + +void CaptionUserPreferences::captionPreferencesChanged() +{ + m_pageGroup->captionPreferencesChanged(); +} + +Vector<String> CaptionUserPreferences::preferredLanguages() const +{ + Vector<String> languages = userPreferredLanguages(); + if (m_testingMode && !m_userPreferredLanguage.isEmpty()) + languages.insert(0, m_userPreferredLanguage); + + return languages; +} + +void CaptionUserPreferences::setPreferredLanguage(const String& language) +{ + m_userPreferredLanguage = language; + notify(); +} + +static String trackDisplayName(TextTrack* track) +{ + if (track->label().isEmpty() && track->language().isEmpty()) + return textTrackNoLabelText(); + if (!track->label().isEmpty()) + return track->label(); + return track->language(); +} + +String CaptionUserPreferences::displayNameForTrack(TextTrack* track) const +{ + return trackDisplayName(track); +} + +static bool textTrackCompare(const RefPtr<TextTrack>& a, const RefPtr<TextTrack>& b) +{ + return codePointCompare(trackDisplayName(a.get()), trackDisplayName(b.get())) < 0; +} + +Vector<RefPtr<TextTrack> > CaptionUserPreferences::sortedTrackListForMenu(TextTrackList* trackList) +{ + ASSERT(trackList); + + Vector<RefPtr<TextTrack> > tracksForMenu; + + for (unsigned i = 0, length = trackList->length(); i < length; ++i) + tracksForMenu.append(trackList->item(i)); + + nonCopyingSort(tracksForMenu.begin(), tracksForMenu.end(), textTrackCompare); + + return tracksForMenu; +} + +int CaptionUserPreferences::textTrackSelectionScore(TextTrack* track, HTMLMediaElement*) const +{ + int trackScore = 0; + + if (track->kind() != TextTrack::captionsKeyword() && track->kind() != TextTrack::subtitlesKeyword()) + return trackScore; + + if (!userPrefersSubtitles() && !userPrefersCaptions()) + return trackScore; + + if (track->kind() == TextTrack::subtitlesKeyword() && userPrefersSubtitles()) + trackScore = 1; + else if (track->kind() == TextTrack::captionsKeyword() && userPrefersCaptions()) + trackScore = 1; + + return trackScore + textTrackLanguageSelectionScore(track, preferredLanguages()); +} + +int CaptionUserPreferences::textTrackLanguageSelectionScore(TextTrack* track, const Vector<String>& preferredLanguages) const +{ + if (track->language().isEmpty()) + return 0; + + size_t languageMatchIndex = indexOfBestMatchingLanguageInList(track->language(), preferredLanguages); + if (languageMatchIndex >= preferredLanguages.size()) + return 0; + + // Matching a track language is more important than matching track type, so this multiplier must be + // greater than the maximum value returned by textTrackSelectionScore. + return (preferredLanguages.size() - languageMatchIndex) * 10; +} + +void CaptionUserPreferences::setCaptionsStyleSheetOverride(const String& override) +{ + m_captionsStyleSheetOverride = override; + updateCaptionStyleSheetOveride(); +} + +void CaptionUserPreferences::updateCaptionStyleSheetOveride() +{ + // Identify our override style sheet with a unique URL - a new scheme and a UUID. + DEFINE_STATIC_LOCAL(KURL, captionsStyleSheetURL, (ParsedURLString, "user-captions-override:01F6AF12-C3B0-4F70-AF5E-A3E00234DC23")); + + pageGroup()->removeUserStyleSheetFromWorld(mainThreadNormalWorld(), captionsStyleSheetURL); + + String captionsOverrideStyleSheet = captionsStyleSheetOverride(); + if (captionsOverrideStyleSheet.isEmpty()) + return; + + pageGroup()->addUserStyleSheetToWorld(mainThreadNormalWorld(), captionsOverrideStyleSheet, captionsStyleSheetURL, Vector<String>(), + Vector<String>(), InjectInAllFrames, UserStyleAuthorLevel, InjectInExistingDocuments); +} + +String CaptionUserPreferences::primaryAudioTrackLanguageOverride() const +{ + if (!m_primaryAudioTrackLanguageOverride.isEmpty()) + return m_primaryAudioTrackLanguageOverride; + return defaultLanguage(); +} + +} + +#endif // ENABLE(VIDEO_TRACK) diff --git a/Source/WebCore/page/CaptionUserPreferences.h b/Source/WebCore/page/CaptionUserPreferences.h index 377f5277e..cdb2e021e 100644 --- a/Source/WebCore/page/CaptionUserPreferences.h +++ b/Source/WebCore/page/CaptionUserPreferences.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2013 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,39 +28,83 @@ #if ENABLE(VIDEO_TRACK) +#include "Language.h" +#include "LocalizedStrings.h" +#include "TextTrack.h" +#include "Timer.h" #include <wtf/PassOwnPtr.h> #include <wtf/text/AtomicString.h> namespace WebCore { +class HTMLMediaElement; class PageGroup; - -class CaptionPreferencesChangedListener { -public: - virtual void captionPreferencesChanged() = 0; -protected: - virtual ~CaptionPreferencesChangedListener() { } -}; +class TextTrackList; class CaptionUserPreferences { public: static PassOwnPtr<CaptionUserPreferences> create(PageGroup* group) { return adoptPtr(new CaptionUserPreferences(group)); } - virtual ~CaptionUserPreferences() { } + virtual ~CaptionUserPreferences(); + + enum CaptionDisplayMode { + Automatic, + ForcedOnly, + AlwaysOn + }; + virtual CaptionDisplayMode captionDisplayMode() const; + virtual void setCaptionDisplayMode(CaptionDisplayMode); + + virtual int textTrackSelectionScore(TextTrack*, HTMLMediaElement*) const; + virtual int textTrackLanguageSelectionScore(TextTrack*, const Vector<String>&) const; + + virtual bool userPrefersCaptions() const; + virtual void setUserPrefersCaptions(bool); + + virtual bool userPrefersSubtitles() const; + virtual void setUserPrefersSubtitles(bool preference); + + virtual bool userPrefersTextDescriptions() const; + virtual void setUserPrefersTextDescriptions(bool preference); - virtual bool userPrefersCaptions() const { return false; } - virtual bool userHasCaptionPreferences() const { return false; } - virtual float captionFontSizeScale() const { return 0.05f; } - virtual String captionsStyleSheetOverride() const { return emptyString(); } - virtual void registerForCaptionPreferencesChangedCallbacks(CaptionPreferencesChangedListener*) { } - virtual void unregisterForCaptionPreferencesChangedCallbacks(CaptionPreferencesChangedListener*) { } + virtual float captionFontSizeScaleAndImportance(bool& important) const { important = false; return 0.05f; } - PageGroup* pageGroup() { return m_pageGroup; } + virtual String captionsStyleSheetOverride() const { return m_captionsStyleSheetOverride; } + virtual void setCaptionsStyleSheetOverride(const String&); + + virtual void setInterestedInCaptionPreferenceChanges() { } + + virtual void captionPreferencesChanged(); + + virtual void setPreferredLanguage(const String&); + virtual Vector<String> preferredLanguages() const; + + virtual String displayNameForTrack(TextTrack*) const; + virtual Vector<RefPtr<TextTrack> > sortedTrackListForMenu(TextTrackList*); + + void setPrimaryAudioTrackLanguageOverride(const String& language) { m_primaryAudioTrackLanguageOverride = language; } + String primaryAudioTrackLanguageOverride() const; + + virtual bool testingMode() const { return m_testingMode; } + virtual void setTestingMode(bool override) { m_testingMode = override; } + + PageGroup* pageGroup() const { return m_pageGroup; } protected: - CaptionUserPreferences(PageGroup* group) : m_pageGroup(group) { } + CaptionUserPreferences(PageGroup*); + void updateCaptionStyleSheetOveride(); private: + void timerFired(Timer<CaptionUserPreferences>*); + void notify(); + PageGroup* m_pageGroup; + CaptionDisplayMode m_displayMode; + Timer<CaptionUserPreferences> m_timer; + String m_userPreferredLanguage; + String m_captionsStyleSheetOverride; + String m_primaryAudioTrackLanguageOverride; + bool m_testingMode; + bool m_havePreferences; }; } diff --git a/Source/WebCore/page/CaptionUserPreferencesMac.h b/Source/WebCore/page/CaptionUserPreferencesMac.h deleted file mode 100644 index 6cba2f1b4..000000000 --- a/Source/WebCore/page/CaptionUserPreferencesMac.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2012 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef CaptionUserPreferencesMac_h -#define CaptionUserPreferencesMac_h - -#if ENABLE(VIDEO_TRACK) - -#include "CSSPropertyNames.h" -#include "CaptionUserPreferences.h" -#include "Color.h" -#include <wtf/HashSet.h> - -namespace WebCore { - -class CaptionUserPreferencesMac : public CaptionUserPreferences { -public: - static PassOwnPtr<CaptionUserPreferencesMac> create(PageGroup* group) { return adoptPtr(new CaptionUserPreferencesMac(group)); } - virtual ~CaptionUserPreferencesMac(); - - virtual bool userPrefersCaptions() const OVERRIDE; - virtual bool userHasCaptionPreferences() const OVERRIDE; - virtual float captionFontSizeScale() const OVERRIDE; - virtual String captionsStyleSheetOverride() const OVERRIDE; - virtual void registerForCaptionPreferencesChangedCallbacks(CaptionPreferencesChangedListener*) OVERRIDE; - virtual void unregisterForCaptionPreferencesChangedCallbacks(CaptionPreferencesChangedListener*) OVERRIDE; - - void captionPreferencesChanged(); - -private: - CaptionUserPreferencesMac(PageGroup*); - - Color captionsWindowColor() const; - Color captionsBackgroundColor() const; - Color captionsTextColor() const; - String captionsDefaultFont() const; - Color captionsEdgeColorForTextColor(const Color&) const; - String captionsTextEdgeStyle() const; - String cssPropertyWithTextEdgeColor(CSSPropertyID, const String&, const Color&) const; - String cssColorProperty(CSSPropertyID, const Color&) const; - - void updateCaptionStyleSheetOveride(); - - HashSet<CaptionPreferencesChangedListener*> m_captionPreferenceChangeListeners; - bool m_listeningForPreferenceChanges; -}; - -} -#endif - -#endif diff --git a/Source/WebCore/page/CaptionUserPreferencesMac.mm b/Source/WebCore/page/CaptionUserPreferencesMac.mm deleted file mode 100644 index 779a4bc04..000000000 --- a/Source/WebCore/page/CaptionUserPreferencesMac.mm +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Copyright (C) 2012 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#import "config.h" - -#if ENABLE(VIDEO_TRACK) - -#import "CaptionUserPreferencesMac.h" - -#import "ColorMac.h" -#import "DOMWrapperWorld.h" -#import "FloatConversion.h" -#import "KURL.h" -#import "PageGroup.h" -#import "TextTrackCue.h" -#import "UserStyleSheetTypes.h" -#import "WebCoreSystemInterface.h" -#import <wtf/RetainPtr.h> -#import <wtf/text/StringBuilder.h> - -using namespace std; - -namespace WebCore { - -static void userCaptionPreferencesChangedNotificationCallback(CFNotificationCenterRef, void* observer, CFStringRef, const void *, CFDictionaryRef) -{ - static_cast<CaptionUserPreferencesMac*>(observer)->captionPreferencesChanged(); -} - - -CaptionUserPreferencesMac::CaptionUserPreferencesMac(PageGroup* group) - : CaptionUserPreferences(group) - , m_listeningForPreferenceChanges(false) -{ -} - -CaptionUserPreferencesMac::~CaptionUserPreferencesMac() -{ - if (wkCaptionAppearanceGetSettingsChangedNotification()) - CFNotificationCenterRemoveObserver(CFNotificationCenterGetLocalCenter(), this, wkCaptionAppearanceGetSettingsChangedNotification(), NULL); -} - -bool CaptionUserPreferencesMac::userHasCaptionPreferences() const -{ - return wkCaptionAppearanceHasUserPreferences(); -} - -bool CaptionUserPreferencesMac::userPrefersCaptions() const -{ - return wkCaptionAppearanceShowCaptionsWhenAvailable(); -} - -void CaptionUserPreferencesMac::registerForCaptionPreferencesChangedCallbacks(CaptionPreferencesChangedListener* listener) -{ - ASSERT(!m_captionPreferenceChangeListeners.contains(listener)); - - if (!wkCaptionAppearanceGetSettingsChangedNotification()) - return; - - if (!m_listeningForPreferenceChanges) { - m_listeningForPreferenceChanges = true; - CFNotificationCenterAddObserver (CFNotificationCenterGetLocalCenter(), this, userCaptionPreferencesChangedNotificationCallback, wkCaptionAppearanceGetSettingsChangedNotification(), NULL, CFNotificationSuspensionBehaviorCoalesce); - updateCaptionStyleSheetOveride(); - } - - m_captionPreferenceChangeListeners.add(listener); -} - -void CaptionUserPreferencesMac::unregisterForCaptionPreferencesChangedCallbacks(CaptionPreferencesChangedListener* listener) -{ - if (wkCaptionAppearanceGetSettingsChangedNotification()) - m_captionPreferenceChangeListeners.remove(listener); -} - -Color CaptionUserPreferencesMac::captionsWindowColor() const -{ - RetainPtr<CGColorRef> color(AdoptCF, wkCaptionAppearanceCopyWindowColor()); - Color windowColor(color.get()); - if (!windowColor.isValid()) - windowColor = Color::transparent; - - CGFloat opacity; - if (wkCaptionAppearanceGetWindowOpacity(&opacity)) - return Color(windowColor.red(), windowColor.green(), windowColor.blue(), static_cast<int>(opacity * 255)); - - if (!color) - return Color(); - - return windowColor; -} - -Color CaptionUserPreferencesMac::captionsBackgroundColor() const -{ - // This default value must be the same as the one specified in mediaControls.css for -webkit-media-text-track-past-nodes - // and webkit-media-text-track-future-nodes. - DEFINE_STATIC_LOCAL(Color, defaultBackgroundColor, (Color(0, 0, 0, 0.8 * 255))); - - RetainPtr<CGColorRef> color(AdoptCF, wkCaptionAppearanceCopyBackgroundColor()); - Color backgroundColor(color.get()); - if (!backgroundColor.isValid()) { - backgroundColor = defaultBackgroundColor; - } - - CGFloat opacity; - if (wkCaptionAppearanceGetBackgroundOpacity(&opacity)) - return Color(backgroundColor.red(), backgroundColor.green(), backgroundColor.blue(), static_cast<int>(opacity * 255)); - - if (!color) - return Color(); - - return backgroundColor; -} - -Color CaptionUserPreferencesMac::captionsTextColor() const -{ - RetainPtr<CGColorRef> color(AdoptCF, wkCaptionAppearanceCopyForegroundColor()); - Color textColor(color.get()); - if (!textColor.isValid()) { - // This default value must be the same as the one specified in mediaControls.css for -webkit-media-text-track-container. - textColor = Color::white; - } - - CGFloat opacity; - if (wkCaptionAppearanceGetForegroundOpacity(&opacity)) - return Color(textColor.red(), textColor.green(), textColor.blue(), static_cast<int>(opacity * 255)); - - if (!color) - return Color(); - - return textColor; -} - -Color CaptionUserPreferencesMac::captionsEdgeColorForTextColor(const Color& textColor) const -{ - int distanceFromWhite = differenceSquared(textColor, Color::white); - int distanceFromBlack = differenceSquared(textColor, Color::black); - - if (distanceFromWhite < distanceFromBlack) - return textColor.dark(); - - return textColor.light(); -} - -String CaptionUserPreferencesMac::cssPropertyWithTextEdgeColor(CSSPropertyID id, const String& value, const Color& textColor) const -{ - StringBuilder builder; - - builder.append(getPropertyNameString(id)); - builder.append(':'); - builder.append(value); - builder.append(' '); - builder.append(captionsEdgeColorForTextColor(textColor).serialized()); - builder.append(';'); - - return builder.toString(); -} - -String CaptionUserPreferencesMac::cssColorProperty(CSSPropertyID id, const Color& color) const -{ - StringBuilder builder; - - builder.append(getPropertyNameString(id)); - builder.append(':'); - builder.append(color.serialized()); - builder.append(';'); - - return builder.toString(); -} - -String CaptionUserPreferencesMac::captionsTextEdgeStyle() const -{ - DEFINE_STATIC_LOCAL(const String, edgeStyleRaised, (" -.05em -.05em 0 ", String::ConstructFromLiteral)); - DEFINE_STATIC_LOCAL(const String, edgeStyleDepressed, (" .05em .05em 0 ", String::ConstructFromLiteral)); - DEFINE_STATIC_LOCAL(const String, edgeStyleDropShadow, (" .075em .075em 0 ", String::ConstructFromLiteral)); - DEFINE_STATIC_LOCAL(const String, edgeStyleUniform, (" .03em ", String::ConstructFromLiteral)); - - Color color = captionsTextColor(); - if (!color.isValid()) - color.setNamedColor("black"); - color = captionsEdgeColorForTextColor(color); - - wkCaptionTextEdgeStyle textEdgeStyle = static_cast<wkCaptionTextEdgeStyle>(wkCaptionAppearanceGetTextEdgeStyle()); - switch (textEdgeStyle) { - case wkCaptionTextEdgeStyleUndefined: - case wkCaptionTextEdgeStyleNone: - return emptyString(); - - case wkCaptionTextEdgeStyleRaised: - return cssPropertyWithTextEdgeColor(CSSPropertyTextShadow, edgeStyleRaised, color); - case wkCaptionTextEdgeStyleDepressed: - return cssPropertyWithTextEdgeColor(CSSPropertyTextShadow, edgeStyleDepressed, color); - case wkCaptionTextEdgeStyleDropShadow: - return cssPropertyWithTextEdgeColor(CSSPropertyTextShadow, edgeStyleDropShadow, color); - case wkCaptionTextEdgeStyleUniform: - return cssPropertyWithTextEdgeColor(CSSPropertyWebkitTextStroke, edgeStyleUniform, color); - - case wkCaptionTextEdgeStyleMax: - ASSERT_NOT_REACHED(); - default: - ASSERT_NOT_REACHED(); - break; - } - - return emptyString(); -} - -String CaptionUserPreferencesMac::captionsDefaultFont() const -{ - RetainPtr<CGFontRef> font(AdoptCF, wkCaptionAppearanceCopyFontForStyle(wkCaptionFontStyleDefault)); - if (!font) - return emptyString(); - - RetainPtr<CFStringRef> name(AdoptCF, CGFontCopyPostScriptName(font.get())); - if (!name) - return emptyString(); - - StringBuilder builder; - - builder.append(getPropertyNameString(CSSPropertyFontFamily)); - builder.append(": \""); - builder.append(name.get()); - builder.append("\";"); - - return builder.toString(); -} - -String CaptionUserPreferencesMac::captionsStyleSheetOverride() const -{ - StringBuilder captionsOverrideStyleSheet; - - Color color = captionsBackgroundColor(); - if (color.isValid()) { - captionsOverrideStyleSheet.append(" video::"); - captionsOverrideStyleSheet.append(TextTrackCue::pastNodesShadowPseudoId()); - captionsOverrideStyleSheet.append('{'); - captionsOverrideStyleSheet.append(cssColorProperty(CSSPropertyBackgroundColor, color)); - captionsOverrideStyleSheet.append('}'); - - captionsOverrideStyleSheet.append(" video::"); - captionsOverrideStyleSheet.append(TextTrackCue::futureNodesShadowPseudoId()); - captionsOverrideStyleSheet.append('{'); - captionsOverrideStyleSheet.append(cssColorProperty(CSSPropertyBackgroundColor, color)); - captionsOverrideStyleSheet.append('}'); - } - - color = captionsWindowColor(); - if (color.isValid()) { - captionsOverrideStyleSheet.append(" video::"); - captionsOverrideStyleSheet.append(TextTrackCueBox::textTrackCueBoxShadowPseudoId()); - captionsOverrideStyleSheet.append('{'); - captionsOverrideStyleSheet.append(cssColorProperty(CSSPropertyBackgroundColor, color)); - captionsOverrideStyleSheet.append('}'); - } - - color = captionsTextColor(); - String edgeStyle = captionsTextEdgeStyle(); - String fontName = captionsDefaultFont(); - if (color.isValid() || !edgeStyle.isEmpty() || !fontName.isEmpty()) { - captionsOverrideStyleSheet.append(" video::"); - captionsOverrideStyleSheet.append(TextTrackCueBox::textTrackCueBoxShadowPseudoId()); - captionsOverrideStyleSheet.append('{'); - - if (color.isValid()) - captionsOverrideStyleSheet.append(cssColorProperty(CSSPropertyColor, color)); - if (!edgeStyle.isEmpty()) - captionsOverrideStyleSheet.append(edgeStyle); - if (!fontName.isEmpty()) - captionsOverrideStyleSheet.append(fontName); - - captionsOverrideStyleSheet.append('}'); - } - - return captionsOverrideStyleSheet.toString(); -} - -float CaptionUserPreferencesMac::captionFontSizeScale() const -{ - CGFloat characterScale = CaptionUserPreferences::captionFontSizeScale(); - CGFloat scaleAdjustment; - - if (!wkCaptionAppearanceGetRelativeCharacterSize(&scaleAdjustment)) - return characterScale; - -#if defined(__LP64__) && __LP64__ - return narrowPrecisionToFloat(scaleAdjustment * characterScale); -#else - return scaleAdjustment * characterScale; -#endif -} - -void CaptionUserPreferencesMac::captionPreferencesChanged() -{ - if (m_captionPreferenceChangeListeners.isEmpty()) - return; - - updateCaptionStyleSheetOveride(); - - for (HashSet<CaptionPreferencesChangedListener*>::iterator i = m_captionPreferenceChangeListeners.begin(); i != m_captionPreferenceChangeListeners.end(); ++i) - (*i)->captionPreferencesChanged(); -} - -void CaptionUserPreferencesMac::updateCaptionStyleSheetOveride() -{ - // Identify our override style sheet with a unique URL - a new scheme and a UUID. - DEFINE_STATIC_LOCAL(KURL, captionsStyleSheetURL, (ParsedURLString, "user-captions-override:01F6AF12-C3B0-4F70-AF5E-A3E00234DC23")); - - pageGroup()->removeUserStyleSheetFromWorld(mainThreadNormalWorld(), captionsStyleSheetURL); - - if (!userHasCaptionPreferences()) - return; - - String captionsOverrideStyleSheet = captionsStyleSheetOverride(); - if (captionsOverrideStyleSheet.isEmpty()) - return; - - pageGroup()->addUserStyleSheetToWorld(mainThreadNormalWorld(), captionsOverrideStyleSheet, captionsStyleSheetURL, Vector<String>(), - Vector<String>(), InjectInAllFrames, UserStyleAuthorLevel, InjectInExistingDocuments); -} - -} - -#endif // ENABLE(VIDEO_TRACK) diff --git a/Source/WebCore/page/CaptionUserPreferencesMediaAF.cpp b/Source/WebCore/page/CaptionUserPreferencesMediaAF.cpp new file mode 100644 index 000000000..cd52997f6 --- /dev/null +++ b/Source/WebCore/page/CaptionUserPreferencesMediaAF.cpp @@ -0,0 +1,853 @@ +/* + * Copyright (C) 2012, 2013 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(VIDEO_TRACK) + +#include "CaptionUserPreferencesMediaAF.h" + +#if HAVE(MEDIA_ACCESSIBILITY_FRAMEWORK) +#include "CoreText/CoreText.h" +#endif +#include "DOMWrapperWorld.h" +#include "FloatConversion.h" +#include "HTMLMediaElement.h" +#include "KURL.h" +#include "Language.h" +#include "LocalizedStrings.h" +#include "Logging.h" +#include "MediaControlElements.h" +#include "PageGroup.h" +#include "SoftLinking.h" +#include "TextTrackCue.h" +#include "TextTrackList.h" +#include "UserStyleSheetTypes.h" +#include <wtf/NonCopyingSort.h> +#include <wtf/RetainPtr.h> +#include <wtf/text/StringBuilder.h> + +#if PLATFORM(IOS) +#import "WebCoreThreadRun.h" +#endif + +#if HAVE(MEDIA_ACCESSIBILITY_FRAMEWORK) +#include "MediaAccessibility/MediaAccessibility.h" +#endif + +#if HAVE(MEDIA_ACCESSIBILITY_FRAMEWORK) + +#if !PLATFORM(WIN) +#define SOFT_LINK_AVF_FRAMEWORK(Lib) SOFT_LINK_FRAMEWORK_OPTIONAL(Lib) +#define SOFT_LINK_AVF(Lib, Name, Type) SOFT_LINK(Lib, Name, Type) +#define SOFT_LINK_AVF_POINTER(Lib, Name, Type) SOFT_LINK_POINTER_OPTIONAL(Lib, Name, Type) +#define SOFT_LINK_AVF_FRAMEWORK_IMPORT(Lib, Fun, ReturnType, Arguments, Signature) SOFT_LINK(Lib, Fun, ReturnType, Arguments, Signature) +#else +#define SOFT_LINK_AVF_FRAMEWORK(Lib) SOFT_LINK_LIBRARY(Lib) +#define SOFT_LINK_AVF(Lib, Name, Type) SOFT_LINK_DLL_IMPORT(Lib, Name, Type) +#define SOFT_LINK_AVF_POINTER(Lib, Name, Type) SOFT_LINK_VARIABLE_DLL_IMPORT_OPTIONAL(Lib, Name, Type) +#define SOFT_LINK_AVF_FRAMEWORK_IMPORT(Lib, Fun, ReturnType, Arguments, Signature) SOFT_LINK_DLL_IMPORT(Lib, Fun, ReturnType, __cdecl, Arguments, Signature) +#endif + +SOFT_LINK_AVF_FRAMEWORK(MediaAccessibility) +SOFT_LINK_AVF_FRAMEWORK(CoreText) + +SOFT_LINK_AVF_FRAMEWORK_IMPORT(MediaAccessibility, MACaptionAppearanceGetDisplayType, MACaptionAppearanceDisplayType, (MACaptionAppearanceDomain domain), (domain)) +SOFT_LINK_AVF_FRAMEWORK_IMPORT(MediaAccessibility, MACaptionAppearanceSetDisplayType, void, (MACaptionAppearanceDomain domain, MACaptionAppearanceDisplayType displayType), (domain, displayType)) +SOFT_LINK_AVF_FRAMEWORK_IMPORT(MediaAccessibility, MACaptionAppearanceCopyForegroundColor, CGColorRef, (MACaptionAppearanceDomain domain, MACaptionAppearanceBehavior *behavior), (domain, behavior)) +SOFT_LINK_AVF_FRAMEWORK_IMPORT(MediaAccessibility, MACaptionAppearanceCopyBackgroundColor, CGColorRef, (MACaptionAppearanceDomain domain, MACaptionAppearanceBehavior *behavior), (domain, behavior)) +SOFT_LINK_AVF_FRAMEWORK_IMPORT(MediaAccessibility, MACaptionAppearanceCopyWindowColor, CGColorRef, (MACaptionAppearanceDomain domain, MACaptionAppearanceBehavior *behavior), (domain, behavior)) +SOFT_LINK_AVF_FRAMEWORK_IMPORT(MediaAccessibility, MACaptionAppearanceGetForegroundOpacity, CGFloat, (MACaptionAppearanceDomain domain, MACaptionAppearanceBehavior *behavior), (domain, behavior)) +SOFT_LINK_AVF_FRAMEWORK_IMPORT(MediaAccessibility, MACaptionAppearanceGetBackgroundOpacity, CGFloat, (MACaptionAppearanceDomain domain, MACaptionAppearanceBehavior *behavior), (domain, behavior)) +SOFT_LINK_AVF_FRAMEWORK_IMPORT(MediaAccessibility, MACaptionAppearanceGetWindowOpacity, CGFloat, (MACaptionAppearanceDomain domain, MACaptionAppearanceBehavior *behavior), (domain, behavior)) +SOFT_LINK_AVF_FRAMEWORK_IMPORT(MediaAccessibility, MACaptionAppearanceGetWindowRoundedCornerRadius, CGFloat, (MACaptionAppearanceDomain domain, MACaptionAppearanceBehavior *behavior), (domain, behavior)) +SOFT_LINK_AVF_FRAMEWORK_IMPORT(MediaAccessibility, MACaptionAppearanceCopyFontDescriptorForStyle, CTFontDescriptorRef, (MACaptionAppearanceDomain domain, MACaptionAppearanceBehavior *behavior, MACaptionAppearanceFontStyle fontStyle), (domain, behavior, fontStyle)) +SOFT_LINK_AVF_FRAMEWORK_IMPORT(MediaAccessibility, MACaptionAppearanceGetRelativeCharacterSize, CGFloat, (MACaptionAppearanceDomain domain, MACaptionAppearanceBehavior *behavior), (domain, behavior)) +SOFT_LINK_AVF_FRAMEWORK_IMPORT(MediaAccessibility, MACaptionAppearanceGetTextEdgeStyle, MACaptionAppearanceTextEdgeStyle, (MACaptionAppearanceDomain domain, MACaptionAppearanceBehavior *behavior), (domain, behavior)) +SOFT_LINK_AVF_FRAMEWORK_IMPORT(MediaAccessibility, MACaptionAppearanceAddSelectedLanguage, bool, (MACaptionAppearanceDomain domain, CFStringRef language), (domain, language)); +SOFT_LINK_AVF_FRAMEWORK_IMPORT(MediaAccessibility, MACaptionAppearanceCopySelectedLanguages, CFArrayRef, (MACaptionAppearanceDomain domain), (domain)); +SOFT_LINK_AVF_FRAMEWORK_IMPORT(MediaAccessibility, MACaptionAppearanceCopyPreferredCaptioningMediaCharacteristics, CFArrayRef, (MACaptionAppearanceDomain domain), (domain)); + +SOFT_LINK_AVF_FRAMEWORK_IMPORT(CoreText, CTFontDescriptorCopyAttribute, CFTypeRef, (CTFontDescriptorRef descriptor, CFStringRef attribute), (descriptor, attribute)); + +#if PLATFORM(WIN) +// These are needed on Windows due to the way DLLs work. We do not need them on other platforms +#define MACaptionAppearanceGetDisplayType softLink_MACaptionAppearanceGetDisplayType +#define MACaptionAppearanceSetDisplayType softLink_MACaptionAppearanceSetDisplayType +#define MACaptionAppearanceCopyForegroundColor softLink_MACaptionAppearanceCopyForegroundColor +#define MACaptionAppearanceCopyBackgroundColor softLink_MACaptionAppearanceCopyBackgroundColor +#define MACaptionAppearanceCopyWindowColor softLink_MACaptionAppearanceCopyWindowColor +#define MACaptionAppearanceGetForegroundOpacity softLink_MACaptionAppearanceGetForegroundOpacity +#define MACaptionAppearanceGetBackgroundOpacity softLink_MACaptionAppearanceGetBackgroundOpacity +#define MACaptionAppearanceGetWindowOpacity softLink_MACaptionAppearanceGetWindowOpacity +#define MACaptionAppearanceGetWindowRoundedCornerRadius softLink_MACaptionAppearanceGetWindowRoundedCornerRadius +#define MACaptionAppearanceCopyFontDescriptorForStyle softLink_MACaptionAppearanceCopyFontDescriptorForStyle +#define MACaptionAppearanceGetRelativeCharacterSize softLink_MACaptionAppearanceGetRelativeCharacterSize +#define MACaptionAppearanceGetTextEdgeStyle softLink_MACaptionAppearanceGetTextEdgeStyle +#define MACaptionAppearanceAddSelectedLanguage softLink_MACaptionAppearanceAddSelectedLanguage +#define MACaptionAppearanceCopySelectedLanguages softLink_MACaptionAppearanceCopySelectedLanguages +#define MACaptionAppearanceCopyPreferredCaptioningMediaCharacteristics softLink_MACaptionAppearanceCopyPreferredCaptioningMediaCharacteristics +#define CTFontDescriptorCopyAttribute softLink_CTFontDescriptorCopyAttribute +#endif + +SOFT_LINK_AVF_POINTER(MediaAccessibility, kMAXCaptionAppearanceSettingsChangedNotification, CFStringRef) +#define kMAXCaptionAppearanceSettingsChangedNotification getkMAXCaptionAppearanceSettingsChangedNotification() + +SOFT_LINK_AVF_POINTER(CoreText, kCTFontNameAttribute, CFStringRef) +#define kCTFontNameAttribute getkCTFontNameAttribute() +#endif + +using namespace std; + +namespace WebCore { + +#if HAVE(MEDIA_ACCESSIBILITY_FRAMEWORK) +static void userCaptionPreferencesChangedNotificationCallback(CFNotificationCenterRef, void* observer, CFStringRef, const void *, CFDictionaryRef) +{ +#if !PLATFORM(IOS) + static_cast<CaptionUserPreferencesMediaAF*>(observer)->captionPreferencesChanged(); +#else + WebThreadRun(^{ + static_cast<CaptionUserPreferencesMediaAF*>(observer)->captionPreferencesChanged(); + }); +#endif +} +#endif + +CaptionUserPreferencesMediaAF::CaptionUserPreferencesMediaAF(PageGroup* group) + : CaptionUserPreferences(group) +#if HAVE(MEDIA_ACCESSIBILITY_FRAMEWORK) + , m_listeningForPreferenceChanges(false) +#endif +{ +} + +CaptionUserPreferencesMediaAF::~CaptionUserPreferencesMediaAF() +{ +#if HAVE(MEDIA_ACCESSIBILITY_FRAMEWORK) + if (kMAXCaptionAppearanceSettingsChangedNotification) + CFNotificationCenterRemoveObserver(CFNotificationCenterGetLocalCenter(), this, kMAXCaptionAppearanceSettingsChangedNotification, 0); +#endif +} + +#if HAVE(MEDIA_ACCESSIBILITY_FRAMEWORK) + +CaptionUserPreferences::CaptionDisplayMode CaptionUserPreferencesMediaAF::captionDisplayMode() const +{ + if (testingMode() || !MediaAccessibilityLibrary()) + return CaptionUserPreferences::captionDisplayMode(); + + MACaptionAppearanceDisplayType displayType = MACaptionAppearanceGetDisplayType(kMACaptionAppearanceDomainUser); + switch (displayType) { + case kMACaptionAppearanceDisplayTypeForcedOnly: + return ForcedOnly; + break; + + case kMACaptionAppearanceDisplayTypeAutomatic: + return Automatic; + break; + + case kMACaptionAppearanceDisplayTypeAlwaysOn: + return AlwaysOn; + break; + } + + ASSERT_NOT_REACHED(); + return ForcedOnly; +} + +void CaptionUserPreferencesMediaAF::setCaptionDisplayMode(CaptionUserPreferences::CaptionDisplayMode mode) +{ + if (testingMode() || !MediaAccessibilityLibrary()) { + CaptionUserPreferences::setCaptionDisplayMode(mode); + return; + } + + MACaptionAppearanceDisplayType displayType = kMACaptionAppearanceDisplayTypeForcedOnly; + switch (mode) { + case Automatic: + displayType = kMACaptionAppearanceDisplayTypeAutomatic; + break; + case ForcedOnly: + displayType = kMACaptionAppearanceDisplayTypeForcedOnly; + break; + case AlwaysOn: + displayType = kMACaptionAppearanceDisplayTypeAlwaysOn; + break; + default: + ASSERT_NOT_REACHED(); + break; + } + + MACaptionAppearanceSetDisplayType(kMACaptionAppearanceDomainUser, displayType); +} + +bool CaptionUserPreferencesMediaAF::userPrefersCaptions() const +{ + bool captionSetting = CaptionUserPreferences::userPrefersCaptions(); + if (captionSetting || testingMode() || !MediaAccessibilityLibrary()) + return captionSetting; + + RetainPtr<CFArrayRef> captioningMediaCharacteristics = adoptCF(MACaptionAppearanceCopyPreferredCaptioningMediaCharacteristics(kMACaptionAppearanceDomainUser)); + return captioningMediaCharacteristics && CFArrayGetCount(captioningMediaCharacteristics.get()); +} + +bool CaptionUserPreferencesMediaAF::userPrefersSubtitles() const +{ + bool subtitlesSetting = CaptionUserPreferences::userPrefersSubtitles(); + if (subtitlesSetting || testingMode() || !MediaAccessibilityLibrary()) + return subtitlesSetting; + + RetainPtr<CFArrayRef> captioningMediaCharacteristics = adoptCF(MACaptionAppearanceCopyPreferredCaptioningMediaCharacteristics(kMACaptionAppearanceDomainUser)); + return !(captioningMediaCharacteristics && CFArrayGetCount(captioningMediaCharacteristics.get())); +} + +void CaptionUserPreferencesMediaAF::setInterestedInCaptionPreferenceChanges() +{ + if (!MediaAccessibilityLibrary()) + return; + + if (!kMAXCaptionAppearanceSettingsChangedNotification) + return; + + if (!m_listeningForPreferenceChanges) { + m_listeningForPreferenceChanges = true; + CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), this, userCaptionPreferencesChangedNotificationCallback, kMAXCaptionAppearanceSettingsChangedNotification, 0, CFNotificationSuspensionBehaviorCoalesce); + } + + updateCaptionStyleSheetOveride(); +} + +void CaptionUserPreferencesMediaAF::captionPreferencesChanged() +{ + if (m_listeningForPreferenceChanges) + updateCaptionStyleSheetOveride(); + + CaptionUserPreferences::captionPreferencesChanged(); +} + +String CaptionUserPreferencesMediaAF::captionsWindowCSS() const +{ + MACaptionAppearanceBehavior behavior; + RetainPtr<CGColorRef> color = adoptCF(MACaptionAppearanceCopyWindowColor(kMACaptionAppearanceDomainUser, &behavior)); + + Color windowColor(color.get()); + if (!windowColor.isValid()) + windowColor = Color::transparent; + + bool important = behavior == kMACaptionAppearanceBehaviorUseValue; + CGFloat opacity = MACaptionAppearanceGetWindowOpacity(kMACaptionAppearanceDomainUser, &behavior); + if (!important) + important = behavior == kMACaptionAppearanceBehaviorUseValue; + String windowStyle = colorPropertyCSS(CSSPropertyBackgroundColor, Color(windowColor.red(), windowColor.green(), windowColor.blue(), static_cast<int>(opacity * 255)), important); + + if (!opacity) + return windowStyle; + + StringBuilder builder; + builder.append(windowStyle); + builder.append(getPropertyNameString(CSSPropertyPadding)); + builder.append(": .4em !important;"); + + return builder.toString(); +} + +String CaptionUserPreferencesMediaAF::captionsBackgroundCSS() const +{ + // This default value must be the same as the one specified in mediaControls.css for -webkit-media-text-track-past-nodes + // and webkit-media-text-track-future-nodes. + DEFINE_STATIC_LOCAL(Color, defaultBackgroundColor, (Color(0, 0, 0, 0.8 * 255))); + + MACaptionAppearanceBehavior behavior; + + RetainPtr<CGColorRef> color = adoptCF(MACaptionAppearanceCopyBackgroundColor(kMACaptionAppearanceDomainUser, &behavior)); + Color backgroundColor(color.get()); + if (!backgroundColor.isValid()) + backgroundColor = defaultBackgroundColor; + + bool important = behavior == kMACaptionAppearanceBehaviorUseValue; + CGFloat opacity = MACaptionAppearanceGetBackgroundOpacity(kMACaptionAppearanceDomainUser, &behavior); + if (!important) + important = behavior == kMACaptionAppearanceBehaviorUseValue; + return colorPropertyCSS(CSSPropertyBackgroundColor, Color(backgroundColor.red(), backgroundColor.green(), backgroundColor.blue(), static_cast<int>(opacity * 255)), important); +} + +Color CaptionUserPreferencesMediaAF::captionsTextColor(bool& important) const +{ + MACaptionAppearanceBehavior behavior; + RetainPtr<CGColorRef> color = adoptCF(MACaptionAppearanceCopyForegroundColor(kMACaptionAppearanceDomainUser, &behavior)); + Color textColor(color.get()); + if (!textColor.isValid()) + // This default value must be the same as the one specified in mediaControls.css for -webkit-media-text-track-container. + textColor = Color::white; + + important = behavior == kMACaptionAppearanceBehaviorUseValue; + CGFloat opacity = MACaptionAppearanceGetForegroundOpacity(kMACaptionAppearanceDomainUser, &behavior); + if (!important) + important = behavior == kMACaptionAppearanceBehaviorUseValue; + return Color(textColor.red(), textColor.green(), textColor.blue(), static_cast<int>(opacity * 255)); +} + +String CaptionUserPreferencesMediaAF::captionsTextColorCSS() const +{ + bool important; + Color textColor = captionsTextColor(important); + + if (!textColor.isValid()) + return emptyString(); + + return colorPropertyCSS(CSSPropertyColor, textColor, important); +} + +String CaptionUserPreferencesMediaAF::windowRoundedCornerRadiusCSS() const +{ + MACaptionAppearanceBehavior behavior; + CGFloat radius = MACaptionAppearanceGetWindowRoundedCornerRadius(kMACaptionAppearanceDomainUser, &behavior); + if (!radius) + return emptyString(); + + StringBuilder builder; + builder.append(getPropertyNameString(CSSPropertyBorderRadius)); + builder.append(String::format(":%.02fpx", radius)); + if (behavior == kMACaptionAppearanceBehaviorUseValue) + builder.append(" !important"); + builder.append(';'); + + return builder.toString(); +} + +Color CaptionUserPreferencesMediaAF::captionsEdgeColorForTextColor(const Color& textColor) const +{ + int distanceFromWhite = differenceSquared(textColor, Color::white); + int distanceFromBlack = differenceSquared(textColor, Color::black); + + if (distanceFromWhite < distanceFromBlack) + return textColor.dark(); + + return textColor.light(); +} + +String CaptionUserPreferencesMediaAF::cssPropertyWithTextEdgeColor(CSSPropertyID id, const String& value, const Color& textColor, bool important) const +{ + StringBuilder builder; + + builder.append(getPropertyNameString(id)); + builder.append(':'); + builder.append(value); + builder.append(' '); + builder.append(captionsEdgeColorForTextColor(textColor).serialized()); + if (important) + builder.append(" !important"); + builder.append(';'); + + return builder.toString(); +} + +String CaptionUserPreferencesMediaAF::colorPropertyCSS(CSSPropertyID id, const Color& color, bool important) const +{ + StringBuilder builder; + + builder.append(getPropertyNameString(id)); + builder.append(':'); + builder.append(color.serialized()); + if (important) + builder.append(" !important"); + builder.append(';'); + + return builder.toString(); +} + +String CaptionUserPreferencesMediaAF::captionsTextEdgeCSS() const +{ + DEFINE_STATIC_LOCAL(const String, edgeStyleRaised, (" -.05em -.05em 0 ", String::ConstructFromLiteral)); + DEFINE_STATIC_LOCAL(const String, edgeStyleDepressed, (" .05em .05em 0 ", String::ConstructFromLiteral)); + DEFINE_STATIC_LOCAL(const String, edgeStyleDropShadow, (" .075em .075em 0 ", String::ConstructFromLiteral)); + DEFINE_STATIC_LOCAL(const String, edgeStyleUniform, (" .03em ", String::ConstructFromLiteral)); + + bool unused; + Color color = captionsTextColor(unused); + if (!color.isValid()) + color.setNamedColor("black"); + color = captionsEdgeColorForTextColor(color); + + MACaptionAppearanceBehavior behavior; + MACaptionAppearanceTextEdgeStyle textEdgeStyle = MACaptionAppearanceGetTextEdgeStyle(kMACaptionAppearanceDomainUser, &behavior); + switch (textEdgeStyle) { + case kMACaptionAppearanceTextEdgeStyleUndefined: + case kMACaptionAppearanceTextEdgeStyleNone: + return emptyString(); + + case kMACaptionAppearanceTextEdgeStyleRaised: + return cssPropertyWithTextEdgeColor(CSSPropertyTextShadow, edgeStyleRaised, color, behavior == kMACaptionAppearanceBehaviorUseValue); + case kMACaptionAppearanceTextEdgeStyleDepressed: + return cssPropertyWithTextEdgeColor(CSSPropertyTextShadow, edgeStyleDepressed, color, behavior == kMACaptionAppearanceBehaviorUseValue); + case kMACaptionAppearanceTextEdgeStyleDropShadow: + return cssPropertyWithTextEdgeColor(CSSPropertyTextShadow, edgeStyleDropShadow, color, behavior == kMACaptionAppearanceBehaviorUseValue); + case kMACaptionAppearanceTextEdgeStyleUniform: + return cssPropertyWithTextEdgeColor(CSSPropertyWebkitTextStroke, edgeStyleUniform, color, behavior == kMACaptionAppearanceBehaviorUseValue); + + default: + ASSERT_NOT_REACHED(); + break; + } + + return emptyString(); +} + +String CaptionUserPreferencesMediaAF::captionsDefaultFontCSS() const +{ + MACaptionAppearanceBehavior behavior; + + RetainPtr<CTFontDescriptorRef> font = adoptCF(MACaptionAppearanceCopyFontDescriptorForStyle(kMACaptionAppearanceDomainUser, &behavior, kMACaptionAppearanceFontStyleDefault)); + if (!font) + return emptyString(); + + RetainPtr<CFTypeRef> name = adoptCF(CTFontDescriptorCopyAttribute(font.get(), kCTFontNameAttribute)); + if (!name) + return emptyString(); + + StringBuilder builder; + + builder.append(getPropertyNameString(CSSPropertyFontFamily)); + builder.append(": \""); + builder.append(static_cast<CFStringRef>(name.get())); + builder.append('"'); + if (behavior == kMACaptionAppearanceBehaviorUseValue) + builder.append(" !important"); + builder.append(';'); + + return builder.toString(); +} + +float CaptionUserPreferencesMediaAF::captionFontSizeScaleAndImportance(bool& important) const +{ + if (testingMode() || !MediaAccessibilityLibrary()) + return CaptionUserPreferences::captionFontSizeScaleAndImportance(important); + + MACaptionAppearanceBehavior behavior; + CGFloat characterScale = CaptionUserPreferences::captionFontSizeScaleAndImportance(important); + CGFloat scaleAdjustment = MACaptionAppearanceGetRelativeCharacterSize(kMACaptionAppearanceDomainUser, &behavior); + + if (!scaleAdjustment) + return characterScale; + + important = behavior == kMACaptionAppearanceBehaviorUseValue; +#if defined(__LP64__) && __LP64__ + return narrowPrecisionToFloat(scaleAdjustment * characterScale); +#else + return scaleAdjustment * characterScale; +#endif +} + +void CaptionUserPreferencesMediaAF::setPreferredLanguage(const String& language) +{ + if (testingMode() || !MediaAccessibilityLibrary()) { + CaptionUserPreferences::setPreferredLanguage(language); + return; + } + + MACaptionAppearanceAddSelectedLanguage(kMACaptionAppearanceDomainUser, language.createCFString().get()); +} + +Vector<String> CaptionUserPreferencesMediaAF::preferredLanguages() const +{ + if (testingMode() || !MediaAccessibilityLibrary()) + return CaptionUserPreferences::preferredLanguages(); + + Vector<String> platformLanguages = platformUserPreferredLanguages(); + Vector<String> override = userPreferredLanguagesOverride(); + if (!override.isEmpty()) { + if (platformLanguages.size() != override.size()) + return override; + for (size_t i = 0; i < override.size(); i++) { + if (override[i] != platformLanguages[i]) + return override; + } + } + + CFIndex languageCount = 0; + RetainPtr<CFArrayRef> languages = adoptCF(MACaptionAppearanceCopySelectedLanguages(kMACaptionAppearanceDomainUser)); + if (languages) + languageCount = CFArrayGetCount(languages.get()); + + if (!languageCount) + return CaptionUserPreferences::preferredLanguages(); + + Vector<String> userPreferredLanguages; + userPreferredLanguages.reserveCapacity(languageCount + platformLanguages.size()); + for (CFIndex i = 0; i < languageCount; i++) + userPreferredLanguages.append(static_cast<CFStringRef>(CFArrayGetValueAtIndex(languages.get(), i))); + + userPreferredLanguages.appendVector(platformLanguages); + + return userPreferredLanguages; +} +#endif // HAVE(MEDIA_ACCESSIBILITY_FRAMEWORK) + +String CaptionUserPreferencesMediaAF::captionsStyleSheetOverride() const +{ + if (testingMode()) + return CaptionUserPreferences::captionsStyleSheetOverride(); + + StringBuilder captionsOverrideStyleSheet; + +#if HAVE(MEDIA_ACCESSIBILITY_FRAMEWORK) + if (!MediaAccessibilityLibrary()) + return CaptionUserPreferences::captionsStyleSheetOverride(); + + String captionsColor = captionsTextColorCSS(); + String edgeStyle = captionsTextEdgeCSS(); + String fontName = captionsDefaultFontCSS(); + String background = captionsBackgroundCSS(); + if (!background.isEmpty() || !captionsColor.isEmpty() || !edgeStyle.isEmpty() || !fontName.isEmpty()) { + captionsOverrideStyleSheet.append(" video::"); + captionsOverrideStyleSheet.append(TextTrackCue::cueShadowPseudoId()); + captionsOverrideStyleSheet.append('{'); + + if (!background.isEmpty()) + captionsOverrideStyleSheet.append(background); + if (!captionsColor.isEmpty()) + captionsOverrideStyleSheet.append(captionsColor); + if (!edgeStyle.isEmpty()) + captionsOverrideStyleSheet.append(edgeStyle); + if (!fontName.isEmpty()) + captionsOverrideStyleSheet.append(fontName); + + captionsOverrideStyleSheet.append('}'); + } + + String windowColor = captionsWindowCSS(); + String windowCornerRadius = windowRoundedCornerRadiusCSS(); + if (!windowColor.isEmpty() || !windowCornerRadius.isEmpty()) { + captionsOverrideStyleSheet.append(" video::"); + captionsOverrideStyleSheet.append(TextTrackCueBox::textTrackCueBoxShadowPseudoId()); + captionsOverrideStyleSheet.append('{'); + + if (!windowColor.isEmpty()) + captionsOverrideStyleSheet.append(windowColor); + if (!windowCornerRadius.isEmpty()) + captionsOverrideStyleSheet.append(windowCornerRadius); + + captionsOverrideStyleSheet.append('}'); + } +#endif // HAVE(MEDIA_ACCESSIBILITY_FRAMEWORK) + + LOG(Media, "CaptionUserPreferencesMediaAF::captionsStyleSheetOverrideSetting sytle to:\n%s", captionsOverrideStyleSheet.toString().utf8().data()); + + return captionsOverrideStyleSheet.toString(); +} + +static String languageIdentifier(const String& languageCode) +{ + if (languageCode.isEmpty()) + return languageCode; + + String lowercaseLanguageCode = languageCode.lower(); + + // Need 2U here to disambiguate String::operator[] from operator(NSString*, int)[] in a production build. + if (lowercaseLanguageCode.length() >= 3 && (lowercaseLanguageCode[2U] == '_' || lowercaseLanguageCode[2U] == '-')) + lowercaseLanguageCode.truncate(2); + + return lowercaseLanguageCode; +} + +static String trackDisplayName(TextTrack* track) +{ + if (track == TextTrack::captionMenuOffItem()) + return textTrackOffMenuItemText(); + if (track == TextTrack::captionMenuAutomaticItem()) + return textTrackAutomaticMenuItemText(); + + StringBuilder displayName; + String label = track->label(); + String trackLanguageIdentifier = track->language(); + + RetainPtr<CFLocaleRef> currentLocale = adoptCF(CFLocaleCopyCurrent()); + RetainPtr<CFStringRef> localeIdentifier = adoptCF(CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorDefault, trackLanguageIdentifier.createCFString().get())); + RetainPtr<CFStringRef> languageCF = adoptCF(CFLocaleCopyDisplayNameForPropertyValue(currentLocale.get(), kCFLocaleLanguageCode, localeIdentifier.get())); + String language = languageCF.get(); + if (!label.isEmpty()) { + if (language.isEmpty() || label.contains(language)) + displayName.append(label); + else { + RetainPtr<CFDictionaryRef> localeDict = adoptCF(CFLocaleCreateComponentsFromLocaleIdentifier(kCFAllocatorDefault, localeIdentifier.get())); + if (localeDict) { + CFStringRef countryCode = 0; + String countryName; + + CFDictionaryGetValueIfPresent(localeDict.get(), kCFLocaleCountryCode, (const void **)&countryCode); + if (countryCode) { + RetainPtr<CFStringRef> countryNameCF = adoptCF(CFLocaleCopyDisplayNameForPropertyValue(currentLocale.get(), kCFLocaleCountryCode, countryCode)); + countryName = countryNameCF.get(); + } + + if (!countryName.isEmpty()) + displayName.append(textTrackCountryAndLanguageMenuItemText(label, countryName, language)); + else + displayName.append(textTrackLanguageMenuItemText(label, language)); + } + } + } else { + String languageAndLocale = CFLocaleCopyDisplayNameForPropertyValue(currentLocale.get(), kCFLocaleIdentifier, trackLanguageIdentifier.createCFString().get()); + if (!languageAndLocale.isEmpty()) + displayName.append(languageAndLocale); + else if (!language.isEmpty()) + displayName.append(language); + else + displayName.append(localeIdentifier.get()); + } + + if (displayName.isEmpty()) + displayName.append(textTrackNoLabelText()); + + if (track->isEasyToRead()) + return easyReaderTrackMenuItemText(displayName.toString()); + + if (track->isClosedCaptions()) + return closedCaptionTrackMenuItemText(displayName.toString()); + + if (track->isSDH()) + return sdhTrackMenuItemText(displayName.toString()); + + return displayName.toString(); +} + +String CaptionUserPreferencesMediaAF::displayNameForTrack(TextTrack* track) const +{ + return trackDisplayName(track); +} + +int CaptionUserPreferencesMediaAF::textTrackSelectionScore(TextTrack* track, HTMLMediaElement* mediaElement) const +{ + CaptionDisplayMode displayMode = captionDisplayMode(); + bool legacyOverride = mediaElement->webkitClosedCaptionsVisible(); + if (displayMode == AlwaysOn && (!userPrefersSubtitles() && !userPrefersCaptions() && !legacyOverride)) + return 0; + if (track->kind() != TextTrack::captionsKeyword() && track->kind() != TextTrack::subtitlesKeyword() && track->kind() != TextTrack::forcedKeyword()) + return 0; + if (!track->isMainProgramContent()) + return 0; + + bool trackHasOnlyForcedSubtitles = track->containsOnlyForcedSubtitles(); + if (!legacyOverride && ((trackHasOnlyForcedSubtitles && displayMode != ForcedOnly) || (!trackHasOnlyForcedSubtitles && displayMode == ForcedOnly))) + return 0; + + Vector<String> userPreferredCaptionLanguages = preferredLanguages(); + + if ((displayMode == Automatic && !legacyOverride) || trackHasOnlyForcedSubtitles) { + + if (!mediaElement || !mediaElement->player()) + return 0; + + String textTrackLanguage = track->language(); + if (textTrackLanguage.isEmpty()) + return 0; + + Vector<String> languageList; + languageList.reserveCapacity(1); + + String audioTrackLanguage; + if (testingMode()) + audioTrackLanguage = primaryAudioTrackLanguageOverride(); + else + audioTrackLanguage = mediaElement->player()->languageOfPrimaryAudioTrack(); + + if (audioTrackLanguage.isEmpty()) + return 0; + + if (trackHasOnlyForcedSubtitles) { + languageList.append(audioTrackLanguage); + size_t offset = indexOfBestMatchingLanguageInList(textTrackLanguage, languageList); + + // Only consider a forced-only track if it IS in the same language as the primary audio track. + if (offset) + return 0; + } else { + languageList.append(defaultLanguage()); + + // Only enable a text track if the current audio track is NOT in the user's preferred language ... + size_t offset = indexOfBestMatchingLanguageInList(audioTrackLanguage, languageList); + if (!offset) + return 0; + + // and the text track matches the user's preferred language. + offset = indexOfBestMatchingLanguageInList(textTrackLanguage, languageList); + if (offset) + return 0; + } + + userPreferredCaptionLanguages = languageList; + } + + int trackScore = 0; + + if (userPrefersCaptions()) { + // When the user prefers accessiblity tracks, rank is SDH, then CC, then subtitles. + if (track->kind() == track->subtitlesKeyword()) + trackScore = 1; + else if (track->isClosedCaptions()) + trackScore = 2; + else + trackScore = 3; + } else { + // When the user prefers translation tracks, rank is subtitles, then SDH, then CC tracks. + if (track->kind() == track->subtitlesKeyword()) + trackScore = 3; + else if (!track->isClosedCaptions()) + trackScore = 2; + else + trackScore = 1; + } + + return trackScore + textTrackLanguageSelectionScore(track, userPreferredCaptionLanguages); +} + +static bool textTrackCompare(const RefPtr<TextTrack>& a, const RefPtr<TextTrack>& b) +{ + String preferredLanguageDisplayName = displayNameForLanguageLocale(languageIdentifier(defaultLanguage())); + String aLanguageDisplayName = displayNameForLanguageLocale(languageIdentifier(a->language())); + String bLanguageDisplayName = displayNameForLanguageLocale(languageIdentifier(b->language())); + + // Tracks in the user's preferred language are always at the top of the menu. + bool aIsPreferredLanguage = !codePointCompare(aLanguageDisplayName, preferredLanguageDisplayName); + bool bIsPreferredLanguage = !codePointCompare(bLanguageDisplayName, preferredLanguageDisplayName); + if ((aIsPreferredLanguage || bIsPreferredLanguage) && (aIsPreferredLanguage != bIsPreferredLanguage)) + return aIsPreferredLanguage; + + // Tracks not in the user's preferred language sort first by language ... + if (codePointCompare(aLanguageDisplayName, bLanguageDisplayName)) + return codePointCompare(aLanguageDisplayName, bLanguageDisplayName) < 0; + + // ... but when tracks have the same language, main program content sorts next highest ... + bool aIsMainContent = a->isMainProgramContent(); + bool bIsMainContent = b->isMainProgramContent(); + if ((aIsMainContent || bIsMainContent) && (aIsMainContent != bIsMainContent)) + return aIsMainContent; + + // ... and main program trakcs sort higher than CC tracks ... + bool aIsCC = a->isClosedCaptions(); + bool bIsCC = b->isClosedCaptions(); + if ((aIsCC || bIsCC) && (aIsCC != bIsCC)) { + if (aIsCC) + return aIsMainContent; + return bIsMainContent; + } + + // ... and tracks of the same type and language sort by the menu item text. + return codePointCompare(trackDisplayName(a.get()), trackDisplayName(b.get())) < 0; +} + +Vector<RefPtr<TextTrack> > CaptionUserPreferencesMediaAF::sortedTrackListForMenu(TextTrackList* trackList) +{ + ASSERT(trackList); + + Vector<RefPtr<TextTrack> > tracksForMenu; + HashSet<String> languagesIncluded; + bool prefersAccessibilityTracks = userPrefersCaptions(); + bool filterTrackList = shouldFilterTrackMenu(); + + for (unsigned i = 0, length = trackList->length(); i < length; ++i) { + TextTrack* track = trackList->item(i); + String language = displayNameForLanguageLocale(track->language()); + + if (track->containsOnlyForcedSubtitles()) { + LOG(Media, "CaptionUserPreferencesMac::sortedTrackListForMenu - skipping '%s' track with language '%s' because it contains only forced subtitles", track->kind().string().utf8().data(), language.utf8().data()); + continue; + } + + if (track->isEasyToRead()) { + LOG(Media, "CaptionUserPreferencesMac::sortedTrackListForMenu - adding '%s' track with language '%s' because it is 'easy to read'", track->kind().string().utf8().data(), language.utf8().data()); + if (!language.isEmpty()) + languagesIncluded.add(language); + tracksForMenu.append(track); + continue; + } + + if (track->mode() == TextTrack::showingKeyword()) { + LOG(Media, "CaptionUserPreferencesMac::sortedTrackListForMenu - adding '%s' track with language '%s' because it is already visible", track->kind().string().utf8().data(), language.utf8().data()); + if (!language.isEmpty()) + languagesIncluded.add(language); + tracksForMenu.append(track); + continue; + } + + if (!language.isEmpty() && track->isMainProgramContent()) { + bool isAccessibilityTrack = track->kind() == track->captionsKeyword(); + if (prefersAccessibilityTracks) { + // In the first pass, include only caption tracks if the user prefers accessibility tracks. + if (!isAccessibilityTrack && filterTrackList) { + LOG(Media, "CaptionUserPreferencesMediaAF::sortedTrackListForMenu - skipping '%s' track with language '%s' because it is NOT an accessibility track", track->kind().string().utf8().data(), language.utf8().data()); + continue; + } + } else { + // In the first pass, only include the first non-CC or SDH track with each language if the user prefers translation tracks. + if (isAccessibilityTrack && filterTrackList) { + LOG(Media, "CaptionUserPreferencesMediaAF::sortedTrackListForMenu - skipping '%s' track with language '%s' because it is an accessibility track", track->kind().string().utf8().data(), language.utf8().data()); + continue; + } + if (languagesIncluded.contains(language) && filterTrackList) { + LOG(Media, "CaptionUserPreferencesMediaAF::sortedTrackListForMenu - skipping '%s' track with language '%s' because it is not the first with this language", track->kind().string().utf8().data(), language.utf8().data()); + continue; + } + } + } + + if (!language.isEmpty()) + languagesIncluded.add(language); + tracksForMenu.append(track); + + LOG(Media, "CaptionUserPreferencesMac::sortedTrackListForMenu - adding '%s' track with language '%s', is%s main program content", track->kind().string().utf8().data(), language.utf8().data(), track->isMainProgramContent() ? "" : " NOT"); + } + + // Now that we have filtered for the user's accessibility/translation preference, add all tracks with a unique language without regard to track type. + for (unsigned i = 0, length = trackList->length(); i < length; ++i) { + TextTrack* track = trackList->item(i); + String language = displayNameForLanguageLocale(track->language()); + + // All candidates with no languge were added the first time through. + if (language.isEmpty()) + continue; + + if (track->containsOnlyForcedSubtitles()) + continue; + + if (!languagesIncluded.contains(language) && track->isMainProgramContent()) { + languagesIncluded.add(language); + tracksForMenu.append(track); + LOG(Media, "CaptionUserPreferencesMediaAF::sortedTrackListForMenu - adding '%s' track with language '%s' because it is the only track with this language", track->kind().string().utf8().data(), language.utf8().data()); + } + } + + nonCopyingSort(tracksForMenu.begin(), tracksForMenu.end(), textTrackCompare); + + tracksForMenu.insert(0, TextTrack::captionMenuOffItem()); + tracksForMenu.insert(1, TextTrack::captionMenuAutomaticItem()); + + return tracksForMenu; +} + +} + +#endif // ENABLE(VIDEO_TRACK) diff --git a/Source/WebCore/page/CaptionUserPreferencesMediaAF.h b/Source/WebCore/page/CaptionUserPreferencesMediaAF.h new file mode 100644 index 000000000..0de7c436d --- /dev/null +++ b/Source/WebCore/page/CaptionUserPreferencesMediaAF.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2012, 2013 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CaptionUserPreferencesMediaAF_h +#define CaptionUserPreferencesMediaAF_h + +#if ENABLE(VIDEO_TRACK) + +#include "CSSPropertyNames.h" +#include "CaptionUserPreferences.h" +#include "Color.h" +#include <wtf/HashSet.h> + +namespace WebCore { + +class CaptionUserPreferencesMediaAF : public CaptionUserPreferences { +public: + static PassOwnPtr<CaptionUserPreferencesMediaAF> create(PageGroup* group) { return adoptPtr(new CaptionUserPreferencesMediaAF(group)); } + virtual ~CaptionUserPreferencesMediaAF(); + +#if HAVE(MEDIA_ACCESSIBILITY_FRAMEWORK) + virtual CaptionDisplayMode captionDisplayMode() const OVERRIDE; + virtual void setCaptionDisplayMode(CaptionDisplayMode) OVERRIDE; + + virtual bool userPrefersCaptions() const OVERRIDE; + virtual bool userPrefersSubtitles() const OVERRIDE; + + virtual float captionFontSizeScaleAndImportance(bool&) const OVERRIDE; + + virtual void setInterestedInCaptionPreferenceChanges() OVERRIDE; + + virtual void setPreferredLanguage(const String&) OVERRIDE; + virtual Vector<String> preferredLanguages() const OVERRIDE; + + virtual void captionPreferencesChanged() OVERRIDE; + + bool shouldFilterTrackMenu() const { return true; } +#else + bool shouldFilterTrackMenu() const { return false; } +#endif + + virtual String captionsStyleSheetOverride() const OVERRIDE; + virtual int textTrackSelectionScore(TextTrack*, HTMLMediaElement*) const OVERRIDE; + virtual Vector<RefPtr<TextTrack> > sortedTrackListForMenu(TextTrackList*) OVERRIDE; + virtual String displayNameForTrack(TextTrack*) const OVERRIDE; + +private: + CaptionUserPreferencesMediaAF(PageGroup*); + +#if HAVE(MEDIA_ACCESSIBILITY_FRAMEWORK) + String captionsWindowCSS() const; + String captionsBackgroundCSS() const; + String captionsTextColorCSS() const; + Color captionsTextColor(bool&) const; + String captionsDefaultFontCSS() const; + Color captionsEdgeColorForTextColor(const Color&) const; + String windowRoundedCornerRadiusCSS() const; + String captionsTextEdgeCSS() const; + String cssPropertyWithTextEdgeColor(CSSPropertyID, const String&, const Color&, bool) const; + String colorPropertyCSS(CSSPropertyID, const Color&, bool) const; + + bool m_listeningForPreferenceChanges; +#endif +}; + +} +#endif + +#endif diff --git a/Source/WebCore/page/Chrome.cpp b/Source/WebCore/page/Chrome.cpp index 84dfcb423..0deaefd49 100644 --- a/Source/WebCore/page/Chrome.cpp +++ b/Source/WebCore/page/Chrome.cpp @@ -65,6 +65,7 @@ using namespace std; Chrome::Chrome(Page* page, ChromeClient* client) : m_page(page) , m_client(client) + , m_displayID(0) { ASSERT(m_client); } @@ -190,11 +191,11 @@ void Chrome::focusedFrameChanged(Frame* frame) const Page* Chrome::createWindow(Frame* frame, const FrameLoadRequest& request, const WindowFeatures& features, const NavigationAction& action) const { Page* newPage = m_client->createWindow(frame, request, features, action); + if (!newPage) + return 0; - if (newPage) { - if (StorageNamespace* oldSessionStorage = m_page->sessionStorage(false)) - newPage->setSessionStorage(oldSessionStorage->copy()); - } + if (StorageNamespace* oldSessionStorage = m_page->sessionStorage(false)) + newPage->setSessionStorage(oldSessionStorage->copy(newPage)); return newPage; } @@ -214,7 +215,7 @@ static bool canRunModalIfDuringPageDismissal(Page* page, ChromeClient::DialogTyp for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext()) { FrameLoader::PageDismissalType dismissal = frame->loader()->pageDismissalEventBeingDispatched(); if (dismissal != FrameLoader::NoDismissal) - return page->chrome()->client()->shouldRunModalDialogDuringPageDismissal(dialog, message, dismissal); + return page->chrome().client()->shouldRunModalDialogDuringPageDismissal(dialog, message, dismissal); } return true; } @@ -293,7 +294,10 @@ bool Chrome::runBeforeUnloadConfirmPanel(const String& message, Frame* frame) // otherwise cause the load to continue while we're in the middle of executing JavaScript. PageGroupLoadDeferrer deferrer(m_page, true); - return m_client->runBeforeUnloadConfirmPanel(message, frame); + InspectorInstrumentationCookie cookie = InspectorInstrumentation::willRunJavaScriptDialog(m_page, message); + bool ok = m_client->runBeforeUnloadConfirmPanel(message, frame); + InspectorInstrumentation::didRunJavaScriptDialog(cookie); + return ok; } void Chrome::closeWindowSoon() @@ -312,7 +316,11 @@ void Chrome::runJavaScriptAlert(Frame* frame, const String& message) ASSERT(frame); notifyPopupOpeningObservers(); - m_client->runJavaScriptAlert(frame, frame->displayStringModifiedByEncoding(message)); + String displayMessage = frame->displayStringModifiedByEncoding(message); + + InspectorInstrumentationCookie cookie = InspectorInstrumentation::willRunJavaScriptDialog(m_page, displayMessage); + m_client->runJavaScriptAlert(frame, displayMessage); + InspectorInstrumentation::didRunJavaScriptDialog(cookie); } bool Chrome::runJavaScriptConfirm(Frame* frame, const String& message) @@ -326,7 +334,12 @@ bool Chrome::runJavaScriptConfirm(Frame* frame, const String& message) ASSERT(frame); notifyPopupOpeningObservers(); - return m_client->runJavaScriptConfirm(frame, frame->displayStringModifiedByEncoding(message)); + String displayMessage = frame->displayStringModifiedByEncoding(message); + + InspectorInstrumentationCookie cookie = InspectorInstrumentation::willRunJavaScriptDialog(m_page, displayMessage); + bool ok = m_client->runJavaScriptConfirm(frame, displayMessage); + InspectorInstrumentation::didRunJavaScriptDialog(cookie); + return ok; } bool Chrome::runJavaScriptPrompt(Frame* frame, const String& prompt, const String& defaultValue, String& result) @@ -340,7 +353,11 @@ bool Chrome::runJavaScriptPrompt(Frame* frame, const String& prompt, const Strin ASSERT(frame); notifyPopupOpeningObservers(); - bool ok = m_client->runJavaScriptPrompt(frame, frame->displayStringModifiedByEncoding(prompt), frame->displayStringModifiedByEncoding(defaultValue), result); + String displayPrompt = frame->displayStringModifiedByEncoding(prompt); + + InspectorInstrumentationCookie cookie = InspectorInstrumentation::willRunJavaScriptDialog(m_page, displayPrompt); + bool ok = m_client->runJavaScriptPrompt(frame, displayPrompt, frame->displayStringModifiedByEncoding(defaultValue), result); + InspectorInstrumentation::didRunJavaScriptDialog(cookie); if (ok) result = frame->displayStringModifiedByEncoding(result); @@ -390,8 +407,8 @@ void Chrome::setToolTip(const HitTestResult& result) if (toolTip.isEmpty() && m_page->settings()->showsURLsInToolTips()) { if (Node* node = result.innerNonSharedNode()) { // Get tooltip representing form action, if relevant - if (node->hasTagName(inputTag)) { - HTMLInputElement* input = static_cast<HTMLInputElement*>(node); + if (isHTMLInputElement(node)) { + HTMLInputElement* input = toHTMLInputElement(node); if (input->isSubmitButton()) if (HTMLFormElement* form = input->form()) { toolTip = form->action(); @@ -422,8 +439,8 @@ void Chrome::setToolTip(const HitTestResult& result) // Lastly, for <input type="file"> that allow multiple files, we'll consider a tooltip for the selected filenames if (toolTip.isEmpty()) { if (Node* node = result.innerNonSharedNode()) { - if (node->hasTagName(inputTag)) { - HTMLInputElement* input = static_cast<HTMLInputElement*>(node); + if (isHTMLInputElement(node)) { + HTMLInputElement* input = toHTMLInputElement(node); toolTip = input->defaultToolTip(); // FIXME: We should obtain text direction of tooltip from @@ -445,6 +462,16 @@ void Chrome::print(Frame* frame) m_client->print(frame); } +void Chrome::enableSuddenTermination() +{ + m_client->enableSuddenTermination(); +} + +void Chrome::disableSuddenTermination() +{ + m_client->disableSuddenTermination(); +} + #if ENABLE(DIRECTORY_UPLOAD) void Chrome::enumerateChosenDirectory(FileChooser* fileChooser) { @@ -503,6 +530,24 @@ void Chrome::scheduleAnimation() } #endif +PlatformDisplayID Chrome::displayID() const +{ + return m_displayID; +} + +void Chrome::windowScreenDidChange(PlatformDisplayID displayID) +{ + if (displayID == m_displayID) + return; + + m_displayID = displayID; + + for (Frame* frame = m_page->mainFrame(); frame; frame = frame->tree()->traverseNext()) { + if (frame->document()) + frame->document()->windowScreenDidChange(displayID); + } +} + // -------- #if ENABLE(DASHBOARD_SUPPORT) || ENABLE(DRAGGABLE_REGION) diff --git a/Source/WebCore/page/Chrome.h b/Source/WebCore/page/Chrome.h index e78f38581..f3de5ba0e 100644 --- a/Source/WebCore/page/Chrome.h +++ b/Source/WebCore/page/Chrome.h @@ -36,158 +36,163 @@ class NSView; namespace WebCore { - class ChromeClient; -#if ENABLE(INPUT_TYPE_COLOR) - class ColorChooser; - class ColorChooserClient; -#endif - class DateTimeChooser; - class DateTimeChooserClient; - class FileChooser; - class FileIconLoader; - class FloatRect; - class Frame; - class Geolocation; - class HitTestResult; - class IntRect; - class NavigationAction; - class Node; - class Page; - class PopupMenu; - class PopupMenuClient; - class PopupOpeningObserver; - class SearchPopupMenu; - - struct DateTimeChooserParameters; - struct FrameLoadRequest; - struct ViewportArguments; - struct WindowFeatures; +class ChromeClient; +class ColorChooser; +class ColorChooserClient; +class DateTimeChooser; +class DateTimeChooserClient; +class FileChooser; +class FileIconLoader; +class FloatRect; +class Frame; +class Geolocation; +class HitTestResult; +class IntRect; +class NavigationAction; +class Node; +class Page; +class PopupMenu; +class PopupMenuClient; +class PopupOpeningObserver; +class SearchPopupMenu; + +struct DateTimeChooserParameters; +struct FrameLoadRequest; +struct ViewportArguments; +struct WindowFeatures; - class Chrome : public HostWindow { - public: - ~Chrome(); - - static PassOwnPtr<Chrome> create(Page*, ChromeClient*); +class Chrome : public HostWindow { +public: + ~Chrome(); - ChromeClient* client() { return m_client; } + static PassOwnPtr<Chrome> create(Page*, ChromeClient*); - // HostWindow methods. + ChromeClient* client() { return m_client; } - virtual void invalidateRootView(const IntRect&, bool) OVERRIDE; - virtual void invalidateContentsAndRootView(const IntRect&, bool) OVERRIDE; - virtual void invalidateContentsForSlowScroll(const IntRect&, bool); - virtual void scroll(const IntSize&, const IntRect&, const IntRect&); + // HostWindow methods. + virtual void invalidateRootView(const IntRect&, bool) OVERRIDE; + virtual void invalidateContentsAndRootView(const IntRect&, bool) OVERRIDE; + virtual void invalidateContentsForSlowScroll(const IntRect&, bool) OVERRIDE; + virtual void scroll(const IntSize&, const IntRect&, const IntRect&) OVERRIDE; #if USE(TILED_BACKING_STORE) - virtual void delegatedScrollRequested(const IntPoint& scrollPoint); + virtual void delegatedScrollRequested(const IntPoint& scrollPoint) OVERRIDE; #endif - virtual IntPoint screenToRootView(const IntPoint&) const OVERRIDE; - virtual IntRect rootViewToScreen(const IntRect&) const OVERRIDE; - virtual PlatformPageClient platformPageClient() const; - virtual void scrollbarsModeDidChange() const; - virtual void setCursor(const Cursor&); - virtual void setCursorHiddenUntilMouseMoves(bool); + virtual IntPoint screenToRootView(const IntPoint&) const OVERRIDE; + virtual IntRect rootViewToScreen(const IntRect&) const OVERRIDE; + virtual PlatformPageClient platformPageClient() const OVERRIDE; + virtual void scrollbarsModeDidChange() const OVERRIDE; + virtual void setCursor(const Cursor&) OVERRIDE; + virtual void setCursorHiddenUntilMouseMoves(bool) OVERRIDE; #if ENABLE(REQUEST_ANIMATION_FRAME) - virtual void scheduleAnimation(); + virtual void scheduleAnimation() OVERRIDE; #endif - void scrollRectIntoView(const IntRect&) const; + virtual PlatformDisplayID displayID() const OVERRIDE; + virtual void windowScreenDidChange(PlatformDisplayID) OVERRIDE; + + void scrollRectIntoView(const IntRect&) const; + + void contentsSizeChanged(Frame*, const IntSize&) const; + void layoutUpdated(Frame*) const; + + void setWindowRect(const FloatRect&) const; + FloatRect windowRect() const; - void contentsSizeChanged(Frame*, const IntSize&) const; - void layoutUpdated(Frame*) const; + FloatRect pageRect() const; - void setWindowRect(const FloatRect&) const; - FloatRect windowRect() const; + void focus() const; + void unfocus() const; - FloatRect pageRect() const; - - void focus() const; - void unfocus() const; + bool canTakeFocus(FocusDirection) const; + void takeFocus(FocusDirection) const; - bool canTakeFocus(FocusDirection) const; - void takeFocus(FocusDirection) const; + void focusedNodeChanged(Node*) const; + void focusedFrameChanged(Frame*) const; - void focusedNodeChanged(Node*) const; - void focusedFrameChanged(Frame*) const; + Page* createWindow(Frame*, const FrameLoadRequest&, const WindowFeatures&, const NavigationAction&) const; + void show() const; - Page* createWindow(Frame*, const FrameLoadRequest&, const WindowFeatures&, const NavigationAction&) const; - void show() const; + bool canRunModal() const; + bool canRunModalNow() const; + void runModal() const; - bool canRunModal() const; - bool canRunModalNow() const; - void runModal() const; + void setToolbarsVisible(bool) const; + bool toolbarsVisible() const; - void setToolbarsVisible(bool) const; - bool toolbarsVisible() const; - - void setStatusbarVisible(bool) const; - bool statusbarVisible() const; - - void setScrollbarsVisible(bool) const; - bool scrollbarsVisible() const; - - void setMenubarVisible(bool) const; - bool menubarVisible() const; - - void setResizable(bool) const; + void setStatusbarVisible(bool) const; + bool statusbarVisible() const; - bool canRunBeforeUnloadConfirmPanel(); - bool runBeforeUnloadConfirmPanel(const String& message, Frame* frame); + void setScrollbarsVisible(bool) const; + bool scrollbarsVisible() const; - void closeWindowSoon(); + void setMenubarVisible(bool) const; + bool menubarVisible() const; - void runJavaScriptAlert(Frame*, const String&); - bool runJavaScriptConfirm(Frame*, const String&); - bool runJavaScriptPrompt(Frame*, const String& message, const String& defaultValue, String& result); - void setStatusbarText(Frame*, const String&); - bool shouldInterruptJavaScript(); + void setResizable(bool) const; - IntRect windowResizerRect() const; + bool canRunBeforeUnloadConfirmPanel(); + bool runBeforeUnloadConfirmPanel(const String& message, Frame*); - void mouseDidMoveOverElement(const HitTestResult&, unsigned modifierFlags); + void closeWindowSoon(); - void setToolTip(const HitTestResult&); + void runJavaScriptAlert(Frame*, const String&); + bool runJavaScriptConfirm(Frame*, const String&); + bool runJavaScriptPrompt(Frame*, const String& message, const String& defaultValue, String& result); + void setStatusbarText(Frame*, const String&); + bool shouldInterruptJavaScript(); - void print(Frame*); + IntRect windowResizerRect() const; + + void mouseDidMoveOverElement(const HitTestResult&, unsigned modifierFlags); + + void setToolTip(const HitTestResult&); + + void print(Frame*); + + void enableSuddenTermination(); + void disableSuddenTermination(); #if ENABLE(INPUT_TYPE_COLOR) - PassOwnPtr<ColorChooser> createColorChooser(ColorChooserClient*, const Color& initialColor); + PassOwnPtr<ColorChooser> createColorChooser(ColorChooserClient*, const Color& initialColor); #endif #if ENABLE(DATE_AND_TIME_INPUT_TYPES) - PassRefPtr<DateTimeChooser> openDateTimeChooser(DateTimeChooserClient*, const DateTimeChooserParameters&); + PassRefPtr<DateTimeChooser> openDateTimeChooser(DateTimeChooserClient*, const DateTimeChooserParameters&); #endif - void runOpenPanel(Frame*, PassRefPtr<FileChooser>); - void loadIconForFiles(const Vector<String>&, FileIconLoader*); + void runOpenPanel(Frame*, PassRefPtr<FileChooser>); + void loadIconForFiles(const Vector<String>&, FileIconLoader*); #if ENABLE(DIRECTORY_UPLOAD) - void enumerateChosenDirectory(FileChooser*); + void enumerateChosenDirectory(FileChooser*); #endif - void dispatchViewportPropertiesDidChange(const ViewportArguments&) const; + void dispatchViewportPropertiesDidChange(const ViewportArguments&) const; - bool requiresFullscreenForVideoPlayback(); + bool requiresFullscreenForVideoPlayback(); #if PLATFORM(MAC) - void focusNSView(NSView*); + void focusNSView(NSView*); #endif - bool selectItemWritingDirectionIsNatural(); - bool selectItemAlignmentFollowsMenuWritingDirection(); - bool hasOpenedPopup() const; - PassRefPtr<PopupMenu> createPopupMenu(PopupMenuClient*) const; - PassRefPtr<SearchPopupMenu> createSearchPopupMenu(PopupMenuClient*) const; + bool selectItemWritingDirectionIsNatural(); + bool selectItemAlignmentFollowsMenuWritingDirection(); + bool hasOpenedPopup() const; + PassRefPtr<PopupMenu> createPopupMenu(PopupMenuClient*) const; + PassRefPtr<SearchPopupMenu> createSearchPopupMenu(PopupMenuClient*) const; + + void registerPopupOpeningObserver(PopupOpeningObserver*); + void unregisterPopupOpeningObserver(PopupOpeningObserver*); - void registerPopupOpeningObserver(PopupOpeningObserver*); - void unregisterPopupOpeningObserver(PopupOpeningObserver*); +private: + Chrome(Page*, ChromeClient*); + void notifyPopupOpeningObservers() const; - private: - Chrome(Page*, ChromeClient*); - void notifyPopupOpeningObservers() const; + Page* m_page; + ChromeClient* m_client; + PlatformDisplayID m_displayID; + Vector<PopupOpeningObserver*> m_popupOpeningObservers; +}; - Page* m_page; - ChromeClient* m_client; - Vector<PopupOpeningObserver*> m_popupOpeningObservers; - }; } #endif // Chrome_h diff --git a/Source/WebCore/page/ChromeClient.h b/Source/WebCore/page/ChromeClient.h index ad6eb1fb1..6fce249eb 100644 --- a/Source/WebCore/page/ChromeClient.h +++ b/Source/WebCore/page/ChromeClient.h @@ -23,6 +23,7 @@ #define ChromeClient_h #include "AXObjectCache.h" +#include "ConsoleAPITypes.h" #include "ConsoleTypes.h" #include "Cursor.h" #include "FocusDirection.h" @@ -37,345 +38,345 @@ #include "WebCoreKeyboardUIMode.h" #include <wtf/Forward.h> #include <wtf/PassOwnPtr.h> -#include <wtf/UnusedParam.h> #include <wtf/Vector.h> -#ifndef __OBJC__ -class NSMenu; -class NSResponder; -#endif - -namespace WebCore { - - class AccessibilityObject; - class DateTimeChooser; - class DateTimeChooserClient; - class Element; - class FileChooser; - class FileIconLoader; - class FloatRect; - class Frame; - class Geolocation; - class GraphicsLayer; - class HTMLInputElement; - class HitTestResult; - class IntRect; - class NavigationAction; - class Node; - class Page; - class PagePopup; - class PagePopupClient; - class PagePopupDriver; - class PopupMenuClient; - class SecurityOrigin; - class GraphicsContext3D; - class Widget; - - struct DateTimeChooserParameters; - struct FrameLoadRequest; - struct ViewportArguments; - struct WindowFeatures; - -#if USE(ACCELERATED_COMPOSITING) - class GraphicsLayer; - class GraphicsLayerFactory; -#endif - -#if ENABLE(INPUT_TYPE_COLOR) - class ColorChooser; - class ColorChooserClient; -#endif - -#if PLATFORM(WIN) && USE(AVFOUNDATION) - struct GraphicsDeviceAdapter; +#if ENABLE(SQL_DATABASE) +#include "DatabaseDetails.h" #endif - class ChromeClient { - public: - virtual void chromeDestroyed() = 0; - - virtual void setWindowRect(const FloatRect&) = 0; - virtual FloatRect windowRect() = 0; - - virtual FloatRect pageRect() = 0; - - virtual void focus() = 0; - virtual void unfocus() = 0; - - virtual bool canTakeFocus(FocusDirection) = 0; - virtual void takeFocus(FocusDirection) = 0; - - virtual void focusedNodeChanged(Node*) = 0; - virtual void focusedFrameChanged(Frame*) = 0; - - // The Frame pointer provides the ChromeClient with context about which - // Frame wants to create the new Page. Also, the newly created window - // should not be shown to the user until the ChromeClient of the newly - // created Page has its show method called. - // The FrameLoadRequest parameter is only for ChromeClient to check if the - // request could be fulfilled. The ChromeClient should not load the request. - virtual Page* createWindow(Frame*, const FrameLoadRequest&, const WindowFeatures&, const NavigationAction&) = 0; - virtual void show() = 0; - - virtual bool canRunModal() = 0; - virtual void runModal() = 0; - - virtual void setToolbarsVisible(bool) = 0; - virtual bool toolbarsVisible() = 0; - - virtual void setStatusbarVisible(bool) = 0; - virtual bool statusbarVisible() = 0; - - virtual void setScrollbarsVisible(bool) = 0; - virtual bool scrollbarsVisible() = 0; - - virtual void setMenubarVisible(bool) = 0; - virtual bool menubarVisible() = 0; - - virtual void setResizable(bool) = 0; - - virtual void addMessageToConsole(MessageSource, MessageType, MessageLevel, const String& message, unsigned int lineNumber, const String& sourceID) = 0; +OBJC_CLASS NSResponder; - virtual bool canRunBeforeUnloadConfirmPanel() = 0; - virtual bool runBeforeUnloadConfirmPanel(const String& message, Frame* frame) = 0; +namespace WebCore { - virtual void closeWindowSoon() = 0; - - virtual void runJavaScriptAlert(Frame*, const String&) = 0; - virtual bool runJavaScriptConfirm(Frame*, const String&) = 0; - virtual bool runJavaScriptPrompt(Frame*, const String& message, const String& defaultValue, String& result) = 0; - virtual void setStatusbarText(const String&) = 0; - virtual bool shouldInterruptJavaScript() = 0; - virtual KeyboardUIMode keyboardUIMode() = 0; - - virtual void* webView() const = 0; - - virtual IntRect windowResizerRect() const = 0; - - // Methods used by HostWindow. - virtual void invalidateRootView(const IntRect&, bool) = 0; - virtual void invalidateContentsAndRootView(const IntRect&, bool) = 0; - virtual void invalidateContentsForSlowScroll(const IntRect&, bool) = 0; - virtual void scroll(const IntSize&, const IntRect&, const IntRect&) = 0; +class AccessibilityObject; +class ColorChooser; +class ColorChooserClient; +class DateTimeChooser; +class DateTimeChooserClient; +class Element; +class FileChooser; +class FileIconLoader; +class FloatRect; +class Frame; +class Geolocation; +class GraphicsContext3D; +class GraphicsLayer; +class GraphicsLayerFactory; +class HitTestResult; +class HTMLInputElement; +class IntRect; +class NavigationAction; +class Node; +class Page; +class PopupMenuClient; +class SecurityOrigin; +class Widget; + +struct DateTimeChooserParameters; +struct FrameLoadRequest; +struct GraphicsDeviceAdapter; +struct ViewportArguments; +struct WindowFeatures; + +class ChromeClient { +public: + virtual void chromeDestroyed() = 0; + + virtual void setWindowRect(const FloatRect&) = 0; + virtual FloatRect windowRect() = 0; + + virtual FloatRect pageRect() = 0; + + virtual void focus() = 0; + virtual void unfocus() = 0; + + virtual bool canTakeFocus(FocusDirection) = 0; + virtual void takeFocus(FocusDirection) = 0; + + virtual void focusedNodeChanged(Node*) = 0; + virtual void focusedFrameChanged(Frame*) = 0; + + // The Frame pointer provides the ChromeClient with context about which + // Frame wants to create the new Page. Also, the newly created window + // should not be shown to the user until the ChromeClient of the newly + // created Page has its show method called. + // The FrameLoadRequest parameter is only for ChromeClient to check if the + // request could be fulfilled. The ChromeClient should not load the request. + virtual Page* createWindow(Frame*, const FrameLoadRequest&, const WindowFeatures&, const NavigationAction&) = 0; + virtual void show() = 0; + + virtual bool canRunModal() = 0; + virtual void runModal() = 0; + + virtual void setToolbarsVisible(bool) = 0; + virtual bool toolbarsVisible() = 0; + + virtual void setStatusbarVisible(bool) = 0; + virtual bool statusbarVisible() = 0; + + virtual void setScrollbarsVisible(bool) = 0; + virtual bool scrollbarsVisible() = 0; + + virtual void setMenubarVisible(bool) = 0; + virtual bool menubarVisible() = 0; + + virtual void setResizable(bool) = 0; + + virtual void addMessageToConsole(MessageSource, MessageLevel, const String& message, unsigned lineNumber, unsigned columnNumber, const String& sourceID) = 0; + // FIXME: Remove this MessageType variant once all the clients are updated. + virtual void addMessageToConsole(MessageSource source, MessageType, MessageLevel level, const String& message, unsigned lineNumber, unsigned columnNumber, const String& sourceID) + { + addMessageToConsole(source, level, message, lineNumber, columnNumber, sourceID); + } + + virtual bool canRunBeforeUnloadConfirmPanel() = 0; + virtual bool runBeforeUnloadConfirmPanel(const String& message, Frame*) = 0; + + virtual void closeWindowSoon() = 0; + + virtual void runJavaScriptAlert(Frame*, const String&) = 0; + virtual bool runJavaScriptConfirm(Frame*, const String&) = 0; + virtual bool runJavaScriptPrompt(Frame*, const String& message, const String& defaultValue, String& result) = 0; + virtual void setStatusbarText(const String&) = 0; + virtual bool shouldInterruptJavaScript() = 0; + virtual KeyboardUIMode keyboardUIMode() = 0; + + virtual IntRect windowResizerRect() const = 0; + + // Methods used by HostWindow. + virtual bool supportsImmediateInvalidation() { return false; } + virtual void invalidateRootView(const IntRect&, bool immediate) = 0; + virtual void invalidateContentsAndRootView(const IntRect&, bool immediate) = 0; + virtual void invalidateContentsForSlowScroll(const IntRect&, bool immediate) = 0; + virtual void scroll(const IntSize&, const IntRect&, const IntRect&) = 0; #if USE(TILED_BACKING_STORE) - virtual void delegatedScrollRequested(const IntPoint&) = 0; + virtual void delegatedScrollRequested(const IntPoint&) = 0; #endif - virtual IntPoint screenToRootView(const IntPoint&) const = 0; - virtual IntRect rootViewToScreen(const IntRect&) const = 0; - virtual PlatformPageClient platformPageClient() const = 0; - virtual void scrollbarsModeDidChange() const = 0; - virtual void setCursor(const Cursor&) = 0; - virtual void setCursorHiddenUntilMouseMoves(bool) = 0; + virtual IntPoint screenToRootView(const IntPoint&) const = 0; + virtual IntRect rootViewToScreen(const IntRect&) const = 0; + virtual PlatformPageClient platformPageClient() const = 0; + virtual void scrollbarsModeDidChange() const = 0; + virtual void setCursor(const Cursor&) = 0; + virtual void setCursorHiddenUntilMouseMoves(bool) = 0; #if ENABLE(REQUEST_ANIMATION_FRAME) && !USE(REQUEST_ANIMATION_FRAME_TIMER) - virtual void scheduleAnimation() = 0; + virtual void scheduleAnimation() = 0; #endif - // End methods used by HostWindow. + // End methods used by HostWindow. + + virtual void dispatchViewportPropertiesDidChange(const ViewportArguments&) const { } + + virtual void contentsSizeChanged(Frame*, const IntSize&) const = 0; + virtual void layoutUpdated(Frame*) const { } + virtual void scrollRectIntoView(const IntRect&) const { }; // Currently only Mac has a non empty implementation. - virtual void dispatchViewportPropertiesDidChange(const ViewportArguments&) const { } + virtual bool shouldUnavailablePluginMessageBeButton(RenderEmbeddedObject::PluginUnavailabilityReason) const { return false; } + virtual void unavailablePluginButtonClicked(Element*, RenderEmbeddedObject::PluginUnavailabilityReason) const { } + virtual void mouseDidMoveOverElement(const HitTestResult&, unsigned modifierFlags) = 0; - virtual void contentsSizeChanged(Frame*, const IntSize&) const = 0; - virtual void layoutUpdated(Frame*) const { } - virtual void scrollRectIntoView(const IntRect&) const { }; // Currently only Mac has a non empty implementation. - - virtual bool shouldUnavailablePluginMessageBeButton(RenderEmbeddedObject::PluginUnavailabilityReason) const { return false; } - virtual void unavailablePluginButtonClicked(Element*, RenderEmbeddedObject::PluginUnavailabilityReason) const { } - virtual void mouseDidMoveOverElement(const HitTestResult&, unsigned modifierFlags) = 0; + virtual void setToolTip(const String&, TextDirection) = 0; - virtual void setToolTip(const String&, TextDirection) = 0; + virtual void print(Frame*) = 0; + virtual bool shouldRubberBandInDirection(ScrollDirection) const = 0; - virtual void print(Frame*) = 0; - virtual bool shouldRubberBandInDirection(ScrollDirection) const = 0; + virtual Color underlayColor() const { return Color(); } #if ENABLE(SQL_DATABASE) - virtual void exceededDatabaseQuota(Frame*, const String& databaseName) = 0; + virtual void exceededDatabaseQuota(Frame*, const String& databaseName, DatabaseDetails) = 0; #endif - // Callback invoked when the application cache fails to save a cache object - // because storing it would grow the database file past its defined maximum - // size or past the amount of free space on the device. - // The chrome client would need to take some action such as evicting some - // old caches. - virtual void reachedMaxAppCacheSize(int64_t spaceNeeded) = 0; - - // Callback invoked when the application cache origin quota is reached. This - // means that the resources attempting to be cached via the manifest are - // more than allowed on this origin. This callback allows the chrome client - // to take action, such as prompting the user to ask to increase the quota - // for this origin. The totalSpaceNeeded parameter is the total amount of - // storage, in bytes, needed to store the new cache along with all of the - // other existing caches for the origin that would not be replaced by - // the new cache. - virtual void reachedApplicationCacheOriginQuota(SecurityOrigin*, int64_t totalSpaceNeeded) = 0; + // Callback invoked when the application cache fails to save a cache object + // because storing it would grow the database file past its defined maximum + // size or past the amount of free space on the device. + // The chrome client would need to take some action such as evicting some + // old caches. + virtual void reachedMaxAppCacheSize(int64_t spaceNeeded) = 0; + + // Callback invoked when the application cache origin quota is reached. This + // means that the resources attempting to be cached via the manifest are + // more than allowed on this origin. This callback allows the chrome client + // to take action, such as prompting the user to ask to increase the quota + // for this origin. The totalSpaceNeeded parameter is the total amount of + // storage, in bytes, needed to store the new cache along with all of the + // other existing caches for the origin that would not be replaced by + // the new cache. + virtual void reachedApplicationCacheOriginQuota(SecurityOrigin*, int64_t totalSpaceNeeded) = 0; #if ENABLE(DASHBOARD_SUPPORT) || ENABLE(DRAGGABLE_REGION) - virtual void annotatedRegionsChanged(); + virtual void annotatedRegionsChanged(); #endif - virtual void populateVisitedLinks(); + virtual void populateVisitedLinks(); - virtual FloatRect customHighlightRect(Node*, const AtomicString& type, const FloatRect& lineRect); - virtual void paintCustomHighlight(Node*, const AtomicString& type, const FloatRect& boxRect, const FloatRect& lineRect, - bool behindText, bool entireLine); + virtual FloatRect customHighlightRect(Node*, const AtomicString& type, const FloatRect& lineRect); + virtual void paintCustomHighlight(Node*, const AtomicString& type, const FloatRect& boxRect, const FloatRect& lineRect, bool behindText, bool entireLine); - virtual bool shouldReplaceWithGeneratedFileForUpload(const String& path, String& generatedFilename); - virtual String generateReplacementFile(const String& path); + virtual bool shouldReplaceWithGeneratedFileForUpload(const String& path, String& generatedFilename); + virtual String generateReplacementFile(const String& path); - virtual bool paintCustomOverhangArea(GraphicsContext*, const IntRect&, const IntRect&, const IntRect&); + virtual bool paintCustomOverhangArea(GraphicsContext*, const IntRect&, const IntRect&, const IntRect&); #if ENABLE(INPUT_TYPE_COLOR) - virtual PassOwnPtr<ColorChooser> createColorChooser(ColorChooserClient*, const Color&) = 0; + virtual PassOwnPtr<ColorChooser> createColorChooser(ColorChooserClient*, const Color&) = 0; #endif #if ENABLE(DATE_AND_TIME_INPUT_TYPES) - // This function is used for: - // - Mandatory date/time choosers if !ENABLE(INPUT_MULTIPLE_FIELDS_UI) - // - Date/time choosers for types for which RenderTheme::supportsCalendarPicker - // returns true, if ENABLE(INPUT_MULTIPLE_FIELDS_UI) - // - <datalist> UI for date/time input types regardless of - // ENABLE(INPUT_MULTIPLE_FIELDS_UI) - virtual PassRefPtr<DateTimeChooser> openDateTimeChooser(DateTimeChooserClient*, const DateTimeChooserParameters&) = 0; + virtual PassRefPtr<DateTimeChooser> openDateTimeChooser(DateTimeChooserClient*, const DateTimeChooserParameters&) = 0; #endif - virtual void runOpenPanel(Frame*, PassRefPtr<FileChooser>) = 0; - // Asynchronous request to load an icon for specified filenames. - virtual void loadIconForFiles(const Vector<String>&, FileIconLoader*) = 0; + virtual void runOpenPanel(Frame*, PassRefPtr<FileChooser>) = 0; + // Asynchronous request to load an icon for specified filenames. + virtual void loadIconForFiles(const Vector<String>&, FileIconLoader*) = 0; #if ENABLE(DIRECTORY_UPLOAD) - // Asychronous request to enumerate all files in a directory chosen by the user. - virtual void enumerateChosenDirectory(FileChooser*) = 0; + // Asychronous request to enumerate all files in a directory chosen by the user. + virtual void enumerateChosenDirectory(FileChooser*) = 0; #endif - // Notification that the given form element has changed. This function - // will be called frequently, so handling should be very fast. - virtual void formStateDidChange(const Node*) = 0; + // Notification that the given form element has changed. This function + // will be called frequently, so handling should be very fast. + virtual void formStateDidChange(const Node*) = 0; - virtual void elementDidFocus(const Node*) { }; - virtual void elementDidBlur(const Node*) { }; + virtual void elementDidFocus(const Node*) { }; + virtual void elementDidBlur(const Node*) { }; + + virtual bool shouldPaintEntireContents() const { return false; } #if USE(ACCELERATED_COMPOSITING) - // Allows ports to customize the type of graphics layers created by this page. - virtual GraphicsLayerFactory* graphicsLayerFactory() const { return 0; } - - // Pass 0 as the GraphicsLayer to detatch the root layer. - virtual void attachRootGraphicsLayer(Frame*, GraphicsLayer*) = 0; - // Sets a flag to specify that the next time content is drawn to the window, - // the changes appear on the screen in synchrony with updates to GraphicsLayers. - virtual void setNeedsOneShotDrawingSynchronization() = 0; - // Sets a flag to specify that the view needs to be updated, so we need - // to do an eager layout before the drawing. - virtual void scheduleCompositingLayerFlush() = 0; - // Returns whether or not the client can render the composited layer, - // regardless of the settings. - virtual bool allowsAcceleratedCompositing() const { return true; } - - enum CompositingTrigger { - ThreeDTransformTrigger = 1 << 0, - VideoTrigger = 1 << 1, - PluginTrigger = 1 << 2, - CanvasTrigger = 1 << 3, - AnimationTrigger = 1 << 4, - FilterTrigger = 1 << 5, - AnimatedOpacityTrigger = 1 << 6, - AllTriggers = 0xFFFFFFFF - }; - typedef unsigned CompositingTriggerFlags; - - // Returns a bitfield indicating conditions that can trigger the compositor. - virtual CompositingTriggerFlags allowedCompositingTriggers() const { return static_cast<CompositingTriggerFlags>(AllTriggers); } + // Allows ports to customize the type of graphics layers created by this page. + virtual GraphicsLayerFactory* graphicsLayerFactory() const { return 0; } + + // Pass 0 as the GraphicsLayer to detatch the root layer. + virtual void attachRootGraphicsLayer(Frame*, GraphicsLayer*) = 0; + // Sets a flag to specify that the next time content is drawn to the window, + // the changes appear on the screen in synchrony with updates to GraphicsLayers. + virtual void setNeedsOneShotDrawingSynchronization() = 0; + // Sets a flag to specify that the view needs to be updated, so we need + // to do an eager layout before the drawing. + virtual void scheduleCompositingLayerFlush() = 0; + // Returns whether or not the client can render the composited layer, + // regardless of the settings. + virtual bool allowsAcceleratedCompositing() const { return true; } + + enum CompositingTrigger { + ThreeDTransformTrigger = 1 << 0, + VideoTrigger = 1 << 1, + PluginTrigger = 1 << 2, + CanvasTrigger = 1 << 3, + AnimationTrigger = 1 << 4, + FilterTrigger = 1 << 5, + ScrollableInnerFrameTrigger = 1 << 6, + AnimatedOpacityTrigger = 1 << 7, + AllTriggers = 0xFFFFFFFF + }; + typedef unsigned CompositingTriggerFlags; + + // Returns a bitfield indicating conditions that can trigger the compositor. + virtual CompositingTriggerFlags allowedCompositingTriggers() const { return static_cast<CompositingTriggerFlags>(AllTriggers); } + + // Returns true if layer tree updates are disabled. + virtual bool layerTreeStateIsFrozen() const { return false; } #endif #if PLATFORM(WIN) && USE(AVFOUNDATION) - virtual GraphicsDeviceAdapter* graphicsDeviceAdapter() const { return 0; } + virtual GraphicsDeviceAdapter* graphicsDeviceAdapter() const { return 0; } #endif - virtual bool supportsFullscreenForNode(const Node*) { return false; } - virtual void enterFullscreenForNode(Node*) { } - virtual void exitFullscreenForNode(Node*) { } - virtual bool requiresFullscreenForVideoPlayback() { return false; } + virtual bool supportsFullscreenForNode(const Node*) { return false; } + virtual void enterFullscreenForNode(Node*) { } + virtual void exitFullscreenForNode(Node*) { } + virtual bool requiresFullscreenForVideoPlayback() { return false; } #if ENABLE(FULLSCREEN_API) - virtual bool supportsFullScreenForElement(const Element*, bool) { return false; } - virtual void enterFullScreenForElement(Element*) { } - virtual void exitFullScreenForElement(Element*) { } - virtual void fullScreenRendererChanged(RenderBox*) { } - virtual void setRootFullScreenLayer(GraphicsLayer*) { } + virtual bool supportsFullScreenForElement(const Element*, bool) { return false; } + virtual void enterFullScreenForElement(Element*) { } + virtual void exitFullScreenForElement(Element*) { } + virtual void fullScreenRendererChanged(RenderBox*) { } + virtual void setRootFullScreenLayer(GraphicsLayer*) { } #endif - + #if USE(TILED_BACKING_STORE) - virtual IntRect visibleRectForTiledBackingStore() const { return IntRect(); } + virtual IntRect visibleRectForTiledBackingStore() const { return IntRect(); } #endif #if PLATFORM(MAC) - virtual NSResponder *firstResponder() { return 0; } - virtual void makeFirstResponder(NSResponder *) { } - // Focuses on the containing view associated with this page. - virtual void makeFirstResponder() { } - virtual void willPopUpMenu(NSMenu *) { } + virtual NSResponder *firstResponder() { return 0; } + virtual void makeFirstResponder(NSResponder *) { } + // Focuses on the containing view associated with this page. + virtual void makeFirstResponder() { } #endif + virtual void enableSuddenTermination() { } + virtual void disableSuddenTermination() { } + #if PLATFORM(WIN) - virtual void setLastSetCursorToCurrentCursor() = 0; + virtual void setLastSetCursorToCurrentCursor() = 0; + virtual void AXStartFrameLoad() = 0; + virtual void AXFinishFrameLoad() = 0; #endif #if ENABLE(TOUCH_EVENTS) - virtual void needTouchEvents(bool) = 0; + virtual void needTouchEvents(bool) = 0; #endif - virtual bool selectItemWritingDirectionIsNatural() = 0; - virtual bool selectItemAlignmentFollowsMenuWritingDirection() = 0; - // Checks if there is an opened popup, called by RenderMenuList::showPopup(). - virtual bool hasOpenedPopup() const = 0; - virtual PassRefPtr<PopupMenu> createPopupMenu(PopupMenuClient*) const = 0; - virtual PassRefPtr<SearchPopupMenu> createSearchPopupMenu(PopupMenuClient*) const = 0; -#if ENABLE(PAGE_POPUP) - // Creates a PagePopup object, and shows it beside originBoundsInRootView. - // The return value can be 0. - virtual PagePopup* openPagePopup(PagePopupClient*, const IntRect& originBoundsInRootView) = 0; - virtual void closePagePopup(PagePopup*) = 0; - // For testing. - virtual void setPagePopupDriver(PagePopupDriver*) = 0; - virtual void resetPagePopupDriver() = 0; -#endif - // This function is called whenever a text field <input> is - // created. The implementation should return true if it wants - // to do something in addTextFieldDecorationsTo(). - // The argument is always non-0. - virtual bool willAddTextFieldDecorationsTo(HTMLInputElement*) { return false; } - // The argument is always non-0. - virtual void addTextFieldDecorationsTo(HTMLInputElement*) { } - - virtual void postAccessibilityNotification(AccessibilityObject*, AXObjectCache::AXNotification) { } - - virtual void notifyScrollerThumbIsVisibleInRect(const IntRect&) { } - virtual void recommendedScrollbarStyleDidChange(int /*newStyle*/) { } - - enum DialogType { - AlertDialog = 0, - ConfirmDialog = 1, - PromptDialog = 2, - HTMLDialog = 3 - }; - virtual bool shouldRunModalDialogDuringPageDismissal(const DialogType&, const String& dialogMessage, FrameLoader::PageDismissalType) const { UNUSED_PARAM(dialogMessage); return true; } - - virtual void numWheelEventHandlersChanged(unsigned) = 0; + virtual bool selectItemWritingDirectionIsNatural() = 0; + virtual bool selectItemAlignmentFollowsMenuWritingDirection() = 0; + // Checks if there is an opened popup, called by RenderMenuList::showPopup(). + virtual bool hasOpenedPopup() const = 0; + virtual PassRefPtr<PopupMenu> createPopupMenu(PopupMenuClient*) const = 0; + virtual PassRefPtr<SearchPopupMenu> createSearchPopupMenu(PopupMenuClient*) const = 0; + + virtual void postAccessibilityNotification(AccessibilityObject*, AXObjectCache::AXNotification) { } + + virtual void notifyScrollerThumbIsVisibleInRect(const IntRect&) { } + virtual void recommendedScrollbarStyleDidChange(int /*newStyle*/) { } + + enum DialogType { + AlertDialog = 0, + ConfirmDialog = 1, + PromptDialog = 2, + HTMLDialog = 3 + }; + virtual bool shouldRunModalDialogDuringPageDismissal(const DialogType&, const String& dialogMessage, FrameLoader::PageDismissalType) const { UNUSED_PARAM(dialogMessage); return true; } + + virtual void numWheelEventHandlersChanged(unsigned) = 0; - virtual bool isSVGImageChromeClient() const { return false; } + virtual bool isSVGImageChromeClient() const { return false; } #if ENABLE(POINTER_LOCK) - virtual bool requestPointerLock() { return false; } - virtual void requestPointerUnlock() { } - virtual bool isPointerLocked() { return false; } + virtual bool requestPointerLock() { return false; } + virtual void requestPointerUnlock() { } + virtual bool isPointerLocked() { return false; } #endif - virtual void logDiagnosticMessage(const String& message, const String& description, const String& status) { UNUSED_PARAM(message); UNUSED_PARAM(description); UNUSED_PARAM(status); } + virtual void logDiagnosticMessage(const String& message, const String& description, const String& status) { UNUSED_PARAM(message); UNUSED_PARAM(description); UNUSED_PARAM(status); } - virtual FloatSize minimumWindowSize() const { return FloatSize(100, 100); }; + virtual FloatSize minimumWindowSize() const { return FloatSize(100, 100); }; - virtual bool isEmptyChromeClient() const { return false; } + virtual bool isEmptyChromeClient() const { return false; } - protected: - virtual ~ChromeClient() { } - }; + virtual String plugInStartLabelTitle(const String& mimeType) const { UNUSED_PARAM(mimeType); return String(); } + virtual String plugInStartLabelSubtitle(const String& mimeType) const { UNUSED_PARAM(mimeType); return String(); } + virtual String plugInExtraStyleSheet() const { return String(); } + virtual String plugInExtraScript() const { return String(); } + + // FIXME: Port should return true using heuristic based on scrollable(RenderBox). + virtual bool shouldAutoscrollForDragAndDrop(RenderBox*) const { return false; } + + virtual void didAssociateFormControls(const Vector<RefPtr<Element> >&) { }; + virtual bool shouldNotifyOnFormChanges() { return false; }; + + virtual void didAddHeaderLayer(GraphicsLayer*) { } + virtual void didAddFooterLayer(GraphicsLayer*) { } + + // These methods are used to report pages that are performing + // some task that we consider to be "active", and so the user + // would likely want the page to remain running uninterrupted. + virtual void incrementActivePageCount() { } + virtual void decrementActivePageCount() { } + +protected: + virtual ~ChromeClient() { } +}; } #endif // ChromeClient_h diff --git a/Source/WebCore/page/Console.cpp b/Source/WebCore/page/Console.cpp index c9bbfd5f2..aef5ccb6f 100644 --- a/Source/WebCore/page/Console.cpp +++ b/Source/WebCore/page/Console.cpp @@ -31,13 +31,16 @@ #include "Chrome.h" #include "ChromeClient.h" +#include "ConsoleAPITypes.h" +#include "ConsoleTypes.h" +#include "Document.h" #include "Frame.h" #include "FrameLoader.h" #include "FrameTree.h" #include "InspectorConsoleInstrumentation.h" #include "InspectorController.h" -#include "MemoryInfo.h" #include "Page.h" +#include "PageConsole.h" #include "PageGroup.h" #include "ScriptArguments.h" #include "ScriptCallStack.h" @@ -45,21 +48,14 @@ #include "ScriptProfile.h" #include "ScriptProfiler.h" #include "ScriptValue.h" +#include "ScriptableDocumentParser.h" +#include "Settings.h" #include <stdio.h> -#include <wtf/UnusedParam.h> #include <wtf/text/CString.h> #include <wtf/text/WTFString.h> -#if PLATFORM(CHROMIUM) -#include "TraceEvent.h" -#endif - namespace WebCore { -namespace { - int muteCount = 0; -} - Console::Console(Frame* frame) : DOMWindowProperty(frame) { @@ -69,105 +65,10 @@ Console::~Console() { } -static void printSourceURLAndLine(const String& sourceURL, unsigned lineNumber) -{ - if (!sourceURL.isEmpty()) { - if (lineNumber > 0) - printf("%s:%d: ", sourceURL.utf8().data(), lineNumber); - else - printf("%s: ", sourceURL.utf8().data()); - } -} - -static void printMessageSourceAndLevelPrefix(MessageSource source, MessageLevel level) -{ - const char* sourceString; - switch (source) { - case HTMLMessageSource: - sourceString = "HTML"; - break; - case XMLMessageSource: - sourceString = "XML"; - break; - case JSMessageSource: - sourceString = "JS"; - break; - case NetworkMessageSource: - sourceString = "NETWORK"; - break; - case ConsoleAPIMessageSource: - sourceString = "CONSOLEAPI"; - break; - case OtherMessageSource: - sourceString = "OTHER"; - break; - default: - ASSERT_NOT_REACHED(); - sourceString = "UNKNOWN"; - break; - } - - const char* levelString; - switch (level) { - case TipMessageLevel: - levelString = "TIP"; - break; - case LogMessageLevel: - levelString = "LOG"; - break; - case WarningMessageLevel: - levelString = "WARN"; - break; - case ErrorMessageLevel: - levelString = "ERROR"; - break; - case DebugMessageLevel: - levelString = "DEBUG"; - break; - default: - ASSERT_NOT_REACHED(); - levelString = "UNKNOWN"; - break; - } - - printf("%s %s:", sourceString, levelString); -} - -void Console::addMessage(MessageSource source, MessageType type, MessageLevel level, const String& message, PassRefPtr<ScriptCallStack> callStack) -{ - addMessage(source, type, level, message, String(), 0, callStack, 0); -} - -void Console::addMessage(MessageSource source, MessageType type, MessageLevel level, const String& message, const String& url, unsigned lineNumber, PassRefPtr<ScriptCallStack> callStack, unsigned long requestIdentifier) -{ - if (muteCount && source != ConsoleAPIMessageSource) - return; - - Page* page = this->page(); - if (!page) - return; - - page->chrome()->client()->addMessageToConsole(source, type, level, message, lineNumber, url); - - if (callStack) - InspectorInstrumentation::addMessageToConsole(page, source, type, level, message, callStack, requestIdentifier); - else - InspectorInstrumentation::addMessageToConsole(page, source, type, level, message, url, lineNumber, requestIdentifier); - - if (!Console::shouldPrintExceptions()) - return; - - printSourceURLAndLine(url, lineNumber); - printMessageSourceAndLevelPrefix(source, level); - - printf(" %s\n", message.utf8().data()); -} - -void Console::addMessage(MessageType type, MessageLevel level, ScriptState* state, PassRefPtr<ScriptArguments> prpArguments, bool acceptNoArguments, bool printTrace) +static void internalAddMessage(Page* page, MessageType type, MessageLevel level, ScriptState* state, PassRefPtr<ScriptArguments> prpArguments, bool acceptNoArguments = false, bool printTrace = false) { RefPtr<ScriptArguments> arguments = prpArguments; - Page* page = this->page(); if (!page) return; @@ -178,42 +79,46 @@ void Console::addMessage(MessageType type, MessageLevel level, ScriptState* stat RefPtr<ScriptCallStack> callStack(createScriptCallStack(state, stackSize)); const ScriptCallFrame& lastCaller = callStack->at(0); - if (shouldPrintExceptions()) { - printSourceURLAndLine(lastCaller.sourceURL(), 0); - printMessageSourceAndLevelPrefix(ConsoleAPIMessageSource, level); + String message; + bool gotMessage = arguments->getFirstArgumentAsString(message); + InspectorInstrumentation::addMessageToConsole(page, ConsoleAPIMessageSource, type, level, message, state, arguments); - for (unsigned i = 0; i < arguments->argumentCount(); ++i) { - String argAsString; - if (arguments->argumentAt(i).getString(arguments->globalState(), argAsString)) - printf(" %s", argAsString.utf8().data()); - } - printf("\n"); + if (page->settings()->privateBrowsingEnabled()) + return; + + if (gotMessage) + page->chrome().client()->addMessageToConsole(ConsoleAPIMessageSource, type, level, message, lastCaller.lineNumber(), lastCaller.columnNumber(), lastCaller.sourceURL()); + + if (!page->settings()->logsPageMessagesToSystemConsoleEnabled() && !PageConsole::shouldPrintExceptions()) + return; + + PageConsole::printSourceURLAndLine(lastCaller.sourceURL(), lastCaller.lineNumber()); + PageConsole::printMessageSourceAndLevelPrefix(ConsoleAPIMessageSource, level); + + for (size_t i = 0; i < arguments->argumentCount(); ++i) { + String argAsString = arguments->argumentAt(i).toString(arguments->globalState()); + printf(" %s", argAsString.utf8().data()); } + printf("\n"); + if (printTrace) { printf("Stack Trace\n"); - for (unsigned i = 0; i < callStack->size(); ++i) { + for (size_t i = 0; i < callStack->size(); ++i) { String functionName = String(callStack->at(i).functionName()); printf("\t%s\n", functionName.utf8().data()); } } - - String message; - if (arguments->getFirstArgumentAsString(message)) - page->chrome()->client()->addMessageToConsole(ConsoleAPIMessageSource, type, level, message, lastCaller.lineNumber(), lastCaller.sourceURL()); - - InspectorInstrumentation::addMessageToConsole(page, ConsoleAPIMessageSource, type, level, message, state, arguments.release()); } void Console::debug(ScriptState* state, PassRefPtr<ScriptArguments> arguments) { - // In Firebug, console.debug has the same behavior as console.log. So we'll do the same. - log(state, arguments); + internalAddMessage(page(), LogMessageType, DebugMessageLevel, state, arguments); } void Console::error(ScriptState* state, PassRefPtr<ScriptArguments> arguments) { - addMessage(LogMessageType, ErrorMessageLevel, state, arguments); + internalAddMessage(page(), LogMessageType, ErrorMessageLevel, state, arguments); } void Console::info(ScriptState* state, PassRefPtr<ScriptArguments> arguments) @@ -223,32 +128,37 @@ void Console::info(ScriptState* state, PassRefPtr<ScriptArguments> arguments) void Console::log(ScriptState* state, PassRefPtr<ScriptArguments> arguments) { - addMessage(LogMessageType, LogMessageLevel, state, arguments); + internalAddMessage(page(), LogMessageType, LogMessageLevel, state, arguments); } void Console::warn(ScriptState* state, PassRefPtr<ScriptArguments> arguments) { - addMessage(LogMessageType, WarningMessageLevel, state, arguments); + internalAddMessage(page(), LogMessageType, WarningMessageLevel, state, arguments); } void Console::dir(ScriptState* state, PassRefPtr<ScriptArguments> arguments) { - addMessage(DirMessageType, LogMessageLevel, state, arguments); + internalAddMessage(page(), DirMessageType, LogMessageLevel, state, arguments); } void Console::dirxml(ScriptState* state, PassRefPtr<ScriptArguments> arguments) { - addMessage(DirXMLMessageType, LogMessageLevel, state, arguments); + internalAddMessage(page(), DirXMLMessageType, LogMessageLevel, state, arguments); +} + +void Console::table(ScriptState* state, PassRefPtr<ScriptArguments> arguments) +{ + internalAddMessage(page(), TableMessageType, LogMessageLevel, state, arguments); } void Console::clear(ScriptState* state, PassRefPtr<ScriptArguments> arguments) { - addMessage(ClearMessageType, LogMessageLevel, state, arguments, true); + internalAddMessage(page(), ClearMessageType, LogMessageLevel, state, arguments, true); } void Console::trace(ScriptState* state, PassRefPtr<ScriptArguments> arguments) { - addMessage(TraceMessageType, LogMessageLevel, state, arguments, true, shouldPrintExceptions()); + internalAddMessage(page(), TraceMessageType, LogMessageLevel, state, arguments, true, true); } void Console::assertCondition(ScriptState* state, PassRefPtr<ScriptArguments> arguments, bool condition) @@ -256,7 +166,7 @@ void Console::assertCondition(ScriptState* state, PassRefPtr<ScriptArguments> ar if (condition) return; - addMessage(AssertMessageType, ErrorMessageLevel, state, arguments, true); + internalAddMessage(page(), AssertMessageType, ErrorMessageLevel, state, arguments, true); } void Console::count(ScriptState* state, PassRefPtr<ScriptArguments> arguments) @@ -264,11 +174,6 @@ void Console::count(ScriptState* state, PassRefPtr<ScriptArguments> arguments) InspectorInstrumentation::consoleCount(page(), state, arguments); } -void Console::markTimeline(PassRefPtr<ScriptArguments> arguments) -{ - InspectorInstrumentation::consoleTimeStamp(m_frame, arguments); -} - #if ENABLE(JAVASCRIPT_DEBUGGER) void Console::profile(const String& title, ScriptState* state) @@ -289,7 +194,7 @@ void Console::profile(const String& title, ScriptState* state) RefPtr<ScriptCallStack> callStack(createScriptCallStack(state, 1)); const ScriptCallFrame& lastCaller = callStack->at(0); - InspectorInstrumentation::addStartProfilingMessageToConsole(page, resolvedTitle, lastCaller.lineNumber(), lastCaller.sourceURL()); + InspectorInstrumentation::addStartProfilingMessageToConsole(page, resolvedTitle, lastCaller.lineNumber(), lastCaller.columnNumber(), lastCaller.sourceURL()); } void Console::profileEnd(const String& title, ScriptState* state) @@ -315,16 +220,10 @@ void Console::profileEnd(const String& title, ScriptState* state) void Console::time(const String& title) { InspectorInstrumentation::startConsoleTiming(m_frame, title); -#if PLATFORM(CHROMIUM) - TRACE_EVENT_COPY_ASYNC_BEGIN0("webkit", title.utf8().data(), this); -#endif } void Console::timeEnd(ScriptState* state, const String& title) { -#if PLATFORM(CHROMIUM) - TRACE_EVENT_COPY_ASYNC_END0("webkit", title.utf8().data(), this); -#endif RefPtr<ScriptCallStack> callStack(createScriptCallStackForConsole(state)); InspectorInstrumentation::stopConsoleTiming(m_frame, title, callStack.release()); } @@ -346,39 +245,7 @@ void Console::groupCollapsed(ScriptState* state, PassRefPtr<ScriptArguments> arg void Console::groupEnd() { - InspectorInstrumentation::addMessageToConsole(page(), ConsoleAPIMessageSource, EndGroupMessageType, LogMessageLevel, String(), String(), 0); -} - -// static -void Console::mute() -{ - muteCount++; -} - -// static -void Console::unmute() -{ - ASSERT(muteCount > 0); - muteCount--; -} - -PassRefPtr<MemoryInfo> Console::memory() const -{ - // FIXME: Because we create a new object here each time, - // console.memory !== console.memory, which seems wrong. - return MemoryInfo::create(m_frame); -} - -static bool printExceptions = false; - -bool Console::shouldPrintExceptions() -{ - return printExceptions; -} - -void Console::setShouldPrintExceptions(bool print) -{ - printExceptions = print; + InspectorInstrumentation::addMessageToConsole(page(), ConsoleAPIMessageSource, EndGroupMessageType, LogMessageLevel, String(), String(), 0, 0); } Page* Console::page() const diff --git a/Source/WebCore/page/Console.h b/Source/WebCore/page/Console.h index 1ef326fd5..a9040715e 100644 --- a/Source/WebCore/page/Console.h +++ b/Source/WebCore/page/Console.h @@ -29,9 +29,7 @@ #ifndef Console_h #define Console_h -#include "ConsoleTypes.h" #include "DOMWindowProperty.h" -#include "ScriptCallStack.h" #include "ScriptProfile.h" #include "ScriptState.h" #include "ScriptWrappable.h" @@ -42,10 +40,8 @@ namespace WebCore { class Frame; -class MemoryInfo; class Page; class ScriptArguments; -class ScriptCallStack; #if ENABLE(JAVASCRIPT_DEBUGGER) typedef Vector<RefPtr<ScriptProfile> > ProfilesArray; @@ -56,9 +52,6 @@ public: static PassRefPtr<Console> create(Frame* frame) { return adoptRef(new Console(frame)); } virtual ~Console(); - void addMessage(MessageSource, MessageType, MessageLevel, const String& message, const String& sourceURL = String(), unsigned lineNumber = 0, PassRefPtr<ScriptCallStack> = 0, unsigned long requestIdentifier = 0); - void addMessage(MessageSource, MessageType, MessageLevel, const String& message, PassRefPtr<ScriptCallStack>); - void debug(ScriptState*, PassRefPtr<ScriptArguments>); void error(ScriptState*, PassRefPtr<ScriptArguments>); void info(ScriptState*, PassRefPtr<ScriptArguments>); @@ -67,10 +60,10 @@ public: void warn(ScriptState*, PassRefPtr<ScriptArguments>); void dir(ScriptState*, PassRefPtr<ScriptArguments>); void dirxml(ScriptState*, PassRefPtr<ScriptArguments>); + void table(ScriptState*, PassRefPtr<ScriptArguments>); void trace(ScriptState*, PassRefPtr<ScriptArguments>); void assertCondition(ScriptState*, PassRefPtr<ScriptArguments>, bool condition); void count(ScriptState*, PassRefPtr<ScriptArguments>); - void markTimeline(PassRefPtr<ScriptArguments>); #if ENABLE(JAVASCRIPT_DEBUGGER) const ProfilesArray& profiles() const { return m_profiles; } void profile(const String&, ScriptState*); @@ -83,17 +76,8 @@ public: void groupCollapsed(ScriptState*, PassRefPtr<ScriptArguments>); void groupEnd(); - static void mute(); - static void unmute(); - - static bool shouldPrintExceptions(); - static void setShouldPrintExceptions(bool); - - PassRefPtr<MemoryInfo> memory() const; - private: inline Page* page() const; - void addMessage(MessageType, MessageLevel, ScriptState*, PassRefPtr<ScriptArguments>, bool acceptNoArguments = false, bool printTrace = false); explicit Console(Frame*); diff --git a/Source/WebCore/page/Console.idl b/Source/WebCore/page/Console.idl index 260217ebf..02d71f938 100644 --- a/Source/WebCore/page/Console.idl +++ b/Source/WebCore/page/Console.idl @@ -27,39 +27,35 @@ */ [ - JSGenerateIsReachable=ImplFrame, - OmitConstructor + NoInterfaceObject, + GenerateIsReachable=ImplFrame, ] interface Console { - [CallWith=ScriptArguments|ScriptState] void debug(); - [CallWith=ScriptArguments|ScriptState] void error(); - [CallWith=ScriptArguments|ScriptState] void info(); - [CallWith=ScriptArguments|ScriptState] void log(); - [CallWith=ScriptArguments|ScriptState] void warn(); - [CallWith=ScriptArguments|ScriptState] void dir(); - [CallWith=ScriptArguments|ScriptState] void dirxml(); - [V8Custom, CallWith=ScriptArguments|ScriptState] void trace(); - [V8Custom, CallWith=ScriptArguments|ScriptState, ImplementedAs=assertCondition] void assert(in boolean condition); - [CallWith=ScriptArguments|ScriptState] void count(); - [CallWith=ScriptArguments] void markTimeline(); + [CallWith=ScriptArguments&ScriptState] void debug(); + [CallWith=ScriptArguments&ScriptState] void error(); + [CallWith=ScriptArguments&ScriptState] void info(); + [CallWith=ScriptArguments&ScriptState] void log(); + [CallWith=ScriptArguments&ScriptState] void warn(); + [CallWith=ScriptArguments&ScriptState] void dir(); + [CallWith=ScriptArguments&ScriptState] void dirxml(); + [CallWith=ScriptArguments&ScriptState] void table(); + [CallWith=ScriptArguments&ScriptState] void trace(); + [CallWith=ScriptArguments&ScriptState, ImplementedAs=assertCondition] void assert(boolean condition); + [CallWith=ScriptArguments&ScriptState] void count(); -#if defined(ENABLE_JAVASCRIPT_DEBUGGER) && ENABLE_JAVASCRIPT_DEBUGGER // As per spec: http://www.w3.org/TR/WebIDL/#idl-sequence // "Sequences must not be used as the type of an attribute, constant or exception field." // FIXME: this will lead to BUG console.profiles !== console.profiles as profile will always returns new array. - readonly attribute ScriptProfile[] profiles; - [Custom] void profile(in DOMString title); - [Custom] void profileEnd(in DOMString title); -#endif + [Conditional=JAVASCRIPT_DEBUGGER] readonly attribute ScriptProfile[] profiles; + [Conditional=JAVASCRIPT_DEBUGGER, Custom] void profile(DOMString title); + [Conditional=JAVASCRIPT_DEBUGGER, Custom] void profileEnd(DOMString title); - void time(in [TreatNullAs=NullString, TreatUndefinedAs=NullString] DOMString title); - [CallWith=ScriptState] void timeEnd(in [TreatNullAs=NullString, TreatUndefinedAs=NullString] DOMString title); + void time([TreatNullAs=NullString, TreatUndefinedAs=NullString] DOMString title); + [CallWith=ScriptState] void timeEnd([TreatNullAs=NullString, TreatUndefinedAs=NullString] DOMString title); [CallWith=ScriptArguments] void timeStamp(); - [CallWith=ScriptArguments|ScriptState] void group(); - [CallWith=ScriptArguments|ScriptState] void groupCollapsed(); + [CallWith=ScriptArguments&ScriptState] void group(); + [CallWith=ScriptArguments&ScriptState] void groupCollapsed(); void groupEnd(); - [CallWith=ScriptArguments|ScriptState] void clear(); - - readonly attribute MemoryInfo memory; + [CallWith=ScriptArguments&ScriptState] void clear(); }; diff --git a/Source/WebCore/page/ConsoleTypes.h b/Source/WebCore/page/ConsoleTypes.h index b01f7ce7a..804a167cc 100644 --- a/Source/WebCore/page/ConsoleTypes.h +++ b/Source/WebCore/page/ConsoleTypes.h @@ -29,34 +29,23 @@ namespace WebCore { enum MessageSource { - HTMLMessageSource, XMLMessageSource, JSMessageSource, NetworkMessageSource, ConsoleAPIMessageSource, + StorageMessageSource, + AppCacheMessageSource, + RenderingMessageSource, + CSSMessageSource, + SecurityMessageSource, OtherMessageSource, }; -// FIXME: make this enum private to inspector, remove it from client callbacks. -// https://bugs.webkit.org/show_bug.cgi?id=66371 -enum MessageType { - LogMessageType, - DirMessageType, - DirXMLMessageType, - TraceMessageType, - StartGroupMessageType, - StartGroupCollapsedMessageType, - EndGroupMessageType, - ClearMessageType, - AssertMessageType -}; - enum MessageLevel { - TipMessageLevel, - LogMessageLevel, - WarningMessageLevel, - ErrorMessageLevel, - DebugMessageLevel + DebugMessageLevel = 4, + LogMessageLevel = 1, + WarningMessageLevel = 2, + ErrorMessageLevel = 3 }; } // namespace WebCore diff --git a/Source/WebCore/page/ContentSecurityPolicy.cpp b/Source/WebCore/page/ContentSecurityPolicy.cpp index be722dc11..7908c1699 100644 --- a/Source/WebCore/page/ContentSecurityPolicy.cpp +++ b/Source/WebCore/page/ContentSecurityPolicy.cpp @@ -37,11 +37,13 @@ #include "InspectorValues.h" #include "KURL.h" #include "PingLoader.h" +#include "RuntimeEnabledFeatures.h" #include "SchemeRegistry.h" #include "ScriptCallStack.h" #include "ScriptCallStackFactory.h" #include "ScriptState.h" #include "SecurityOrigin.h" +#include "SecurityPolicyViolationEvent.h" #include "TextEncoding.h" #include <wtf/HashSet.h> #include <wtf/text/TextPosition.h> @@ -104,6 +106,7 @@ bool isMediaTypeCharacter(UChar c) return !isASCIISpace(c) && c != '/'; } +// CSP 1.0 Directives static const char connectSrc[] = "connect-src"; static const char defaultSrc[] = "default-src"; static const char fontSrc[] = "font-src"; @@ -115,11 +118,13 @@ static const char reportURI[] = "report-uri"; static const char sandbox[] = "sandbox"; static const char scriptSrc[] = "script-src"; static const char styleSrc[] = "style-src"; -#if ENABLE(CSP_NEXT) + +// CSP 1.1 Directives +static const char baseURI[] = "base-uri"; static const char formAction[] = "form-action"; static const char pluginTypes[] = "plugin-types"; static const char scriptNonce[] = "script-nonce"; -#endif +static const char reflectedXSS[] = "reflected-xss"; bool isDirectiveName(const String& name) { @@ -135,9 +140,11 @@ bool isDirectiveName(const String& name) || equalIgnoringCase(name, scriptSrc) || equalIgnoringCase(name, styleSrc) #if ENABLE(CSP_NEXT) + || equalIgnoringCase(name, baseURI) || equalIgnoringCase(name, formAction) || equalIgnoringCase(name, pluginTypes) || equalIgnoringCase(name, scriptNonce) + || equalIgnoringCase(name, reflectedXSS) #endif ); } @@ -145,19 +152,28 @@ bool isDirectiveName(const String& name) FeatureObserver::Feature getFeatureObserverType(ContentSecurityPolicy::HeaderType type) { switch (type) { - case ContentSecurityPolicy::EnforceAllDirectives: + case ContentSecurityPolicy::PrefixedEnforce: return FeatureObserver::PrefixedContentSecurityPolicy; - case ContentSecurityPolicy::EnforceStableDirectives: + case ContentSecurityPolicy::Enforce: return FeatureObserver::ContentSecurityPolicy; - case ContentSecurityPolicy::ReportAllDirectives: + case ContentSecurityPolicy::PrefixedReport: return FeatureObserver::PrefixedContentSecurityPolicyReportOnly; - case ContentSecurityPolicy::ReportStableDirectives: + case ContentSecurityPolicy::Report: return FeatureObserver::ContentSecurityPolicyReportOnly; } ASSERT_NOT_REACHED(); return FeatureObserver::NumberOfFeatures; } +const ScriptCallFrame& getFirstNonNativeFrame(PassRefPtr<ScriptCallStack> stack) +{ + int frameNumber = 0; + if (!stack->at(0).lineNumber() && stack->size() > 1 && stack->at(1).lineNumber()) + frameNumber = 1; + + return stack->at(frameNumber); +} + } // namespace static bool skipExactly(const UChar*& position, const UChar* end, UChar delimiter) @@ -192,10 +208,29 @@ static void skipWhile(const UChar*& position, const UChar* end) ++position; } +static bool isSourceListNone(const String& value) +{ + const UChar* begin = value.characters(); + const UChar* end = value.characters() + value.length(); + skipWhile<isASCIISpace>(begin, end); + + const UChar* position = begin; + skipWhile<isSourceCharacter>(position, end); + if (!equalIgnoringCase("'none'", begin, position - begin)) + return false; + + skipWhile<isASCIISpace>(position, end); + if (position != end) + return false; + + return true; +} + class CSPSource { public: - CSPSource(const String& scheme, const String& host, int port, const String& path, bool hostHasWildcard, bool portHasWildcard) - : m_scheme(scheme) + CSPSource(ContentSecurityPolicy* policy, const String& scheme, const String& host, int port, const String& path, bool hostHasWildcard, bool portHasWildcard) + : m_policy(policy) + , m_scheme(scheme) , m_host(host) , m_port(port) , m_path(path) @@ -216,6 +251,14 @@ public: private: bool schemeMatches(const KURL& url) const { + if (m_scheme.isEmpty()) { + String protectedResourceScheme(m_policy->securityOrigin()->protocol()); +#if ENABLE(CSP_NEXT) + if (equalIgnoringCase("http", protectedResourceScheme)) + return url.protocolIs("http") || url.protocolIs("https"); +#endif + return equalIgnoringCase(url.protocol(), protectedResourceScheme); + } return equalIgnoringCase(url.protocol(), m_scheme); } @@ -252,16 +295,17 @@ private: return true; if (!port) - return isDefaultPortForProtocol(m_port, m_scheme); + return isDefaultPortForProtocol(m_port, url.protocol()); if (!m_port) - return isDefaultPortForProtocol(port, m_scheme); + return isDefaultPortForProtocol(port, url.protocol()); return false; } bool isSchemeOnly() const { return m_host.isEmpty(); } + ContentSecurityPolicy* m_policy; String m_scheme; String m_host; int m_port; @@ -313,6 +357,9 @@ CSPSourceList::CSPSourceList(ContentSecurityPolicy* policy, const String& direct void CSPSourceList::parse(const String& value) { + // We represent 'none' as an empty m_list. + if (isSourceListNone(value)) + return; parse(value.characters(), value.characters() + value.length()); } @@ -338,7 +385,6 @@ void CSPSourceList::parse(const UChar* begin, const UChar* end) { const UChar* position = begin; - bool isFirstSourceInList = true; while (position < end) { skipWhile<isASCIISpace>(position, end); if (position == end) @@ -347,10 +393,6 @@ void CSPSourceList::parse(const UChar* begin, const UChar* end) const UChar* beginSource = position; skipWhile<isSourceCharacter>(position, end); - if (isFirstSourceInList && equalIgnoringCase("'none'", beginSource, position - beginSource)) - return; // We represent 'none' as an empty m_list. - isFirstSourceInList = false; - String scheme, host, path; int port = 0; bool hostHasWildcard = false; @@ -362,11 +404,9 @@ void CSPSourceList::parse(const UChar* begin, const UChar* end) // list itself. if (scheme.isEmpty() && host.isEmpty()) continue; - if (scheme.isEmpty()) - scheme = m_policy->securityOrigin()->protocol(); if (isDirectiveName(host)) m_policy->reportDirectiveAsSourceExpression(m_directiveName, host); - m_list.append(CSPSource(scheme, host, port, path, hostHasWildcard, portHasWildcard)); + m_list.append(CSPSource(m_policy, scheme, host, port, path, hostHasWildcard, portHasWildcard)); } else m_policy->reportInvalidSourceExpression(m_directiveName, String(beginSource, position - beginSource)); @@ -385,6 +425,9 @@ bool CSPSourceList::parseSource(const UChar* begin, const UChar* end, if (begin == end) return false; + if (equalIgnoringCase("'none'", begin, end - begin)) + return false; + if (end - begin == 1 && *begin == '*') { addSourceStar(); return true; @@ -603,7 +646,7 @@ bool CSPSourceList::parsePort(const UChar* begin, const UChar* end, int& port, b void CSPSourceList::addSourceSelf() { - m_list.append(CSPSource(m_policy->securityOrigin()->protocol(), m_policy->securityOrigin()->host(), m_policy->securityOrigin()->port(), String(), false, false)); + m_list.append(CSPSource(m_policy, m_policy->securityOrigin()->protocol(), m_policy->securityOrigin()->host(), m_policy->securityOrigin()->port(), String(), false, false)); } void CSPSourceList::addSourceStar() @@ -807,9 +850,13 @@ public: bool allowMediaFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const; bool allowConnectToSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const; bool allowFormAction(const KURL&, ContentSecurityPolicy::ReportingStatus) const; + bool allowBaseURI(const KURL&, ContentSecurityPolicy::ReportingStatus) const; void gatherReportURIs(DOMStringList&) const; - const String& evalDisabledErrorMessage() { return m_evalDisabledErrorMessage; } + const String& evalDisabledErrorMessage() const { return m_evalDisabledErrorMessage; } + ContentSecurityPolicy::ReflectedXSSDisposition reflectedXSSDisposition() const { return m_reflectedXSSDisposition; } + bool isReportOnly() const { return m_reportOnly; } + const Vector<KURL>& reportURIs() const { return m_reportURIs; } private: CSPDirectiveList(ContentSecurityPolicy*, ContentSecurityPolicy::HeaderType); @@ -820,6 +867,7 @@ private: void parseReportURI(const String& name, const String& value); void parseScriptNonce(const String& name, const String& value); void parsePluginTypes(const String& name, const String& value); + void parseReflectedXSS(const String& name, const String& value); void addDirective(const String& name, const String& value); void applySandboxPolicy(const String& name, const String& sandboxPolicy); @@ -827,7 +875,7 @@ private: void setCSPDirective(const String& name, const String& value, OwnPtr<CSPDirectiveType>&); SourceListDirective* operativeDirective(SourceListDirective*) const; - void reportViolation(const String& directiveText, const String& consoleMessage, const KURL& blockedURL = KURL(), const String& contextURL = String(), const WTF::OrdinalNumber& contextLine = WTF::OrdinalNumber::beforeFirst(), ScriptState* = 0) const; + void reportViolation(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL = KURL(), const String& contextURL = String(), const WTF::OrdinalNumber& contextLine = WTF::OrdinalNumber::beforeFirst(), ScriptState* = 0) const; bool checkEval(SourceListDirective*) const; bool checkInline(SourceListDirective*) const; @@ -841,7 +889,7 @@ private: bool checkInlineAndReportViolation(SourceListDirective*, const String& consoleMessage, const String& contextURL, const WTF::OrdinalNumber& contextLine, bool isScript) const; bool checkNonceAndReportViolation(NonceDirective*, const String& nonce, const String& consoleMessage, const String& contextURL, const WTF::OrdinalNumber& contextLine) const; - bool checkSourceAndReportViolation(SourceListDirective*, const KURL&, const String& type) const; + bool checkSourceAndReportViolation(SourceListDirective*, const KURL&, const String& effectiveDirective) const; bool checkMediaTypeAndReportViolation(MediaListDirective*, const String& type, const String& typeAttribute, const String& consoleMessage) const; bool denyIfEnforcingPolicy() const { return m_reportOnly; } @@ -851,12 +899,13 @@ private: String m_header; ContentSecurityPolicy::HeaderType m_headerType; - bool m_experimental; bool m_reportOnly; bool m_haveSandboxPolicy; + ContentSecurityPolicy::ReflectedXSSDisposition m_reflectedXSSDisposition; OwnPtr<MediaListDirective> m_pluginTypes; OwnPtr<NonceDirective> m_scriptNonce; + OwnPtr<SourceListDirective> m_baseURI; OwnPtr<SourceListDirective> m_connectSrc; OwnPtr<SourceListDirective> m_defaultSrc; OwnPtr<SourceListDirective> m_fontSrc; @@ -876,12 +925,11 @@ private: CSPDirectiveList::CSPDirectiveList(ContentSecurityPolicy* policy, ContentSecurityPolicy::HeaderType type) : m_policy(policy) , m_headerType(type) - , m_experimental(false) , m_reportOnly(false) , m_haveSandboxPolicy(false) + , m_reflectedXSSDisposition(ContentSecurityPolicy::ReflectedXSSUnset) { - m_reportOnly = (type == ContentSecurityPolicy::ReportStableDirectives || type == ContentSecurityPolicy::ReportAllDirectives); - m_experimental = (type == ContentSecurityPolicy::ReportAllDirectives || type == ContentSecurityPolicy::EnforceAllDirectives); + m_reportOnly = (type == ContentSecurityPolicy::Report || type == ContentSecurityPolicy::PrefixedReport); } PassOwnPtr<CSPDirectiveList> CSPDirectiveList::create(ContentSecurityPolicy* policy, const String& header, ContentSecurityPolicy::HeaderType type) @@ -894,13 +942,16 @@ PassOwnPtr<CSPDirectiveList> CSPDirectiveList::create(ContentSecurityPolicy* pol directives->setEvalDisabledErrorMessage(message); } + if (directives->isReportOnly() && directives->reportURIs().isEmpty()) + policy->reportMissingReportURI(header); + return directives.release(); } -void CSPDirectiveList::reportViolation(const String& directiveText, const String& consoleMessage, const KURL& blockedURL, const String& contextURL, const WTF::OrdinalNumber& contextLine, ScriptState* state) const +void CSPDirectiveList::reportViolation(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL, const String& contextURL, const WTF::OrdinalNumber& contextLine, ScriptState* state) const { String message = m_reportOnly ? "[Report Only] " + consoleMessage : consoleMessage; - m_policy->reportViolation(directiveText, message, blockedURL, m_reportURIs, m_header, contextURL, contextLine, state); + m_policy->reportViolation(directiveText, effectiveDirective, message, blockedURL, m_reportURIs, m_header, contextURL, contextLine, state); } bool CSPDirectiveList::checkEval(SourceListDirective* directive) const @@ -946,7 +997,7 @@ bool CSPDirectiveList::checkEvalAndReportViolation(SourceListDirective* directiv if (directive == m_defaultSrc) suffix = " Note that 'script-src' was not explicitly set, so 'default-src' is used as a fallback."; - reportViolation(directive->text(), consoleMessage + "\"" + directive->text() + "\"." + suffix + "\n", KURL(), contextURL, contextLine, state); + reportViolation(directive->text(), scriptSrc, consoleMessage + "\"" + directive->text() + "\"." + suffix + "\n", KURL(), contextURL, contextLine, state); if (!m_reportOnly) { m_policy->reportBlockedScriptExecutionToInspector(directive->text()); return false; @@ -958,7 +1009,7 @@ bool CSPDirectiveList::checkNonceAndReportViolation(NonceDirective* directive, c { if (checkNonce(directive, nonce)) return true; - reportViolation(directive->text(), consoleMessage + "\"" + directive->text() + "\".\n", KURL(), contextURL, contextLine); + reportViolation(directive->text(), scriptNonce, consoleMessage + "\"" + directive->text() + "\".\n", KURL(), contextURL, contextLine); return denyIfEnforcingPolicy(); } @@ -971,7 +1022,7 @@ bool CSPDirectiveList::checkMediaTypeAndReportViolation(MediaListDirective* dire if (typeAttribute.isEmpty()) message = message + " When enforcing the 'plugin-types' directive, the plugin's media type must be explicitly declared with a 'type' attribute on the containing element (e.g. '<object type=\"[TYPE GOES HERE]\" ...>')."; - reportViolation(directive->text(), message + "\n", KURL()); + reportViolation(directive->text(), pluginTypes, message + "\n", KURL()); return denyIfEnforcingPolicy(); } @@ -984,7 +1035,7 @@ bool CSPDirectiveList::checkInlineAndReportViolation(SourceListDirective* direct if (directive == m_defaultSrc) suffix = makeString(" Note that '", (isScript ? "script" : "style"), "-src' was not explicitly set, so 'default-src' is used as a fallback."); - reportViolation(directive->text(), consoleMessage + "\"" + directive->text() + "\"." + suffix + "\n", KURL(), contextURL, contextLine); + reportViolation(directive->text(), isScript ? scriptSrc : styleSrc, consoleMessage + "\"" + directive->text() + "\"." + suffix + "\n", KURL(), contextURL, contextLine); if (!m_reportOnly) { if (isScript) @@ -994,22 +1045,38 @@ bool CSPDirectiveList::checkInlineAndReportViolation(SourceListDirective* direct return true; } -bool CSPDirectiveList::checkSourceAndReportViolation(SourceListDirective* directive, const KURL& url, const String& type) const +bool CSPDirectiveList::checkSourceAndReportViolation(SourceListDirective* directive, const KURL& url, const String& effectiveDirective) const { if (checkSource(directive, url)) return true; - String prefix = makeString("Refused to load the ", type, " '"); - if (type == "connect") + String prefix; + if (baseURI == effectiveDirective) + prefix = "Refused to set the document's base URI to '"; + else if (connectSrc == effectiveDirective) prefix = "Refused to connect to '"; - if (type == "form") + else if (fontSrc == effectiveDirective) + prefix = "Refused to load the font '"; + else if (formAction == effectiveDirective) prefix = "Refused to send form data to '"; + else if (frameSrc == effectiveDirective) + prefix = "Refused to frame '"; + else if (imgSrc == effectiveDirective) + prefix = "Refused to load the image '"; + else if (mediaSrc == effectiveDirective) + prefix = "Refused to load media from '"; + else if (objectSrc == effectiveDirective) + prefix = "Refused to load plugin data from '"; + else if (scriptSrc == effectiveDirective) + prefix = "Refused to load the script '"; + else if (styleSrc == effectiveDirective) + prefix = "Refused to load the stylesheet '"; String suffix = String(); if (directive == m_defaultSrc) - suffix = " Note that '" + type + "-src' was not explicitly set, so 'default-src' is used as a fallback."; + suffix = " Note that '" + effectiveDirective + "' was not explicitly set, so 'default-src' is used as a fallback."; - reportViolation(directive->text(), prefix + url.string() + "' because it violates the following Content Security Policy directive: \"" + directive->text() + "\"." + suffix + "\n", url); + reportViolation(directive->text(), effectiveDirective, prefix + url.stringCenterEllipsizedToLength() + "' because it violates the following Content Security Policy directive: \"" + directive->text() + "\"." + suffix + "\n", url); return denyIfEnforcingPolicy(); } @@ -1066,81 +1133,73 @@ bool CSPDirectiveList::allowScriptNonce(const String& nonce, const String& conte DEFINE_STATIC_LOCAL(String, consoleMessage, (ASCIILiteral("Refused to execute script because it violates the following Content Security Policy directive: "))); if (url.isEmpty()) return checkNonceAndReportViolation(m_scriptNonce.get(), nonce, consoleMessage, contextURL, contextLine); - return checkNonceAndReportViolation(m_scriptNonce.get(), nonce, "Refused to load '" + url.string() + "' because it violates the following Content Security Policy directive: ", contextURL, contextLine); + return checkNonceAndReportViolation(m_scriptNonce.get(), nonce, "Refused to load '" + url.stringCenterEllipsizedToLength() + "' because it violates the following Content Security Policy directive: ", contextURL, contextLine); } bool CSPDirectiveList::allowPluginType(const String& type, const String& typeAttribute, const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const { return reportingStatus == ContentSecurityPolicy::SendReport ? - checkMediaTypeAndReportViolation(m_pluginTypes.get(), type, typeAttribute, "Refused to load '" + url.string() + "' (MIME type '" + typeAttribute + "') because it violates the following Content Security Policy Directive: ") : + checkMediaTypeAndReportViolation(m_pluginTypes.get(), type, typeAttribute, "Refused to load '" + url.stringCenterEllipsizedToLength() + "' (MIME type '" + typeAttribute + "') because it violates the following Content Security Policy Directive: ") : checkMediaType(m_pluginTypes.get(), type, typeAttribute); } bool CSPDirectiveList::allowScriptFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const { - DEFINE_STATIC_LOCAL(String, type, (ASCIILiteral("script"))); return reportingStatus == ContentSecurityPolicy::SendReport ? - checkSourceAndReportViolation(operativeDirective(m_scriptSrc.get()), url, type) : + checkSourceAndReportViolation(operativeDirective(m_scriptSrc.get()), url, scriptSrc) : checkSource(operativeDirective(m_scriptSrc.get()), url); } bool CSPDirectiveList::allowObjectFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const { - DEFINE_STATIC_LOCAL(String, type, (ASCIILiteral("object"))); if (url.isBlankURL()) return true; return reportingStatus == ContentSecurityPolicy::SendReport ? - checkSourceAndReportViolation(operativeDirective(m_objectSrc.get()), url, type) : + checkSourceAndReportViolation(operativeDirective(m_objectSrc.get()), url, objectSrc) : checkSource(operativeDirective(m_objectSrc.get()), url); } bool CSPDirectiveList::allowChildFrameFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const { - DEFINE_STATIC_LOCAL(String, type, (ASCIILiteral("frame"))); if (url.isBlankURL()) return true; return reportingStatus == ContentSecurityPolicy::SendReport ? - checkSourceAndReportViolation(operativeDirective(m_frameSrc.get()), url, type) : + checkSourceAndReportViolation(operativeDirective(m_frameSrc.get()), url, frameSrc) : checkSource(operativeDirective(m_frameSrc.get()), url); } bool CSPDirectiveList::allowImageFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const { - DEFINE_STATIC_LOCAL(String, type, (ASCIILiteral("image"))); return reportingStatus == ContentSecurityPolicy::SendReport ? - checkSourceAndReportViolation(operativeDirective(m_imgSrc.get()), url, type) : + checkSourceAndReportViolation(operativeDirective(m_imgSrc.get()), url, imgSrc) : checkSource(operativeDirective(m_imgSrc.get()), url); } bool CSPDirectiveList::allowStyleFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const { - DEFINE_STATIC_LOCAL(String, type, (ASCIILiteral("style"))); return reportingStatus == ContentSecurityPolicy::SendReport ? - checkSourceAndReportViolation(operativeDirective(m_styleSrc.get()), url, type) : + checkSourceAndReportViolation(operativeDirective(m_styleSrc.get()), url, styleSrc) : checkSource(operativeDirective(m_styleSrc.get()), url); } bool CSPDirectiveList::allowFontFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const { - DEFINE_STATIC_LOCAL(String, type, (ASCIILiteral("font"))); return reportingStatus == ContentSecurityPolicy::SendReport ? - checkSourceAndReportViolation(operativeDirective(m_fontSrc.get()), url, type) : + checkSourceAndReportViolation(operativeDirective(m_fontSrc.get()), url, fontSrc) : checkSource(operativeDirective(m_fontSrc.get()), url); } bool CSPDirectiveList::allowMediaFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const { - DEFINE_STATIC_LOCAL(String, type, (ASCIILiteral("media"))); return reportingStatus == ContentSecurityPolicy::SendReport ? - checkSourceAndReportViolation(operativeDirective(m_mediaSrc.get()), url, type) : + checkSourceAndReportViolation(operativeDirective(m_mediaSrc.get()), url, mediaSrc) : checkSource(operativeDirective(m_mediaSrc.get()), url); } bool CSPDirectiveList::allowConnectToSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const { - DEFINE_STATIC_LOCAL(String, type, (ASCIILiteral("connect"))); return reportingStatus == ContentSecurityPolicy::SendReport ? - checkSourceAndReportViolation(operativeDirective(m_connectSrc.get()), url, type) : + checkSourceAndReportViolation(operativeDirective(m_connectSrc.get()), url, connectSrc) : checkSource(operativeDirective(m_connectSrc.get()), url); } @@ -1152,12 +1211,18 @@ void CSPDirectiveList::gatherReportURIs(DOMStringList& list) const bool CSPDirectiveList::allowFormAction(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const { - DEFINE_STATIC_LOCAL(String, type, (ASCIILiteral("form"))); return reportingStatus == ContentSecurityPolicy::SendReport ? - checkSourceAndReportViolation(m_formAction.get(), url, type) : + checkSourceAndReportViolation(m_formAction.get(), url, formAction) : checkSource(m_formAction.get(), url); } +bool CSPDirectiveList::allowBaseURI(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const +{ + return reportingStatus == ContentSecurityPolicy::SendReport ? + checkSourceAndReportViolation(m_baseURI.get(), url, baseURI) : + checkSource(m_baseURI.get(), url); +} + // policy = directive-list // directive-list = [ directive *( ";" [ directive ] ) ] // @@ -1286,6 +1351,51 @@ void CSPDirectiveList::applySandboxPolicy(const String& name, const String& sand m_policy->reportInvalidSandboxFlags(invalidTokens); } +void CSPDirectiveList::parseReflectedXSS(const String& name, const String& value) +{ + if (m_reflectedXSSDisposition != ContentSecurityPolicy::ReflectedXSSUnset) { + m_policy->reportDuplicateDirective(name); + m_reflectedXSSDisposition = ContentSecurityPolicy::ReflectedXSSInvalid; + return; + } + + if (value.isEmpty()) { + m_reflectedXSSDisposition = ContentSecurityPolicy::ReflectedXSSInvalid; + m_policy->reportInvalidReflectedXSS(value); + return; + } + + const UChar* position = value.characters(); + const UChar* end = position + value.length(); + + skipWhile<isASCIISpace>(position, end); + const UChar* begin = position; + skipWhile<isNotASCIISpace>(position, end); + + // value1 + // ^ + if (equalIgnoringCase("allow", begin, position - begin)) + m_reflectedXSSDisposition = ContentSecurityPolicy::AllowReflectedXSS; + else if (equalIgnoringCase("filter", begin, position - begin)) + m_reflectedXSSDisposition = ContentSecurityPolicy::FilterReflectedXSS; + else if (equalIgnoringCase("block", begin, position - begin)) + m_reflectedXSSDisposition = ContentSecurityPolicy::BlockReflectedXSS; + else { + m_reflectedXSSDisposition = ContentSecurityPolicy::ReflectedXSSInvalid; + m_policy->reportInvalidReflectedXSS(value); + return; + } + + skipWhile<isASCIISpace>(position, end); + if (position == end && m_reflectedXSSDisposition != ContentSecurityPolicy::ReflectedXSSUnset) + return; + + // value1 value2 + // ^ + m_reflectedXSSDisposition = ContentSecurityPolicy::ReflectedXSSInvalid; + m_policy->reportInvalidReflectedXSS(value); +} + void CSPDirectiveList::addDirective(const String& name, const String& value) { ASSERT(!name.isEmpty()); @@ -1313,13 +1423,19 @@ void CSPDirectiveList::addDirective(const String& name, const String& value) else if (equalIgnoringCase(name, reportURI)) parseReportURI(name, value); #if ENABLE(CSP_NEXT) - else if (m_experimental) { - if (equalIgnoringCase(name, formAction)) + else if (m_policy->experimentalFeaturesEnabled()) { + if (equalIgnoringCase(name, baseURI)) + setCSPDirective<SourceListDirective>(name, value, m_baseURI); + else if (equalIgnoringCase(name, formAction)) setCSPDirective<SourceListDirective>(name, value, m_formAction); else if (equalIgnoringCase(name, pluginTypes)) setCSPDirective<MediaListDirective>(name, value, m_pluginTypes); else if (equalIgnoringCase(name, scriptNonce)) setCSPDirective<NonceDirective>(name, value, m_scriptNonce); + else if (equalIgnoringCase(name, reflectedXSS)) + parseReflectedXSS(name, value); + else + m_policy->reportUnsupportedDirective(name); } #endif else @@ -1346,7 +1462,7 @@ void ContentSecurityPolicy::copyStateFrom(const ContentSecurityPolicy* other) void ContentSecurityPolicy::didReceiveHeader(const String& header, HeaderType type) { if (m_scriptExecutionContext->isDocument()) { - Document* document = static_cast<Document*>(m_scriptExecutionContext); + Document* document = toDocument(m_scriptExecutionContext); if (document->domWindow()) FeatureObserver::observe(document->domWindow(), getFeatureObserverType(type)); } @@ -1362,16 +1478,17 @@ void ContentSecurityPolicy::didReceiveHeader(const String& header, HeaderType ty // header1,header2 OR header1 // ^ ^ - m_policies.append(CSPDirectiveList::create(this, String(begin, position - begin), type)); + OwnPtr<CSPDirectiveList> policy = CSPDirectiveList::create(this, String(begin, position - begin), type); + if (!policy->isReportOnly() && !policy->allowEval(0, SuppressReport)) + m_scriptExecutionContext->disableEval(policy->evalDisabledErrorMessage()); + + m_policies.append(policy.release()); // Skip the comma, and begin the next header from the current position. ASSERT(position == end || *position == ','); skipExactly(position, end, ','); begin = position; } - - if (!allowEval(0, SuppressReport)) - m_scriptExecutionContext->disableEval(evalDisabledErrorMessage()); } void ContentSecurityPolicy::setOverrideAllowInlineStyle(bool value) @@ -1386,7 +1503,7 @@ const String& ContentSecurityPolicy::deprecatedHeader() const ContentSecurityPolicy::HeaderType ContentSecurityPolicy::deprecatedHeaderType() const { - return m_policies.isEmpty() ? EnforceStableDirectives : m_policies[0]->headerType(); + return m_policies.isEmpty() ? Enforce : m_policies[0]->headerType(); } template<bool (CSPDirectiveList::*allowed)(ContentSecurityPolicy::ReportingStatus) const> @@ -1537,11 +1654,26 @@ bool ContentSecurityPolicy::allowFormAction(const KURL& url, ContentSecurityPoli return isAllowedByAllWithURL<&CSPDirectiveList::allowFormAction>(m_policies, url, reportingStatus); } +bool ContentSecurityPolicy::allowBaseURI(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const +{ + return isAllowedByAllWithURL<&CSPDirectiveList::allowBaseURI>(m_policies, url, reportingStatus); +} + bool ContentSecurityPolicy::isActive() const { return !m_policies.isEmpty(); } +ContentSecurityPolicy::ReflectedXSSDisposition ContentSecurityPolicy::reflectedXSSDisposition() const +{ + ReflectedXSSDisposition disposition = ReflectedXSSUnset; + for (size_t i = 0; i < m_policies.size(); ++i) { + if (m_policies[i]->reflectedXSSDisposition() > disposition) + disposition = std::max(disposition, m_policies[i]->reflectedXSSDisposition()); + } + return disposition; +} + void ContentSecurityPolicy::gatherReportURIs(DOMStringList& list) const { for (size_t i = 0; i < m_policies.size(); ++i) @@ -1568,22 +1700,66 @@ void ContentSecurityPolicy::enforceSandboxFlags(SandboxFlags mask) const m_scriptExecutionContext->enforceSandboxFlags(mask); } -void ContentSecurityPolicy::reportViolation(const String& directiveText, const String& consoleMessage, const KURL& blockedURL, const Vector<KURL>& reportURIs, const String& header, const String& contextURL, const WTF::OrdinalNumber& contextLine, ScriptState* state) const +static String stripURLForUseInReport(Document* document, const KURL& url) { - logToConsole(consoleMessage, contextURL, contextLine, state); + if (!url.isValid()) + return String(); + if (!url.isHierarchical() || url.protocolIs("file")) + return url.protocol(); + return document->securityOrigin()->canRequest(url) ? url.strippedForUseAsReferrer() : SecurityOrigin::create(url)->toString(); +} - if (reportURIs.isEmpty()) +#if ENABLE(CSP_NEXT) +static void gatherSecurityPolicyViolationEventData(SecurityPolicyViolationEventInit& init, Document* document, const String& directiveText, const String& effectiveDirective, const KURL& blockedURL, const String& header) +{ + init.documentURI = document->url().string(); + init.referrer = document->referrer(); + init.blockedURI = stripURLForUseInReport(document, blockedURL); + init.violatedDirective = directiveText; + init.effectiveDirective = effectiveDirective; + init.originalPolicy = header; + init.sourceFile = String(); + init.lineNumber = 0; + + RefPtr<ScriptCallStack> stack = createScriptCallStack(2, false); + if (!stack) return; + const ScriptCallFrame& callFrame = getFirstNonNativeFrame(stack); + + if (callFrame.lineNumber()) { + KURL source = KURL(ParsedURLString, callFrame.sourceURL()); + init.sourceFile = stripURLForUseInReport(document, source); + init.lineNumber = callFrame.lineNumber(); + } +} +#endif + +void ContentSecurityPolicy::reportViolation(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL, const Vector<KURL>& reportURIs, const String& header, const String& contextURL, const WTF::OrdinalNumber& contextLine, ScriptState* state) const +{ + logToConsole(consoleMessage, contextURL, contextLine, state); + // FIXME: Support sending reports from worker. if (!m_scriptExecutionContext->isDocument()) return; - Document* document = static_cast<Document*>(m_scriptExecutionContext); + Document* document = toDocument(m_scriptExecutionContext); Frame* frame = document->frame(); if (!frame) return; +#if ENABLE(CSP_NEXT) + if (experimentalFeaturesEnabled()) { + // FIXME: This code means that we're gathering information like line numbers twice. Once we can bring this out from behind the flag, we should reuse the data gathered here when generating the JSON report below. + SecurityPolicyViolationEventInit init; + gatherSecurityPolicyViolationEventData(init, document, directiveText, effectiveDirective, blockedURL, header); + document->enqueueDocumentEvent(SecurityPolicyViolationEvent::create(eventNames().securitypolicyviolationEvent, init)); + } +#endif + + if (reportURIs.isEmpty()) + return; + // We need to be careful here when deciding what information to send to the // report-uri. Currently, we send only the current document's URL and the // directive that was violated. The document's URL is safe to send because @@ -1596,15 +1772,27 @@ void ContentSecurityPolicy::reportViolation(const String& directiveText, const S RefPtr<InspectorObject> cspReport = InspectorObject::create(); cspReport->setString("document-uri", document->url().strippedForUseAsReferrer()); - String referrer = document->referrer(); - cspReport->setString("referrer", referrer); - if (!directiveText.isEmpty()) - cspReport->setString("violated-directive", directiveText); + cspReport->setString("referrer", document->referrer()); + cspReport->setString("violated-directive", directiveText); +#if ENABLE(CSP_NEXT) + if (experimentalFeaturesEnabled()) + cspReport->setString("effective-directive", effectiveDirective); +#else + UNUSED_PARAM(effectiveDirective); +#endif cspReport->setString("original-policy", header); - if (blockedURL.isValid()) - cspReport->setString("blocked-uri", document->securityOrigin()->canRequest(blockedURL) ? blockedURL.strippedForUseAsReferrer() : SecurityOrigin::create(blockedURL)->toString()); - else - cspReport->setString("blocked-uri", String()); + cspReport->setString("blocked-uri", stripURLForUseInReport(document, blockedURL)); + + RefPtr<ScriptCallStack> stack = createScriptCallStack(2, false); + if (stack) { + const ScriptCallFrame& callFrame = getFirstNonNativeFrame(stack); + + if (callFrame.lineNumber()) { + KURL source = KURL(ParsedURLString, callFrame.sourceURL()); + cspReport->setString("source-file", stripURLForUseInReport(document, source)); + cspReport->setNumber("line-number", callFrame.lineNumber()); + } + } RefPtr<InspectorObject> reportObject = InspectorObject::create(); reportObject->setObject("csp-report", cspReport.release()); @@ -1662,6 +1850,11 @@ void ContentSecurityPolicy::reportInvalidSandboxFlags(const String& invalidFlags logToConsole("Error while parsing the 'sandbox' Content Security Policy directive: " + invalidFlags); } +void ContentSecurityPolicy::reportInvalidReflectedXSS(const String& invalidValue) const +{ + logToConsole("The 'reflected-xss' Content Security Policy directive has the invalid value \"" + invalidValue + "\". Value values are \"allow\", \"filter\", and \"block\"."); +} + void ContentSecurityPolicy::reportInvalidDirectiveValueCharacter(const String& directiveName, const String& value) const { String message = makeString("The value for Content Security Policy directive '", directiveName, "' contains an invalid character: '", value, "'. Non-whitespace characters outside ASCII 0x21-0x7E must be percent-encoded, as described in RFC 3986, section 2.1: http://tools.ietf.org/html/rfc3986#section-2.1."); @@ -1688,21 +1881,20 @@ void ContentSecurityPolicy::reportInvalidNonce(const String& nonce) const void ContentSecurityPolicy::reportInvalidSourceExpression(const String& directiveName, const String& source) const { String message = makeString("The source list for Content Security Policy directive '", directiveName, "' contains an invalid source: '", source, "'. It will be ignored."); + if (equalIgnoringCase(source, "'none'")) + message = makeString(message, " Note that 'none' has no effect unless it is the only expression in the source list."); logToConsole(message); } +void ContentSecurityPolicy::reportMissingReportURI(const String& policy) const +{ + logToConsole("The Content Security Policy '" + policy + "' was delivered in report-only mode, but does not specify a 'report-uri'; the policy will have no effect. Please either add a 'report-uri' directive, or deliver the policy via the 'Content-Security-Policy' header."); +} + void ContentSecurityPolicy::logToConsole(const String& message, const String& contextURL, const WTF::OrdinalNumber& contextLine, ScriptState* state) const { - RefPtr<ScriptCallStack> callStack; - if (InspectorInstrumentation::consoleAgentEnabled(m_scriptExecutionContext)) { - if (state) - callStack = createScriptCallStackForConsole(state); - else - callStack = createScriptCallStack(ScriptCallStack::maxCallStackSizeToCapture, true); - if (callStack && !callStack->size()) - callStack = 0; - } - m_scriptExecutionContext->addConsoleMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, message, contextURL, contextLine.oneBasedInt(), callStack); + // FIXME: <http://webkit.org/b/114317> ContentSecurityPolicy::logToConsole should include a column number + m_scriptExecutionContext->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, message, contextURL, contextLine.oneBasedInt(), 0, state); } void ContentSecurityPolicy::reportBlockedScriptExecutionToInspector(const String& directiveText) const @@ -1710,4 +1902,13 @@ void ContentSecurityPolicy::reportBlockedScriptExecutionToInspector(const String InspectorInstrumentation::scriptExecutionBlockedByCSP(m_scriptExecutionContext, directiveText); } +bool ContentSecurityPolicy::experimentalFeaturesEnabled() const +{ +#if ENABLE(CSP_NEXT) + return RuntimeEnabledFeatures::experimentalContentSecurityPolicyFeaturesEnabled(); +#else + return false; +#endif +} + } diff --git a/Source/WebCore/page/ContentSecurityPolicy.h b/Source/WebCore/page/ContentSecurityPolicy.h index d2cf3b540..36342286f 100644 --- a/Source/WebCore/page/ContentSecurityPolicy.h +++ b/Source/WebCore/page/ContentSecurityPolicy.h @@ -60,10 +60,10 @@ public: void copyStateFrom(const ContentSecurityPolicy*); enum HeaderType { - ReportStableDirectives, - EnforceStableDirectives, - ReportAllDirectives, - EnforceAllDirectives + Report, + Enforce, + PrefixedReport, + PrefixedEnforce }; enum ReportingStatus { @@ -71,6 +71,15 @@ public: SuppressReport }; + // Be sure to update the behavior of XSSAuditor::combineXSSProtectionHeaderAndCSP whenever you change this enum's content or ordering. + enum ReflectedXSSDisposition { + ReflectedXSSUnset = 0, + AllowReflectedXSS, + ReflectedXSSInvalid, + FilterReflectedXSS, + BlockReflectedXSS + }; + void didReceiveHeader(const String&, HeaderType); // These functions are wrong because they assume that there is only one header. @@ -95,6 +104,9 @@ public: bool allowMediaFromSource(const KURL&, ReportingStatus = SendReport) const; bool allowConnectToSource(const KURL&, ReportingStatus = SendReport) const; bool allowFormAction(const KURL&, ReportingStatus = SendReport) const; + bool allowBaseURI(const KURL&, ReportingStatus = SendReport) const; + + ReflectedXSSDisposition reflectedXSSDisposition() const; void setOverrideAllowInlineStyle(bool); @@ -109,8 +121,10 @@ public: void reportInvalidPluginTypes(const String&) const; void reportInvalidSandboxFlags(const String&) const; void reportInvalidSourceExpression(const String& directiveName, const String& source) const; + void reportInvalidReflectedXSS(const String&) const; + void reportMissingReportURI(const String&) const; void reportUnsupportedDirective(const String&) const; - void reportViolation(const String& directiveText, const String& consoleMessage, const KURL& blockedURL, const Vector<KURL>& reportURIs, const String& header, const String& contextURL = String(), const WTF::OrdinalNumber& contextLine = WTF::OrdinalNumber::beforeFirst(), ScriptState* = 0) const; + void reportViolation(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL, const Vector<KURL>& reportURIs, const String& header, const String& contextURL = String(), const WTF::OrdinalNumber& contextLine = WTF::OrdinalNumber::beforeFirst(), ScriptState* = 0) const; void reportBlockedScriptExecutionToInspector(const String& directiveText) const; @@ -120,6 +134,8 @@ public: void enforceSandboxFlags(SandboxFlags) const; String evalDisabledErrorMessage() const; + bool experimentalFeaturesEnabled() const; + private: explicit ContentSecurityPolicy(ScriptExecutionContext*); diff --git a/Source/WebCore/page/ContextMenuController.cpp b/Source/WebCore/page/ContextMenuController.cpp index adf0a797a..a7152259a 100644 --- a/Source/WebCore/page/ContextMenuController.cpp +++ b/Source/WebCore/page/ContextMenuController.cpp @@ -43,6 +43,7 @@ #include "Event.h" #include "EventHandler.h" #include "EventNames.h" +#include "ExceptionCodePlaceholder.h" #include "FormState.h" #include "Frame.h" #include "FrameLoadRequest.h" @@ -142,6 +143,8 @@ void ContextMenuController::showContextMenu(Event* event, PassRefPtr<ContextMenu PassOwnPtr<ContextMenu> ContextMenuController::createContextMenu(Event* event) { + ASSERT(event); + if (!event->isMouseEvent()) return nullptr; @@ -149,7 +152,7 @@ PassOwnPtr<ContextMenu> ContextMenuController::createContextMenu(Event* event) HitTestResult result(mouseEvent->absoluteLocation()); if (Frame* frame = event->target()->toNode()->document()->frame()) - result = frame->eventHandler()->hitTestResultAtPoint(mouseEvent->absoluteLocation(), false); + result = frame->eventHandler()->hitTestResultAtPoint(mouseEvent->absoluteLocation()); if (!result.innerNonSharedNode()) return nullptr; @@ -181,10 +184,10 @@ static void openNewWindow(const KURL& urlToLoad, Frame* frame) FrameLoadRequest request(frame->document()->securityOrigin(), ResourceRequest(urlToLoad, frame->loader()->outgoingReferrer())); Page* newPage = oldPage; if (!frame->settings() || frame->settings()->supportsMultipleWindows()) { - newPage = oldPage->chrome()->createWindow(frame, request, WindowFeatures(), NavigationAction(request.resourceRequest())); + newPage = oldPage->chrome().createWindow(frame, request, WindowFeatures(), NavigationAction(request.resourceRequest())); if (!newPage) return; - newPage->chrome()->show(); + newPage->chrome().show(); } newPage->mainFrame()->loader()->loadFrameRequest(request, false, false, 0, 0, MaybeSendReferrer); } @@ -194,7 +197,7 @@ static void openNewWindow(const KURL& urlToLoad, Frame* frame) static void insertUnicodeCharacter(UChar character, Frame* frame) { String text(&character, 1); - if (!frame->editor()->shouldInsertText(text, frame->selection()->toNormalizedRange().get(), EditorInsertActionTyped)) + if (!frame->editor().shouldInsertText(text, frame->selection()->toNormalizedRange().get(), EditorInsertActionTyped)) return; TypingCommand::insertText(frame->document(), text, 0, TypingCommand::TextCompositionNone); @@ -225,34 +228,38 @@ void ContextMenuController::contextMenuItemSelected(ContextMenuItem* item) openNewWindow(m_hitTestResult.absoluteLinkURL(), frame); break; case ContextMenuItemTagDownloadLinkToDisk: - // FIXME: Some day we should be able to do this from within WebCore. + // FIXME: Some day we should be able to do this from within WebCore. (Bug 117709) m_client->downloadURL(m_hitTestResult.absoluteLinkURL()); break; case ContextMenuItemTagCopyLinkToClipboard: - frame->editor()->copyURL(m_hitTestResult.absoluteLinkURL(), m_hitTestResult.textContent()); + frame->editor().copyURL(m_hitTestResult.absoluteLinkURL(), m_hitTestResult.textContent()); break; case ContextMenuItemTagOpenImageInNewWindow: openNewWindow(m_hitTestResult.absoluteImageURL(), frame); break; case ContextMenuItemTagDownloadImageToDisk: - // FIXME: Some day we should be able to do this from within WebCore. + // FIXME: Some day we should be able to do this from within WebCore. (Bug 117709) m_client->downloadURL(m_hitTestResult.absoluteImageURL()); break; case ContextMenuItemTagCopyImageToClipboard: // FIXME: The Pasteboard class is not written yet // For now, call into the client. This is temporary! - frame->editor()->copyImage(m_hitTestResult); + frame->editor().copyImage(m_hitTestResult); break; #if PLATFORM(QT) || PLATFORM(GTK) || PLATFORM(EFL) case ContextMenuItemTagCopyImageUrlToClipboard: - frame->editor()->copyURL(m_hitTestResult.absoluteImageURL(), m_hitTestResult.textContent()); + frame->editor().copyURL(m_hitTestResult.absoluteImageURL(), m_hitTestResult.textContent()); break; #endif case ContextMenuItemTagOpenMediaInNewWindow: openNewWindow(m_hitTestResult.absoluteMediaURL(), frame); break; + case ContextMenuItemTagDownloadMediaToDisk: + // FIXME: Some day we should be able to do this from within WebCore. (Bug 117709) + m_client->downloadURL(m_hitTestResult.absoluteMediaURL()); + break; case ContextMenuItemTagCopyMediaLinkToClipboard: - frame->editor()->copyURL(m_hitTestResult.absoluteMediaURL(), m_hitTestResult.textContent()); + frame->editor().copyURL(m_hitTestResult.absoluteMediaURL(), m_hitTestResult.textContent()); break; case ContextMenuItemTagToggleMediaControls: m_hitTestResult.toggleMediaControlsDisplay(); @@ -260,6 +267,9 @@ void ContextMenuController::contextMenuItemSelected(ContextMenuItem* item) case ContextMenuItemTagToggleMediaLoop: m_hitTestResult.toggleMediaLoopPlayback(); break; + case ContextMenuItemTagToggleVideoFullscreen: + m_hitTestResult.toggleMediaFullscreenState(); + break; case ContextMenuItemTagEnterVideoFullscreen: m_hitTestResult.enterFullscreenForVideo(); break; @@ -278,7 +288,7 @@ void ContextMenuController::contextMenuItemSelected(ContextMenuItem* item) break; } case ContextMenuItemTagCopy: - frame->editor()->copy(); + frame->editor().copy(); break; case ContextMenuItemTagGoBack: if (Page* page = frame->page()) @@ -295,14 +305,14 @@ void ContextMenuController::contextMenuItemSelected(ContextMenuItem* item) frame->loader()->reload(); break; case ContextMenuItemTagCut: - frame->editor()->command("Cut").execute(); + frame->editor().command("Cut").execute(); break; case ContextMenuItemTagPaste: - frame->editor()->command("Paste").execute(); + frame->editor().command("Paste").execute(); break; #if PLATFORM(GTK) case ContextMenuItemTagDelete: - frame->editor()->performDelete(); + frame->editor().performDelete(); break; case ContextMenuItemTagUnicodeInsertLRMMark: insertUnicodeCharacter(leftToRightMark, frame); @@ -337,23 +347,36 @@ void ContextMenuController::contextMenuItemSelected(ContextMenuItem* item) #endif #if PLATFORM(GTK) || PLATFORM(QT) || PLATFORM(EFL) case ContextMenuItemTagSelectAll: - frame->editor()->command("SelectAll").execute(); + frame->editor().command("SelectAll").execute(); break; #endif - case ContextMenuItemTagSpellingGuess: - ASSERT(frame->editor()->selectedText().length()); - if (frame->editor()->shouldInsertText(item->title(), frame->selection()->toNormalizedRange().get(), EditorInsertActionPasted)) { + case ContextMenuItemTagSpellingGuess: { + FrameSelection* frameSelection = frame->selection(); + if (frame->editor().shouldInsertText(item->title(), frameSelection->toNormalizedRange().get(), EditorInsertActionPasted)) { Document* document = frame->document(); - RefPtr<ReplaceSelectionCommand> command = ReplaceSelectionCommand::create(document, createFragmentFromMarkup(document, item->title(), ""), ReplaceSelectionCommand::SelectReplacement | ReplaceSelectionCommand::MatchStyle | ReplaceSelectionCommand::PreventNesting); + ReplaceSelectionCommand::CommandOptions replaceOptions = ReplaceSelectionCommand::MatchStyle | ReplaceSelectionCommand::PreventNesting; + + if (frame->editor().behavior().shouldAllowSpellingSuggestionsWithoutSelection()) { + ASSERT(frameSelection->isCaretOrRange()); + VisibleSelection wordSelection(frameSelection->base()); + wordSelection.expandUsingGranularity(WordGranularity); + frameSelection->setSelection(wordSelection); + } else { + ASSERT(frame->editor().selectedText().length()); + replaceOptions |= ReplaceSelectionCommand::SelectReplacement; + } + + RefPtr<ReplaceSelectionCommand> command = ReplaceSelectionCommand::create(document, createFragmentFromMarkup(document, item->title(), ""), replaceOptions); applyCommand(command); - frame->selection()->revealSelection(ScrollAlignment::alignToEdgeIfNeeded); + frameSelection->revealSelection(ScrollAlignment::alignToEdgeIfNeeded); } break; + } case ContextMenuItemTagIgnoreSpelling: - frame->editor()->ignoreSpelling(); + frame->editor().ignoreSpelling(); break; case ContextMenuItemTagLearnSpelling: - frame->editor()->learnSpelling(); + frame->editor().learnSpelling(); break; case ContextMenuItemTagSearchWeb: m_client->searchWithGoogle(frame); @@ -372,25 +395,24 @@ void ContextMenuController::contextMenuItemSelected(ContextMenuItem* item) frame->loader()->loadFrameRequest(FrameLoadRequest(frame->document()->securityOrigin(), ResourceRequest(m_hitTestResult.absoluteLinkURL(), frame->loader()->outgoingReferrer())), false, false, 0, 0, MaybeSendReferrer); break; case ContextMenuItemTagBold: - frame->editor()->command("ToggleBold").execute(); + frame->editor().command("ToggleBold").execute(); break; case ContextMenuItemTagItalic: - frame->editor()->command("ToggleItalic").execute(); + frame->editor().command("ToggleItalic").execute(); break; case ContextMenuItemTagUnderline: - frame->editor()->toggleUnderline(); + frame->editor().toggleUnderline(); break; case ContextMenuItemTagOutline: // We actually never enable this because CSS does not have a way to specify an outline font, // which may make this difficult to implement. Maybe a special case of text-shadow? break; case ContextMenuItemTagStartSpeaking: { - ExceptionCode ec; RefPtr<Range> selectedRange = frame->selection()->toNormalizedRange(); - if (!selectedRange || selectedRange->collapsed(ec)) { + if (!selectedRange || selectedRange->collapsed(IGNORE_EXCEPTION)) { Document* document = m_hitTestResult.innerNonSharedNode()->document(); selectedRange = document->createRange(); - selectedRange->selectNode(document->documentElement(), ec); + selectedRange->selectNode(document->documentElement(), IGNORE_EXCEPTION); } m_client->speak(plainText(selectedRange.get())); break; @@ -399,22 +421,22 @@ void ContextMenuController::contextMenuItemSelected(ContextMenuItem* item) m_client->stopSpeaking(); break; case ContextMenuItemTagDefaultDirection: - frame->editor()->setBaseWritingDirection(NaturalWritingDirection); + frame->editor().setBaseWritingDirection(NaturalWritingDirection); break; case ContextMenuItemTagLeftToRight: - frame->editor()->setBaseWritingDirection(LeftToRightWritingDirection); + frame->editor().setBaseWritingDirection(LeftToRightWritingDirection); break; case ContextMenuItemTagRightToLeft: - frame->editor()->setBaseWritingDirection(RightToLeftWritingDirection); + frame->editor().setBaseWritingDirection(RightToLeftWritingDirection); break; case ContextMenuItemTagTextDirectionDefault: - frame->editor()->command("MakeTextWritingDirectionNatural").execute(); + frame->editor().command("MakeTextWritingDirectionNatural").execute(); break; case ContextMenuItemTagTextDirectionLeftToRight: - frame->editor()->command("MakeTextWritingDirectionLeftToRight").execute(); + frame->editor().command("MakeTextWritingDirectionLeftToRight").execute(); break; case ContextMenuItemTagTextDirectionRightToLeft: - frame->editor()->command("MakeTextWritingDirectionRightToLeft").execute(); + frame->editor().command("MakeTextWritingDirectionRightToLeft").execute(); break; #if PLATFORM(MAC) case ContextMenuItemTagSearchInSpotlight: @@ -422,65 +444,65 @@ void ContextMenuController::contextMenuItemSelected(ContextMenuItem* item) break; #endif case ContextMenuItemTagShowSpellingPanel: - frame->editor()->showSpellingGuessPanel(); + frame->editor().showSpellingGuessPanel(); break; case ContextMenuItemTagCheckSpelling: - frame->editor()->advanceToNextMisspelling(); + frame->editor().advanceToNextMisspelling(); break; case ContextMenuItemTagCheckSpellingWhileTyping: - frame->editor()->toggleContinuousSpellChecking(); + frame->editor().toggleContinuousSpellChecking(); break; case ContextMenuItemTagCheckGrammarWithSpelling: - frame->editor()->toggleGrammarChecking(); + frame->editor().toggleGrammarChecking(); break; #if PLATFORM(MAC) case ContextMenuItemTagShowFonts: - frame->editor()->showFontPanel(); + frame->editor().showFontPanel(); break; case ContextMenuItemTagStyles: - frame->editor()->showStylesPanel(); + frame->editor().showStylesPanel(); break; case ContextMenuItemTagShowColors: - frame->editor()->showColorPanel(); + frame->editor().showColorPanel(); break; #endif #if USE(APPKIT) case ContextMenuItemTagMakeUpperCase: - frame->editor()->uppercaseWord(); + frame->editor().uppercaseWord(); break; case ContextMenuItemTagMakeLowerCase: - frame->editor()->lowercaseWord(); + frame->editor().lowercaseWord(); break; case ContextMenuItemTagCapitalize: - frame->editor()->capitalizeWord(); + frame->editor().capitalizeWord(); break; #endif #if PLATFORM(MAC) case ContextMenuItemTagChangeBack: - frame->editor()->changeBackToReplacedString(m_hitTestResult.replacedString()); + frame->editor().changeBackToReplacedString(m_hitTestResult.replacedString()); break; #endif #if USE(AUTOMATIC_TEXT_REPLACEMENT) case ContextMenuItemTagShowSubstitutions: - frame->editor()->showSubstitutionsPanel(); + frame->editor().showSubstitutionsPanel(); break; case ContextMenuItemTagSmartCopyPaste: - frame->editor()->toggleSmartInsertDelete(); + frame->editor().toggleSmartInsertDelete(); break; case ContextMenuItemTagSmartQuotes: - frame->editor()->toggleAutomaticQuoteSubstitution(); + frame->editor().toggleAutomaticQuoteSubstitution(); break; case ContextMenuItemTagSmartDashes: - frame->editor()->toggleAutomaticDashSubstitution(); + frame->editor().toggleAutomaticDashSubstitution(); break; case ContextMenuItemTagSmartLinks: - frame->editor()->toggleAutomaticLinkDetection(); + frame->editor().toggleAutomaticLinkDetection(); break; case ContextMenuItemTagTextReplacement: - frame->editor()->toggleAutomaticTextReplacement(); + frame->editor().toggleAutomaticTextReplacement(); break; case ContextMenuItemTagCorrectSpellingAutomatically: - frame->editor()->toggleAutomaticSpellingCorrection(); + frame->editor().toggleAutomaticSpellingCorrection(); break; #endif #if ENABLE(INSPECTOR) @@ -490,7 +512,7 @@ void ContextMenuController::contextMenuItemSelected(ContextMenuItem* item) break; #endif case ContextMenuItemTagDictationAlternative: - frame->editor()->applyDictationAlternativelternative(item->title()); + frame->editor().applyDictationAlternativelternative(item->title()); break; default: break; @@ -717,6 +739,18 @@ static bool selectionContainsPossibleWord(Frame* frame) #endif #endif +#if PLATFORM(MAC) +#define SUPPORTS_TOGGLE_VIDEO_FULLSCREEN 1 +#else +#define SUPPORTS_TOGGLE_VIDEO_FULLSCREEN 0 +#endif + +#if PLATFORM(MAC) +#define SUPPORTS_TOGGLE_SHOW_HIDE_MEDIA_CONTROLS 1 +#else +#define SUPPORTS_TOGGLE_SHOW_HIDE_MEDIA_CONTROLS 0 +#endif + void ContextMenuController::populate() { ContextMenuItem OpenLinkItem(ActionType, ContextMenuItemTagOpenLink, contextMenuItemTagOpenLink()); @@ -737,17 +771,24 @@ void ContextMenuController::populate() contextMenuItemTagCopyImageUrlToClipboard()); #endif ContextMenuItem OpenMediaInNewWindowItem(ActionType, ContextMenuItemTagOpenMediaInNewWindow, String()); - ContextMenuItem CopyMediaLinkItem(ActionType, ContextMenuItemTagCopyMediaLinkToClipboard, - String()); + ContextMenuItem DownloadMediaItem(ActionType, ContextMenuItemTagDownloadMediaToDisk, String()); + ContextMenuItem CopyMediaLinkItem(ActionType, ContextMenuItemTagCopyMediaLinkToClipboard, String()); ContextMenuItem MediaPlayPause(ActionType, ContextMenuItemTagMediaPlayPause, contextMenuItemTagMediaPlay()); ContextMenuItem MediaMute(ActionType, ContextMenuItemTagMediaMute, contextMenuItemTagMediaMute()); +#if SUPPORTS_TOGGLE_SHOW_HIDE_MEDIA_CONTROLS + ContextMenuItem ToggleMediaControls(ActionType, ContextMenuItemTagToggleMediaControls, + contextMenuItemTagHideMediaControls()); +#else ContextMenuItem ToggleMediaControls(CheckableActionType, ContextMenuItemTagToggleMediaControls, contextMenuItemTagToggleMediaControls()); +#endif ContextMenuItem ToggleMediaLoop(CheckableActionType, ContextMenuItemTagToggleMediaLoop, contextMenuItemTagToggleMediaLoop()); - ContextMenuItem EnterVideoFullscreen(ActionType, ContextMenuItemTagEnterVideoFullscreen, + ContextMenuItem EnterVideoFullscreen(ActionType, ContextMenuItemTagEnterVideoFullscreen, + contextMenuItemTagEnterVideoFullscreen()); + ContextMenuItem ToggleVideoFullscreen(ActionType, ContextMenuItemTagToggleVideoFullscreen, contextMenuItemTagEnterVideoFullscreen()); #if PLATFORM(MAC) ContextMenuItem SearchSpotlightItem(ActionType, ContextMenuItemTagSearchInSpotlight, @@ -784,7 +825,7 @@ void ContextMenuController::populate() if (!node) return; #if PLATFORM(GTK) - if (!m_hitTestResult.isContentEditable() && (node->isElementNode() && static_cast<Element*>(node)->isFormControlElement())) + if (!m_hitTestResult.isContentEditable() && (node->isElementNode() && toElement(node)->isFormControlElement())) return; #endif Frame* frame = node->document()->frame(); @@ -830,18 +871,23 @@ void ContextMenuController::populate() appendItem(MediaMute, m_contextMenu.get()); appendItem(ToggleMediaControls, m_contextMenu.get()); appendItem(ToggleMediaLoop, m_contextMenu.get()); +#if SUPPORTS_TOGGLE_VIDEO_FULLSCREEN + appendItem(ToggleVideoFullscreen, m_contextMenu.get()); +#else appendItem(EnterVideoFullscreen, m_contextMenu.get()); - +#endif appendItem(*separatorItem(), m_contextMenu.get()); appendItem(CopyMediaLinkItem, m_contextMenu.get()); appendItem(OpenMediaInNewWindowItem, m_contextMenu.get()); + if (loader->client()->canHandleRequest(ResourceRequest(mediaURL))) + appendItem(DownloadMediaItem, m_contextMenu.get()); } if (imageURL.isEmpty() && linkURL.isEmpty() && mediaURL.isEmpty()) { if (m_hitTestResult.isSelected()) { if (selectionContainsPossibleWord(frame)) { #if PLATFORM(MAC) - String selectedString = frame->displayStringModifiedByEncoding(frame->editor()->selectedText()); + String selectedString = frame->displayStringModifiedByEncoding(frame->editor().selectedText()); ContextMenuItem LookUpInDictionaryItem(ActionType, ContextMenuItemTagLookUpInDictionary, contextMenuItemTagLookUpInDictionary(selectedString)); #if INCLUDE_SPOTLIGHT_CONTEXT_MENU_ITEM @@ -875,8 +921,8 @@ void ContextMenuController::populate() if (!(frame->page() && frame->page()->inspectorController()->hasInspectorFrontendClient())) { #endif - // In GTK+ and EFL, unavailable items are not hidden but insensitive. -#if PLATFORM(GTK) || PLATFORM(EFL) + // In GTK+ unavailable items are not hidden but insensitive. +#if PLATFORM(GTK) appendItem(BackItem, m_contextMenu.get()); appendItem(ForwardItem, m_contextMenu.get()); appendItem(StopItem, m_contextMenu.get()); @@ -908,13 +954,13 @@ void ContextMenuController::populate() bool inPasswordField = selection->isInPasswordField(); if (!inPasswordField) { bool haveContextMenuItemsForMisspellingOrGrammer = false; - bool spellCheckingEnabled = frame->editor()->isSpellCheckingEnabledFor(node); + bool spellCheckingEnabled = frame->editor().isSpellCheckingEnabledFor(node); if (spellCheckingEnabled) { // Consider adding spelling-related or grammar-related context menu items (never both, since a single selected range // is never considered a misspelling and bad grammar at the same time) bool misspelling; bool badGrammar; - Vector<String> guesses = frame->editor()->guessesForMisspelledOrUngrammaticalSelection(misspelling, badGrammar); + Vector<String> guesses = frame->editor().guessesForMisspelledOrUngrammatical(misspelling, badGrammar); if (misspelling || badGrammar) { size_t size = guesses.size(); if (!size) { @@ -941,7 +987,7 @@ void ContextMenuController::populate() appendItem(IgnoreGrammarItem, m_contextMenu.get()); appendItem(*separatorItem(), m_contextMenu.get()); haveContextMenuItemsForMisspellingOrGrammer = true; -#if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 +#if PLATFORM(MAC) } else { // If the string was autocorrected, generate a contextual menu item allowing it to be changed back. String replacedString = m_hitTestResult.replacedString(); @@ -982,7 +1028,7 @@ void ContextMenuController::populate() if (m_hitTestResult.isSelected() && !inPasswordField && selectionContainsPossibleWord(frame)) { #if PLATFORM(MAC) - String selectedString = frame->displayStringModifiedByEncoding(frame->editor()->selectedText()); + String selectedString = frame->displayStringModifiedByEncoding(frame->editor().selectedText()); ContextMenuItem LookUpInDictionaryItem(ActionType, ContextMenuItemTagLookUpInDictionary, contextMenuItemTagLookUpInDictionary(selectedString)); #if INCLUDE_SPOTLIGHT_CONTEXT_MENU_ITEM @@ -1033,7 +1079,7 @@ void ContextMenuController::populate() appendItem(transformationsMenuItem, m_contextMenu.get()); #endif #if PLATFORM(GTK) - bool shouldShowFontMenu = frame->editor()->canEditRichly(); + bool shouldShowFontMenu = frame->editor().canEditRichly(); #else bool shouldShowFontMenu = true; #endif @@ -1049,7 +1095,7 @@ void ContextMenuController::populate() appendItem(SpeechMenuItem, m_contextMenu.get()); #endif #if PLATFORM(GTK) - EditorClient* client = frame->editor()->client(); + EditorClient* client = frame->editor().client(); if (client && client->shouldShowUnicodeMenu()) { ContextMenuItem UnicodeMenuItem(SubmenuType, ContextMenuItemTagUnicode, contextMenuItemTagUnicode()); createAndAppendUnicodeSubMenu(UnicodeMenuItem); @@ -1064,7 +1110,7 @@ void ContextMenuController::populate() if (Page* page = frame->page()) { if (Settings* settings = page->settings()) { bool includeTextDirectionSubmenu = settings->textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuAlwaysIncluded - || (settings->textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuAutomaticallyIncluded && frame->editor()->hasBidiSelection()); + || (settings->textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuAutomaticallyIncluded && frame->editor().hasBidiSelection()); if (includeTextDirectionSubmenu) { ContextMenuItem TextDirectionMenuItem(SubmenuType, ContextMenuItemTagTextDirectionMenu, contextMenuItemTagTextDirectionMenu()); @@ -1125,7 +1171,7 @@ void ContextMenuController::checkOrEnableIfNeeded(ContextMenuItem& item) const switch (item.action()) { case ContextMenuItemTagCheckSpelling: - shouldEnable = frame->editor()->canEdit(); + shouldEnable = frame->editor().canEdit(); break; case ContextMenuItemTagDefaultDirection: shouldCheck = false; @@ -1134,44 +1180,44 @@ void ContextMenuController::checkOrEnableIfNeeded(ContextMenuItem& item) const case ContextMenuItemTagLeftToRight: case ContextMenuItemTagRightToLeft: { String direction = item.action() == ContextMenuItemTagLeftToRight ? "ltr" : "rtl"; - shouldCheck = frame->editor()->selectionHasStyle(CSSPropertyDirection, direction) != FalseTriState; + shouldCheck = frame->editor().selectionHasStyle(CSSPropertyDirection, direction) != FalseTriState; shouldEnable = true; break; } case ContextMenuItemTagTextDirectionDefault: { - Editor::Command command = frame->editor()->command("MakeTextWritingDirectionNatural"); + Editor::Command command = frame->editor().command("MakeTextWritingDirectionNatural"); shouldCheck = command.state() == TrueTriState; shouldEnable = command.isEnabled(); break; } case ContextMenuItemTagTextDirectionLeftToRight: { - Editor::Command command = frame->editor()->command("MakeTextWritingDirectionLeftToRight"); + Editor::Command command = frame->editor().command("MakeTextWritingDirectionLeftToRight"); shouldCheck = command.state() == TrueTriState; shouldEnable = command.isEnabled(); break; } case ContextMenuItemTagTextDirectionRightToLeft: { - Editor::Command command = frame->editor()->command("MakeTextWritingDirectionRightToLeft"); + Editor::Command command = frame->editor().command("MakeTextWritingDirectionRightToLeft"); shouldCheck = command.state() == TrueTriState; shouldEnable = command.isEnabled(); break; } case ContextMenuItemTagCopy: - shouldEnable = frame->editor()->canDHTMLCopy() || frame->editor()->canCopy(); + shouldEnable = frame->editor().canDHTMLCopy() || frame->editor().canCopy(); break; case ContextMenuItemTagCut: - shouldEnable = frame->editor()->canDHTMLCut() || frame->editor()->canCut(); + shouldEnable = frame->editor().canDHTMLCut() || frame->editor().canCut(); break; case ContextMenuItemTagIgnoreSpelling: case ContextMenuItemTagLearnSpelling: shouldEnable = frame->selection()->isRange(); break; case ContextMenuItemTagPaste: - shouldEnable = frame->editor()->canDHTMLPaste() || frame->editor()->canPaste(); + shouldEnable = frame->editor().canDHTMLPaste() || frame->editor().canPaste(); break; #if PLATFORM(GTK) case ContextMenuItemTagDelete: - shouldEnable = frame->editor()->canDelete(); + shouldEnable = frame->editor().canDelete(); break; case ContextMenuItemTagInputMethods: case ContextMenuItemTagUnicode: @@ -1194,78 +1240,78 @@ void ContextMenuController::checkOrEnableIfNeeded(ContextMenuItem& item) const break; #endif case ContextMenuItemTagUnderline: { - shouldCheck = frame->editor()->selectionHasStyle(CSSPropertyWebkitTextDecorationsInEffect, "underline") != FalseTriState; - shouldEnable = frame->editor()->canEditRichly(); + shouldCheck = frame->editor().selectionHasStyle(CSSPropertyWebkitTextDecorationsInEffect, "underline") != FalseTriState; + shouldEnable = frame->editor().canEditRichly(); break; } case ContextMenuItemTagLookUpInDictionary: shouldEnable = frame->selection()->isRange(); break; case ContextMenuItemTagCheckGrammarWithSpelling: - if (frame->editor()->isGrammarCheckingEnabled()) + if (frame->editor().isGrammarCheckingEnabled()) shouldCheck = true; shouldEnable = true; break; case ContextMenuItemTagItalic: { - shouldCheck = frame->editor()->selectionHasStyle(CSSPropertyFontStyle, "italic") != FalseTriState; - shouldEnable = frame->editor()->canEditRichly(); + shouldCheck = frame->editor().selectionHasStyle(CSSPropertyFontStyle, "italic") != FalseTriState; + shouldEnable = frame->editor().canEditRichly(); break; } case ContextMenuItemTagBold: { - shouldCheck = frame->editor()->selectionHasStyle(CSSPropertyFontWeight, "bold") != FalseTriState; - shouldEnable = frame->editor()->canEditRichly(); + shouldCheck = frame->editor().selectionHasStyle(CSSPropertyFontWeight, "bold") != FalseTriState; + shouldEnable = frame->editor().canEditRichly(); break; } case ContextMenuItemTagOutline: shouldEnable = false; break; case ContextMenuItemTagShowSpellingPanel: - if (frame->editor()->spellingPanelIsShowing()) + if (frame->editor().spellingPanelIsShowing()) item.setTitle(contextMenuItemTagShowSpellingPanel(false)); else item.setTitle(contextMenuItemTagShowSpellingPanel(true)); - shouldEnable = frame->editor()->canEdit(); + shouldEnable = frame->editor().canEdit(); break; case ContextMenuItemTagNoGuessesFound: shouldEnable = false; break; case ContextMenuItemTagCheckSpellingWhileTyping: - shouldCheck = frame->editor()->isContinuousSpellCheckingEnabled(); + shouldCheck = frame->editor().isContinuousSpellCheckingEnabled(); break; #if PLATFORM(MAC) case ContextMenuItemTagSubstitutionsMenu: case ContextMenuItemTagTransformationsMenu: break; case ContextMenuItemTagShowSubstitutions: - if (frame->editor()->substitutionsPanelIsShowing()) + if (frame->editor().substitutionsPanelIsShowing()) item.setTitle(contextMenuItemTagShowSubstitutions(false)); else item.setTitle(contextMenuItemTagShowSubstitutions(true)); - shouldEnable = frame->editor()->canEdit(); + shouldEnable = frame->editor().canEdit(); break; case ContextMenuItemTagMakeUpperCase: case ContextMenuItemTagMakeLowerCase: case ContextMenuItemTagCapitalize: case ContextMenuItemTagChangeBack: - shouldEnable = frame->editor()->canEdit(); + shouldEnable = frame->editor().canEdit(); break; case ContextMenuItemTagCorrectSpellingAutomatically: - shouldCheck = frame->editor()->isAutomaticSpellingCorrectionEnabled(); + shouldCheck = frame->editor().isAutomaticSpellingCorrectionEnabled(); break; case ContextMenuItemTagSmartCopyPaste: - shouldCheck = frame->editor()->smartInsertDeleteEnabled(); + shouldCheck = frame->editor().smartInsertDeleteEnabled(); break; case ContextMenuItemTagSmartQuotes: - shouldCheck = frame->editor()->isAutomaticQuoteSubstitutionEnabled(); + shouldCheck = frame->editor().isAutomaticQuoteSubstitutionEnabled(); break; case ContextMenuItemTagSmartDashes: - shouldCheck = frame->editor()->isAutomaticDashSubstitutionEnabled(); + shouldCheck = frame->editor().isAutomaticDashSubstitutionEnabled(); break; case ContextMenuItemTagSmartLinks: - shouldCheck = frame->editor()->isAutomaticLinkDetectionEnabled(); + shouldCheck = frame->editor().isAutomaticLinkDetectionEnabled(); break; case ContextMenuItemTagTextReplacement: - shouldCheck = frame->editor()->isAutomaticTextReplacementEnabled(); + shouldCheck = frame->editor().isAutomaticTextReplacementEnabled(); break; case ContextMenuItemTagStopSpeaking: shouldEnable = client() && client()->isSpeaking(); @@ -1288,7 +1334,7 @@ void ContextMenuController::checkOrEnableIfNeeded(ContextMenuItem& item) const shouldEnable = !frame->loader()->documentLoader()->isLoadingInAPISense(); break; case ContextMenuItemTagFontMenu: - shouldEnable = frame->editor()->canEditRichly(); + shouldEnable = frame->editor().canEditRichly(); break; #else case ContextMenuItemTagGoBack: @@ -1315,6 +1361,12 @@ void ContextMenuController::checkOrEnableIfNeeded(ContextMenuItem& item) const else item.setTitle(contextMenuItemTagOpenAudioInNewWindow()); break; + case ContextMenuItemTagDownloadMediaToDisk: + if (m_hitTestResult.mediaIsVideo()) + item.setTitle(contextMenuItemTagDownloadVideoToDisk()); + else + item.setTitle(contextMenuItemTagDownloadAudioToDisk()); + break; case ContextMenuItemTagCopyMediaLinkToClipboard: if (m_hitTestResult.mediaIsVideo()) item.setTitle(contextMenuItemTagCopyVideoLinkToClipboard()); @@ -1322,11 +1374,20 @@ void ContextMenuController::checkOrEnableIfNeeded(ContextMenuItem& item) const item.setTitle(contextMenuItemTagCopyAudioLinkToClipboard()); break; case ContextMenuItemTagToggleMediaControls: +#if SUPPORTS_TOGGLE_SHOW_HIDE_MEDIA_CONTROLS + item.setTitle(m_hitTestResult.mediaControlsEnabled() ? contextMenuItemTagHideMediaControls() : contextMenuItemTagShowMediaControls()); +#else shouldCheck = m_hitTestResult.mediaControlsEnabled(); +#endif break; case ContextMenuItemTagToggleMediaLoop: shouldCheck = m_hitTestResult.mediaLoopEnabled(); break; + case ContextMenuItemTagToggleVideoFullscreen: +#if SUPPORTS_TOGGLE_VIDEO_FULLSCREEN + item.setTitle(m_hitTestResult.mediaIsInFullscreen() ? contextMenuItemTagExitVideoFullscreen() : contextMenuItemTagEnterVideoFullscreen()); + break; +#endif case ContextMenuItemTagEnterVideoFullscreen: shouldEnable = m_hitTestResult.mediaSupportsFullscreen(); break; diff --git a/Source/WebCore/page/Coordinates.h b/Source/WebCore/page/Coordinates.h deleted file mode 100644 index 3de1366f1..000000000 --- a/Source/WebCore/page/Coordinates.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2009 Apple Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef Coordinates_h -#define Coordinates_h - -#include "Event.h" -#include <wtf/RefCounted.h> - -namespace WebCore { - -class Coordinates : public RefCounted<Coordinates> { -public: - static PassRefPtr<Coordinates> create(double latitude, double longitude, bool providesAltitude, double altitude, double accuracy, bool providesAltitudeAccuracy, double altitudeAccuracy, bool providesHeading, double heading, bool providesSpeed, double speed) { return adoptRef(new Coordinates(latitude, longitude, providesAltitude, altitude, accuracy, providesAltitudeAccuracy, altitudeAccuracy, providesHeading, heading, providesSpeed, speed)); } - - PassRefPtr<Coordinates> isolatedCopy() const - { - return Coordinates::create(m_latitude, m_longitude, m_canProvideAltitude, m_altitude, m_accuracy, m_canProvideAltitudeAccuracy, m_altitudeAccuracy, m_canProvideHeading, m_heading, m_canProvideSpeed, m_speed); - } - - double latitude() const { return m_latitude; } - double longitude() const { return m_longitude; } - double altitude() const { return m_altitude; } - double accuracy() const { return m_accuracy; } - double altitudeAccuracy() const { return m_altitudeAccuracy; } - double heading() const { return m_heading; } - double speed() const { return m_speed; } - - bool canProvideAltitude() const { return m_canProvideAltitude; } - bool canProvideAltitudeAccuracy() const { return m_canProvideAltitudeAccuracy; } - bool canProvideHeading() const { return m_canProvideHeading; } - bool canProvideSpeed() const { return m_canProvideSpeed; } - -private: - Coordinates(double latitude, double longitude, bool providesAltitude, double altitude, double accuracy, bool providesAltitudeAccuracy, double altitudeAccuracy, bool providesHeading, double heading, bool providesSpeed, double speed) - : m_latitude(latitude) - , m_longitude(longitude) - , m_altitude(altitude) - , m_accuracy(accuracy) - , m_altitudeAccuracy(altitudeAccuracy) - , m_heading(heading) - , m_speed(speed) - , m_canProvideAltitude(providesAltitude) - , m_canProvideAltitudeAccuracy(providesAltitudeAccuracy) - , m_canProvideHeading(providesHeading) - , m_canProvideSpeed(providesSpeed) - { - } - - double m_latitude; - double m_longitude; - double m_altitude; - double m_accuracy; - double m_altitudeAccuracy; - double m_heading; - double m_speed; - - bool m_canProvideAltitude; - bool m_canProvideAltitudeAccuracy; - bool m_canProvideHeading; - bool m_canProvideSpeed; -}; - -} // namespace WebCore - -#endif // Coordinates_h diff --git a/Source/WebCore/page/Crypto.cpp b/Source/WebCore/page/Crypto.cpp index 16709e9e0..ae416ee17 100644 --- a/Source/WebCore/page/Crypto.cpp +++ b/Source/WebCore/page/Crypto.cpp @@ -31,6 +31,7 @@ #include "Crypto.h" #include "ExceptionCode.h" +#include "ScriptWrappableInlines.h" #include <wtf/ArrayBufferView.h> #include <wtf/CryptographicallyRandomNumber.h> @@ -58,7 +59,6 @@ Crypto::Crypto() void Crypto::getRandomValues(ArrayBufferView* array, ExceptionCode& ec) { -#if USE(OS_RANDOMNESS) if (!array || !isIntegerArray(array)) { ec = TYPE_MISMATCH_ERR; return; @@ -68,10 +68,6 @@ void Crypto::getRandomValues(ArrayBufferView* array, ExceptionCode& ec) return; } cryptographicallyRandomValues(array->baseAddress(), array->byteLength()); -#else - ASSERT_UNUSED(array, array); - ec = NOT_SUPPORTED_ERR; -#endif } } diff --git a/Source/WebCore/page/Crypto.idl b/Source/WebCore/page/Crypto.idl index 589281af5..5813305e2 100644 --- a/Source/WebCore/page/Crypto.idl +++ b/Source/WebCore/page/Crypto.idl @@ -27,8 +27,9 @@ */ [ - OmitConstructor + NoInterfaceObject, + ImplementationLacksVTable ] interface Crypto { - void getRandomValues(in ArrayBufferView array) raises(DOMException); + [Custom, RaisesException] ArrayBufferView getRandomValues(ArrayBufferView array); }; diff --git a/Source/WebCore/page/DOMSecurityPolicy.idl b/Source/WebCore/page/DOMSecurityPolicy.idl index 2e17fb745..de0467e63 100644 --- a/Source/WebCore/page/DOMSecurityPolicy.idl +++ b/Source/WebCore/page/DOMSecurityPolicy.idl @@ -24,7 +24,6 @@ [ Conditional=CSP_NEXT, - OmitConstructor, InterfaceName=SecurityPolicy ] interface DOMSecurityPolicy { readonly attribute boolean allowsEval; @@ -34,14 +33,14 @@ readonly attribute DOMStringList reportURIs; - boolean allowsConnectionTo(in DOMString url); - boolean allowsFontFrom(in DOMString url); - boolean allowsFormAction(in DOMString url); - boolean allowsFrameFrom(in DOMString url); - boolean allowsImageFrom(in DOMString url); - boolean allowsMediaFrom(in DOMString url); - boolean allowsObjectFrom(in DOMString url); - boolean allowsPluginType(in DOMString type); - boolean allowsScriptFrom(in DOMString url); - boolean allowsStyleFrom(in DOMString url); + boolean allowsConnectionTo(DOMString url); + boolean allowsFontFrom(DOMString url); + boolean allowsFormAction(DOMString url); + boolean allowsFrameFrom(DOMString url); + boolean allowsImageFrom(DOMString url); + boolean allowsMediaFrom(DOMString url); + boolean allowsObjectFrom(DOMString url); + boolean allowsPluginType(DOMString type); + boolean allowsScriptFrom(DOMString url); + boolean allowsStyleFrom(DOMString url); }; diff --git a/Source/WebCore/page/DOMSelection.cpp b/Source/WebCore/page/DOMSelection.cpp index 062443ac4..79c8a1fd0 100644 --- a/Source/WebCore/page/DOMSelection.cpp +++ b/Source/WebCore/page/DOMSelection.cpp @@ -397,11 +397,10 @@ void DOMSelection::addRange(Range* r) } RefPtr<Range> range = selection->selection().toNormalizedRange(); - ExceptionCode ec = 0; - if (r->compareBoundaryPoints(Range::START_TO_START, range.get(), ec) == -1) { + if (r->compareBoundaryPoints(Range::START_TO_START, range.get(), IGNORE_EXCEPTION) == -1) { // We don't support discontiguous selection. We don't do anything if r and range don't intersect. - if (r->compareBoundaryPoints(Range::START_TO_END, range.get(), ec) > -1) { - if (r->compareBoundaryPoints(Range::END_TO_END, range.get(), ec) == -1) + if (r->compareBoundaryPoints(Range::START_TO_END, range.get(), IGNORE_EXCEPTION) > -1) { + if (r->compareBoundaryPoints(Range::END_TO_END, range.get(), IGNORE_EXCEPTION) == -1) // The original range and r intersect. selection->setSelection(VisibleSelection(r->startPosition(), range->endPosition(), DOWNSTREAM)); else @@ -410,8 +409,9 @@ void DOMSelection::addRange(Range* r) } } else { // We don't support discontiguous selection. We don't do anything if r and range don't intersect. + ExceptionCode ec = 0; if (r->compareBoundaryPoints(Range::END_TO_START, range.get(), ec) < 1 && !ec) { - if (r->compareBoundaryPoints(Range::END_TO_END, range.get(), ec) == -1) + if (r->compareBoundaryPoints(Range::END_TO_END, range.get(), IGNORE_EXCEPTION) == -1) // The original range contains r. selection->setSelection(VisibleSelection(range.get())); else @@ -438,15 +438,12 @@ void DOMSelection::deleteFromDocument() if (!selectedRange) return; - ExceptionCode ec = 0; - selectedRange->deleteContents(ec); - ASSERT(!ec); + selectedRange->deleteContents(ASSERT_NO_EXCEPTION); - setBaseAndExtent(selectedRange->startContainer(ec), selectedRange->startOffset(ec), selectedRange->startContainer(ec), selectedRange->startOffset(ec), ec); - ASSERT(!ec); + setBaseAndExtent(selectedRange->startContainer(ASSERT_NO_EXCEPTION), selectedRange->startOffset(), selectedRange->startContainer(), selectedRange->startOffset(), ASSERT_NO_EXCEPTION); } -bool DOMSelection::containsNode(const Node* n, bool allowPartial) const +bool DOMSelection::containsNode(Node* n, bool allowPartial) const { if (!m_frame) return false; @@ -456,27 +453,28 @@ bool DOMSelection::containsNode(const Node* n, bool allowPartial) const if (!n || m_frame->document() != n->document() || selection->isNone()) return false; - ContainerNode* parentNode = n->parentNode(); - unsigned nodeIndex = n->nodeIndex(); + RefPtr<Node> node = n; RefPtr<Range> selectedRange = selection->selection().toNormalizedRange(); - if (!parentNode) + ContainerNode* parentNode = node->parentNode(); + if (!parentNode || !parentNode->inDocument()) return false; + unsigned nodeIndex = node->nodeIndex(); ExceptionCode ec = 0; - bool nodeFullySelected = Range::compareBoundaryPoints(parentNode, nodeIndex, selectedRange->startContainer(ec), selectedRange->startOffset(ec), ec) >= 0 && !ec - && Range::compareBoundaryPoints(parentNode, nodeIndex + 1, selectedRange->endContainer(ec), selectedRange->endOffset(ec), ec) <= 0 && !ec; + bool nodeFullySelected = Range::compareBoundaryPoints(parentNode, nodeIndex, selectedRange->startContainer(), selectedRange->startOffset(), ec) >= 0 && !ec + && Range::compareBoundaryPoints(parentNode, nodeIndex + 1, selectedRange->endContainer(), selectedRange->endOffset(), ec) <= 0 && !ec; ASSERT(!ec); if (nodeFullySelected) return true; - bool nodeFullyUnselected = (Range::compareBoundaryPoints(parentNode, nodeIndex, selectedRange->endContainer(ec), selectedRange->endOffset(ec), ec) > 0 && !ec) - || (Range::compareBoundaryPoints(parentNode, nodeIndex + 1, selectedRange->startContainer(ec), selectedRange->startOffset(ec), ec) < 0 && !ec); + bool nodeFullyUnselected = (Range::compareBoundaryPoints(parentNode, nodeIndex, selectedRange->endContainer(), selectedRange->endOffset(), ec) > 0 && !ec) + || (Range::compareBoundaryPoints(parentNode, nodeIndex + 1, selectedRange->startContainer(), selectedRange->startOffset(), ec) < 0 && !ec); ASSERT(!ec); if (nodeFullyUnselected) return false; - return allowPartial || n->isTextNode(); + return allowPartial || node->isTextNode(); } void DOMSelection::selectAllChildren(Node* n, ExceptionCode& ec) diff --git a/Source/WebCore/page/DOMSelection.h b/Source/WebCore/page/DOMSelection.h index 76b1b46ef..1dda6abea 100644 --- a/Source/WebCore/page/DOMSelection.h +++ b/Source/WebCore/page/DOMSelection.h @@ -84,7 +84,7 @@ namespace WebCore { void removeAllRanges(); void addRange(Range*); void deleteFromDocument(); - bool containsNode(const Node*, bool partlyContained) const; + bool containsNode(Node*, bool partlyContained) const; void selectAllChildren(Node*, ExceptionCode&); String toString(); diff --git a/Source/WebCore/page/DOMSelection.idl b/Source/WebCore/page/DOMSelection.idl index ee6979ae1..e187473b4 100644 --- a/Source/WebCore/page/DOMSelection.idl +++ b/Source/WebCore/page/DOMSelection.idl @@ -30,7 +30,7 @@ // This is based off of Mozilla's Selection interface // https://developer.mozilla.org/En/DOM/Selection [ - JSGenerateIsReachable=ImplFrame, + GenerateIsReachable=ImplFrame, InterfaceName=Selection ] interface DOMSelection { readonly attribute Node anchorNode; @@ -41,28 +41,22 @@ readonly attribute boolean isCollapsed; readonly attribute long rangeCount; - void collapse(in [Optional=DefaultIsUndefined] Node node, - in [Optional=DefaultIsUndefined] long index) - raises(DOMException); - void collapseToEnd() - raises(DOMException); - void collapseToStart() - raises(DOMException); + [RaisesException] void collapse([Default=Undefined] optional Node node, + [Default=Undefined] optional long index); + [RaisesException] void collapseToEnd(); + [RaisesException] void collapseToStart(); void deleteFromDocument(); - boolean containsNode(in [Optional=DefaultIsUndefined] Node node, - in [Optional=DefaultIsUndefined] boolean allowPartial); - void selectAllChildren(in [Optional=DefaultIsUndefined] Node node) - raises(DOMException); + boolean containsNode([Default=Undefined] optional Node node, + [Default=Undefined] optional boolean allowPartial); + [RaisesException] void selectAllChildren([Default=Undefined] optional Node node); - void extend(in [Optional=DefaultIsUndefined] Node node, - in [Optional=DefaultIsUndefined] long offset) - raises(DOMException); + [RaisesException] void extend([Default=Undefined] optional Node node, + [Default=Undefined] optional long offset); - Range getRangeAt(in [Optional=DefaultIsUndefined] long index) - raises(DOMException); + [RaisesException] Range getRangeAt([Default=Undefined] optional long index); void removeAllRanges(); - void addRange(in [Optional=DefaultIsUndefined] Range range); + void addRange([Default=Undefined] optional Range range); #if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT [NotEnumerable] DOMString toString(); @@ -78,17 +72,15 @@ // IE's type accessor returns "none", "text" and "control" readonly attribute DOMString type; - void modify(in [Optional=DefaultIsUndefined] DOMString alter, - in [Optional=DefaultIsUndefined] DOMString direction, - in [Optional=DefaultIsUndefined] DOMString granularity); - void setBaseAndExtent(in [Optional=DefaultIsUndefined] Node baseNode, - in [Optional=DefaultIsUndefined] long baseOffset, - in [Optional=DefaultIsUndefined] Node extentNode, - in [Optional=DefaultIsUndefined] long extentOffset) - raises(DOMException); - void setPosition(in [Optional=DefaultIsUndefined] Node node, - in [Optional=DefaultIsUndefined] long offset) - raises(DOMException); + void modify([Default=Undefined] optional DOMString alter, + [Default=Undefined] optional DOMString direction, + [Default=Undefined] optional DOMString granularity); + [RaisesException] void setBaseAndExtent([Default=Undefined] optional Node baseNode, + [Default=Undefined] optional long baseOffset, + [Default=Undefined] optional Node extentNode, + [Default=Undefined] optional long extentOffset); + [RaisesException] void setPosition([Default=Undefined] optional Node node, + [Default=Undefined] optional long offset); // IE extentions // http://msdn.microsoft.com/en-us/library/ms535869(VS.85).aspx diff --git a/Source/WebCore/page/DOMTimer.cpp b/Source/WebCore/page/DOMTimer.cpp index 9f206ebcd..5bb251121 100644 --- a/Source/WebCore/page/DOMTimer.cpp +++ b/Source/WebCore/page/DOMTimer.cpp @@ -30,7 +30,7 @@ #include "InspectorInstrumentation.h" #include "ScheduledAction.h" #include "ScriptExecutionContext.h" -#include "WebCoreMemoryInstrumentation.h" +#include "UserGestureIndicator.h" #include <wtf/CurrentTime.h> #include <wtf/HashSet.h> #include <wtf/StdLibExtras.h> @@ -54,15 +54,15 @@ static inline bool shouldForwardUserGesture(int interval, int nestingLevel) DOMTimer::DOMTimer(ScriptExecutionContext* context, PassOwnPtr<ScheduledAction> action, int interval, bool singleShot) : SuspendableTimer(context) - , m_timeoutId(context->newUniqueID()) , m_nestingLevel(timerNestingLevel + 1) , m_action(action) , m_originalInterval(interval) + , m_shouldForwardUserGesture(shouldForwardUserGesture(interval, m_nestingLevel)) { - if (shouldForwardUserGesture(interval, m_nestingLevel)) - m_userGestureToken = UserGestureIndicator::currentToken(); - - context->addTimeout(m_timeoutId, this); + // Keep asking for the next id until we're given one that we don't already have. + do { + m_timeoutId = context->circularSequentialID(); + } while (!context->addTimeout(m_timeoutId, this)); double intervalMilliseconds = intervalClampedToMinimum(interval, context->minimumTimerInterval()); if (singleShot) @@ -108,8 +108,9 @@ void DOMTimer::fired() ScriptExecutionContext* context = scriptExecutionContext(); timerNestingLevel = m_nestingLevel; ASSERT(!context->activeDOMObjectsAreSuspended()); + UserGestureIndicator gestureIndicator(m_shouldForwardUserGesture ? DefinitelyProcessingUserGesture : PossiblyProcessingUserGesture); // Only the first execution of a multi-shot timer should get an affirmative user gesture indicator. - UserGestureIndicator gestureIndicator(m_userGestureToken.release()); + m_shouldForwardUserGesture = false; InspectorInstrumentationCookie cookie = InspectorInstrumentation::willFireTimer(context, m_timeoutId); @@ -199,12 +200,4 @@ double DOMTimer::alignedFireTime(double fireTime) const return fireTime; } -void DOMTimer::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const -{ - MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::DOM); - SuspendableTimer::reportMemoryUsage(memoryObjectInfo); - info.addMember(m_action); - info.addMember(m_userGestureToken); -} - } // namespace WebCore diff --git a/Source/WebCore/page/DOMTimer.h b/Source/WebCore/page/DOMTimer.h index dddf2a67b..e6291e6c7 100644 --- a/Source/WebCore/page/DOMTimer.h +++ b/Source/WebCore/page/DOMTimer.h @@ -28,7 +28,6 @@ #define DOMTimer_h #include "SuspendableTimer.h" -#include "UserGestureIndicator.h" #include <wtf/OwnPtr.h> #include <wtf/PassOwnPtr.h> @@ -53,8 +52,6 @@ namespace WebCore { // to events like moving a tab to the background. void adjustMinimumTimerInterval(double oldMinimumTimerInterval); - virtual void reportMemoryUsage(MemoryObjectInfo*) const OVERRIDE; - private: DOMTimer(ScriptExecutionContext*, PassOwnPtr<ScheduledAction>, int interval, bool singleShot); virtual void fired(); @@ -68,7 +65,7 @@ namespace WebCore { int m_nestingLevel; OwnPtr<ScheduledAction> m_action; int m_originalInterval; - RefPtr<UserGestureIndicator::Token> m_userGestureToken; + bool m_shouldForwardUserGesture; }; } // namespace WebCore diff --git a/Source/WebCore/page/DOMWindow.cpp b/Source/WebCore/page/DOMWindow.cpp index f557ba6de..5b0664f00 100644 --- a/Source/WebCore/page/DOMWindow.cpp +++ b/Source/WebCore/page/DOMWindow.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2008, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008, 2010, 2013 Apple Inc. All rights reserved. * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) * * Redistribution and use in source and binary forms, with or without @@ -27,11 +27,11 @@ #include "config.h" #include "DOMWindow.h" -#include "AbstractDatabase.h" #include "BackForwardController.h" -#include "BarInfo.h" +#include "BarProp.h" #include "BeforeUnloadEvent.h" #include "CSSComputedStyleDeclaration.h" +#include "CSSRule.h" #include "CSSRuleList.h" #include "Chrome.h" #include "ChromeClient.h" @@ -44,20 +44,23 @@ #include "DOMTimer.h" #include "DOMTokenList.h" #include "DOMURL.h" +#include "DOMWindowCSS.h" #include "DOMWindowExtension.h" #include "DOMWindowNotifications.h" -#include "Database.h" -#include "DatabaseCallback.h" #include "DeviceMotionController.h" #include "DeviceOrientationController.h" #include "Document.h" #include "DocumentLoader.h" +#include "Editor.h" #include "Element.h" #include "EventException.h" +#include "EventHandler.h" #include "EventListener.h" #include "EventNames.h" #include "ExceptionCode.h" +#include "ExceptionCodePlaceholder.h" #include "FloatRect.h" +#include "FocusController.h" #include "Frame.h" #include "FrameLoadRequest.h" #include "FrameLoader.h" @@ -74,6 +77,7 @@ #include "MessageEvent.h" #include "Navigator.h" #include "Page.h" +#include "PageConsole.h" #include "PageGroup.h" #include "PageTransitionEvent.h" #include "Performance.h" @@ -83,7 +87,9 @@ #include "Screen.h" #include "ScriptCallStack.h" #include "ScriptCallStackFactory.h" +#include "ScriptController.h" #include "SecurityOrigin.h" +#include "SecurityPolicy.h" #include "SerializedScriptValue.h" #include "Settings.h" #include "Storage.h" @@ -102,6 +108,10 @@ #include <wtf/text/Base64.h> #include <wtf/text/WTFString.h> +#if ENABLE(PROXIMITY_EVENTS) +#include "DeviceProximityController.h" +#endif + #if ENABLE(REQUEST_ANIMATION_FRAME) #include "RequestAnimationFrameCallback.h" #endif @@ -165,20 +175,16 @@ static DOMWindowSet& windowsWithBeforeUnloadEventListeners() static void addUnloadEventListener(DOMWindow* domWindow) { DOMWindowSet& set = windowsWithUnloadEventListeners(); - if (set.isEmpty()) - disableSuddenTermination(); - set.add(domWindow); + if (set.add(domWindow).isNewEntry) + domWindow->disableSuddenTermination(); } static void removeUnloadEventListener(DOMWindow* domWindow) { DOMWindowSet& set = windowsWithUnloadEventListeners(); DOMWindowSet::iterator it = set.find(domWindow); - if (it == set.end()) - return; - set.remove(it); - if (set.isEmpty()) - enableSuddenTermination(); + if (set.remove(it)) + domWindow->enableSuddenTermination(); } static void removeAllUnloadEventListeners(DOMWindow* domWindow) @@ -188,27 +194,22 @@ static void removeAllUnloadEventListeners(DOMWindow* domWindow) if (it == set.end()) return; set.removeAll(it); - if (set.isEmpty()) - enableSuddenTermination(); + domWindow->enableSuddenTermination(); } static void addBeforeUnloadEventListener(DOMWindow* domWindow) { DOMWindowSet& set = windowsWithBeforeUnloadEventListeners(); - if (set.isEmpty()) - disableSuddenTermination(); - set.add(domWindow); + if (set.add(domWindow).isNewEntry) + domWindow->disableSuddenTermination(); } static void removeBeforeUnloadEventListener(DOMWindow* domWindow) { DOMWindowSet& set = windowsWithBeforeUnloadEventListeners(); DOMWindowSet::iterator it = set.find(domWindow); - if (it == set.end()) - return; - set.remove(it); - if (set.isEmpty()) - enableSuddenTermination(); + if (set.remove(it)) + domWindow->enableSuddenTermination(); } static void removeAllBeforeUnloadEventListeners(DOMWindow* domWindow) @@ -218,8 +219,7 @@ static void removeAllBeforeUnloadEventListeners(DOMWindow* domWindow) if (it == set.end()) return; set.removeAll(it); - if (set.isEmpty()) - enableSuddenTermination(); + domWindow->enableSuddenTermination(); } static bool allowsBeforeUnloadListeners(DOMWindow* window) @@ -262,12 +262,11 @@ bool DOMWindow::dispatchAllPendingBeforeUnloadEvents() if (!frame->loader()->shouldClose()) return false; - } - enableSuddenTermination(); + window->enableSuddenTermination(); + } alreadyDispatched = true; - return true; } @@ -300,9 +299,9 @@ void DOMWindow::dispatchAllPendingUnloadEvents() window->dispatchEvent(PageTransitionEvent::create(eventNames().pagehideEvent, false), window->document()); window->dispatchEvent(Event::create(eventNames().unloadEvent, false, false), window->document()); - } - enableSuddenTermination(); + window->enableSuddenTermination(); + } alreadyDispatched = true; } @@ -318,29 +317,29 @@ FloatRect DOMWindow::adjustWindowRect(Page* page, const FloatRect& pendingChange ASSERT(page); FloatRect screen = screenAvailableRect(page->mainFrame()->view()); - FloatRect window = page->chrome()->windowRect(); + FloatRect window = page->chrome().windowRect(); // Make sure we're in a valid state before adjusting dimensions. - ASSERT(isfinite(screen.x())); - ASSERT(isfinite(screen.y())); - ASSERT(isfinite(screen.width())); - ASSERT(isfinite(screen.height())); - ASSERT(isfinite(window.x())); - ASSERT(isfinite(window.y())); - ASSERT(isfinite(window.width())); - ASSERT(isfinite(window.height())); + ASSERT(std::isfinite(screen.x())); + ASSERT(std::isfinite(screen.y())); + ASSERT(std::isfinite(screen.width())); + ASSERT(std::isfinite(screen.height())); + ASSERT(std::isfinite(window.x())); + ASSERT(std::isfinite(window.y())); + ASSERT(std::isfinite(window.width())); + ASSERT(std::isfinite(window.height())); // Update window values if new requested values are not NaN. - if (!isnan(pendingChanges.x())) + if (!std::isnan(pendingChanges.x())) window.setX(pendingChanges.x()); - if (!isnan(pendingChanges.y())) + if (!std::isnan(pendingChanges.y())) window.setY(pendingChanges.y()); - if (!isnan(pendingChanges.width())) + if (!std::isnan(pendingChanges.width())) window.setWidth(pendingChanges.width()); - if (!isnan(pendingChanges.height())) + if (!std::isnan(pendingChanges.height())) window.setHeight(pendingChanges.height()); - FloatSize minimumSize = page->chrome()->client()->minimumWindowSize(); + FloatSize minimumSize = page->chrome().client()->minimumWindowSize(); // Let size 0 pass through, since that indicates default size, not minimum size. if (window.width()) window.setWidth(min(max(minimumSize.width(), window.width()), screen.width())); @@ -354,12 +353,6 @@ FloatRect DOMWindow::adjustWindowRect(Page* page, const FloatRect& pendingChange return window; } -// FIXME: We can remove this function once V8 showModalDialog is changed to use DOMWindow. -void DOMWindow::parseModalDialogFeatures(const String& string, HashMap<String, String>& map) -{ - WindowFeatures::parseDialogFeatures(string, map); -} - bool DOMWindow::allowPopUp(Frame* firstFrame) { ASSERT(firstFrame); @@ -383,7 +376,7 @@ bool DOMWindow::canShowModalDialog(const Frame* frame) Page* page = frame->page(); if (!page) return false; - return page->chrome()->canRunModal(); + return page->chrome().canRunModal(); } bool DOMWindow::canShowModalDialogNow(const Frame* frame) @@ -393,7 +386,7 @@ bool DOMWindow::canShowModalDialogNow(const Frame* frame) Page* page = frame->page(); if (!page) return false; - return page->chrome()->canRunModalNow(); + return page->chrome().canRunModalNow(); } DOMWindow::DOMWindow(Document* document) @@ -635,57 +628,57 @@ Crypto* DOMWindow::crypto() const return m_crypto.get(); } -BarInfo* DOMWindow::locationbar() const +BarProp* DOMWindow::locationbar() const { if (!isCurrentlyDisplayedInFrame()) return 0; if (!m_locationbar) - m_locationbar = BarInfo::create(m_frame, BarInfo::Locationbar); + m_locationbar = BarProp::create(m_frame, BarProp::Locationbar); return m_locationbar.get(); } -BarInfo* DOMWindow::menubar() const +BarProp* DOMWindow::menubar() const { if (!isCurrentlyDisplayedInFrame()) return 0; if (!m_menubar) - m_menubar = BarInfo::create(m_frame, BarInfo::Menubar); + m_menubar = BarProp::create(m_frame, BarProp::Menubar); return m_menubar.get(); } -BarInfo* DOMWindow::personalbar() const +BarProp* DOMWindow::personalbar() const { if (!isCurrentlyDisplayedInFrame()) return 0; if (!m_personalbar) - m_personalbar = BarInfo::create(m_frame, BarInfo::Personalbar); + m_personalbar = BarProp::create(m_frame, BarProp::Personalbar); return m_personalbar.get(); } -BarInfo* DOMWindow::scrollbars() const +BarProp* DOMWindow::scrollbars() const { if (!isCurrentlyDisplayedInFrame()) return 0; if (!m_scrollbars) - m_scrollbars = BarInfo::create(m_frame, BarInfo::Scrollbars); + m_scrollbars = BarProp::create(m_frame, BarProp::Scrollbars); return m_scrollbars.get(); } -BarInfo* DOMWindow::statusbar() const +BarProp* DOMWindow::statusbar() const { if (!isCurrentlyDisplayedInFrame()) return 0; if (!m_statusbar) - m_statusbar = BarInfo::create(m_frame, BarInfo::Statusbar); + m_statusbar = BarProp::create(m_frame, BarProp::Statusbar); return m_statusbar.get(); } -BarInfo* DOMWindow::toolbar() const +BarProp* DOMWindow::toolbar() const { if (!isCurrentlyDisplayedInFrame()) return 0; if (!m_toolbar) - m_toolbar = BarInfo::create(m_frame, BarInfo::Toolbar); + m_toolbar = BarProp::create(m_frame, BarProp::Toolbar); return m_toolbar.get(); } @@ -698,6 +691,13 @@ Console* DOMWindow::console() const return m_console.get(); } +PageConsole* DOMWindow::pageConsole() const +{ + if (!isCurrentlyDisplayedInFrame()) + return 0; + return m_frame->page() ? m_frame->page()->console() : 0; +} + DOMApplicationCache* DOMWindow::applicationCache() const { if (!isCurrentlyDisplayedInFrame()) @@ -745,13 +745,13 @@ Storage* DOMWindow::sessionStorage(ExceptionCode& ec) const if (!document) return 0; - if (!document->securityOrigin()->canAccessLocalStorage(document->topDocument()->securityOrigin())) { + if (!document->securityOrigin()->canAccessSessionStorage(document->topOrigin())) { ec = SECURITY_ERR; return 0; } if (m_sessionStorage) { - if (!m_sessionStorage->area()->canAccessStorage(m_frame)) { + if (!m_sessionStorage->area().canAccessStorage(m_frame)) { ec = SECURITY_ERR; return 0; } @@ -767,7 +767,6 @@ Storage* DOMWindow::sessionStorage(ExceptionCode& ec) const ec = SECURITY_ERR; return 0; } - InspectorInstrumentation::didUseDOMStorage(page, storageArea.get(), false, m_frame); m_sessionStorage = Storage::create(m_frame, storageArea.release()); return m_sessionStorage.get(); @@ -782,13 +781,13 @@ Storage* DOMWindow::localStorage(ExceptionCode& ec) const if (!document) return 0; - if (!document->securityOrigin()->canAccessLocalStorage(document->topDocument()->securityOrigin())) { + if (!document->securityOrigin()->canAccessLocalStorage(0)) { ec = SECURITY_ERR; return 0; } if (m_localStorage) { - if (!m_localStorage->area()->canAccessStorage(m_frame)) { + if (!m_localStorage->area().canAccessStorage(m_frame)) { ec = SECURITY_ERR; return 0; } @@ -802,12 +801,16 @@ Storage* DOMWindow::localStorage(ExceptionCode& ec) const if (!page->settings()->localStorageEnabled()) return 0; - RefPtr<StorageArea> storageArea = page->group().localStorage()->storageArea(document->securityOrigin()); + RefPtr<StorageArea> storageArea; + if (!document->securityOrigin()->canAccessLocalStorage(document->topOrigin())) + storageArea = page->group().transientLocalStorage(document->topOrigin())->storageArea(document->securityOrigin()); + else + storageArea = page->group().localStorage()->storageArea(document->securityOrigin()); + if (!storageArea->canAccessStorage(m_frame)) { ec = SECURITY_ERR; return 0; } - InspectorInstrumentation::didUseDOMStorage(page, storageArea.get(), true, m_frame); m_localStorage = Storage::create(m_frame, storageArea.release()); return m_localStorage.get(); @@ -890,7 +893,7 @@ void DOMWindow::dispatchMessageEventWithOriginCheck(SecurityOrigin* intendedTarg if (!intendedTargetOrigin->isSameSchemeHostPort(document()->securityOrigin())) { String message = "Unable to post message to " + intendedTargetOrigin->toString() + ". Recipient has origin " + document()->securityOrigin()->toString() + ".\n"; - console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, message, stackTrace); + pageConsole()->addMessage(SecurityMessageSource, ErrorMessageLevel, message, stackTrace); return; } } @@ -926,18 +929,23 @@ void DOMWindow::focus(ScriptExecutionContext* context) bool allowFocus = WindowFocusAllowedIndicator::windowFocusAllowed() || !m_frame->settings()->windowFocusRestricted(); if (context) { ASSERT(isMainThread()); - Document* activeDocument = static_cast<Document*>(context); - if (opener() && activeDocument->domWindow() == opener()) + Document* activeDocument = toDocument(context); + if (opener() && opener() != this && activeDocument->domWindow() == opener()) allowFocus = true; } // If we're a top level window, bring the window to the front. if (m_frame == page->mainFrame() && allowFocus) - page->chrome()->focus(); + page->chrome().focus(); if (!m_frame) return; + // Clear the current frame's focused node if a new frame is about to be focused. + Frame* focusedFrame = page->focusController()->focusedFrame(); + if (focusedFrame && focusedFrame != m_frame) + focusedFrame->document()->setFocusedElement(0); + m_frame->eventHandler()->focusDocumentView(); } @@ -957,7 +965,7 @@ void DOMWindow::blur() if (m_frame != page->mainFrame()) return; - page->chrome()->unfocus(); + page->chrome().unfocus(); } void DOMWindow::close(ScriptExecutionContext* context) @@ -974,7 +982,7 @@ void DOMWindow::close(ScriptExecutionContext* context) if (context) { ASSERT(isMainThread()); - Document* activeDocument = static_cast<Document*>(context); + Document* activeDocument = toDocument(context); if (!activeDocument) return; @@ -991,7 +999,7 @@ void DOMWindow::close(ScriptExecutionContext* context) if (!m_frame->loader()->shouldClose()) return; - page->chrome()->closeWindowSoon(); + page->chrome().closeWindowSoon(); } void DOMWindow::print() @@ -1003,12 +1011,18 @@ void DOMWindow::print() if (!page) return; + // Pages are not allowed to bring up a modal print dialog during BeforeUnload dispatch. + if (page->isAnyFrameHandlingBeforeUnloadEvent()) { + printErrorMessage("Use of window.print is not allowed during beforeunload event dispatch."); + return; + } + if (m_frame->loader()->activeDocumentLoader()->isLoading()) { m_shouldPrintWhenFinishedLoading = true; return; } m_shouldPrintWhenFinishedLoading = false; - page->chrome()->print(m_frame); + page->chrome().print(m_frame); } void DOMWindow::stop() @@ -1026,19 +1040,31 @@ void DOMWindow::alert(const String& message) if (!m_frame) return; + // Pages are not allowed to cause modal alerts during BeforeUnload dispatch. + if (page() && page()->isAnyFrameHandlingBeforeUnloadEvent()) { + printErrorMessage("Use of window.alert is not allowed during beforeunload event dispatch."); + return; + } + m_frame->document()->updateStyleIfNeeded(); Page* page = m_frame->page(); if (!page) return; - page->chrome()->runJavaScriptAlert(m_frame, message); + page->chrome().runJavaScriptAlert(m_frame, message); } bool DOMWindow::confirm(const String& message) { if (!m_frame) return false; + + // Pages are not allowed to cause modal alerts during BeforeUnload dispatch. + if (page() && page()->isAnyFrameHandlingBeforeUnloadEvent()) { + printErrorMessage("Use of window.confirm is not allowed during beforeunload event dispatch."); + return false; + } m_frame->document()->updateStyleIfNeeded(); @@ -1046,7 +1072,7 @@ bool DOMWindow::confirm(const String& message) if (!page) return false; - return page->chrome()->runJavaScriptConfirm(m_frame, message); + return page->chrome().runJavaScriptConfirm(m_frame, message); } String DOMWindow::prompt(const String& message, const String& defaultValue) @@ -1054,6 +1080,12 @@ String DOMWindow::prompt(const String& message, const String& defaultValue) if (!m_frame) return String(); + // Pages are not allowed to cause modal alerts during BeforeUnload dispatch. + if (page() && page()->isAnyFrameHandlingBeforeUnloadEvent()) { + printErrorMessage("Use of window.prompt is not allowed during beforeunload event dispatch."); + return String(); + } + m_frame->document()->updateStyleIfNeeded(); Page* page = m_frame->page(); @@ -1061,7 +1093,7 @@ String DOMWindow::prompt(const String& message, const String& defaultValue) return String(); String returnValue; - if (page->chrome()->runJavaScriptPrompt(m_frame, message, defaultValue, returnValue)) + if (page->chrome().runJavaScriptPrompt(m_frame, message, defaultValue, returnValue)) return returnValue; return String(); @@ -1105,7 +1137,7 @@ bool DOMWindow::find(const String& string, bool caseSensitive, bool backwards, b return false; // FIXME (13016): Support wholeWord, searchInFrames and showDialog - return m_frame->editor()->findString(string, !backwards, caseSensitive, wrap, false); + return m_frame->editor().findString(string, !backwards, caseSensitive, wrap, false); } bool DOMWindow::offscreenBuffering() const @@ -1122,7 +1154,7 @@ int DOMWindow::outerHeight() const if (!page) return 0; - return static_cast<int>(page->chrome()->windowRect().height()); + return static_cast<int>(page->chrome().windowRect().height()); } int DOMWindow::outerWidth() const @@ -1134,7 +1166,7 @@ int DOMWindow::outerWidth() const if (!page) return 0; - return static_cast<int>(page->chrome()->windowRect().width()); + return static_cast<int>(page->chrome().windowRect().width()); } int DOMWindow::innerHeight() const @@ -1148,7 +1180,7 @@ int DOMWindow::innerHeight() const // If the device height is overridden, do not include the horizontal scrollbar into the innerHeight (since it is absent on the real device). bool includeScrollbars = !InspectorInstrumentation::shouldApplyScreenHeightOverride(m_frame); - return view->mapFromLayoutToCSSUnits(static_cast<int>(view->visibleContentRect(includeScrollbars).height())); + return view->mapFromLayoutToCSSUnits(static_cast<int>(view->visibleContentRect(includeScrollbars ? ScrollableArea::IncludeScrollbars : ScrollableArea::ExcludeScrollbars).height())); } int DOMWindow::innerWidth() const @@ -1162,7 +1194,7 @@ int DOMWindow::innerWidth() const // If the device width is overridden, do not include the vertical scrollbar into the innerWidth (since it is absent on the real device). bool includeScrollbars = !InspectorInstrumentation::shouldApplyScreenWidthOverride(m_frame); - return view->mapFromLayoutToCSSUnits(static_cast<int>(view->visibleContentRect(includeScrollbars).width())); + return view->mapFromLayoutToCSSUnits(static_cast<int>(view->visibleContentRect(includeScrollbars ? ScrollableArea::IncludeScrollbars : ScrollableArea::ExcludeScrollbars).width())); } int DOMWindow::screenX() const @@ -1174,7 +1206,7 @@ int DOMWindow::screenX() const if (!page) return 0; - return static_cast<int>(page->chrome()->windowRect().x()); + return static_cast<int>(page->chrome().windowRect().x()); } int DOMWindow::screenY() const @@ -1186,7 +1218,7 @@ int DOMWindow::screenY() const if (!page) return 0; - return static_cast<int>(page->chrome()->windowRect().y()); + return static_cast<int>(page->chrome().windowRect().y()); } int DOMWindow::scrollX() const @@ -1244,6 +1276,7 @@ void DOMWindow::setName(const String& string) return; m_frame->tree()->setName(string); + m_frame->loader()->client()->didChangeName(string); } void DOMWindow::setStatus(const String& string) @@ -1258,7 +1291,7 @@ void DOMWindow::setStatus(const String& string) return; ASSERT(m_frame->document()); // Client calls shouldn't be made when the frame is in inconsistent state. - page->chrome()->setStatusbarText(m_frame, m_status); + page->chrome().setStatusbarText(m_frame, m_status); } void DOMWindow::setDefaultStatus(const String& string) @@ -1273,7 +1306,7 @@ void DOMWindow::setDefaultStatus(const String& string) return; ASSERT(m_frame->document()); // Client calls shouldn't be made when the frame is in inconsistent state. - page->chrome()->setStatusbarText(m_frame, m_defaultStatus); + page->chrome().setStatusbarText(m_frame, m_defaultStatus); } DOMWindow* DOMWindow::self() const @@ -1323,8 +1356,7 @@ DOMWindow* DOMWindow::top() const Document* DOMWindow::document() const { ScriptExecutionContext* context = ContextDestructionObserver::scriptExecutionContext(); - ASSERT(!context || context->isDocument()); - return static_cast<Document*>(context); + return toDocument(context); } PassRefPtr<StyleMedia> DOMWindow::styleMedia() const @@ -1364,7 +1396,15 @@ PassRefPtr<CSSRuleList> DOMWindow::getMatchedCSSRules(Element* element, const St PseudoId pseudoId = CSSSelector::pseudoId(pseudoType); - return m_frame->document()->styleResolver()->pseudoStyleRulesForElement(element, pseudoId, rulesToInclude); + Vector<RefPtr<StyleRuleBase> > matchedRules = m_frame->document()->ensureStyleResolver()->pseudoStyleRulesForElement(element, pseudoId, rulesToInclude); + if (matchedRules.isEmpty()) + return 0; + + RefPtr<StaticCSSRuleList> ruleList = StaticCSSRuleList::create(); + for (unsigned i = 0; i < matchedRules.size(); ++i) + ruleList->rules().append(matchedRules[i]->createCSSOMWrapper()); + + return ruleList.release(); } PassRefPtr<WebKitPoint> DOMWindow::webkitConvertPointFromNodeToPage(Node* node, const WebKitPoint* p) const @@ -1439,80 +1479,71 @@ void DOMWindow::scrollTo(int x, int y) const view->setScrollPosition(layoutPos); } -void DOMWindow::moveBy(float x, float y) const +bool DOMWindow::allowedToChangeWindowGeometry() const { if (!m_frame) - return; - - Page* page = m_frame->page(); + return false; + const Page* page = m_frame->page(); if (!page) - return; - + return false; if (m_frame != page->mainFrame()) + return false; + // Prevent web content from tricking the user into initiating a drag. + if (m_frame->eventHandler()->mousePressed()) + return false; + return true; +} + +void DOMWindow::moveBy(float x, float y) const +{ + if (!allowedToChangeWindowGeometry()) return; - FloatRect fr = page->chrome()->windowRect(); + Page* page = m_frame->page(); + FloatRect fr = page->chrome().windowRect(); FloatRect update = fr; update.move(x, y); // Security check (the spec talks about UniversalBrowserWrite to disable this check...) - page->chrome()->setWindowRect(adjustWindowRect(page, update)); + page->chrome().setWindowRect(adjustWindowRect(page, update)); } void DOMWindow::moveTo(float x, float y) const { - if (!m_frame) + if (!allowedToChangeWindowGeometry()) return; Page* page = m_frame->page(); - if (!page) - return; - - if (m_frame != page->mainFrame()) - return; - - FloatRect fr = page->chrome()->windowRect(); + FloatRect fr = page->chrome().windowRect(); FloatRect sr = screenAvailableRect(page->mainFrame()->view()); fr.setLocation(sr.location()); FloatRect update = fr; update.move(x, y); // Security check (the spec talks about UniversalBrowserWrite to disable this check...) - page->chrome()->setWindowRect(adjustWindowRect(page, update)); + page->chrome().setWindowRect(adjustWindowRect(page, update)); } void DOMWindow::resizeBy(float x, float y) const { - if (!m_frame) + if (!allowedToChangeWindowGeometry()) return; Page* page = m_frame->page(); - if (!page) - return; - - if (m_frame != page->mainFrame()) - return; - - FloatRect fr = page->chrome()->windowRect(); + FloatRect fr = page->chrome().windowRect(); FloatSize dest = fr.size() + FloatSize(x, y); FloatRect update(fr.location(), dest); - page->chrome()->setWindowRect(adjustWindowRect(page, update)); + page->chrome().setWindowRect(adjustWindowRect(page, update)); } void DOMWindow::resizeTo(float width, float height) const { - if (!m_frame) + if (!allowedToChangeWindowGeometry()) return; Page* page = m_frame->page(); - if (!page) - return; - - if (m_frame != page->mainFrame()) - return; - - FloatRect fr = page->chrome()->windowRect(); + FloatRect fr = page->chrome().windowRect(); FloatSize dest = FloatSize(width, height); FloatRect update(fr.location(), dest); - page->chrome()->setWindowRect(adjustWindowRect(page, update)); + page->chrome().setWindowRect(adjustWindowRect(page, update)); } int DOMWindow::setTimeout(PassOwnPtr<ScheduledAction> action, int timeout, ExceptionCode& ec) @@ -1575,15 +1606,23 @@ void DOMWindow::cancelAnimationFrame(int id) } #endif +#if ENABLE(CSS3_CONDITIONAL_RULES) +DOMWindowCSS* DOMWindow::css() +{ + if (!m_css) + m_css = DOMWindowCSS::create(); + return m_css.get(); +} +#endif + static void didAddStorageEventListener(DOMWindow* window) { // Creating these WebCore::Storage objects informs the system that we'd like to receive // notifications about storage events that might be triggered in other processes. Rather // than subscribe to these notifications explicitly, we subscribe to them implicitly to // simplify the work done by the system. - ExceptionCode unused; - window->localStorage(unused); - window->sessionStorage(unused); + window->localStorage(IGNORE_EXCEPTION); + window->sessionStorage(IGNORE_EXCEPTION); } bool DOMWindow::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture) @@ -1596,7 +1635,7 @@ bool DOMWindow::addEventListener(const AtomicString& eventType, PassRefPtr<Event if (eventType == eventNames().mousewheelEvent) document->didAddWheelEventHandler(); else if (eventNames().isTouchEventType(eventType)) - document->didAddTouchEventHandler(); + document->didAddTouchEventHandler(document); else if (eventType == eventNames().storageEvent) didAddStorageEventListener(this); } @@ -1615,6 +1654,13 @@ bool DOMWindow::addEventListener(const AtomicString& eventType, PassRefPtr<Event } #endif +#if ENABLE(PROXIMITY_EVENTS) + else if (eventType == eventNames().webkitdeviceproximityEvent) { + if (DeviceProximityController* controller = DeviceProximityController::from(page())) + controller->addDeviceEventListener(this); + } +#endif + return true; } @@ -1627,7 +1673,7 @@ bool DOMWindow::removeEventListener(const AtomicString& eventType, EventListener if (eventType == eventNames().mousewheelEvent) document->didRemoveWheelEventHandler(); else if (eventNames().isTouchEventType(eventType)) - document->didRemoveTouchEventHandler(); + document->didRemoveTouchEventHandler(document); } if (eventType == eventNames().unloadEvent) @@ -1644,6 +1690,13 @@ bool DOMWindow::removeEventListener(const AtomicString& eventType, EventListener } #endif +#if ENABLE(PROXIMITY_EVENTS) + else if (eventType == eventNames().webkitdeviceproximityEvent) { + if (DeviceProximityController* controller = DeviceProximityController::from(page())) + controller->removeDeviceEventListener(this); + } +#endif + return true; } @@ -1699,6 +1752,15 @@ void DOMWindow::removeAllEventListeners() if (DeviceOrientationController* controller = DeviceOrientationController::from(page())) controller->removeAllDeviceEventListeners(this); #endif +#if ENABLE(TOUCH_EVENTS) + if (Document* document = this->document()) + document->didRemoveEventTargetNode(document); +#endif + +#if ENABLE(PROXIMITY_EVENTS) + if (DeviceProximityController* controller = DeviceProximityController::from(page())) + controller->removeAllDeviceEventListeners(this); +#endif removeAllUnloadEventListeners(this); removeAllBeforeUnloadEventListeners(this); @@ -1768,15 +1830,7 @@ void DOMWindow::printErrorMessage(const String& message) if (message.isEmpty()) return; - Settings* settings = m_frame->settings(); - if (!settings) - return; - if (settings->privateBrowsingEnabled()) - return; - - // FIXME: Add arguments so that we can provide a correct source URL and line number. - RefPtr<ScriptCallStack> stackTrace = createScriptCallStack(ScriptCallStack::maxCallStackSizeToCapture, true); - console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, message, stackTrace.release()); + pageConsole()->addMessage(JSMessageSource, ErrorMessageLevel, message); } String DOMWindow::crossDomainAccessErrorMessage(DOMWindow* activeWindow) @@ -1788,32 +1842,36 @@ String DOMWindow::crossDomainAccessErrorMessage(DOMWindow* activeWindow) ASSERT(!activeWindow->document()->securityOrigin()->canAccess(document()->securityOrigin())); // FIXME: This message, and other console messages, have extra newlines. Should remove them. - String message = "Unsafe JavaScript attempt to access frame with URL " + document()->url().string() + " from frame with URL " + activeWindowURL.string() + "."; + SecurityOrigin* activeOrigin = activeWindow->document()->securityOrigin(); + SecurityOrigin* targetOrigin = document()->securityOrigin(); + String message = "Blocked a frame with origin \"" + activeOrigin->toString() + "\" from accessing a frame with origin \"" + targetOrigin->toString() + "\". "; - // Sandbox errors. + // Sandbox errors: Use the origin of the frames' location, rather than their actual origin (since we know that at least one will be "null"). + KURL activeURL = activeWindow->document()->url(); + KURL targetURL = document()->url(); if (document()->isSandboxed(SandboxOrigin) || activeWindow->document()->isSandboxed(SandboxOrigin)) { + message = "Blocked a frame at \"" + SecurityOrigin::create(activeURL)->toString() + "\" from accessing a frame at \"" + SecurityOrigin::create(targetURL)->toString() + "\". "; if (document()->isSandboxed(SandboxOrigin) && activeWindow->document()->isSandboxed(SandboxOrigin)) - return "Sandbox access violation: " + message + " Both frames are sandboxed into unique origins.\n"; + return "Sandbox access violation: " + message + " Both frames are sandboxed and lack the \"allow-same-origin\" flag."; if (document()->isSandboxed(SandboxOrigin)) - return "Sandbox access violation: " + message + " The frame being accessed is sandboxed into a unique origin.\n"; - return "Sandbox access violation: " + message + " The frame requesting access is sandboxed into a unique origin.\n"; + return "Sandbox access violation: " + message + " The frame being accessed is sandboxed and lacks the \"allow-same-origin\" flag."; + return "Sandbox access violation: " + message + " The frame requesting access is sandboxed and lacks the \"allow-same-origin\" flag."; } - SecurityOrigin* activeOrigin = activeWindow->document()->securityOrigin(); - SecurityOrigin* targetOrigin = document()->securityOrigin(); + // Protocol errors: Use the URL's protocol rather than the origin's protocol so that we get a useful message for non-heirarchal URLs like 'data:'. if (targetOrigin->protocol() != activeOrigin->protocol()) - return message + " The frame requesting access has a protocol of '" + activeOrigin->protocol() + "', the frame being accessed has a protocol of '" + targetOrigin->protocol() + "'. Protocols must match.\n"; + return message + " The frame requesting access has a protocol of \"" + activeURL.protocol() + "\", the frame being accessed has a protocol of \"" + targetURL.protocol() + "\". Protocols must match.\n"; // 'document.domain' errors. if (targetOrigin->domainWasSetInDOM() && activeOrigin->domainWasSetInDOM()) - return message + " The frame requesting access set 'document.domain' to '" + activeOrigin->domain() + "', the frame being accessed set it to '" + targetOrigin->domain() + "'. Both must set 'document.domain' to the same value to allow access.\n"; + return message + "The frame requesting access set \"document.domain\" to \"" + activeOrigin->domain() + "\", the frame being accessed set it to \"" + targetOrigin->domain() + "\". Both must set \"document.domain\" to the same value to allow access."; if (activeOrigin->domainWasSetInDOM()) - return message + " The frame requesting access set 'document.domain' to '" + activeOrigin->domain() + "', but the frame being accessed did not. Both must set 'document.domain' to the same value to allow access.\n"; + return message + "The frame requesting access set \"document.domain\" to \"" + activeOrigin->domain() + "\", but the frame being accessed did not. Both must set \"document.domain\" to the same value to allow access."; if (targetOrigin->domainWasSetInDOM()) - return message + " The frame being accessed set 'document.domain' to '" + targetOrigin->domain() + "', but the frame requesting access did not. Both must set 'document.domain' to the same value to allow access.\n"; + return message + "The frame being accessed set \"document.domain\" to \"" + targetOrigin->domain() + "\", but the frame requesting access did not. Both must set \"document.domain\" to the same value to allow access."; // Default. - return message + " Domains, protocols and ports must match.\n"; + return message + "Protocols, domains, and ports must match."; } bool DOMWindow::isInsecureScriptAccess(DOMWindow* activeWindow, const String& urlString) @@ -1840,14 +1898,11 @@ bool DOMWindow::isInsecureScriptAccess(DOMWindow* activeWindow, const String& ur return true; } -Frame* DOMWindow::createWindow(const String& urlString, const AtomicString& frameName, const WindowFeatures& windowFeatures, +PassRefPtr<Frame> DOMWindow::createWindow(const String& urlString, const AtomicString& frameName, const WindowFeatures& windowFeatures, DOMWindow* activeWindow, Frame* firstFrame, Frame* openerFrame, PrepareDialogFunction function, void* functionContext) { Frame* activeFrame = activeWindow->frame(); - // For whatever reason, Firefox uses the first frame to determine the outgoingReferrer. We replicate that behavior here. - String referrer = firstFrame->loader()->outgoingReferrer(); - KURL completedURL = urlString.isEmpty() ? KURL(ParsedURLString, emptyString()) : firstFrame->document()->completeURL(urlString); if (!completedURL.isEmpty() && !completedURL.isValid()) { // Don't expose client code to invalid URLs. @@ -1855,6 +1910,9 @@ Frame* DOMWindow::createWindow(const String& urlString, const AtomicString& fram return 0; } + // For whatever reason, Firefox uses the first frame to determine the outgoingReferrer. We replicate that behavior here. + String referrer = SecurityPolicy::generateReferrerHeader(firstFrame->document()->referrerPolicy(), completedURL, firstFrame->loader()->outgoingReferrer()); + ResourceRequest request(completedURL, referrer); FrameLoader::addHTTPOriginIfNeeded(request, firstFrame->loader()->outgoingOrigin()); FrameLoadRequest frameRequest(activeWindow->document()->securityOrigin(), request, frameName); @@ -1862,7 +1920,7 @@ Frame* DOMWindow::createWindow(const String& urlString, const AtomicString& fram // We pass the opener frame for the lookupFrame in case the active frame is different from // the opener frame, and the name references a frame relative to the opener frame. bool created; - Frame* newFrame = WebCore::createWindow(activeFrame, openerFrame, frameRequest, windowFeatures, created); + RefPtr<Frame> newFrame = WebCore::createWindow(activeFrame, openerFrame, frameRequest, windowFeatures, created); if (!newFrame) return 0; @@ -1870,7 +1928,7 @@ Frame* DOMWindow::createWindow(const String& urlString, const AtomicString& fram newFrame->page()->setOpenedByDOM(); if (newFrame->document()->domWindow()->isInsecureScriptAccess(activeWindow, completedURL)) - return newFrame; + return newFrame.release(); if (function) function(newFrame->document()->domWindow(), functionContext); @@ -1882,7 +1940,11 @@ Frame* DOMWindow::createWindow(const String& urlString, const AtomicString& fram newFrame->navigationScheduler()->scheduleLocationChange(activeWindow->document()->securityOrigin(), completedURL.string(), referrer, lockHistory, false); } - return newFrame; + // Navigating the new frame could result in it being detached from its page by a navigation policy delegate. + if (!newFrame->page()) + return 0; + + return newFrame.release(); } PassRefPtr<DOMWindow> DOMWindow::open(const String& urlString, const AtomicString& frameName, const String& windowFeaturesString, @@ -1940,7 +2002,7 @@ PassRefPtr<DOMWindow> DOMWindow::open(const String& urlString, const AtomicStrin } WindowFeatures windowFeatures(windowFeaturesString); - Frame* result = createWindow(urlString, frameName, windowFeatures, activeWindow, firstFrame, m_frame); + RefPtr<Frame> result = createWindow(urlString, frameName, windowFeatures, activeWindow, firstFrame, m_frame); return result ? result->document()->domWindow() : 0; } @@ -1956,16 +2018,33 @@ void DOMWindow::showModalDialog(const String& urlString, const String& dialogFea if (!firstFrame) return; + // Pages are not allowed to cause modal alerts during BeforeUnload dispatch. + if (page() && page()->isAnyFrameHandlingBeforeUnloadEvent()) { + printErrorMessage("Use of window.showModalDialog is not allowed during beforeunload event dispatch."); + return; + } + if (!canShowModalDialogNow(m_frame) || !firstWindow->allowPopUp()) return; WindowFeatures windowFeatures(dialogFeaturesString, screenAvailableRect(m_frame->view())); - Frame* dialogFrame = createWindow(urlString, emptyAtom, windowFeatures, + RefPtr<Frame> dialogFrame = createWindow(urlString, emptyAtom, windowFeatures, activeWindow, firstFrame, m_frame, function, functionContext); if (!dialogFrame) return; + dialogFrame->page()->chrome().runModal(); +} - dialogFrame->page()->chrome()->runModal(); +void DOMWindow::enableSuddenTermination() +{ + if (Page* page = this->page()) + page->chrome().enableSuddenTermination(); +} + +void DOMWindow::disableSuddenTermination() +{ + if (Page* page = this->page()) + page->chrome().disableSuddenTermination(); } } // namespace WebCore diff --git a/Source/WebCore/page/DOMWindow.h b/Source/WebCore/page/DOMWindow.h index 79029d08b..38f07828f 100644 --- a/Source/WebCore/page/DOMWindow.h +++ b/Source/WebCore/page/DOMWindow.h @@ -35,7 +35,7 @@ namespace WebCore { - class BarInfo; + class BarProp; class CSSRuleList; class CSSStyleDeclaration; class Console; @@ -59,6 +59,7 @@ namespace WebCore { class Navigator; class Node; class Page; + class PageConsole; class Performance; class PostMessageTimer; class ScheduledAction; @@ -69,6 +70,7 @@ namespace WebCore { class Storage; class StyleMedia; class WebKitPoint; + class DOMWindowCSS; #if ENABLE(REQUEST_ANIMATION_FRAME) class RequestAnimationFrameCallback; @@ -122,9 +124,6 @@ namespace WebCore { static FloatRect adjustWindowRect(Page*, const FloatRect& pendingChanges); - // FIXME: We can remove this function once V8 showModalDialog is changed to use DOMWindow. - static void parseModalDialogFeatures(const String&, HashMap<String, String>&); - bool allowPopUp(); // Call on first window, not target window. static bool allowPopUp(Frame* firstFrame); static bool canShowModalDialog(const Frame*); @@ -135,12 +134,12 @@ namespace WebCore { Screen* screen() const; History* history() const; Crypto* crypto() const; - BarInfo* locationbar() const; - BarInfo* menubar() const; - BarInfo* personalbar() const; - BarInfo* scrollbars() const; - BarInfo* statusbar() const; - BarInfo* toolbar() const; + BarProp* locationbar() const; + BarProp* menubar() const; + BarProp* personalbar() const; + BarProp* scrollbars() const; + BarProp* statusbar() const; + BarProp* toolbar() const; Navigator* navigator() const; Navigator* clientInformation() const { return navigator(); } @@ -235,12 +234,13 @@ namespace WebCore { PassRefPtr<WebKitPoint> webkitConvertPointFromNodeToPage(Node*, const WebKitPoint*) const; Console* console() const; + PageConsole* pageConsole() const; void printErrorMessage(const String&); String crossDomainAccessErrorMessage(DOMWindow* activeWindow); void postMessage(PassRefPtr<SerializedScriptValue> message, const MessagePortArray*, const String& targetOrigin, DOMWindow* source, ExceptionCode&); - // FIXME: remove this when we update the ObjC bindings (bug #28774). + // Needed for Objective-C bindings (see bug 28774). void postMessage(PassRefPtr<SerializedScriptValue> message, MessagePort*, const String& targetOrigin, DOMWindow* source, ExceptionCode&); void postMessageTimerFired(PassOwnPtr<PostMessageTimer>); void dispatchMessageEventWithOriginCheck(SecurityOrigin* intendedTargetOrigin, PassRefPtr<Event>, PassRefPtr<ScriptCallStack>); @@ -268,6 +268,10 @@ namespace WebCore { void cancelAnimationFrame(int id); #endif +#if ENABLE(CSS3_CONDITIONAL_RULES) + DOMWindowCSS* css(); +#endif + // Events // EventTarget API virtual bool addEventListener(const AtomicString& eventType, PassRefPtr<EventListener>, bool useCapture); @@ -276,6 +280,7 @@ namespace WebCore { using EventTarget::dispatchEvent; bool dispatchEvent(PassRefPtr<Event> prpEvent, PassRefPtr<EventTarget> prpTarget); + void dispatchLoadEvent(); DEFINE_ATTRIBUTE_EVENT_LISTENER(abort); @@ -311,6 +316,8 @@ namespace WebCore { DEFINE_ATTRIBUTE_EVENT_LISTENER(loadstart); DEFINE_ATTRIBUTE_EVENT_LISTENER(message); DEFINE_ATTRIBUTE_EVENT_LISTENER(mousedown); + DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseenter); + DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseleave); DEFINE_ATTRIBUTE_EVENT_LISTENER(mousemove); DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseout); DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseover); @@ -348,6 +355,7 @@ namespace WebCore { DEFINE_MAPPED_ATTRIBUTE_EVENT_LISTENER(webkitanimationiteration, webkitAnimationIteration); DEFINE_MAPPED_ATTRIBUTE_EVENT_LISTENER(webkitanimationend, webkitAnimationEnd); DEFINE_MAPPED_ATTRIBUTE_EVENT_LISTENER(webkittransitionend, webkitTransitionEnd); + DEFINE_MAPPED_ATTRIBUTE_EVENT_LISTENER(transitionend, transitionend); void captureEvents(); void releaseEvents(); @@ -404,10 +412,14 @@ namespace WebCore { void willDetachDocumentFromFrame(); void willDestroyCachedFrame(); + void enableSuddenTermination(); + void disableSuddenTermination(); + private: explicit DOMWindow(Document*); Page* page(); + bool allowedToChangeWindowGeometry() const; virtual void frameDestroyed() OVERRIDE; virtual void willDetachPage() OVERRIDE; @@ -417,7 +429,7 @@ namespace WebCore { virtual EventTargetData* eventTargetData(); virtual EventTargetData* ensureEventTargetData(); - static Frame* createWindow(const String& urlString, const AtomicString& frameName, const WindowFeatures&, + static PassRefPtr<Frame> createWindow(const String& urlString, const AtomicString& frameName, const WindowFeatures&, DOMWindow* activeWindow, Frame* firstFrame, Frame* openerFrame, PrepareDialogFunction = 0, void* functionContext = 0); bool isInsecureScriptAccess(DOMWindow* activeWindow, const String& urlString); @@ -435,12 +447,12 @@ namespace WebCore { mutable RefPtr<Screen> m_screen; mutable RefPtr<History> m_history; mutable RefPtr<Crypto> m_crypto; - mutable RefPtr<BarInfo> m_locationbar; - mutable RefPtr<BarInfo> m_menubar; - mutable RefPtr<BarInfo> m_personalbar; - mutable RefPtr<BarInfo> m_scrollbars; - mutable RefPtr<BarInfo> m_statusbar; - mutable RefPtr<BarInfo> m_toolbar; + mutable RefPtr<BarProp> m_locationbar; + mutable RefPtr<BarProp> m_menubar; + mutable RefPtr<BarProp> m_personalbar; + mutable RefPtr<BarProp> m_scrollbars; + mutable RefPtr<BarProp> m_statusbar; + mutable RefPtr<BarProp> m_toolbar; mutable RefPtr<Console> m_console; mutable RefPtr<Navigator> m_navigator; mutable RefPtr<Location> m_location; @@ -458,6 +470,10 @@ namespace WebCore { #if ENABLE(WEB_TIMING) mutable RefPtr<Performance> m_performance; #endif + +#if ENABLE(CSS3_CONDITIONAL_RULES) + mutable RefPtr<DOMWindowCSS> m_css; +#endif }; inline String DOMWindow::status() const diff --git a/Source/WebCore/page/DOMWindow.idl b/Source/WebCore/page/DOMWindow.idl index 5fe8c177a..c64482ab9 100644 --- a/Source/WebCore/page/DOMWindow.idl +++ b/Source/WebCore/page/DOMWindow.idl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008, 2009, 2013 Apple Inc. All rights reserved. * Copyright (C) 2011 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,34 +34,31 @@ JSCustomToNativeObject, CustomPutFunction, EventTarget, - ExtendsDOMGlobalObject, JSGenerateToNativeObject, ReplaceableConstructor, JSLegacyParent=JSDOMWindowBase, - V8CustomToJSObject, - V8NoWrapperCache, InterfaceName=Window ] interface DOMWindow { // DOM Level 0 [Replaceable] readonly attribute Screen screen; [Replaceable, DoNotCheckSecurityOnGetter] readonly attribute History history; - [Replaceable] readonly attribute BarInfo locationbar; - [Replaceable] readonly attribute BarInfo menubar; - [Replaceable] readonly attribute BarInfo personalbar; - [Replaceable] readonly attribute BarInfo scrollbars; - [Replaceable] readonly attribute BarInfo statusbar; - [Replaceable] readonly attribute BarInfo toolbar; + [Replaceable] readonly attribute BarProp locationbar; + [Replaceable] readonly attribute BarProp menubar; + [Replaceable] readonly attribute BarProp personalbar; + [Replaceable] readonly attribute BarProp scrollbars; + [Replaceable] readonly attribute BarProp statusbar; + [Replaceable] readonly attribute BarProp toolbar; [Replaceable] readonly attribute Navigator navigator; [Replaceable] readonly attribute Navigator clientInformation; readonly attribute Crypto crypto; #if !defined(LANGUAGE_CPP) || !LANGUAGE_CPP - attribute [DoNotCheckSecurity, CustomSetter, V8Unforgeable] Location location; + [DoNotCheckSecurity, CustomSetter] attribute Location location; #endif - [Replaceable, CustomGetter, V8CustomSetter] readonly attribute Event event; + [Replaceable, CustomGetter] readonly attribute Event event; DOMSelection getSelection(); - readonly attribute [CheckSecurityForNode] Element frameElement; + [CheckSecurityForNode] readonly attribute Element frameElement; [DoNotCheckSecurity, CallWith=ScriptExecutionContext] void focus(); [DoNotCheckSecurity] void blur(); @@ -70,26 +67,26 @@ void print(); void stop(); - [Custom] DOMWindow open(in DOMString url, - in DOMString name, - in [Optional] DOMString options); + [Custom] DOMWindow open(DOMString url, + DOMString name, + optional DOMString options); - [Custom] DOMObject showModalDialog(in DOMString url, - in [Optional] DOMObject dialogArgs, - in [Optional] DOMString featureArgs); + [Custom] any showModalDialog(DOMString url, + optional any dialogArgs, + optional DOMString featureArgs); - void alert(in [Optional=DefaultIsUndefined] DOMString message); - boolean confirm(in [Optional=DefaultIsUndefined] DOMString message); - [TreatReturnedNullStringAs=Null] DOMString prompt(in [Optional=DefaultIsUndefined] DOMString message, - in [TreatNullAs=NullString, TreatUndefinedAs=NullString,Optional=DefaultIsUndefined] DOMString defaultValue); + void alert([Default=Undefined] optional DOMString message); + boolean confirm([Default=Undefined] optional DOMString message); + [TreatReturnedNullStringAs=Null] DOMString prompt([Default=Undefined] optional DOMString message, + [TreatNullAs=NullString, TreatUndefinedAs=NullString,Default=Undefined] optional DOMString defaultValue); - boolean find(in [Optional=DefaultIsUndefined] DOMString string, - in [Optional=DefaultIsUndefined] boolean caseSensitive, - in [Optional=DefaultIsUndefined] boolean backwards, - in [Optional=DefaultIsUndefined] boolean wrap, - in [Optional=DefaultIsUndefined] boolean wholeWord, - in [Optional=DefaultIsUndefined] boolean searchInFrames, - in [Optional=DefaultIsUndefined] boolean showDialog); + boolean find([Default=Undefined] optional DOMString string, + [Default=Undefined] optional boolean caseSensitive, + [Default=Undefined] optional boolean backwards, + [Default=Undefined] optional boolean wrap, + [Default=Undefined] optional boolean wholeWord, + [Default=Undefined] optional boolean searchInFrames, + [Default=Undefined] optional boolean showDialog); [Replaceable] readonly attribute boolean offscreenBuffering; @@ -106,15 +103,15 @@ readonly attribute long pageXOffset; readonly attribute long pageYOffset; - void scrollBy(in [Optional=DefaultIsUndefined] long x, in [Optional=DefaultIsUndefined] long y); - void scrollTo(in [Optional=DefaultIsUndefined] long x, in [Optional=DefaultIsUndefined] long y); - void scroll(in [Optional=DefaultIsUndefined] long x, in [Optional=DefaultIsUndefined] long y); - void moveBy(in [Optional=DefaultIsUndefined] float x, in [Optional=DefaultIsUndefined] float y); // FIXME: this should take longs not floats. - void moveTo(in [Optional=DefaultIsUndefined] float x, in [Optional=DefaultIsUndefined] float y); // FIXME: this should take longs not floats. - void resizeBy(in [Optional=DefaultIsUndefined] float x, in [Optional=DefaultIsUndefined] float y); // FIXME: this should take longs not floats. - void resizeTo(in [Optional=DefaultIsUndefined] float width, in [Optional=DefaultIsUndefined] float height); // FIXME: this should take longs not floats. + void scrollBy([Default=Undefined] optional long x, [Default=Undefined] optional long y); + void scrollTo([Default=Undefined] optional long x, [Default=Undefined] optional long y); + void scroll([Default=Undefined] optional long x, [Default=Undefined] optional long y); + void moveBy([Default=Undefined] optional float x, [Default=Undefined] optional float y); // FIXME: this should take longs not floats. + void moveTo([Default=Undefined] optional float x, [Default=Undefined] optional float y); // FIXME: this should take longs not floats. + void resizeBy([Default=Undefined] optional float x, [Default=Undefined] optional float y); // FIXME: this should take longs not floats. + void resizeTo([Default=Undefined] optional float width, [Default=Undefined] optional float height); // FIXME: this should take longs not floats. - readonly attribute [DoNotCheckSecurity] boolean closed; + [DoNotCheckSecurity] readonly attribute boolean closed; [Replaceable, DoNotCheckSecurityOnGetter] readonly attribute unsigned long length; @@ -129,45 +126,43 @@ // Self referential attributes [Replaceable, DoNotCheckSecurityOnGetter] readonly attribute DOMWindow self; - [DoNotCheckSecurity, V8Unforgeable] readonly attribute DOMWindow window; + [DoNotCheckSecurity] readonly attribute DOMWindow window; [Replaceable, DoNotCheckSecurityOnGetter] readonly attribute DOMWindow frames; - [Replaceable, DoNotCheckSecurityOnGetter, V8CustomSetter] readonly attribute DOMWindow opener; + [Replaceable, DoNotCheckSecurityOnGetter] readonly attribute DOMWindow opener; [Replaceable, DoNotCheckSecurityOnGetter] readonly attribute DOMWindow parent; - [DoNotCheckSecurityOnGetter, V8Unforgeable] readonly attribute DOMWindow top; + [DoNotCheckSecurityOnGetter] readonly attribute DOMWindow top; // DOM Level 2 AbstractView Interface readonly attribute Document document; // CSSOM View Module - MediaQueryList matchMedia(in DOMString query); + MediaQueryList matchMedia(DOMString query); // styleMedia has been removed from the CSSOM View specification. readonly attribute StyleMedia styleMedia; // DOM Level 2 Style Interface - CSSStyleDeclaration getComputedStyle(in [Optional=DefaultIsUndefined] Element element, - in [TreatNullAs=NullString, TreatUndefinedAs=NullString,Optional=DefaultIsUndefined] DOMString pseudoElement); + CSSStyleDeclaration getComputedStyle([Default=Undefined] optional Element element, + [TreatNullAs=NullString, TreatUndefinedAs=NullString,Default=Undefined] optional DOMString pseudoElement); // WebKit extensions #if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT - CSSRuleList getMatchedCSSRules(in [Optional=DefaultIsUndefined] Element element, - in [TreatNullAs=NullString, TreatUndefinedAs=NullString,Optional=DefaultIsUndefined] DOMString pseudoElement); + CSSRuleList getMatchedCSSRules([Default=Undefined] optional Element element, + [TreatNullAs=NullString, TreatUndefinedAs=NullString,Default=Undefined] optional DOMString pseudoElement); #endif [Replaceable] readonly attribute double devicePixelRatio; - WebKitPoint webkitConvertPointFromPageToNode(in [Optional=DefaultIsUndefined] Node node, - in [Optional=DefaultIsUndefined] WebKitPoint p); - WebKitPoint webkitConvertPointFromNodeToPage(in [Optional=DefaultIsUndefined] Node node, - in [Optional=DefaultIsUndefined] WebKitPoint p); + WebKitPoint webkitConvertPointFromPageToNode([Default=Undefined] optional Node node, + [Default=Undefined] optional WebKitPoint p); + WebKitPoint webkitConvertPointFromNodeToPage([Default=Undefined] optional Node node, + [Default=Undefined] optional WebKitPoint p); - readonly attribute [V8EnabledAtRuntime] DOMApplicationCache applicationCache; + readonly attribute DOMApplicationCache applicationCache; - readonly attribute [V8EnabledAtRuntime] Storage sessionStorage - getter raises(DOMException); - readonly attribute [V8EnabledAtRuntime] Storage localStorage - getter raises(DOMException); + [GetterRaisesException] readonly attribute Storage sessionStorage; + [GetterRaisesException] readonly attribute Storage localStorage; #if defined(ENABLE_ORIENTATION_EVENTS) && ENABLE_ORIENTATION_EVENTS // This is the interface orientation in degrees. Some examples are: @@ -180,52 +175,25 @@ // cross-document messaging #if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT - [DoNotCheckSecurity, Custom] void postMessage(in SerializedScriptValue message, in DOMString targetOrigin) - raises(DOMException); - [DoNotCheckSecurity, Custom] void postMessage(in SerializedScriptValue message, in DOMString targetOrigin, in Array messagePorts) - raises(DOMException); - -#if defined(ENABLE_LEGACY_VENDOR_PREFIXES) && ENABLE_LEGACY_VENDOR_PREFIXES - [DoNotCheckSecurity, Custom] void webkitPostMessage(in SerializedScriptValue message, in DOMString targetOrigin) - raises(DOMException); - [DoNotCheckSecurity, Custom] void webkitPostMessage(in SerializedScriptValue message, in DOMString targetOrigin, in Array transferList) - raises(DOMException); -#endif // defined(ENABLE_LEGACY_VENDOR_PREFIXES) && ENABLE_LEGACY_VENDOR_PREFIXES - + [DoNotCheckSecurity, Custom, RaisesException] void postMessage(SerializedScriptValue message, DOMString targetOrigin, optional Array messagePorts); #else // There's no good way to expose an array via the ObjC bindings, so for now just allow passing in a single port. - [DoNotCheckSecurity, Custom] void postMessage(in SerializedScriptValue message, in [Optional] MessagePort messagePort, in DOMString targetOrigin) - raises(DOMException); + [DoNotCheckSecurity, Custom, RaisesException] void postMessage(SerializedScriptValue message, optional MessagePort messagePort, DOMString targetOrigin); #endif #if defined(ENABLE_WEB_TIMING) && ENABLE_WEB_TIMING [Replaceable] readonly attribute Performance performance; #endif - // Timers - [Custom] long setTimeout(in [Optional=DefaultIsUndefined] TimeoutHandler handler, - in [Optional=DefaultIsUndefined] long timeout); - // [Custom] long setTimeout(in TimeoutHandler handler, in long timeout, arguments...); - // [Custom] long setTimeout(in DOMString code, in long timeout); - void clearTimeout(in [Optional=DefaultIsUndefined] long handle); - [Custom] long setInterval(in TimeoutHandler handler, in long timeout); - // [Custom] long setInterval(in TimeoutHandler handler, in long timeout, arguments...); - // [Custom] long setInterval(in DOMString code, in long timeout); - void clearInterval(in [Optional=DefaultIsUndefined] long handle); - #if defined(ENABLE_REQUEST_ANIMATION_FRAME) && ENABLE_REQUEST_ANIMATION_FRAME - [V8MeasureAs=UnprefixedRequestAnimationFrame] long requestAnimationFrame(in [Callback] RequestAnimationFrameCallback callback); - void cancelAnimationFrame(in long id); - [V8MeasureAs=PrefixedRequestAnimationFrame] long webkitRequestAnimationFrame(in [Callback] RequestAnimationFrameCallback callback); - [ImplementedAs=cancelAnimationFrame] void webkitCancelAnimationFrame(in long id); - [ImplementedAs=cancelAnimationFrame] void webkitCancelRequestAnimationFrame(in long id); // This is a deprecated alias for webkitCancelAnimationFrame(). Remove this when removing vendor prefix. + long requestAnimationFrame(RequestAnimationFrameCallback callback); + void cancelAnimationFrame(long id); + long webkitRequestAnimationFrame(RequestAnimationFrameCallback callback); + [ImplementedAs=cancelAnimationFrame] void webkitCancelAnimationFrame(long id); + [ImplementedAs=cancelAnimationFrame] void webkitCancelRequestAnimationFrame(long id); // This is a deprecated alias for webkitCancelAnimationFrame(). Remove this when removing vendor prefix. #endif - // Base64 - DOMString atob(in [TreatNullAs=NullString,Optional=DefaultIsUndefined] DOMString string) - raises(DOMException); - DOMString btoa(in [TreatNullAs=NullString,Optional=DefaultIsUndefined] DOMString string) - raises(DOMException); + [Replaceable,Conditional=CSS3_CONDITIONAL_RULES] readonly attribute DOMWindowCSS CSS; // Events attribute EventListener onabort; @@ -261,6 +229,8 @@ attribute EventListener onloadstart; attribute EventListener onmessage; attribute EventListener onmousedown; + attribute EventListener onmouseenter; + attribute EventListener onmouseleave; attribute EventListener onmousemove; attribute EventListener onmouseout; attribute EventListener onmouseover; @@ -305,509 +275,50 @@ attribute EventListener onwebkitanimationiteration; attribute EventListener onwebkitanimationstart; attribute EventListener onwebkittransitionend; + attribute EventListener ontransitionend; #if defined(ENABLE_ORIENTATION_EVENTS) && ENABLE_ORIENTATION_EVENTS attribute EventListener onorientationchange; #endif - attribute [Conditional=TOUCH_EVENTS,V8EnabledAtRuntime] EventListener ontouchstart; - attribute [Conditional=TOUCH_EVENTS,V8EnabledAtRuntime] EventListener ontouchmove; - attribute [Conditional=TOUCH_EVENTS,V8EnabledAtRuntime] EventListener ontouchend; - attribute [Conditional=TOUCH_EVENTS,V8EnabledAtRuntime] EventListener ontouchcancel; + [Conditional=TOUCH_EVENTS] attribute EventListener ontouchstart; + [Conditional=TOUCH_EVENTS] attribute EventListener ontouchmove; + [Conditional=TOUCH_EVENTS] attribute EventListener ontouchend; + [Conditional=TOUCH_EVENTS] attribute EventListener ontouchcancel; - attribute [Conditional=DEVICE_ORIENTATION,V8EnabledAtRuntime] EventListener ondevicemotion; - attribute [Conditional=DEVICE_ORIENTATION,V8EnabledAtRuntime] EventListener ondeviceorientation; + [Conditional=DEVICE_ORIENTATION] attribute EventListener ondevicemotion; + [Conditional=DEVICE_ORIENTATION] attribute EventListener ondeviceorientation; - attribute [Conditional=PROXIMITY_EVENTS] EventListener onwebkitdeviceproximity; + [Conditional=PROXIMITY_EVENTS] attribute EventListener onwebkitdeviceproximity; // EventTarget interface - [Custom] void addEventListener(in DOMString type, - in EventListener listener, - in [Optional] boolean useCapture); - [Custom] void removeEventListener(in DOMString type, - in EventListener listener, - in [Optional] boolean useCapture); - boolean dispatchEvent(in Event evt) - raises(EventException); - - [V8Custom] void captureEvents(/*in long eventFlags*/); - [V8Custom] void releaseEvents(/*in long eventFlags*/); + [Custom] void addEventListener(DOMString type, + EventListener listener, + optional boolean useCapture); + [Custom] void removeEventListener(DOMString type, + EventListener listener, + optional boolean useCapture); + [RaisesException] boolean dispatchEvent(Event evt); -#if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT - // Global constructors - attribute StyleSheetConstructor StyleSheet; - attribute CSSStyleSheetConstructor CSSStyleSheet; + void captureEvents(/*in long eventFlags*/); + void releaseEvents(/*in long eventFlags*/); - attribute CSSValueConstructor CSSValue; - attribute CSSPrimitiveValueConstructor CSSPrimitiveValue; - attribute CSSValueListConstructor CSSValueList; - attribute WebKitCSSTransformValueConstructor WebKitCSSTransformValue; - -#if defined(ENABLE_CSS_SHADERS) && ENABLE_CSS_SHADERS - attribute WebKitCSSMixFunctionValueConstructor WebKitCSSMixFunctionValue; -#endif - -#if defined(ENABLE_CSS_FILTERS) && ENABLE_CSS_FILTERS - attribute WebKitCSSFilterValueConstructor WebKitCSSFilterValue; -#endif - -#if defined(ENABLE_CSS_DEVICE_ADAPTATION) && ENABLE_CSS_DEVICE_ADAPTATION - attribute WebKitCSSViewportRuleConstructor WebKitCSSViewportRule; -#endif - - attribute CSSRuleConstructor CSSRule; - attribute CSSCharsetRuleConstructor CSSCharsetRule; - attribute CSSFontFaceRuleConstructor CSSFontFaceRule; - attribute CSSImportRuleConstructor CSSImportRule; - attribute CSSMediaRuleConstructor CSSMediaRule; - attribute CSSPageRuleConstructor CSSPageRule; - attribute CSSStyleRuleConstructor CSSStyleRule; - - attribute CSSStyleDeclarationConstructor CSSStyleDeclaration; - attribute MediaListConstructor MediaList; - attribute CounterConstructor Counter; - attribute CSSRuleListConstructor CSSRuleList; - attribute RectConstructor Rect; - attribute RGBColorConstructor RGBColor; - attribute StyleSheetListConstructor StyleSheetList; - - // FIXME: Implement the commented-out global constructors for interfaces listed in DOM Level 3 Core specification. - attribute DOMCoreExceptionConstructor DOMException; - attribute DOMStringListConstructor DOMStringList; -// attribute NameListConstructor NameList; -// attribute DOMImplementationListConstructor DOMImplementationList; -// attribute DOMImplementationSourceConstructor DOMImplementationSource; - attribute DOMImplementationConstructor DOMImplementation; - attribute DOMSettableTokenListConstructor DOMSettableTokenList; - attribute DOMTokenListConstructor DOMTokenList; - attribute DocumentFragmentConstructor DocumentFragment; - attribute DocumentConstructor Document; - attribute NodeConstructor Node; - attribute NodeListConstructor NodeList; - [Conditional=MICRODATA] attribute PropertyNodeListConstructor PropertyNodeList; - attribute NamedNodeMapConstructor NamedNodeMap; - attribute CharacterDataConstructor CharacterData; - attribute AttrConstructor Attr; - attribute ElementConstructor Element; - attribute TextConstructor Text; - attribute CommentConstructor Comment; -// attribute TypeInfoConstructor TypeInfo; -// attribute UserDataHandlerConstructor UserDataHandler; -// attribute DOMErrorConstructor DOMError; -// attribute DOMErrorHandlerConstructor DOMErrorHandler -// attribute DOMLocatorConstructor DOMLocator; -// attribute DOMConfigurationConstructor DOMConfiguration; - attribute CDATASectionConstructor CDATASection; - attribute DocumentTypeConstructor DocumentType; - attribute NotationConstructor Notation; - attribute EntityConstructor Entity; - attribute EntityReferenceConstructor EntityReference; - attribute ProcessingInstructionConstructor ProcessingInstruction; - [Conditional=SHADOW_DOM, V8EnabledAtRuntime=shadowDOM] attribute ShadowRootConstructor WebKitShadowRoot; - [Conditional=SHADOW_DOM, V8EnabledAtRuntime=shadowDOM] attribute HTMLContentElementConstructor HTMLContentElement; - [Conditional=SHADOW_DOM, V8EnabledAtRuntime=shadowDOM] attribute HTMLShadowElementConstructor HTMLShadowElement; - - attribute DOMSelectionConstructor Selection; - attribute DOMWindowConstructor Window; - - attribute HTMLDocumentConstructor HTMLDocument; - attribute HTMLElementConstructor HTMLElement; - attribute HTMLAnchorElementConstructor HTMLAnchorElement; - attribute HTMLAppletElementConstructor HTMLAppletElement; - attribute HTMLAreaElementConstructor HTMLAreaElement; - attribute HTMLBRElementConstructor HTMLBRElement; - attribute HTMLBaseElementConstructor HTMLBaseElement; - attribute HTMLBaseFontElementConstructor HTMLBaseFontElement; - attribute HTMLBodyElementConstructor HTMLBodyElement; - attribute HTMLButtonElementConstructor HTMLButtonElement; - attribute HTMLCanvasElementConstructor HTMLCanvasElement; - attribute HTMLDListElementConstructor HTMLDListElement; - [Conditional=DATALIST_ELEMENT] attribute HTMLDataListElementConstructor HTMLDataListElement; - [Conditional=DIALOG_ELEMENT, V8EnabledPerContext=dialogElement] attribute HTMLDialogElementConstructor HTMLDialogElement; - attribute HTMLDirectoryElementConstructor HTMLDirectoryElement; - attribute HTMLDivElementConstructor HTMLDivElement; - attribute HTMLEmbedElementConstructor HTMLEmbedElement; - attribute HTMLFieldSetElementConstructor HTMLFieldSetElement; - attribute HTMLFontElementConstructor HTMLFontElement; - attribute HTMLFormElementConstructor HTMLFormElement; - attribute HTMLFrameElementConstructor HTMLFrameElement; - attribute HTMLFrameSetElementConstructor HTMLFrameSetElement; - attribute HTMLHRElementConstructor HTMLHRElement; - attribute HTMLHeadElementConstructor HTMLHeadElement; - attribute HTMLHeadingElementConstructor HTMLHeadingElement; - attribute HTMLHtmlElementConstructor HTMLHtmlElement; - attribute HTMLIFrameElementConstructor HTMLIFrameElement; - attribute HTMLImageElementConstructor HTMLImageElement; - attribute HTMLInputElementConstructor HTMLInputElement; - attribute HTMLKeygenElementConstructor HTMLKeygenElement; - attribute HTMLLIElementConstructor HTMLLIElement; - attribute HTMLLabelElementConstructor HTMLLabelElement; - attribute HTMLLegendElementConstructor HTMLLegendElement; - attribute HTMLLinkElementConstructor HTMLLinkElement; - attribute HTMLMapElementConstructor HTMLMapElement; - attribute HTMLMarqueeElementConstructor HTMLMarqueeElement; - attribute HTMLMenuElementConstructor HTMLMenuElement; - attribute HTMLMetaElementConstructor HTMLMetaElement; -#if defined(ENABLE_METER_ELEMENT) && ENABLE_METER_ELEMENT - attribute HTMLMeterElementConstructor HTMLMeterElement; -#endif - attribute HTMLModElementConstructor HTMLModElement; - attribute HTMLOListElementConstructor HTMLOListElement; - attribute HTMLObjectElementConstructor HTMLObjectElement; - attribute HTMLOptGroupElementConstructor HTMLOptGroupElement; - attribute HTMLOptionElementConstructor HTMLOptionElement; - attribute HTMLOutputElementConstructor HTMLOutputElement; - attribute HTMLParagraphElementConstructor HTMLParagraphElement; - attribute HTMLParamElementConstructor HTMLParamElement; - attribute HTMLPreElementConstructor HTMLPreElement; -#if defined(ENABLE_PROGRESS_ELEMENT) && ENABLE_PROGRESS_ELEMENT - attribute HTMLProgressElementConstructor HTMLProgressElement; -#endif - attribute HTMLQuoteElementConstructor HTMLQuoteElement; - attribute HTMLScriptElementConstructor HTMLScriptElement; - attribute HTMLSelectElementConstructor HTMLSelectElement; - attribute HTMLSpanElementConstructor HTMLSpanElement; - attribute HTMLStyleElementConstructor HTMLStyleElement; - attribute HTMLTableCaptionElementConstructor HTMLTableCaptionElement; - attribute HTMLTableCellElementConstructor HTMLTableCellElement; - attribute HTMLTableColElementConstructor HTMLTableColElement; - attribute HTMLTableElementConstructor HTMLTableElement; - attribute HTMLTableRowElementConstructor HTMLTableRowElement; - attribute HTMLTableSectionElementConstructor HTMLTableSectionElement; - attribute HTMLTextAreaElementConstructor HTMLTextAreaElement; - attribute HTMLTitleElementConstructor HTMLTitleElement; - attribute HTMLUListElementConstructor HTMLUListElement; - - attribute HTMLCollectionConstructor HTMLCollection; - attribute HTMLAllCollectionConstructor HTMLAllCollection; - attribute HTMLFormControlsCollectionConstructor HTMLFormControlsCollection; - attribute HTMLOptionsCollectionConstructor HTMLOptionsCollection; - [Conditional=MICRODATA] attribute HTMLPropertiesCollectionConstructor HTMLPropertiesCollection; - attribute HTMLUnknownElementConstructor HTMLUnknownElement; - - [JSCustomGetter, CustomConstructor] attribute HTMLImageElementConstructorConstructor Image; // Usable with new operator - [JSCustomGetter] attribute HTMLOptionElementConstructorConstructor Option; // Usable with new operator - - [Conditional=ENCRYPTED_MEDIA, V8EnabledAtRuntime=encryptedMedia] attribute MediaKeyErrorConstructor MediaKeyError; - [Conditional=ENCRYPTED_MEDIA, V8EnabledAtRuntime=encryptedMedia] attribute MediaKeyEventConstructor MediaKeyEvent; - - [Conditional=VIDEO_TRACK, V8EnabledAtRuntime=webkitVideoTrack] attribute HTMLTrackElementConstructor HTMLTrackElement; - [Conditional=VIDEO_TRACK, V8EnabledAtRuntime=webkitVideoTrack] attribute TextTrackConstructor TextTrack; - [Conditional=VIDEO_TRACK, V8EnabledAtRuntime=webkitVideoTrack] attribute TextTrackCueConstructor TextTrackCue; // Usable with the new operator - [Conditional=VIDEO_TRACK, V8EnabledAtRuntime=webkitVideoTrack] attribute TextTrackCueListConstructor TextTrackCueList; - [Conditional=VIDEO_TRACK, V8EnabledAtRuntime=webkitVideoTrack] attribute TextTrackListConstructor TextTrackList; - [Conditional=VIDEO_TRACK, V8EnabledAtRuntime=webkitVideoTrack] attribute TrackEventConstructor TrackEvent; - - [JSCustomGetter, Conditional=VIDEO, V8EnabledAtRuntime] attribute HTMLAudioElementConstructorConstructor Audio; // Usable with the new operator - [Conditional=VIDEO, V8EnabledAtRuntime] attribute HTMLAudioElementConstructor HTMLAudioElement; - [Conditional=VIDEO, V8EnabledAtRuntime] attribute HTMLMediaElementConstructor HTMLMediaElement; - [Conditional=VIDEO, V8EnabledAtRuntime] attribute HTMLVideoElementConstructor HTMLVideoElement; - [Conditional=VIDEO, V8EnabledAtRuntime] attribute MediaErrorConstructor MediaError; - [Conditional=VIDEO, V8EnabledAtRuntime] attribute TimeRangesConstructor TimeRanges; - [Conditional=VIDEO, V8EnabledAtRuntime] attribute HTMLSourceElementConstructor HTMLSourceElement; - [Conditional=VIDEO, V8EnabledAtRuntime] attribute MediaControllerConstructor MediaController; - - [Conditional=WEB_INTENTS_TAG] attribute HTMLIntentElementConstructor HTMLIntentElement; - - attribute CanvasPatternConstructor CanvasPattern; - attribute CanvasGradientConstructor CanvasGradient; - attribute CanvasRenderingContext2DConstructor CanvasRenderingContext2D; - - attribute ImageDataConstructor ImageData; - attribute TextMetricsConstructor TextMetrics; - - [Conditional=WEBGL] attribute WebGLActiveInfoConstructor WebGLActiveInfo; - [Conditional=WEBGL] attribute WebGLBufferConstructor WebGLBuffer; - [Conditional=WEBGL] attribute WebGLFramebufferConstructor WebGLFramebuffer; - [Conditional=WEBGL] attribute WebGLProgramConstructor WebGLProgram; - [Conditional=WEBGL] attribute WebGLRenderbufferConstructor WebGLRenderbuffer; - [Conditional=WEBGL] attribute WebGLRenderingContextConstructor WebGLRenderingContext; - [Conditional=WEBGL] attribute WebGLShaderConstructor WebGLShader; - [Conditional=WEBGL] attribute WebGLShaderPrecisionFormatConstructor WebGLShaderPrecisionFormat; - [Conditional=WEBGL] attribute WebGLTextureConstructor WebGLTexture; - [Conditional=WEBGL] attribute WebGLUniformLocationConstructor WebGLUniformLocation; - - attribute DOMStringMapConstructor DOMStringMap; - - attribute ArrayBufferConstructor ArrayBuffer; // Usable with new operator - attribute Int8ArrayConstructor Int8Array; // Usable with new operator - attribute Uint8ArrayConstructor Uint8Array; // Usable with new operator - attribute Uint8ClampedArrayConstructor Uint8ClampedArray; // Usable with new operator - attribute Int16ArrayConstructor Int16Array; // Usable with new operator - attribute Uint16ArrayConstructor Uint16Array; // Usable with new operator - attribute Int32ArrayConstructor Int32Array; // Usable with new operator - attribute Uint32ArrayConstructor Uint32Array; // Usable with new operator - attribute Float32ArrayConstructor Float32Array; // Usable with new operator - attribute Float64ArrayConstructor Float64Array; // Usable with new operator - attribute DataViewConstructor DataView; // Usable with new operator - - // Event Constructors - attribute EventConstructor Event; - attribute BeforeLoadEventConstructor BeforeLoadEvent; - attribute CompositionEventConstructor CompositionEvent; - attribute CustomEventConstructor CustomEvent; - attribute ErrorEventConstructor ErrorEvent; - attribute HashChangeEventConstructor HashChangeEvent; - attribute KeyboardEventConstructor KeyboardEvent; - attribute MessageEventConstructor MessageEvent; - attribute MouseEventConstructor MouseEvent; - attribute MutationEventConstructor MutationEvent; - attribute OverflowEventConstructor OverflowEvent; - attribute PopStateEventConstructor PopStateEvent; - attribute PageTransitionEventConstructor PageTransitionEvent; - attribute ProgressEventConstructor ProgressEvent; - attribute TextEventConstructor TextEvent; - attribute UIEventConstructor UIEvent; - attribute WebKitAnimationEventConstructor WebKitAnimationEvent; - attribute WebKitTransitionEventConstructor WebKitTransitionEvent; - attribute WheelEventConstructor WheelEvent; - attribute XMLHttpRequestProgressEventConstructor XMLHttpRequestProgressEvent; - [Conditional=DEVICE_ORIENTATION, V8EnabledAtRuntime] attribute DeviceMotionEventConstructor DeviceMotionEvent; - [Conditional=DEVICE_ORIENTATION, V8EnabledAtRuntime] attribute DeviceOrientationEventConstructor DeviceOrientationEvent; - [Conditional=TOUCH_EVENTS] attribute TouchConstructor Touch; - [Conditional=TOUCH_EVENTS] attribute TouchEventConstructor TouchEvent; - [Conditional=TOUCH_EVENTS] attribute TouchListConstructor TouchList; - attribute StorageEventConstructor StorageEvent; - [Conditional=INPUT_SPEECH] attribute SpeechInputEventConstructor SpeechInputEvent; - [Conditional=WEBGL] attribute WebGLContextEventConstructor WebGLContextEvent; - [Conditional=PROXIMITY_EVENTS] attribute DeviceProximityEventConstructor DeviceProximityEvent; - - attribute EventExceptionConstructor EventException; - - attribute WebKitCSSKeyframeRuleConstructor WebKitCSSKeyframeRule; - attribute WebKitCSSKeyframesRuleConstructor WebKitCSSKeyframesRule; - [Conditional=CSS_REGIONS] attribute WebKitCSSRegionRuleConstructor WebKitCSSRegionRule; - - attribute WebKitCSSMatrixConstructor WebKitCSSMatrix; // Usable with the new operator - - attribute WebKitPointConstructor WebKitPoint; // Usable with new the operator - - attribute ClipboardConstructor Clipboard; - - [Conditional=WORKERS] attribute WorkerConstructor Worker; // Usable with the new operator - [Conditional=SHARED_WORKERS, JSCustomGetter, V8EnabledAtRuntime] attribute SharedWorkerConstructor SharedWorker; // Usable with the new operator - - attribute FileConstructor File; - attribute FileListConstructor FileList; - attribute BlobConstructor Blob; - - attribute NodeFilterConstructor NodeFilter; - attribute RangeConstructor Range; - attribute RangeExceptionConstructor RangeException; - - attribute EventSourceConstructor EventSource; // Usable with new the operator - - // Mozilla has a separate XMLDocument object for XML documents. +#if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT + // Additional constructors. + [CustomGetter, CustomConstructor] attribute HTMLImageElementNamedConstructor Image; // Usable with new operator + // Mozilla has a separate XMLDocument object for XML documents. // We just use Document for this. attribute DocumentConstructor XMLDocument; - attribute DOMParserConstructor DOMParser; - attribute XMLSerializerConstructor XMLSerializer; - attribute XMLHttpRequestConstructor XMLHttpRequest; // Usable with the new operator - attribute XMLHttpRequestUploadConstructor XMLHttpRequestUpload; - attribute XMLHttpRequestExceptionConstructor XMLHttpRequestException; - [Conditional=XSLT] attribute XSLTProcessorConstructor XSLTProcessor; // Usable with the new operator - -#if defined(ENABLE_CHANNEL_MESSAGING) && ENABLE_CHANNEL_MESSAGING - attribute MessagePortConstructor MessagePort; - attribute MessageChannelConstructor MessageChannel; // Usable with the new operator -#endif - - attribute DOMPluginConstructor Plugin; - attribute DOMPluginArrayConstructor PluginArray; - - attribute DOMMimeTypeConstructor MimeType; - attribute DOMMimeTypeArrayConstructor MimeTypeArray; - - attribute ClientRectConstructor ClientRect; - attribute ClientRectListConstructor ClientRectList; - - attribute StorageConstructor Storage; - -#if defined(ENABLE_ANIMATION_API) && ENABLE_ANIMATION_API - attribute WebKitAnimationConstructor WebKitAnimation; - attribute WebKitAnimationListConstructor WebKitAnimationList; -#endif - - attribute XPathEvaluatorConstructor XPathEvaluator; - attribute XPathResultConstructor XPathResult; - attribute XPathExceptionConstructor XPathException; - - [Conditional=SVG] attribute SVGZoomEventConstructor SVGZoomEvent; - -#if defined(ENABLE_SVG) && ENABLE_SVG - // Expose all implemented SVG 1.1 interfaces, excluding the SVG MI interfaces: - // SVGAnimatedPathData, SVGAnimatedPoints, SVGExternalResourcesRequired, - // SVGFilterPrimitiveStandardAttributes, SVGFitToViewBox, SVGLangSpace, SVGLocatable - // SVGStylable, SVGTests, SVGTransformable, SVGURIReference, SVGZoomAndPan - attribute SVGAElementConstructor SVGAElement; - attribute SVGAngleConstructor SVGAngle; - attribute SVGAnimatedAngleConstructor SVGAnimatedAngle; - attribute SVGAnimatedBooleanConstructor SVGAnimatedBoolean; - attribute SVGAnimatedEnumerationConstructor SVGAnimatedEnumeration; - attribute SVGAnimatedIntegerConstructor SVGAnimatedInteger; - attribute SVGAnimatedLengthConstructor SVGAnimatedLength; - attribute SVGAnimatedLengthListConstructor SVGAnimatedLengthList; - attribute SVGAnimatedNumberConstructor SVGAnimatedNumber; - attribute SVGAnimatedNumberListConstructor SVGAnimatedNumberList; - attribute SVGAnimatedPreserveAspectRatioConstructor SVGAnimatedPreserveAspectRatio; - attribute SVGAnimatedRectConstructor SVGAnimatedRect; - attribute SVGAnimatedStringConstructor SVGAnimatedString; - attribute SVGAnimatedTransformListConstructor SVGAnimatedTransformList; - attribute SVGCircleElementConstructor SVGCircleElement; - attribute SVGClipPathElementConstructor SVGClipPathElement; - attribute SVGColorConstructor SVGColor; - attribute SVGCursorElementConstructor SVGCursorElement; -// attribute SVGCSSRuleConstructor SVGCSSRule; - attribute SVGDefsElementConstructor SVGDefsElement; - attribute SVGDescElementConstructor SVGDescElement; - attribute SVGDocumentConstructor SVGDocument; - attribute SVGElementConstructor SVGElement; - attribute SVGElementInstanceConstructor SVGElementInstance; - attribute SVGElementInstanceListConstructor SVGElementInstanceList; - attribute SVGEllipseElementConstructor SVGEllipseElement; - attribute SVGForeignObjectElementConstructor SVGForeignObjectElement; - attribute SVGExceptionConstructor SVGException; - attribute SVGGElementConstructor SVGGElement; - attribute SVGGradientElementConstructor SVGGradientElement; - attribute SVGImageElementConstructor SVGImageElement; - attribute SVGLengthConstructor SVGLength; - attribute SVGLengthListConstructor SVGLengthList; - attribute SVGLinearGradientElementConstructor SVGLinearGradientElement; - attribute SVGLineElementConstructor SVGLineElement; - attribute SVGMarkerElementConstructor SVGMarkerElement; - attribute SVGMaskElementConstructor SVGMaskElement; - attribute SVGMatrixConstructor SVGMatrix; - attribute SVGMetadataElementConstructor SVGMetadataElement; - attribute SVGNumberConstructor SVGNumber; - attribute SVGNumberListConstructor SVGNumberList; - attribute SVGPaintConstructor SVGPaint; - attribute SVGPathElementConstructor SVGPathElement; - attribute SVGPathSegConstructor SVGPathSeg; - attribute SVGPathSegArcAbsConstructor SVGPathSegArcAbs; - attribute SVGPathSegArcRelConstructor SVGPathSegArcRel; - attribute SVGPathSegClosePathConstructor SVGPathSegClosePath; - attribute SVGPathSegCurvetoCubicAbsConstructor SVGPathSegCurvetoCubicAbs; - attribute SVGPathSegCurvetoCubicRelConstructor SVGPathSegCurvetoCubicRel; - attribute SVGPathSegCurvetoCubicSmoothAbsConstructor SVGPathSegCurvetoCubicSmoothAbs; - attribute SVGPathSegCurvetoCubicSmoothRelConstructor SVGPathSegCurvetoCubicSmoothRel; - attribute SVGPathSegCurvetoQuadraticAbsConstructor SVGPathSegCurvetoQuadraticAbs; - attribute SVGPathSegCurvetoQuadraticRelConstructor SVGPathSegCurvetoQuadraticRel; - attribute SVGPathSegCurvetoQuadraticSmoothAbsConstructor SVGPathSegCurvetoQuadraticSmoothAbs; - attribute SVGPathSegCurvetoQuadraticSmoothRelConstructor SVGPathSegCurvetoQuadraticSmoothRel; - attribute SVGPathSegLinetoAbsConstructor SVGPathSegLinetoAbs; - attribute SVGPathSegLinetoHorizontalAbsConstructor SVGPathSegLinetoHorizontalAbs; - attribute SVGPathSegLinetoHorizontalRelConstructor SVGPathSegLinetoHorizontalRel; - attribute SVGPathSegLinetoRelConstructor SVGPathSegLinetoRel; - attribute SVGPathSegLinetoVerticalAbsConstructor SVGPathSegLinetoVerticalAbs; - attribute SVGPathSegLinetoVerticalRelConstructor SVGPathSegLinetoVerticalRel; - attribute SVGPathSegListConstructor SVGPathSegList; - attribute SVGPathSegMovetoAbsConstructor SVGPathSegMovetoAbs; - attribute SVGPathSegMovetoRelConstructor SVGPathSegMovetoRel; - attribute SVGPatternElementConstructor SVGPatternElement; - attribute SVGPointConstructor SVGPoint; - attribute SVGPointListConstructor SVGPointList; - attribute SVGPolygonElementConstructor SVGPolygonElement; - attribute SVGPolylineElementConstructor SVGPolylineElement; - attribute SVGPreserveAspectRatioConstructor SVGPreserveAspectRatio; - attribute SVGRadialGradientElementConstructor SVGRadialGradientElement; - attribute SVGRectConstructor SVGRect; - attribute SVGRectElementConstructor SVGRectElement; - attribute SVGRenderingIntentConstructor SVGRenderingIntent; - attribute SVGScriptElementConstructor SVGScriptElement; - attribute SVGStopElementConstructor SVGStopElement; - attribute SVGStringListConstructor SVGStringList; - attribute SVGStyleElementConstructor SVGStyleElement; - attribute SVGSVGElementConstructor SVGSVGElement; - attribute SVGSwitchElementConstructor SVGSwitchElement; - attribute SVGSymbolElementConstructor SVGSymbolElement; - attribute SVGTextContentElementConstructor SVGTextContentElement; - attribute SVGTextElementConstructor SVGTextElement; - attribute SVGTextPathElementConstructor SVGTextPathElement; - attribute SVGTextPositioningElementConstructor SVGTextPositioningElement; - attribute SVGTitleElementConstructor SVGTitleElement; - attribute SVGTransformConstructor SVGTransform; - attribute SVGTransformListConstructor SVGTransformList; - attribute SVGTRefElementConstructor SVGTRefElement; - attribute SVGTSpanElementConstructor SVGTSpanElement; - attribute SVGUnitTypesConstructor SVGUnitTypes; - attribute SVGUseElementConstructor SVGUseElement; - attribute SVGViewElementConstructor SVGViewElement; - attribute SVGViewSpecConstructor SVGViewSpec; - attribute SVGZoomAndPanConstructor SVGZoomAndPan; - - attribute SVGAnimateColorElementConstructor SVGAnimateColorElement; - attribute SVGAnimateElementConstructor SVGAnimateElement; - attribute SVGAnimateMotionElementConstructor SVGAnimateMotionElement; - attribute SVGAnimateTransformElementConstructor SVGAnimateTransformElement; - attribute SVGMPathElementConstructor SVGMPathElement; - attribute SVGSetElementConstructor SVGSetElement; - -#if defined(ENABLE_SVG_FONTS) && ENABLE_SVG_FONTS - attribute SVGAltGlyphDefElementConstructor SVGAltGlyphDefElement; - attribute SVGAltGlyphElementConstructor SVGAltGlyphElement; - attribute SVGAltGlyphItemElementConstructor SVGAltGlyphItemElement; -// attribute SVGDefinitionSrcElementConstructor SVGDefinitionSrcElement; - attribute SVGFontElementConstructor SVGFontElement; - attribute SVGFontFaceElementConstructor SVGFontFaceElement; - attribute SVGFontFaceFormatElementConstructor SVGFontFaceFormatElement; - attribute SVGFontFaceNameElementConstructor SVGFontFaceNameElement; - attribute SVGFontFaceSrcElementConstructor SVGFontFaceSrcElement; - attribute SVGFontFaceUriElementConstructor SVGFontFaceUriElement; - attribute SVGGlyphElementConstructor SVGGlyphElement; - attribute SVGGlyphRefElementConstructor SVGGlyphRefElement; - attribute SVGHKernElementConstructor SVGHKernElement; - attribute SVGMissingGlyphElementConstructor SVGMissingGlyphElement; - attribute SVGVKernElementConstructor SVGVKernElement; -#endif - -#if defined(ENABLE_FILTERS) && ENABLE_FILTERS - attribute SVGComponentTransferFunctionElementConstructor SVGComponentTransferFunctionElement; - attribute SVGFEBlendElementConstructor SVGFEBlendElement; - attribute SVGFEColorMatrixElementConstructor SVGFEColorMatrixElement; - attribute SVGFEComponentTransferElementConstructor SVGFEComponentTransferElement; - attribute SVGFECompositeElementConstructor SVGFECompositeElement; - attribute SVGFEConvolveMatrixElementConstructor SVGFEConvolveMatrixElement; - attribute SVGFEDiffuseLightingElementConstructor SVGFEDiffuseLightingElement; - attribute SVGFEDisplacementMapElementConstructor SVGFEDisplacementMapElement; - attribute SVGFEDistantLightElementConstructor SVGFEDistantLightElement; - attribute SVGFEDropShadowElementConstructor SVGFEDropShadowElement; - attribute SVGFEFloodElementConstructor SVGFEFloodElement; - attribute SVGFEFuncAElementConstructor SVGFEFuncAElement; - attribute SVGFEFuncBElementConstructor SVGFEFuncBElement; - attribute SVGFEFuncGElementConstructor SVGFEFuncGElement; - attribute SVGFEFuncRElementConstructor SVGFEFuncRElement; - attribute SVGFEGaussianBlurElementConstructor SVGFEGaussianBlurElement; - attribute SVGFEImageElementConstructor SVGFEImageElement; - attribute SVGFEMergeElementConstructor SVGFEMergeElement; - attribute SVGFEMergeNodeElementConstructor SVGFEMergeNodeElement; - attribute SVGFEMorphologyElementConstructor SVGFEMorphologyElement; - attribute SVGFEOffsetElementConstructor SVGFEOffsetElement; - attribute SVGFEPointLightElementConstructor SVGFEPointLightElement; - attribute SVGFESpecularLightingElementConstructor SVGFESpecularLightingElement; - attribute SVGFESpotLightElementConstructor SVGFESpotLightElement; - attribute SVGFETileElementConstructor SVGFETileElement; - attribute SVGFETurbulenceElementConstructor SVGFETurbulenceElement; - attribute SVGFilterElementConstructor SVGFilterElement; -#endif -#endif - - attribute DOMFormDataConstructor FormData; - - [Conditional=BLOB|FILE_SYSTEM] attribute FileErrorConstructor FileError; - [Conditional=BLOB] attribute FileReaderConstructor FileReader; - - [Conditional=BLOB] attribute DOMURLConstructor URL; [Conditional=BLOB] attribute DOMURLConstructor webkitURL; // FIXME: deprecate this. - - [Conditional=MUTATION_OBSERVERS] attribute MutationObserverConstructor WebKitMutationObserver; - - [Conditional=MEDIA_SOURCE, V8EnabledAtRuntime=mediaSource] attribute MediaSourceConstructor WebKitMediaSource; - [Conditional=MEDIA_SOURCE, V8EnabledAtRuntime=mediaSource] attribute SourceBufferConstructor WebKitSourceBuffer; - [Conditional=MEDIA_SOURCE, V8EnabledAtRuntime=mediaSource] attribute SourceBufferListConstructor WebKitSourceBufferList; - + attribute MutationObserverConstructor WebKitMutationObserver; // FIXME: Add metrics to determine when we can remove this. + [Conditional=INDEXED_DATABASE] attribute IDBCursorConstructor webkitIDBCursor; + [Conditional=INDEXED_DATABASE] attribute IDBDatabaseConstructor webkitIDBDatabase; + [Conditional=INDEXED_DATABASE] attribute IDBFactoryConstructor webkitIDBFactory; + [Conditional=INDEXED_DATABASE] attribute IDBIndexConstructor webkitIDBIndex; + [Conditional=INDEXED_DATABASE] attribute IDBKeyRangeConstructor webkitIDBKeyRange; + [Conditional=INDEXED_DATABASE] attribute IDBObjectStoreConstructor webkitIDBObjectStore; + [Conditional=INDEXED_DATABASE] attribute IDBRequestConstructor webkitIDBRequest; + [Conditional=INDEXED_DATABASE] attribute IDBTransactionConstructor webkitIDBTransaction; #endif // defined(LANGUAGE_JAVASCRIPT) - -#if defined(V8_BINDING) && V8_BINDING - // window.toString() requires special handling in V8 - [V8DoNotCheckSignature, DoNotCheckSecurity, Custom, NotEnumerable] DOMString toString(); -#endif // defined(V8_BINDING) }; +DOMWindow implements WindowTimers; +DOMWindow implements WindowBase64; diff --git a/Source/WebCore/page/DOMWindowExtension.cpp b/Source/WebCore/page/DOMWindowExtension.cpp index e475538b2..0b0779e6b 100644 --- a/Source/WebCore/page/DOMWindowExtension.cpp +++ b/Source/WebCore/page/DOMWindowExtension.cpp @@ -29,6 +29,7 @@ #include "DOMWindow.h" #include "DOMWrapperWorld.h" #include "Frame.h" +#include "FrameLoader.h" #include "FrameLoaderClient.h" namespace WebCore { diff --git a/Source/WebCore/page/DOMWindowPagePopup.cpp b/Source/WebCore/page/DOMWindowPagePopup.cpp deleted file mode 100644 index b9fc7ca69..000000000 --- a/Source/WebCore/page/DOMWindowPagePopup.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2012 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "DOMWindowPagePopup.h" - -#if ENABLE(PAGE_POPUP) -#include "DOMWindow.h" -#include "PagePopupController.h" - -namespace WebCore { - -DOMWindowPagePopup::DOMWindowPagePopup(PagePopupClient* popupClient) - : m_controller(PagePopupController::create(popupClient)) -{ - ASSERT(popupClient); -} - -DOMWindowPagePopup::~DOMWindowPagePopup() -{ - m_controller->clearPagePopupClient(); -} - -const AtomicString& DOMWindowPagePopup::supplementName() -{ - DEFINE_STATIC_LOCAL(AtomicString, name, ("DOMWindowPagePopup", AtomicString::ConstructFromLiteral)); - return name; -} - -PagePopupController* DOMWindowPagePopup::pagePopupController(DOMWindow* window) -{ - DOMWindowPagePopup* supplement = static_cast<DOMWindowPagePopup*>(from(window, supplementName())); - ASSERT(supplement); - return supplement->m_controller.get(); -} - -void DOMWindowPagePopup::install(DOMWindow* window, PagePopupClient* popupClient) -{ - ASSERT(window); - ASSERT(popupClient); - provideTo(window, supplementName(), adoptPtr(new DOMWindowPagePopup(popupClient))); -} - -void DOMWindowPagePopup::uninstall(DOMWindow* window) -{ - ASSERT(window); - window->removeSupplement(supplementName()); -} - -} -#endif diff --git a/Source/WebCore/page/DOMWindowPagePopup.h b/Source/WebCore/page/DOMWindowPagePopup.h deleted file mode 100644 index 855997475..000000000 --- a/Source/WebCore/page/DOMWindowPagePopup.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2012 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef DOMWindowPagePopup_h -#define DOMWindowPagePopup_h - -#if ENABLE(PAGE_POPUP) -#include "Supplementable.h" - -namespace WebCore { - -class DOMWindow; -class PagePopupClient; -class PagePopupController; - -class DOMWindowPagePopup : public Supplement<DOMWindow> { -public: - static PagePopupController* pagePopupController(DOMWindow*); - static void install(DOMWindow*, PagePopupClient*); - static void uninstall(DOMWindow*); - ~DOMWindowPagePopup(); - -private: - explicit DOMWindowPagePopup(PagePopupClient*); - static const AtomicString& supplementName(); - - RefPtr<PagePopupController> m_controller; -}; - -} -#endif -#endif diff --git a/Source/WebCore/page/DOMWindowPagePopup.idl b/Source/WebCore/page/DOMWindowPagePopup.idl deleted file mode 100644 index 301d8b963..000000000 --- a/Source/WebCore/page/DOMWindowPagePopup.idl +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2012 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -[ - Conditional=PAGE_POPUP, - Supplemental=DOMWindow -] interface DOMWindowPagePopup { - [V8EnabledPerContext=pagePopup] readonly attribute PagePopupController pagePopupController; -}; diff --git a/Source/WebCore/page/DeviceController.cpp b/Source/WebCore/page/DeviceController.cpp index be270db87..02a882477 100644 --- a/Source/WebCore/page/DeviceController.cpp +++ b/Source/WebCore/page/DeviceController.cpp @@ -71,8 +71,9 @@ void DeviceController::removeAllDeviceEventListeners(DOMWindow* window) m_client->stopUpdating(); } -void DeviceController::dispatchDeviceEvent(PassRefPtr<Event> event) +void DeviceController::dispatchDeviceEvent(PassRefPtr<Event> prpEvent) { + RefPtr<Event> event = prpEvent; Vector<RefPtr<DOMWindow> > listenerVector; copyToVector(m_listeners, listenerVector); for (size_t i = 0; i < listenerVector.size(); ++i) { diff --git a/Source/WebCore/page/DiagnosticLoggingKeys.cpp b/Source/WebCore/page/DiagnosticLoggingKeys.cpp index 8f3b4d603..a4354a647 100644 --- a/Source/WebCore/page/DiagnosticLoggingKeys.cpp +++ b/Source/WebCore/page/DiagnosticLoggingKeys.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2013 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,70 +28,59 @@ namespace WebCore { -const String& DiagnosticLoggingKeys::mediaLoadedKey() +String DiagnosticLoggingKeys::mediaLoadedKey() { - DEFINE_STATIC_LOCAL(const String, key, (ASCIILiteral("mediaLoaded"))); - return key; + return ASCIILiteral("mediaLoaded"); } -const String& DiagnosticLoggingKeys::mediaLoadingFailedKey() +String DiagnosticLoggingKeys::mediaLoadingFailedKey() { - DEFINE_STATIC_LOCAL(const String, key, (ASCIILiteral("mediaFailedLoading"))); - return key; + return ASCIILiteral("mediaFailedLoading"); } -const String& DiagnosticLoggingKeys::pluginLoadedKey() +String DiagnosticLoggingKeys::pluginLoadedKey() { - DEFINE_STATIC_LOCAL(const String, key, (ASCIILiteral("pluginLoaded"))); - return key; + return ASCIILiteral("pluginLoaded"); } -const String& DiagnosticLoggingKeys::pluginLoadingFailedKey() +String DiagnosticLoggingKeys::pluginLoadingFailedKey() { - DEFINE_STATIC_LOCAL(const String, key, (ASCIILiteral("pluginFailedLoading"))); - return key; + return ASCIILiteral("pluginFailedLoading"); } -const String& DiagnosticLoggingKeys::pageContainsPluginKey() +String DiagnosticLoggingKeys::pageContainsPluginKey() { - DEFINE_STATIC_LOCAL(const String, key, (ASCIILiteral("pageContainsPlugin"))); - return key; + return ASCIILiteral("pageContainsPlugin"); } -const String& DiagnosticLoggingKeys::pageContainsAtLeastOnePluginKey() +String DiagnosticLoggingKeys::pageContainsAtLeastOnePluginKey() { - DEFINE_STATIC_LOCAL(const String, key, (ASCIILiteral("pageContainsAtLeastOnePlugin"))); - return key; + return ASCIILiteral("pageContainsAtLeastOnePlugin"); } -const String& DiagnosticLoggingKeys::pageContainsMediaEngineKey() +String DiagnosticLoggingKeys::pageContainsMediaEngineKey() { - DEFINE_STATIC_LOCAL(const String, key, (ASCIILiteral("pageContainsMediaEngine"))); - return key; + return ASCIILiteral("pageContainsMediaEngine"); } -const String& DiagnosticLoggingKeys::pageContainsAtLeastOneMediaEngineKey() +String DiagnosticLoggingKeys::pageContainsAtLeastOneMediaEngineKey() { - DEFINE_STATIC_LOCAL(const String, key, (ASCIILiteral("pageContainsAtLeastOneMediaEngine"))); - return key; + return ASCIILiteral("pageContainsAtLeastOneMediaEngine"); } -const String& DiagnosticLoggingKeys::passKey() +String DiagnosticLoggingKeys::passKey() { - DEFINE_STATIC_LOCAL(const String, key, (ASCIILiteral("pass"))); - return key; + return ASCIILiteral("pass"); } -const String& DiagnosticLoggingKeys::failKey() +String DiagnosticLoggingKeys::failKey() { - DEFINE_STATIC_LOCAL(const String, key, (ASCIILiteral("fail"))); - return key; + return ASCIILiteral("fail"); } -const String& DiagnosticLoggingKeys::noopKey() +String DiagnosticLoggingKeys::noopKey() { - DEFINE_STATIC_LOCAL(const String, key, (ASCIILiteral("noop"))); - return key; + return ASCIILiteral("noop"); } } diff --git a/Source/WebCore/page/DiagnosticLoggingKeys.h b/Source/WebCore/page/DiagnosticLoggingKeys.h index 52e8964c9..baa51563e 100644 --- a/Source/WebCore/page/DiagnosticLoggingKeys.h +++ b/Source/WebCore/page/DiagnosticLoggingKeys.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2013 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,20 +32,20 @@ namespace WebCore { class DiagnosticLoggingKeys { public: - // Message keys - static const String& mediaLoadedKey(); - static const String& mediaLoadingFailedKey(); - static const String& pluginLoadedKey(); - static const String& pluginLoadingFailedKey(); - static const String& pageContainsPluginKey(); - static const String& pageContainsAtLeastOnePluginKey(); - static const String& pageContainsMediaEngineKey(); - static const String& pageContainsAtLeastOneMediaEngineKey(); + // Message keys. + static String mediaLoadedKey(); + static String mediaLoadingFailedKey(); + static String pluginLoadedKey(); + static String pluginLoadingFailedKey(); + static String pageContainsPluginKey(); + static String pageContainsAtLeastOnePluginKey(); + static String pageContainsMediaEngineKey(); + static String pageContainsAtLeastOneMediaEngineKey(); - // Success keys - static const String& passKey(); - static const String& failKey(); - static const String& noopKey(); + // Success keys. + static String passKey(); + static String failKey(); + static String noopKey(); }; } diff --git a/Source/WebCore/page/DragController.cpp b/Source/WebCore/page/DragController.cpp index 3a0dd16d2..2537040d8 100644 --- a/Source/WebCore/page/DragController.cpp +++ b/Source/WebCore/page/DragController.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2009, 2010, 2013 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,6 +27,8 @@ #include "DragController.h" #if ENABLE(DRAG_SUPPORT) + +#include "CachedImage.h" #include "Clipboard.h" #include "ClipboardAccessPolicy.h" #include "CachedResourceLoader.h" @@ -36,10 +38,12 @@ #include "DragClient.h" #include "DragData.h" #include "DragSession.h" +#include "DragState.h" #include "Editor.h" #include "EditorClient.h" #include "Element.h" #include "EventHandler.h" +#include "ExceptionCodePlaceholder.h" #include "FloatRect.h" #include "Frame.h" #include "FrameLoadRequest.h" @@ -47,6 +51,7 @@ #include "FrameSelection.h" #include "FrameView.h" #include "HTMLAnchorElement.h" +#include "HTMLImageElement.h" #include "HTMLInputElement.h" #include "HTMLNames.h" #include "HTMLPlugInElement.h" @@ -55,9 +60,10 @@ #include "Image.h" #include "ImageOrientation.h" #include "MoveSelectionCommand.h" -#include "Node.h" #include "Page.h" #include "PlatformKeyboardEvent.h" +#include "PluginDocument.h" +#include "PluginViewBase.h" #include "RenderFileUploadControl.h" #include "RenderImage.h" #include "RenderView.h" @@ -142,10 +148,9 @@ static PassRefPtr<DocumentFragment> documentFragmentFromDragData(DragData* dragD title = url; } RefPtr<Node> anchorText = document->createTextNode(title); - ExceptionCode ec; - anchor->appendChild(anchorText, ec); + anchor->appendChild(anchorText, IGNORE_EXCEPTION); RefPtr<DocumentFragment> fragment = document->createDocumentFragment(); - fragment->appendChild(anchor, ec); + fragment->appendChild(anchor, IGNORE_EXCEPTION); return fragment.get(); } } @@ -292,7 +297,7 @@ static Element* elementUnderMouse(Document* documentUnderMouse, const IntPoint& float zoomFactor = frame ? frame->pageZoomFactor() : 1; LayoutPoint point = roundedLayoutPoint(FloatPoint(p.x() * zoomFactor, p.y() * zoomFactor)); - HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active); + HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowShadowContent); HitTestResult result(point); documentUnderMouse->renderView()->hitTest(request, result); @@ -300,9 +305,9 @@ static Element* elementUnderMouse(Document* documentUnderMouse, const IntPoint& while (n && !n->isElementNode()) n = n->parentNode(); if (n) - n = n->shadowAncestorNode(); + n = n->deprecatedShadowAncestorNode(); - return static_cast<Element*>(n); + return toElement(n); } bool DragController::tryDocumentDrag(DragData* dragData, DragDestinationAction actionMask, DragSession& dragSession) @@ -366,7 +371,7 @@ bool DragController::tryDocumentDrag(DragData* dragData, DragDestinationAction a unsigned numberOfFiles = dragData->numberOfFiles(); if (m_fileInputElementUnderMouse) { - if (m_fileInputElementUnderMouse->disabled()) + if (m_fileInputElementUnderMouse->isDisabledFormControl()) dragSession.numberOfItemsToBeAccepted = 0; else if (m_fileInputElementUnderMouse->multiple()) dragSession.numberOfItemsToBeAccepted = numberOfFiles; @@ -405,7 +410,18 @@ DragOperation DragController::operationForLoad(DragData* dragData) { ASSERT(dragData); Document* doc = m_page->mainFrame()->documentAtPoint(dragData->clientPosition()); - if (doc && (m_didInitiateDrag || doc->isPluginDocument() || doc->rendererIsEditable())) + + bool pluginDocumentAcceptsDrags = false; + + if (doc && doc->isPluginDocument()) { + const Widget* widget = toPluginDocument(doc)->pluginWidget(); + const PluginViewBase* pluginView = (widget && widget->isPluginViewBase()) ? static_cast<const PluginViewBase*>(widget) : 0; + + if (pluginView) + pluginDocumentAcceptsDrags = pluginView->shouldAllowNavigationFromDrags(); + } + + if (doc && (m_didInitiateDrag || (doc->isPluginDocument() && !pluginDocumentAcceptsDrags) || doc->rendererIsEditable())) return DragOperationNone; return dragOperation(dragData); } @@ -425,9 +441,8 @@ bool DragController::dispatchTextInputEventFor(Frame* innerFrame, DragData* drag { ASSERT(m_page->dragCaretController()->hasCaret()); String text = m_page->dragCaretController()->isContentRichlyEditable() ? "" : dragData->asPlainText(innerFrame); - Node* target = innerFrame->editor()->findEventTargetFrom(m_page->dragCaretController()->caretPosition()); - ExceptionCode ec = 0; - return target->dispatchEvent(TextEvent::createForDrop(innerFrame->document()->domWindow(), text), ec); + Node* target = innerFrame->editor().findEventTargetFrom(m_page->dragCaretController()->caretPosition()); + return target->dispatchEvent(TextEvent::createForDrop(innerFrame->document()->domWindow(), text), IGNORE_EXCEPTION); } bool DragController::concludeEditDrag(DragData* dragData) @@ -458,12 +473,12 @@ bool DragController::concludeEditDrag(DragData* dragData) if (!color.isValid()) return false; RefPtr<Range> innerRange = innerFrame->selection()->toNormalizedRange(); - RefPtr<StylePropertySet> style = StylePropertySet::create(); + RefPtr<MutableStylePropertySet> style = MutableStylePropertySet::create(); style->setProperty(CSSPropertyColor, color.serialized(), false); - if (!innerFrame->editor()->shouldApplyStyle(style.get(), innerRange.get())) + if (!innerFrame->editor().shouldApplyStyle(style.get(), innerRange.get())) return false; m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dragData); - innerFrame->editor()->applyStyle(style.get(), EditActionSetColor); + innerFrame->editor().applyStyle(style.get(), EditActionSetColor); return true; } @@ -471,7 +486,7 @@ bool DragController::concludeEditDrag(DragData* dragData) // fileInput should be the element we hit tested for, unless it was made // display:none in a drop event handler. ASSERT(fileInput == element || !fileInput->renderer()); - if (fileInput->disabled()) + if (fileInput->isDisabledFormControl()) return false; return fileInput->receiveDroppedFiles(dragData); @@ -496,7 +511,7 @@ bool DragController::concludeEditDrag(DragData* dragData) if (dragIsMove(innerFrame->selection(), dragData) || dragCaret.isContentRichlyEditable()) { bool chosePlainText = false; RefPtr<DocumentFragment> fragment = documentFragmentFromDragData(dragData, innerFrame.get(), range, true, chosePlainText); - if (!fragment || !innerFrame->editor()->shouldInsertFragment(fragment, range, EditorInsertActionDropped)) { + if (!fragment || !innerFrame->editor().shouldInsertFragment(fragment, range, EditorInsertActionDropped)) { return false; } @@ -504,7 +519,7 @@ bool DragController::concludeEditDrag(DragData* dragData) if (dragIsMove(innerFrame->selection(), dragData)) { // NSTextView behavior is to always smart delete on moving a selection, // but only to smart insert if the selection granularity is word granularity. - bool smartDelete = innerFrame->editor()->smartInsertDeleteEnabled(); + bool smartDelete = innerFrame->editor().smartInsertDeleteEnabled(); bool smartInsert = smartDelete && innerFrame->selection()->granularity() == WordGranularity && dragData->canSmartReplace(); applyCommand(MoveSelectionCommand::create(fragment, dragCaret.base(), smartInsert, smartDelete)); } else { @@ -519,7 +534,7 @@ bool DragController::concludeEditDrag(DragData* dragData) } } else { String text = dragData->asPlainText(innerFrame.get()); - if (text.isEmpty() || !innerFrame->editor()->shouldInsertText(text, range.get(), EditorInsertActionDropped)) { + if (text.isEmpty() || !innerFrame->editor().shouldInsertText(text, range.get(), EditorInsertActionDropped)) { return false; } @@ -548,7 +563,7 @@ bool DragController::canProcessDrag(DragData* dragData) if (!m_page->mainFrame()->contentRenderer()) return false; - result = m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(point, true); + result = m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(point, HitTestRequest::ReadOnly | HitTestRequest::Active); if (!result.innerNonSharedNode()) return false; @@ -620,17 +635,19 @@ bool DragController::tryDHTMLDrag(DragData* dragData, DragOperation& operation) return true; } -Node* DragController::draggableNode(const Frame* src, Node* startNode, const IntPoint& dragOrigin, DragState& state) const +Element* DragController::draggableElement(const Frame* sourceFrame, Element* startElement, const IntPoint& dragOrigin, DragState& state) const { - state.m_dragType = (src->selection()->contains(dragOrigin)) ? DragSourceActionSelection : DragSourceActionNone; + state.type = (sourceFrame->selection()->contains(dragOrigin)) ? DragSourceActionSelection : DragSourceActionNone; + if (!startElement) + return 0; - for (const RenderObject* renderer = startNode->renderer(); renderer; renderer = renderer->parent()) { - Node* node = renderer->node(); + for (const RenderObject* renderer = startElement->renderer(); renderer; renderer = renderer->parent()) { + Node* node = renderer->nonPseudoNode(); if (!node) // Anonymous render blocks don't correspond to actual DOM nodes, so we skip over them // for the purposes of finding a draggable node. continue; - if (!(state.m_dragType & DragSourceActionSelection) && node->isTextNode() && node->canStartSelection()) + if (!(state.type & DragSourceActionSelection) && node->isTextNode() && node->canStartSelection()) // In this case we have a click in the unselected portion of text. If this text is // selectable, we want to start the selection process instead of looking for a parent // to try to drag. @@ -638,29 +655,29 @@ Node* DragController::draggableNode(const Frame* src, Node* startNode, const Int if (node->isElementNode()) { EUserDrag dragMode = renderer->style()->userDrag(); if ((m_dragSourceAction & DragSourceActionDHTML) && dragMode == DRAG_ELEMENT) { - state.m_dragType = static_cast<DragSourceAction>(state.m_dragType | DragSourceActionDHTML); - return node; + state.type = static_cast<DragSourceAction>(state.type | DragSourceActionDHTML); + return toElement(node); } if (dragMode == DRAG_AUTO) { if ((m_dragSourceAction & DragSourceActionImage) - && node->hasTagName(HTMLNames::imgTag) - && src->settings() - && src->settings()->loadsImagesAutomatically()) { - state.m_dragType = static_cast<DragSourceAction>(state.m_dragType | DragSourceActionImage); - return node; + && isHTMLImageElement(node) + && sourceFrame->settings() + && sourceFrame->settings()->loadsImagesAutomatically()) { + state.type = static_cast<DragSourceAction>(state.type | DragSourceActionImage); + return toElement(node); } if ((m_dragSourceAction & DragSourceActionLink) - && node->hasTagName(HTMLNames::aTag) - && static_cast<HTMLAnchorElement*>(node)->isLiveLink()) { - state.m_dragType = static_cast<DragSourceAction>(state.m_dragType | DragSourceActionLink); - return node; + && isHTMLAnchorElement(node) + && toHTMLAnchorElement(node)->isLiveLink()) { + state.type = static_cast<DragSourceAction>(state.type | DragSourceActionLink); + return toElement(node); } } } } // We either have nothing to drag or we have a selection and we're not over a draggable element. - return (state.m_dragType & DragSourceActionSelection) ? startNode : 0; + return (state.type & DragSourceActionSelection) ? startElement : 0; } static CachedImage* getCachedImage(Element* element) @@ -688,9 +705,7 @@ static void prepareClipboardForImageDrag(Frame* source, Clipboard* clipboard, El { if (node->isContentRichlyEditable()) { RefPtr<Range> range = source->document()->createRange(); - ExceptionCode ec = 0; - range->selectNode(node, ec); - ASSERT(!ec); + range->selectNode(node, ASSERT_NO_EXCEPTION); source->selection()->setSelection(VisibleSelection(range.get(), DOWNSTREAM)); } clipboard->declareAndWriteDragImage(node, !linkURL.isEmpty() ? linkURL : imageURL, label, source); @@ -734,8 +749,8 @@ bool DragController::startDrag(Frame* src, const DragState& state, DragOperation if (!src->view() || !src->contentRenderer()) return false; - HitTestResult hitTestResult = src->eventHandler()->hitTestResultAtPoint(dragOrigin, true); - if (!state.m_dragSrc->contains(hitTestResult.innerNode())) + HitTestResult hitTestResult = src->eventHandler()->hitTestResultAtPoint(dragOrigin, HitTestRequest::ReadOnly | HitTestRequest::Active); + if (!state.source->contains(hitTestResult.innerNode())) // The original node being dragged isn't under the drag origin anymore... maybe it was // hidden or moved out from under the cursor. Regardless, we don't want to start a drag on // something that's not actually under the drag origin. @@ -752,10 +767,10 @@ bool DragController::startDrag(Frame* src, const DragState& state, DragOperation IntPoint dragLoc(0, 0); IntPoint dragImageOffset(0, 0); - Clipboard* clipboard = state.m_dragClipboard.get(); - if (state.m_dragType == DragSourceActionDHTML) + Clipboard* clipboard = state.clipboard.get(); + if (state.type == DragSourceActionDHTML) dragImage = clipboard->createDragImage(dragImageOffset); - if (state.m_dragType == DragSourceActionSelection || !imageURL.isEmpty() || !linkURL.isEmpty()) + if (state.type == DragSourceActionSelection || !imageURL.isEmpty() || !linkURL.isEmpty()) // Selection, image, and link drags receive a default set of allowed drag operations that // follows from: // http://trac.webkit.org/browser/trunk/WebKit/mac/WebView/WebHTMLView.mm?rev=48526#L3430 @@ -770,33 +785,35 @@ bool DragController::startDrag(Frame* src, const DragState& state, DragOperation bool startedDrag = true; // optimism - we almost always manage to start the drag - Node* node = state.m_dragSrc.get(); + Element* element = state.source.get(); - Image* image = getImage(static_cast<Element*>(node)); - if (state.m_dragType == DragSourceActionSelection) { + Image* image = getImage(element); + if (state.type == DragSourceActionSelection) { if (!clipboard->hasData()) { - if (enclosingTextFormControl(src->selection()->start())) - clipboard->writePlainText(src->editor()->selectedText()); - else { - RefPtr<Range> selectionRange = src->selection()->toNormalizedRange(); - ASSERT(selectionRange); + RefPtr<Range> selectionRange = src->selection()->toNormalizedRange(); + ASSERT(selectionRange); + + src->editor().willWriteSelectionToPasteboard(selectionRange.get()); + if (enclosingTextFormControl(src->selection()->start())) + clipboard->writePlainText(src->editor().selectedTextForClipboard()); + else clipboard->writeRange(selectionRange.get(), src); - } + + src->editor().didWriteSelectionToPasteboard(); } m_client->willPerformDragSourceAction(DragSourceActionSelection, dragOrigin, clipboard); if (!dragImage) { - dragImage = createDragImageForSelection(src); + dragImage = dissolveDragImageToFraction(src->dragImageForSelection(), DragImageAlpha); dragLoc = dragLocForSelectionDrag(src); m_dragOffset = IntPoint(dragOrigin.x() - dragLoc.x(), dragOrigin.y() - dragLoc.y()); } doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false); - } else if (!imageURL.isEmpty() && node && node->isElementNode() && image && !image->isNull() + } else if (!imageURL.isEmpty() && element && image && !image->isNull() && (m_dragSourceAction & DragSourceActionImage)) { // We shouldn't be starting a drag for an image that can't provide an extension. // This is an early detection for problems encountered later upon drop. ASSERT(!image->filenameExtension().isEmpty()); - Element* element = static_cast<Element*>(node); if (!clipboard->hasData()) { m_draggingImageURL = imageURL; prepareClipboardForImageDrag(src, clipboard, element, linkURL, imageURL, hitTestResult.altDisplayString()); @@ -830,18 +847,21 @@ bool DragController::startDrag(Frame* src, const DragState& state, DragOperation m_client->willPerformDragSourceAction(DragSourceActionLink, dragOrigin, clipboard); if (!dragImage) { - dragImage = createDragImageForLink(linkURL, hitTestResult.textContent(), src); + dragImage = createDragImageForLink(linkURL, hitTestResult.textContent(), src->settings() ? src->settings()->fontRenderingMode() : NormalRenderingMode); IntSize size = dragImageSize(dragImage); m_dragOffset = IntPoint(-size.width() / 2, -LinkDragBorderInset); dragLoc = IntPoint(mouseDraggedPoint.x() + m_dragOffset.x(), mouseDraggedPoint.y() + m_dragOffset.y()); } doSystemDrag(dragImage, dragLoc, mouseDraggedPoint, clipboard, src, true); - } else if (state.m_dragType == DragSourceActionDHTML) { - ASSERT(m_dragSourceAction & DragSourceActionDHTML); - m_client->willPerformDragSourceAction(DragSourceActionDHTML, dragOrigin, clipboard); - doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false); + } else if (state.type == DragSourceActionDHTML) { + if (dragImage) { + ASSERT(m_dragSourceAction & DragSourceActionDHTML); + m_client->willPerformDragSourceAction(DragSourceActionDHTML, dragOrigin, clipboard); + doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false); + } else + startedDrag = false; } else { - // draggableNode() determined an image or link node was draggable, but it turns out the + // draggableElement() determined an image or link node was draggable, but it turns out the // image or link had no URL, so there is nothing to drag. startedDrag = false; } @@ -854,7 +874,7 @@ bool DragController::startDrag(Frame* src, const DragState& state, DragOperation void DragController::doImageDrag(Element* element, const IntPoint& dragOrigin, const IntRect& rect, Clipboard* clipboard, Frame* frame, IntPoint& dragImageOffset) { IntPoint mouseDownPoint = dragOrigin; - DragImageRef dragImage; + DragImageRef dragImage = 0; IntPoint origin; Image* image = getImage(element); @@ -880,9 +900,11 @@ void DragController::doImageDrag(Element* element, const IntPoint& dragOrigin, c dy *= scale; origin.setY((int)(dy + 0.5)); } else { - dragImage = createDragImageIconForCachedImage(getCachedImage(element)); - if (dragImage) - origin = IntPoint(DragIconRightInset - dragImageSize(dragImage).width(), DragIconBottomInset); + if (CachedImage* cachedImage = getCachedImage(element)) { + dragImage = createDragImageIconForCachedImageFilename(cachedImage->response().suggestedFilename()); + if (dragImage) + origin = IntPoint(DragIconRightInset - dragImageSize(dragImage).width(), DragIconBottomInset); + } } dragImageOffset = mouseDownPoint + origin; diff --git a/Source/WebCore/page/DragController.h b/Source/WebCore/page/DragController.h index c7927cb47..9fe7a64d1 100644 --- a/Source/WebCore/page/DragController.h +++ b/Source/WebCore/page/DragController.h @@ -37,8 +37,6 @@ namespace WebCore { class Document; class DragClient; class DragData; - struct DragSession; - struct DragState; class Element; class Frame; class FrameSelection; @@ -49,7 +47,10 @@ namespace WebCore { class Page; class PlatformMouseEvent; class Range; - + + struct DragSession; + struct DragState; + class DragController { WTF_MAKE_NONCOPYABLE(DragController); WTF_MAKE_FAST_ALLOCATED; public: @@ -78,7 +79,7 @@ namespace WebCore { DragDestinationAction dragDestinationAction() const { return m_dragDestinationAction; } DragSourceAction delegateDragSourceAction(const IntPoint& rootViewPoint); - Node* draggableNode(const Frame*, Node*, const IntPoint&, DragState&) const; + Element* draggableElement(const Frame*, Element* start, const IntPoint&, DragState&) const; void dragEnded(); void placeDragCaret(const IntPoint&); @@ -109,8 +110,6 @@ namespace WebCore { void mouseMovedIntoDocument(Document*); - IntRect selectionDraggingRect(Frame*); - bool doDrag(Frame* src, Clipboard* clipboard, DragImageRef dragImage, const KURL& linkURL, const KURL& imageURL, Node* node, IntPoint& dragLoc, IntPoint& dragImageOffset); void doImageDrag(Element*, const IntPoint&, const IntRect&, Clipboard*, Frame*, IntPoint&); void doSystemDrag(DragImageRef, const IntPoint&, const IntPoint&, Clipboard*, Frame*, bool forLink); void cleanupAfterSystemDrag(); diff --git a/Source/WebCore/page/DragState.h b/Source/WebCore/page/DragState.h index 7eae9e0af..70849fdc5 100644 --- a/Source/WebCore/page/DragState.h +++ b/Source/WebCore/page/DragState.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2011 Google Inc. + * Copyright (C) 2013 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,30 +29,15 @@ #include "Clipboard.h" #include "DragActions.h" -#include "Node.h" -#include <wtf/Forward.h> -#include <wtf/Noncopyable.h> -#include <wtf/RefPtr.h> +#include "Element.h" namespace WebCore { -class Clipboard; -class Node; - struct DragState { - WTF_MAKE_NONCOPYABLE(DragState); - WTF_MAKE_FAST_ALLOCATED; -public: - enum EventDispatchPolicy { - DoNotDispatchEvents, - DispatchEvents, - }; - DragState() { } - bool shouldDispatchEvents() const { return m_eventDispatchPolicy == DispatchEvents; } - RefPtr<Node> m_dragSrc; // element that may be a drag source, for the current mouse gesture - EventDispatchPolicy m_eventDispatchPolicy; - DragSourceAction m_dragType; - RefPtr<Clipboard> m_dragClipboard; // used on only the source side of dragging + RefPtr<Element> source; // Element that may be a drag source, for the current mouse gesture. + bool shouldDispatchEvents; + DragSourceAction type; + RefPtr<Clipboard> clipboard; // Used on only the source side of dragging. }; } // namespace WebCore diff --git a/Source/WebCore/page/EditorClient.h b/Source/WebCore/page/EditorClient.h index e38fda50d..c8bb3e48e 100644 --- a/Source/WebCore/page/EditorClient.h +++ b/Source/WebCore/page/EditorClient.h @@ -52,6 +52,7 @@ class HTMLElement; class KeyboardEvent; class Node; class Range; +class SharedBuffer; class SpellChecker; class StylePropertySet; class TextCheckerClient; @@ -67,7 +68,6 @@ public: virtual void frameWillDetachPage(Frame*) = 0; virtual bool shouldDeleteRange(Range*) = 0; - virtual bool shouldShowDeleteInterface(HTMLElement*) = 0; virtual bool smartInsertDeleteEnabled() = 0; virtual bool isSelectTrailingWhitespaceEnabled() = 0; virtual bool isContinuousSpellCheckingEnabled() = 0; @@ -89,7 +89,9 @@ public: virtual void respondToChangedContents() = 0; virtual void respondToChangedSelection(Frame*) = 0; virtual void didEndEditing() = 0; + virtual void willWriteSelectionToPasteboard(Range*) = 0; virtual void didWriteSelectionToPasteboard() = 0; + virtual void getClientPasteboardDataForRange(Range*, Vector<String>& pasteboardTypes, Vector<RefPtr<SharedBuffer> >& pasteboardData) = 0; virtual void didSetSelectionTypesForPasteboard() = 0; virtual void registerUndoStep(PassRefPtr<UndoStep>) = 0; @@ -127,6 +129,7 @@ public: virtual void lowercaseWord() = 0; virtual void capitalizeWord() = 0; #endif + #if USE(AUTOMATIC_TEXT_REPLACEMENT) virtual void showSubstitutionsPanel(bool show) = 0; virtual bool substitutionsPanelIsShowing() = 0; @@ -142,6 +145,10 @@ public: virtual bool isAutomaticSpellingCorrectionEnabled() = 0; virtual void toggleAutomaticSpellingCorrection() = 0; #endif + +#if ENABLE(DELETION_UI) + virtual bool shouldShowDeleteInterface(HTMLElement*) = 0; +#endif #if PLATFORM(GTK) virtual bool shouldShowUnicodeMenu() = 0; diff --git a/Source/WebCore/page/EventHandler.cpp b/Source/WebCore/page/EventHandler.cpp index 22d616e0f..c2a172a8d 100644 --- a/Source/WebCore/page/EventHandler.cpp +++ b/Source/WebCore/page/EventHandler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2013 Apple Inc. All rights reserved. * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) * Copyright (C) 2012 Digia Plc. and/or its subsidiary(-ies) * @@ -29,10 +29,10 @@ #include "EventHandler.h" #include "AXObjectCache.h" +#include "AutoscrollController.h" #include "CachedImage.h" #include "Chrome.h" #include "ChromeClient.h" -#include "ComposedShadowTreeWalker.h" #include "Cursor.h" #include "CursorList.h" #include "Document.h" @@ -42,6 +42,8 @@ #include "Editor.h" #include "EditorClient.h" #include "EventNames.h" +#include "EventPathWalker.h" +#include "ExceptionCodePlaceholder.h" #include "FloatPoint.h" #include "FloatRect.h" #include "FocusController.h" @@ -77,7 +79,6 @@ #include "Settings.h" #include "ShadowRoot.h" #include "SpatialNavigation.h" -#include "StaticHashSetNodeList.h" #include "StyleCachedImage.h" #include "TextEvent.h" #include "TextIterator.h" @@ -111,6 +112,10 @@ #include "TouchList.h" #endif +#if ENABLE(CSS_IMAGE_SET) +#include "StyleCachedImageSet.h" +#endif + namespace WebCore { using namespace HTMLNames; @@ -133,20 +138,23 @@ const int CompositionEventKeyCode = 229; using namespace SVGNames; #endif -// When the autoscroll or the panScroll is triggered when do the scroll every 0.05s to make it smooth -const double autoscrollInterval = 0.05; +// The amount of time to wait before sending a fake mouse event, triggered +// during a scroll. The short interval is used if the content responds to the mouse events quickly enough, +// otherwise the long interval is used. +const double fakeMouseMoveShortInterval = 0.1; +const double fakeMouseMoveLongInterval = 0.250; -// The amount of time to wait before sending a fake mouse event, triggered during a scroll. -const double fakeMouseMoveMinimumInterval = 0.1; -// Amount to increase the fake mouse event throttling when the running average exceeds the delay. -// Picked fairly arbitrarily. -const double fakeMouseMoveIntervalIncrease = 0.05; -const double fakeMouseMoveRunningAverageCount = 10; -// Decrease the fakeMouseMoveInterval when the current delay is >2x the running average, -// but only decrease to 3/4 the current delay to avoid too much thrashing. -// Not sure this distinction really matters in practice. -const double fakeMouseMoveIntervalReductionLimit = 0.5; -const double fakeMouseMoveIntervalReductionFraction = 0.75; +// The amount of time to wait for a cursor update on style and layout changes +// Set to 50Hz, no need to be faster than common screen refresh rate +const double cursorUpdateInterval = 0.02; + +const int maximumCursorSize = 128; +#if ENABLE(MOUSE_CURSOR_SCALE) +// It's pretty unlikely that a scale of less than one would ever be used. But all we really +// need to ensure here is that the scale isn't so small that integer overflow can occur when +// dividing cursor sizes (limited above) by the scale. +const double minimumCursorScale = 0.001; +#endif enum NoCursorChangeType { NoCursorChange }; @@ -163,28 +171,21 @@ private: Cursor m_cursor; }; -class RunningAverageDurationTracker { +class MaximumDurationTracker { public: - RunningAverageDurationTracker(double* average, unsigned numberOfRunsToTrack) - : m_average(average) - , m_numberOfRunsToTrack(numberOfRunsToTrack) + explicit MaximumDurationTracker(double *maxDuration) + : m_maxDuration(maxDuration) , m_start(monotonicallyIncreasingTime()) { } - ~RunningAverageDurationTracker() + ~MaximumDurationTracker() { - double duration = monotonicallyIncreasingTime() - m_start; - if (!*m_average) { - *m_average = duration; - return; - } - *m_average = (*m_average * (m_numberOfRunsToTrack - 1) + (duration)) / m_numberOfRunsToTrack; + *m_maxDuration = max(*m_maxDuration, monotonicallyIncreasingTime() - m_start); } private: - double* m_average; - unsigned m_numberOfRunsToTrack; + double* m_maxDuration; double m_start; }; @@ -255,17 +256,18 @@ public: }; #endif -static inline ScrollGranularity wheelGranularityToScrollGranularity(WheelEvent::Granularity granularity) +static inline ScrollGranularity wheelGranularityToScrollGranularity(unsigned deltaMode) { - switch (granularity) { - case WheelEvent::Page: + switch (deltaMode) { + case WheelEvent::DOM_DELTA_PAGE: return ScrollByPage; - case WheelEvent::Line: + case WheelEvent::DOM_DELTA_LINE: return ScrollByLine; - case WheelEvent::Pixel: + case WheelEvent::DOM_DELTA_PIXEL: + return ScrollByPixel; + default: return ScrollByPixel; } - return ScrollByPixel; } static inline bool scrollNode(float delta, ScrollGranularity granularity, ScrollDirection positiveDirection, ScrollDirection negativeDirection, Node* node, Node** stopNode) @@ -279,31 +281,13 @@ static inline bool scrollNode(float delta, ScrollGranularity granularity, Scroll return enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, granularity, absDelta, stopNode); } -static Node* closestScrollableNodeInDocumentIfPossible(Node* node) -{ - for (Node* scrollableNode = node; scrollableNode; scrollableNode = scrollableNode->parentNode()) { - if (scrollableNode->isDocumentNode()) - break; - RenderObject* renderer = scrollableNode->renderer(); - if (renderer && renderer->isBox() && toRenderBox(renderer)->canBeScrolledAndHasScrollableArea()) - return scrollableNode; - } - return node; -} - -#if ENABLE(GESTURE_EVENTS) static inline bool shouldGesturesTriggerActive() { // If the platform we're on supports GestureTapDown and GestureTapCancel then we'll // rely on them to set the active state. Unfortunately there's no generic way to // know in advance what event types are supported. -#if PLATFORM(CHROMIUM) && !OS(ANDROID) - return true; -#else return false; -#endif } -#endif #if !PLATFORM(MAC) @@ -332,22 +316,19 @@ EventHandler::EventHandler(Frame* frame) #endif , m_mouseDownWasSingleClickInSelection(false) , m_selectionInitiationState(HaveNotStartedSelection) - , m_panScrollInProgress(false) - , m_panScrollButtonPressed(false) - , m_springLoadedPanScrollInProgress(false) , m_hoverTimer(this, &EventHandler::hoverTimerFired) - , m_autoscrollTimer(this, &EventHandler::autoscrollTimerFired) - , m_autoscrollRenderer(0) - , m_autoscrollInProgress(false) + , m_cursorUpdateTimer(this, &EventHandler::cursorUpdateTimerFired) + , m_autoscrollController(adoptPtr(new AutoscrollController)) , m_mouseDownMayStartAutoscroll(false) , m_mouseDownWasInSubframe(false) - , m_fakeMouseMoveEventTimer(this, &EventHandler::fakeMouseMoveEventTimerFired, fakeMouseMoveMinimumInterval) + , m_fakeMouseMoveEventTimer(this, &EventHandler::fakeMouseMoveEventTimerFired) #if ENABLE(SVG) , m_svgPan(false) #endif , m_resizeLayer(0) , m_eventHandlerWillResetCapturingMouseEventsNode(0) , m_clickCount(0) + , m_mousePositionIsUnknown(true) , m_mouseDownTimestamp(0) , m_widgetIsLatched(false) #if PLATFORM(MAC) @@ -356,18 +337,30 @@ EventHandler::EventHandler(Frame* frame) , m_activationEventNumber(-1) #endif #if ENABLE(TOUCH_EVENTS) + , m_originatingTouchPointTargetKey(0) , m_touchPressed(false) #endif - , m_mouseMovedDurationRunningAverage(0) +#if ENABLE(GESTURE_EVENTS) + , m_scrollGestureHandlingNode(0) + , m_lastHitTestResultOverWidget(false) +#endif + , m_maxMouseMovedDuration(0) , m_baseEventType(PlatformEvent::NoType) , m_didStartDrag(false) , m_didLongPressInvokeContextMenu(false) + , m_isHandlingWheelEvent(false) +#if ENABLE(CURSOR_VISIBILITY) + , m_autoHideCursorTimer(this, &EventHandler::autoHideCursorTimerFired) +#endif { } EventHandler::~EventHandler() { ASSERT(!m_fakeMouseMoveEventTimer.isActive()); +#if ENABLE(CURSOR_VISIBILITY) + ASSERT(!m_autoHideCursorTimer.isActive()); +#endif } #if ENABLE(DRAG_SUPPORT) @@ -381,7 +374,11 @@ DragState& EventHandler::dragState() void EventHandler::clear() { m_hoverTimer.stop(); + m_cursorUpdateTimer.stop(); m_fakeMouseMoveEventTimer.stop(); +#if ENABLE(CURSOR_VISIBILITY) + cancelAutoHideCursorTimer(); +#endif m_resizeLayer = 0; m_nodeUnderMouse = 0; m_lastNodeUnderMouse = 0; @@ -398,8 +395,9 @@ void EventHandler::clear() m_dragTarget = 0; m_shouldOnlyFireDragOverEvent = false; #endif - m_currentMousePosition = IntPoint(); - m_currentMouseGlobalPosition = IntPoint(); + m_mousePositionIsUnknown = true; + m_lastKnownMousePosition = IntPoint(); + m_lastKnownMouseGlobalPosition = IntPoint(); m_mousePressNode = 0; m_mousePressed = false; m_capturesDragging = false; @@ -408,12 +406,16 @@ void EventHandler::clear() m_previousWheelScrolledNode = 0; #if ENABLE(TOUCH_EVENTS) m_originatingTouchPointTargets.clear(); + m_originatingTouchPointDocument.clear(); + m_originatingTouchPointTargetKey = 0; #endif #if ENABLE(GESTURE_EVENTS) m_scrollGestureHandlingNode = 0; + m_lastHitTestResultOverWidget = false; + m_previousGestureScrolledNode = 0; m_scrollbarHandlingScrollGesture = 0; #endif - m_mouseMovedDurationRunningAverage = 0; + m_maxMouseMovedDuration = 0; m_baseEventType = PlatformEvent::NoType; m_didStartDrag = false; m_didLongPressInvokeContextMenu = false; @@ -440,7 +442,25 @@ static inline bool dispatchSelectStart(Node* node) return node->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true)); } -bool EventHandler::updateSelectionForMouseDownDispatchingSelectStart(Node* targetNode, const VisibleSelection& newSelection, TextGranularity granularity) +static VisibleSelection expandSelectionToRespectUserSelectAll(Node* targetNode, const VisibleSelection& selection) +{ +#if ENABLE(USERSELECT_ALL) + Node* rootUserSelectAll = Position::rootUserSelectAllForNode(targetNode); + if (!rootUserSelectAll) + return selection; + + VisibleSelection newSelection(selection); + newSelection.setBase(positionBeforeNode(rootUserSelectAll).upstream(CanCrossEditingBoundary)); + newSelection.setExtent(positionAfterNode(rootUserSelectAll).downstream(CanCrossEditingBoundary)); + + return newSelection; +#else + UNUSED_PARAM(targetNode); + return selection; +#endif +} + +bool EventHandler::updateSelectionForMouseDownDispatchingSelectStart(Node* targetNode, const VisibleSelection& selection, TextGranularity granularity) { if (Position::nodeIsUserSelectNone(targetNode)) return false; @@ -448,13 +468,6 @@ bool EventHandler::updateSelectionForMouseDownDispatchingSelectStart(Node* targe if (!dispatchSelectStart(targetNode)) return false; - VisibleSelection selection(newSelection); -#if ENABLE(USERSELECT_ALL) - if (Node* rootUserSelectAll = Position::rootUserSelectAllForNode(targetNode)) { - selection.setBase(positionBeforeNode(rootUserSelectAll).upstream(CanCrossEditingBoundary)); - selection.setExtent(positionAfterNode(rootUserSelectAll).downstream(CanCrossEditingBoundary)); - } -#endif if (selection.isRange()) m_selectionInitiationState = ExtendedSelection; else { @@ -482,7 +495,7 @@ void EventHandler::selectClosestWordFromHitTestResult(const HitTestResult& resul if (appendTrailingWhitespace == ShouldAppendTrailingWhitespace && newSelection.isRange()) newSelection.appendTrailingWhitespace(); - updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, WordGranularity); + updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), WordGranularity); } } @@ -490,7 +503,7 @@ void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestRe { if (m_mouseDownMayStartSelect) { selectClosestWordFromHitTestResult(result.hitTestResult(), - (result.event().clickCount() == 2 && m_frame->editor()->isSelectTrailingWhitespaceEnabled()) ? ShouldAppendTrailingWhitespace : DontAppendTrailingWhitespace); + (result.event().clickCount() == 2 && m_frame->editor().isSelectTrailingWhitespaceEnabled()) ? ShouldAppendTrailingWhitespace : DontAppendTrailingWhitespace); } } @@ -508,7 +521,7 @@ void EventHandler::selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHit if (pos.isNotNull() && pos.deepEquivalent().deprecatedNode()->isDescendantOf(URLElement)) newSelection = VisibleSelection::selectionFromContentsOfNode(URLElement); - updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, WordGranularity); + updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), WordGranularity); } } @@ -546,7 +559,7 @@ bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestR newSelection.expandUsingGranularity(ParagraphGranularity); } - return updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, ParagraphGranularity); + return updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), ParagraphGranularity); } static int textDistance(const Position& start, const Position& end) @@ -584,8 +597,15 @@ bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestR TextGranularity granularity = CharacterGranularity; if (extendSelection && newSelection.isCaretOrRange()) { - ASSERT(m_frame->settings()); - if (m_frame->settings()->editingBehaviorType() == EditingMacBehavior) { + VisibleSelection selectionInUserSelectAll = expandSelectionToRespectUserSelectAll(innerNode, VisibleSelection(pos)); + if (selectionInUserSelectAll.isRange()) { + if (comparePositions(selectionInUserSelectAll.start(), newSelection.start()) < 0) + pos = selectionInUserSelectAll.start(); + else if (comparePositions(newSelection.end(), selectionInUserSelectAll.end()) < 0) + pos = selectionInUserSelectAll.end(); + } + + if (!m_frame->editor().behavior().shouldConsiderSelectionAsDirectional() && pos.isNotNull()) { // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection // was created right-to-left Position start = newSelection.start(); @@ -604,8 +624,8 @@ bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestR newSelection.expandUsingGranularity(m_frame->selection()->granularity()); } } else - newSelection = VisibleSelection(visiblePos); - + newSelection = expandSelectionToRespectUserSelectAll(innerNode, visiblePos); + bool handled = updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, granularity); if (event.event().button() == MiddleButton) { @@ -620,17 +640,14 @@ static inline bool canMouseDownStartSelect(Node* node) if (!node || !node->renderer()) return true; - if (!node->canStartSelection()) - return false; - - return true; + return node->canStartSelection() || Position::nodeIsUserSelectAll(node); } bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& event) { #if ENABLE(DRAG_SUPPORT) // Reset drag state. - dragState().m_dragSrc = 0; + dragState().source = 0; #endif cancelFakeMouseMoveEvent(); @@ -645,8 +662,8 @@ bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& eve bool singleClick = event.event().clickCount() <= 1; // If we got the event back, that must mean it wasn't prevented, - // so it's allowed to start a drag or selection. - m_mouseDownMayStartSelect = canMouseDownStartSelect(event.targetNode()); + // so it's allowed to start a drag or selection if it wasn't in a scrollbar. + m_mouseDownMayStartSelect = canMouseDownStartSelect(event.targetNode()) && !event.scrollbar(); #if ENABLE(DRAG_SUPPORT) // Careful that the drag starting logic stays in sync with eventMayStartDrag() @@ -662,10 +679,10 @@ bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& eve #if ENABLE(SVG) if (m_frame->document()->isSVGDocument() - && static_cast<SVGDocument*>(m_frame->document())->zoomAndPanEnabled()) { + && toSVGDocument(m_frame->document())->zoomAndPanEnabled()) { if (event.event().shiftKey() && singleClick) { m_svgPan = true; - static_cast<SVGDocument*>(m_frame->document())->startPan(m_frame->view()->windowToContents(event.event().position())); + toSVGDocument(m_frame->document())->startPan(m_frame->view()->windowToContents(event.event().position())); return true; } } @@ -700,46 +717,26 @@ bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& eve return swallowEvent; } -// There are two kinds of renderer that can autoscroll. -static bool canAutoscroll(RenderObject* renderer) -{ - if (!renderer->isBox()) - return false; - - // Check for a box that can be scrolled in its own right. - if (toRenderBox(renderer)->canBeScrolledAndHasScrollableArea()) - return true; - - // Check for a box that represents the top level of a web page. - // This can be scrolled by calling Chrome::scrollRectIntoView. - // This only has an effect on the Mac platform in applications - // that put web views into scrolling containers, such as Mac OS X Mail. - // The code for this is in RenderLayer::scrollRectToVisible. - if (renderer->node() != renderer->document()) - return false; - Frame* frame = renderer->frame(); - if (!frame) - return false; - Page* page = frame->page(); - return page && page->mainFrame() == frame; -} - #if ENABLE(DRAG_SUPPORT) bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& event) { - if (handleDrag(event, ShouldCheckDragHysteresis)) - return true; - if (!m_mousePressed) return false; + if (handleDrag(event, ShouldCheckDragHysteresis)) + return true; + Node* targetNode = event.targetNode(); if (event.event().button() != LeftButton || !targetNode) return false; RenderObject* renderer = targetNode->renderer(); if (!renderer) { - renderer = targetNode->parentNode() ? targetNode->parentNode()->renderer() : 0; + Node* parent = EventPathWalker::parent(targetNode); + if (!parent) + return false; + + renderer = parent->renderer(); if (!renderer || !renderer->isListBox()) return false; } @@ -750,25 +747,13 @@ bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& e m_mouseDownMayStartDrag = false; - if (m_mouseDownMayStartAutoscroll && !m_panScrollInProgress) { - // Find a renderer that can autoscroll. - while (renderer && !canAutoscroll(renderer)) { - if (!renderer->parent() && renderer->node() == renderer->document() && renderer->document()->ownerElement()) - renderer = renderer->document()->ownerElement()->renderer(); - else - renderer = renderer->parent(); - } - - if (renderer) { - m_autoscrollInProgress = true; - handleAutoscroll(renderer); - } - + if (m_mouseDownMayStartAutoscroll && !panScrollInProgress()) { + m_autoscrollController->startAutoscrollForSelection(renderer); m_mouseDownMayStartAutoscroll = false; } if (m_selectionInitiationState != ExtendedSelection) { - HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active); + HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowShadowContent); HitTestResult result(m_mouseDownPos); m_frame->document()->renderView()->hitTest(request, result); @@ -799,11 +784,11 @@ bool EventHandler::eventMayStartDrag(const PlatformMouseEvent& event) const return false; updateDragSourceActionsAllowed(); - HitTestRequest request(HitTestRequest::ReadOnly); + HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowShadowContent); HitTestResult result(view->windowToContents(event.position())); m_frame->contentRenderer()->hitTest(request, result); DragState state; - return result.innerNode() && page->dragController()->draggableNode(m_frame, result.innerNode(), result.roundedPointInInnerNodeFrame(), state); + return result.innerElement() && page->dragController()->draggableElement(m_frame, result.innerElement(), result.roundedPointInInnerNodeFrame(), state); } void EventHandler::updateSelectionForMouseDrag() @@ -815,10 +800,8 @@ void EventHandler::updateSelectionForMouseDrag() if (!renderer) return; - HitTestRequest request(HitTestRequest::ReadOnly | - HitTestRequest::Active | - HitTestRequest::Move); - HitTestResult result(view->windowToContents(m_currentMousePosition)); + HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::Move | HitTestRequest::DisallowShadowContent); + HitTestResult result(view->windowToContents(m_lastKnownMousePosition)); renderer->hitTest(request, result); updateSelectionForMouseDrag(result); } @@ -931,7 +914,7 @@ bool EventHandler::handleMouseUp(const MouseEventWithHitTestResults& event) bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event) { - if (m_autoscrollInProgress) + if (autoscrollInProgress()) stopAutoscrollTimer(); if (handleMouseUp(event)) @@ -939,7 +922,6 @@ bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& e // Used to prevent mouseMoveEvent from initiating a drag before // the mouse is pressed again. - m_frame->selection()->setCaretBlinkingSuspended(false); m_mousePressed = false; m_capturesDragging = false; #if ENABLE(DRAG_SUPPORT) @@ -986,132 +968,46 @@ bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& e return handled; } -void EventHandler::handleAutoscroll(RenderObject* renderer) -{ - // We don't want to trigger the autoscroll or the panScroll if it's already active - if (m_autoscrollTimer.isActive()) - return; - - setAutoscrollRenderer(renderer); - #if ENABLE(PAN_SCROLLING) - if (m_panScrollInProgress) { - m_panScrollStartPos = currentMousePosition(); - if (FrameView* view = m_frame->view()) - view->addPanScrollIcon(m_panScrollStartPos); - // If we're not in the top frame we notify it that we doing a panScroll. - if (Page* page = m_frame->page()) { - Frame* mainFrame = page->mainFrame(); - if (m_frame != mainFrame) - mainFrame->eventHandler()->m_panScrollInProgress = true; - } - } -#endif - - startAutoscrollTimer(); -} -void EventHandler::autoscrollTimerFired(Timer<EventHandler>*) +void EventHandler::didPanScrollStart() { - RenderObject* r = autoscrollRenderer(); - if (!r || !r->isBox()) { - stopAutoscrollTimer(); - return; - } - - if (m_autoscrollInProgress) { - if (!m_mousePressed) { - stopAutoscrollTimer(); - return; - } - toRenderBox(r)->autoscroll(); - } else { - // we verify that the main frame hasn't received the order to stop the panScroll - if (Page* page = m_frame->page()) { - if (!page->mainFrame()->eventHandler()->m_panScrollInProgress) { - stopAutoscrollTimer(); - return; - } - } -#if ENABLE(PAN_SCROLLING) - updatePanScrollState(); - toRenderBox(r)->panScroll(m_panScrollStartPos); -#endif - } + m_autoscrollController->didPanScrollStart(); } -#if ENABLE(PAN_SCROLLING) - -void EventHandler::startPanScrolling(RenderObject* renderer) +void EventHandler::didPanScrollStop() { - m_panScrollInProgress = true; - m_panScrollButtonPressed = true; - handleAutoscroll(renderer); - invalidateClick(); + m_autoscrollController->didPanScrollStop(); } -void EventHandler::updatePanScrollState() +void EventHandler::startPanScrolling(RenderObject* renderer) { - FrameView* view = m_frame->view(); - if (!view) + if (!renderer->isBox()) return; - - // At the original click location we draw a 4 arrowed icon. Over this icon there won't be any scroll - // So we don't want to change the cursor over this area - bool east = m_panScrollStartPos.x() < (m_currentMousePosition.x() - ScrollView::noPanScrollRadius); - bool west = m_panScrollStartPos.x() > (m_currentMousePosition.x() + ScrollView::noPanScrollRadius); - bool north = m_panScrollStartPos.y() > (m_currentMousePosition.y() + ScrollView::noPanScrollRadius); - bool south = m_panScrollStartPos.y() < (m_currentMousePosition.y() - ScrollView::noPanScrollRadius); - - if ((east || west || north || south) && m_panScrollButtonPressed) - m_springLoadedPanScrollInProgress = true; - - if (north) { - if (east) - view->setCursor(northEastPanningCursor()); - else if (west) - view->setCursor(northWestPanningCursor()); - else - view->setCursor(northPanningCursor()); - } else if (south) { - if (east) - view->setCursor(southEastPanningCursor()); - else if (west) - view->setCursor(southWestPanningCursor()); - else - view->setCursor(southPanningCursor()); - } else if (east) - view->setCursor(eastPanningCursor()); - else if (west) - view->setCursor(westPanningCursor()); - else - view->setCursor(middlePanningCursor()); + m_autoscrollController->startPanScrolling(toRenderBox(renderer), lastKnownMousePosition()); + invalidateClick(); } #endif // ENABLE(PAN_SCROLLING) RenderObject* EventHandler::autoscrollRenderer() const { - return m_autoscrollRenderer; + return m_autoscrollController->autoscrollRenderer(); } void EventHandler::updateAutoscrollRenderer() { - if (!m_autoscrollRenderer) - return; - - HitTestResult hitTest = hitTestResultAtPoint(m_panScrollStartPos, true); - - if (Node* nodeAtPoint = hitTest.innerNode()) - m_autoscrollRenderer = nodeAtPoint->renderer(); + m_autoscrollController->updateAutoscrollRenderer(); +} - while (m_autoscrollRenderer && !canAutoscroll(m_autoscrollRenderer)) - m_autoscrollRenderer = m_autoscrollRenderer->parent(); +bool EventHandler::autoscrollInProgress() const +{ + return m_autoscrollController->autoscrollInProgress(); } -void EventHandler::setAutoscrollRenderer(RenderObject* renderer) +bool EventHandler::panScrollInProgress() const { - m_autoscrollRenderer = renderer; + return m_autoscrollController->panScrollInProgress(); } #if ENABLE(DRAG_SUPPORT) @@ -1132,7 +1028,7 @@ DragSourceAction EventHandler::updateDragSourceActionsAllowed() const } #endif // ENABLE(DRAG_SUPPORT) -HitTestResult EventHandler::hitTestResultAtPoint(const LayoutPoint& point, bool allowShadowContent, bool ignoreClipping, HitTestScrollbars testScrollbars, HitTestRequest::HitTestRequestType hitType, const LayoutSize& padding) +HitTestResult EventHandler::hitTestResultAtPoint(const LayoutPoint& point, HitTestRequest::HitTestRequestType hitType, const LayoutSize& padding) { // We always send hitTestResultAtPoint to the main frame if we have one, // otherwise we might hit areas that are obscured by higher frames. @@ -1143,7 +1039,7 @@ HitTestResult EventHandler::hitTestResultAtPoint(const LayoutPoint& point, bool FrameView* mainView = mainFrame->view(); if (frameView && mainView) { IntPoint mainFramePoint = mainView->rootViewToContents(frameView->contentsToRootView(roundedIntPoint(point))); - return mainFrame->eventHandler()->hitTestResultAtPoint(mainFramePoint, allowShadowContent, ignoreClipping, testScrollbars, hitType, padding); + return mainFrame->eventHandler()->hitTestResultAtPoint(mainFramePoint, hitType, padding); } } } @@ -1152,89 +1048,22 @@ HitTestResult EventHandler::hitTestResultAtPoint(const LayoutPoint& point, bool if (!m_frame->contentRenderer()) return result; - if (ignoreClipping) - hitType |= HitTestRequest::IgnoreClipping; - if (allowShadowContent) - hitType |= HitTestRequest::AllowShadowContent; - HitTestRequest request(hitType); - m_frame->contentRenderer()->hitTest(request, result); - while (true) { - Node* n = result.innerNode(); - if (!result.isOverWidget() || !n || !n->renderer() || !n->renderer()->isWidget()) - break; - RenderWidget* renderWidget = toRenderWidget(n->renderer()); - Widget* widget = renderWidget->widget(); - if (!widget || !widget->isFrameView()) - break; - Frame* frame = static_cast<HTMLFrameElementBase*>(n)->contentFrame(); - if (!frame || !frame->contentRenderer()) - break; - FrameView* view = static_cast<FrameView*>(widget); - LayoutPoint widgetPoint(result.localPoint().x() + view->scrollX() - renderWidget->borderLeft() - renderWidget->paddingLeft(), - result.localPoint().y() + view->scrollY() - renderWidget->borderTop() - renderWidget->paddingTop()); - HitTestResult widgetHitTestResult(widgetPoint, padding.height(), padding.width(), padding.height(), padding.width()); - widgetHitTestResult.setPointInMainFrame(result.pointInMainFrame()); - frame->contentRenderer()->hitTest(request, widgetHitTestResult); - result = widgetHitTestResult; - - if (testScrollbars == ShouldHitTestScrollbars) { - Scrollbar* eventScrollbar = view->scrollbarAtPoint(roundedIntPoint(point)); - if (eventScrollbar) - result.setScrollbar(eventScrollbar); - } - } + // hitTestResultAtPoint is specifically used to hitTest into all frames, thus it always allows child frame content. + HitTestRequest request(hitType | HitTestRequest::AllowChildFrameContent); + m_frame->contentRenderer()->hitTest(request, result); + if (!request.readOnly()) + m_frame->document()->updateHoverActiveState(request, result.innerElement()); - if (!allowShadowContent) + if (request.disallowsShadowContent()) result.setToNonShadowAncestor(); return result; } - -void EventHandler::startAutoscrollTimer() -{ - m_autoscrollTimer.startRepeating(autoscrollInterval); -} - void EventHandler::stopAutoscrollTimer(bool rendererIsBeingDestroyed) { - if (m_autoscrollInProgress) { - if (m_mouseDownWasInSubframe) { - if (Frame* subframe = subframeForTargetNode(m_mousePressNode.get())) - subframe->eventHandler()->stopAutoscrollTimer(rendererIsBeingDestroyed); - return; - } - } - - if (autoscrollRenderer()) { - if (!rendererIsBeingDestroyed && (m_autoscrollInProgress || m_panScrollInProgress)) - toRenderBox(autoscrollRenderer())->stopAutoscroll(); -#if ENABLE(PAN_SCROLLING) - if (m_panScrollInProgress) { - if (FrameView* view = m_frame->view()) { - view->removePanScrollIcon(); - view->setCursor(pointerCursor()); - } - } -#endif - - setAutoscrollRenderer(0); - } - - m_autoscrollTimer.stop(); - - m_panScrollInProgress = false; - m_springLoadedPanScrollInProgress = false; - - // If we're not in the top frame we notify it that we are not doing a panScroll any more. - if (Page* page = m_frame->page()) { - Frame* mainFrame = page->mainFrame(); - if (m_frame != mainFrame) - mainFrame->eventHandler()->m_panScrollInProgress = false; - } - - m_autoscrollInProgress = false; + m_autoscrollController->stopAutoscrollTimer(rendererIsBeingDestroyed); } Node* EventHandler::mousePressNode() const @@ -1252,7 +1081,7 @@ bool EventHandler::scrollOverflow(ScrollDirection direction, ScrollGranularity g Node* node = startingNode; if (!node) - node = m_frame->document()->focusedNode(); + node = m_frame->document()->focusedElement(); if (!node) node = m_mousePressNode.get(); @@ -1273,7 +1102,7 @@ bool EventHandler::logicalScrollOverflow(ScrollLogicalDirection direction, Scrol Node* node = startingNode; if (!node) - node = m_frame->document()->focusedNode(); + node = m_frame->document()->focusedElement(); if (!node) node = m_mousePressNode.get(); @@ -1335,9 +1164,9 @@ bool EventHandler::logicalScrollRecursively(ScrollLogicalDirection direction, Sc return frame->eventHandler()->logicalScrollRecursively(direction, granularity, m_frame->ownerElement()); } -IntPoint EventHandler::currentMousePosition() const +IntPoint EventHandler::lastKnownMousePosition() const { - return m_currentMousePosition; + return m_lastKnownMousePosition; } Frame* EventHandler::subframeForHitTestResult(const MouseEventWithHitTestResults& hitTestResult) @@ -1360,12 +1189,12 @@ Frame* EventHandler::subframeForTargetNode(Node* node) if (!widget || !widget->isFrameView()) return 0; - return static_cast<FrameView*>(widget)->frame(); + return toFrameView(widget)->frame(); } static bool isSubmitImage(Node* node) { - return node && node->hasTagName(inputTag) && static_cast<HTMLInputElement*>(node)->isImageButton(); + return node && isHTMLInputElement(node) && toHTMLInputElement(node)->isImageButton(); } // Returns true if the node's editable block is not current focused for editing @@ -1409,7 +1238,50 @@ bool EventHandler::useHandCursor(Node* node, bool isOverLink, bool shiftKey) return ((isOverLink || isSubmitImage(node)) && (!editable || editableLinkEnabled)); } -OptionalCursor EventHandler::selectCursor(const MouseEventWithHitTestResults& event, Scrollbar* scrollbar) +void EventHandler::cursorUpdateTimerFired(Timer<EventHandler>*) +{ + ASSERT(m_frame); + ASSERT(m_frame->document()); + + updateCursor(); +} + +void EventHandler::updateCursor() +{ + if (m_mousePositionIsUnknown) + return; + + FrameView* view = m_frame->view(); + if (!view) + return; + + RenderView* renderView = view->renderView(); + if (!renderView) + return; + + if (!view->shouldSetCursor()) + return; + + bool shiftKey; + bool ctrlKey; + bool altKey; + bool metaKey; + PlatformKeyboardEvent::getCurrentModifierState(shiftKey, ctrlKey, altKey, metaKey); + + m_frame->document()->updateLayout(); + + HitTestRequest request(HitTestRequest::ReadOnly); + HitTestResult result(view->windowToContents(m_lastKnownMousePosition)); + renderView->hitTest(request, result); + + OptionalCursor optionalCursor = selectCursor(result, shiftKey); + if (optionalCursor.isCursorChange()) { + m_currentMouseCursor = optionalCursor.cursor(); + view->setCursor(m_currentMouseCursor); + } +} + +OptionalCursor EventHandler::selectCursor(const HitTestResult& result, bool shiftKey) { if (m_resizeLayer && m_resizeLayer->inResizeMode()) return NoCursorChange; @@ -1417,15 +1289,28 @@ OptionalCursor EventHandler::selectCursor(const MouseEventWithHitTestResults& ev Page* page = m_frame->page(); if (!page) return NoCursorChange; - if (page->mainFrame()->eventHandler()->m_panScrollInProgress) +#if ENABLE(PAN_SCROLLING) + if (page->mainFrame()->eventHandler()->panScrollInProgress()) + return NoCursorChange; +#endif + + Node* node = result.targetNode(); + if (!node) return NoCursorChange; - Node* node = event.targetNode(); - RenderObject* renderer = node ? node->renderer() : 0; + RenderObject* renderer = node->renderer(); RenderStyle* style = renderer ? renderer->style() : 0; bool horizontalText = !style || style->isHorizontalWritingMode(); const Cursor& iBeam = horizontalText ? iBeamCursor() : verticalTextCursor(); +#if ENABLE(CURSOR_VISIBILITY) + if (style && style->cursorVisibility() == CursorVisibilityAutoHide) { + FeatureObserver::observe(m_frame->document(), FeatureObserver::CursorVisibility); + startAutoHideCursorTimer(); + } else + cancelAutoHideCursorTimer(); +#endif + // During selection, use an I-beam no matter what we're over. // If a drag may be starting or we're capturing mouse events for a particular node, don't treat this as a selection. if (m_mousePressed && m_mouseDownMayStartSelect @@ -1437,7 +1322,7 @@ OptionalCursor EventHandler::selectCursor(const MouseEventWithHitTestResults& ev if (renderer) { Cursor overrideCursor; - switch (renderer->getCursor(roundedIntPoint(event.localPoint()), overrideCursor)) { + switch (renderer->getCursor(roundedIntPoint(result.localPoint()), overrideCursor)) { case SetCursorBasedOnStyle: break; case SetCursor: @@ -1450,37 +1335,53 @@ OptionalCursor EventHandler::selectCursor(const MouseEventWithHitTestResults& ev if (style && style->cursors()) { const CursorList* cursors = style->cursors(); for (unsigned i = 0; i < cursors->size(); ++i) { - CachedImage* cimage = 0; - StyleImage* image = (*cursors)[i].image(); - if (image && image->isCachedImage()) - cimage = static_cast<StyleCachedImage*>(image)->cachedImage(); - if (!cimage) + StyleImage* styleImage = (*cursors)[i].image(); + if (!styleImage) continue; + CachedImage* cachedImage = styleImage->cachedImage(); + if (!cachedImage) + continue; + float scale = styleImage->imageScaleFactor(); + // Get hotspot and convert from logical pixels to physical pixels. IntPoint hotSpot = (*cursors)[i].hotSpot(); - // Limit the size of cursors so that they cannot be used to cover UI elements in chrome. - IntSize size = cimage->imageForRenderer(renderer)->size(); - if (size.width() > 128 || size.height() > 128) + hotSpot.scale(scale, scale); + IntSize size = cachedImage->imageForRenderer(renderer)->size(); + if (cachedImage->errorOccurred()) + continue; + // Limit the size of cursors (in UI pixels) so that they cannot be + // used to cover UI elements in chrome. + size.scale(1 / scale); + if (size.width() > maximumCursorSize || size.height() > maximumCursorSize) + continue; + + Image* image = cachedImage->imageForRenderer(renderer); +#if ENABLE(MOUSE_CURSOR_SCALE) + // Ensure no overflow possible in calculations above. + if (scale < minimumCursorScale) continue; - if (!cimage->errorOccurred()) - return Cursor(cimage->imageForRenderer(renderer), hotSpot); + return Cursor(image, hotSpot, scale); +#else + ASSERT(scale == 1); + return Cursor(image, hotSpot); +#endif // ENABLE(MOUSE_CURSOR_SCALE) } } switch (style ? style->cursor() : CURSOR_AUTO) { case CURSOR_AUTO: { - bool editable = (node && node->rendererIsEditable()); + bool editable = node->rendererIsEditable(); - if (useHandCursor(node, event.isOverLink(), event.event().shiftKey())) + if (useHandCursor(node, result.isOverLink(), shiftKey)) return handCursor(); bool inResizer = false; if (renderer) { if (RenderLayer* layer = renderer->enclosingLayer()) { if (FrameView* view = m_frame->view()) - inResizer = layer->isPointInResizeControl(view->windowToContents(event.event().position())); + inResizer = layer->isPointInResizeControl(view->windowToContents(roundedIntPoint(result.localPoint()))); } } - if ((editable || (renderer && renderer->isText() && node->canStartSelection())) && !inResizer && !scrollbar) + if ((editable || (renderer && renderer->isText() && node->canStartSelection())) && !inResizer && !result.scrollbar()) return iBeam; return pointerCursor(); } @@ -1558,6 +1459,37 @@ OptionalCursor EventHandler::selectCursor(const MouseEventWithHitTestResults& ev return pointerCursor(); } +#if ENABLE(CURSOR_VISIBILITY) +void EventHandler::startAutoHideCursorTimer() +{ + Page* page = m_frame->page(); + if (!page) + return; + + m_autoHideCursorTimer.startOneShot(page->settings()->timeWithoutMouseMovementBeforeHidingControls()); + + // The fake mouse move event screws up the auto-hide feature (by resetting the auto-hide timer) + // so cancel any pending fake mouse moves. + if (m_fakeMouseMoveEventTimer.isActive()) + m_fakeMouseMoveEventTimer.stop(); +} + +void EventHandler::cancelAutoHideCursorTimer() +{ + if (m_autoHideCursorTimer.isActive()) + m_autoHideCursorTimer.stop(); +} + +void EventHandler::autoHideCursorTimerFired(Timer<EventHandler>* timer) +{ + ASSERT_UNUSED(timer, timer == &m_autoHideCursorTimer); + m_currentMouseCursor = noneCursor(); + FrameView* view = m_frame->view(); + if (view && view->isActive()) + view->setCursor(m_currentMouseCursor); +} +#endif + static LayoutPoint documentPointForWindowPoint(Frame* frame, const IntPoint& windowPoint) { FrameView* view = frame->view(); @@ -1589,8 +1521,7 @@ bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent) cancelFakeMouseMoveEvent(); m_mousePressed = true; m_capturesDragging = true; - m_currentMousePosition = mouseEvent.position(); - m_currentMouseGlobalPosition = mouseEvent.globalPosition(); + setLastKnownMousePosition(mouseEvent); m_mouseDownTimestamp = mouseEvent.timestamp(); #if ENABLE(DRAG_SUPPORT) m_mouseDownMayStartDrag = false; @@ -1605,8 +1536,8 @@ bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent) } m_mouseDownWasInSubframe = false; - HitTestRequest request(HitTestRequest::Active); - // Save the document point we generate in case the window coordinate is invalidated by what happens + HitTestRequest request(HitTestRequest::Active | HitTestRequest::DisallowShadowContent); + // Save the document point we generate in case the window coordinate is invalidated by what happens // when we dispatch the event. LayoutPoint documentPoint = documentPointForWindowPoint(m_frame, mouseEvent.position()); MouseEventWithHitTestResults mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent); @@ -1633,10 +1564,9 @@ bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent) #if ENABLE(PAN_SCROLLING) // We store whether pan scrolling is in progress before calling stopAutoscrollTimer() - // because it will set m_panScrollInProgress to false on return. - bool isPanScrollInProgress = m_frame->page() && m_frame->page()->mainFrame()->eventHandler()->m_panScrollInProgress; - if (isPanScrollInProgress || m_autoscrollInProgress) - stopAutoscrollTimer(); + // because it will set m_autoscrollType to NoAutoscroll on return. + bool isPanScrollInProgress = m_frame->page() && m_frame->page()->mainFrame()->eventHandler()->panScrollInProgress(); + stopAutoscrollTimer(); if (isPanScrollInProgress) { // We invalidate the click when exiting pan scrolling so that we don't inadvertently navigate // away from the current page (e.g. the click was on a hyperlink). See <rdar://problem/6095023>. @@ -1669,7 +1599,7 @@ bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent) // in case the scrollbar widget was destroyed when the mouse event was handled. if (mev.scrollbar()) { const bool wasLastScrollBar = mev.scrollbar() == m_lastScrollbarUnderMouse.get(); - HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active); + HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowShadowContent); mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent); if (wasLastScrollBar && mev.scrollbar() != m_lastScrollbarUnderMouse.get()) m_lastScrollbarUnderMouse = 0; @@ -1688,8 +1618,8 @@ bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent) // If a mouse event handler changes the input element type to one that has a widget associated, // we'd like to EventHandler::handleMousePressEvent to pass the event to the widget and thus the // event target node can't still be the shadow node. - if (mev.targetNode()->isShadowRoot() && toShadowRoot(mev.targetNode())->host()->hasTagName(inputTag)) { - HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active); + if (mev.targetNode()->isShadowRoot() && isHTMLInputElement(toShadowRoot(mev.targetNode())->host())) { + HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowShadowContent); mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent); } @@ -1714,14 +1644,15 @@ bool EventHandler::handleMouseDoubleClickEvent(const PlatformMouseEvent& mouseEv { RefPtr<FrameView> protector(m_frame->view()); + m_frame->selection()->setCaretBlinkingSuspended(false); + UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture); // We get this instead of a second mouse-up m_mousePressed = false; - m_currentMousePosition = mouseEvent.position(); - m_currentMouseGlobalPosition = mouseEvent.globalPosition(); + setLastKnownMousePosition(mouseEvent); - HitTestRequest request(HitTestRequest::Active); + HitTestRequest request(HitTestRequest::Active | HitTestRequest::DisallowShadowContent); MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent); Frame* subframe = subframeForHitTestResult(mev); if (m_eventHandlerWillResetCapturingMouseEventsNode) @@ -1763,15 +1694,7 @@ static RenderLayer* layerForNode(Node* node) bool EventHandler::mouseMoved(const PlatformMouseEvent& event) { RefPtr<FrameView> protector(m_frame->view()); - RunningAverageDurationTracker durationTracker(&m_mouseMovedDurationRunningAverage, fakeMouseMoveRunningAverageCount); - - -#if ENABLE(TOUCH_EVENTS) - // FIXME: this should be moved elsewhere to also be able to dispatch touchcancel events. - bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(event); - if (defaultPrevented) - return true; -#endif + MaximumDurationTracker maxDurationTracker(&m_maxMouseMovedDuration); HitTestResult hoveredNode = HitTestResult(LayoutPoint()); bool result = handleMouseMoveEvent(event, &hoveredNode); @@ -1791,8 +1714,8 @@ bool EventHandler::mouseMoved(const PlatformMouseEvent& event) frameView->mouseMovedInContentArea(); hoveredNode.setToNonShadowAncestor(); - page->chrome()->mouseDidMoveOverElement(hoveredNode, event.modifierFlags()); - page->chrome()->setToolTip(hoveredNode); + page->chrome().mouseDidMoveOverElement(hoveredNode, event.modifierFlags()); + page->chrome().setToolTip(hoveredNode); return result; } @@ -1812,18 +1735,26 @@ bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent, Hi if (!m_frame) return false; +#if ENABLE(TOUCH_EVENTS) + bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(mouseEvent); + if (defaultPrevented) + return true; +#endif + RefPtr<FrameView> protector(m_frame->view()); - m_currentMousePosition = mouseEvent.position(); - m_currentMouseGlobalPosition = mouseEvent.globalPosition(); + + setLastKnownMousePosition(mouseEvent); if (m_hoverTimer.isActive()) m_hoverTimer.stop(); + m_cursorUpdateTimer.stop(); + cancelFakeMouseMoveEvent(); #if ENABLE(SVG) if (m_svgPan) { - static_cast<SVGDocument*>(m_frame->document())->updatePan(m_frame->view()->windowToContents(m_currentMousePosition)); + toSVGDocument(m_frame->document())->updatePan(m_frame->view()->windowToContents(m_lastKnownMousePosition)); return true; } #endif @@ -1835,7 +1766,7 @@ bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent, Hi if (m_lastScrollbarUnderMouse && m_mousePressed) return m_lastScrollbarUnderMouse->mouseMoved(mouseEvent); - HitTestRequest::HitTestRequestType hitType = HitTestRequest::Move; + HitTestRequest::HitTestRequestType hitType = HitTestRequest::Move | HitTestRequest::DisallowShadowContent | HitTestRequest::AllowFrameScrollbars; if (m_mousePressed) hitType |= HitTestRequest::Active; else if (onlyUpdateScrollbars) { @@ -1856,18 +1787,13 @@ bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent, Hi if (hoveredNode) *hoveredNode = mev.hitTestResult(); - Scrollbar* scrollbar = 0; - if (m_resizeLayer && m_resizeLayer->inResizeMode()) m_resizeLayer->resize(mouseEvent, m_offsetFromResizeCorner); else { - if (FrameView* view = m_frame->view()) - scrollbar = view->scrollbarAtPoint(mouseEvent.position()); - - if (!scrollbar) - scrollbar = mev.scrollbar(); - + Scrollbar* scrollbar = mev.scrollbar(); updateLastScrollbarUnderMouse(scrollbar, !m_mousePressed); + if (!m_mousePressed && scrollbar) + scrollbar->mouseMoved(mouseEvent); // Handle hover effects on platforms that support visual feedback on scrollbar hovering. if (onlyUpdateScrollbars) return true; } @@ -1888,10 +1814,8 @@ bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent, Hi if (newSubframe->view()) swallowEvent |= passMouseMoveEventToSubframe(mev, newSubframe.get(), hoveredNode); } else { - if (scrollbar && !m_mousePressed) - scrollbar->mouseMoved(mouseEvent); // Handle hover effects on platforms that support visual feedback on scrollbar hovering. if (FrameView* view = m_frame->view()) { - OptionalCursor optionalCursor = selectCursor(mev, scrollbar); + OptionalCursor optionalCursor = selectCursor(mev.hitTestResult(), mouseEvent.shiftKey()); if (optionalCursor.isCursorChange()) { m_currentMouseCursor = optionalCursor.cursor(); view->setCursor(m_currentMouseCursor); @@ -1919,10 +1843,36 @@ void EventHandler::invalidateClick() m_clickNode = 0; } +inline static bool mouseIsReleasedOnPressedElement(Node* targetNode, Node* clickNode) +{ + if (targetNode == clickNode) + return true; + + if (!targetNode) + return false; + + ShadowRoot* containingShadowRoot = targetNode->containingShadowRoot(); + if (!containingShadowRoot) + return false; + + // FIXME: When an element in UA ShadowDOM (e.g. inner element in <input>) is clicked, + // we assume that the host element is clicked. This is necessary for implementing <input type="range"> etc. + // However, we should not check ShadowRoot type basically. + // https://bugs.webkit.org/show_bug.cgi?id=108047 + if (containingShadowRoot->type() != ShadowRoot::UserAgentShadowRoot) + return false; + + Node* adjustedTargetNode = targetNode->shadowHost(); + Node* adjustedClickNode = clickNode ? clickNode->shadowHost() : 0; + return adjustedTargetNode == adjustedClickNode; +} + bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent) { RefPtr<FrameView> protector(m_frame->view()); + m_frame->selection()->setCaretBlinkingSuspended(false); + #if ENABLE(TOUCH_EVENTS) bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(mouseEvent); if (defaultPrevented) @@ -1932,20 +1882,16 @@ bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent) UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture); #if ENABLE(PAN_SCROLLING) - if (mouseEvent.button() == MiddleButton) - m_panScrollButtonPressed = false; - if (m_springLoadedPanScrollInProgress) - stopAutoscrollTimer(); + m_autoscrollController->handleMouseReleaseEvent(mouseEvent); #endif m_mousePressed = false; - m_currentMousePosition = mouseEvent.position(); - m_currentMouseGlobalPosition = mouseEvent.globalPosition(); + setLastKnownMousePosition(mouseEvent); #if ENABLE(SVG) if (m_svgPan) { m_svgPan = false; - static_cast<SVGDocument*>(m_frame->document())->updatePan(m_frame->view()->windowToContents(m_currentMousePosition)); + toSVGDocument(m_frame->document())->updatePan(m_frame->view()->windowToContents(m_lastKnownMousePosition)); return true; } #endif @@ -1955,10 +1901,13 @@ bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent) if (m_lastScrollbarUnderMouse) { invalidateClick(); - return m_lastScrollbarUnderMouse->mouseUp(mouseEvent); + m_lastScrollbarUnderMouse->mouseUp(mouseEvent); + bool cancelable = true; + bool setUnder = false; + return !dispatchMouseEvent(eventNames().mouseupEvent, m_lastNodeUnderMouse.get(), cancelable, m_clickCount, mouseEvent, setUnder); } - HitTestRequest request(HitTestRequest::Release); + HitTestRequest request(HitTestRequest::Release | HitTestRequest::DisallowShadowContent); MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent); Frame* subframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev); if (m_eventHandlerWillResetCapturingMouseEventsNode) @@ -1968,12 +1917,9 @@ bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent) bool swallowMouseUpEvent = !dispatchMouseEvent(eventNames().mouseupEvent, mev.targetNode(), true, m_clickCount, mouseEvent, false); - Node* clickTarget = mev.targetNode(); - if (clickTarget) - clickTarget = clickTarget->shadowAncestorNode(); - Node* adjustedClickNode = m_clickNode ? m_clickNode->shadowAncestorNode() : 0; + bool contextMenuEvent = mouseEvent.button() == RightButton; - bool swallowClickEvent = m_clickCount > 0 && mouseEvent.button() != RightButton && clickTarget == adjustedClickNode && !dispatchMouseEvent(eventNames().clickEvent, mev.targetNode(), true, m_clickCount, mouseEvent, true); + bool swallowClickEvent = m_clickCount > 0 && !contextMenuEvent && mouseIsReleasedOnPressedElement(mev.targetNode(), m_clickNode.get()) && !dispatchMouseEvent(eventNames().clickEvent, mev.targetNode(), true, m_clickCount, mouseEvent, true); if (m_resizeLayer) { m_resizeLayer->setInResizeMode(false); @@ -2015,10 +1961,12 @@ bool EventHandler::handlePasteGlobalSelection(const PlatformMouseEvent& mouseEve return false; #endif + if (!m_frame->page()) + return false; Frame* focusFrame = m_frame->page()->focusController()->focusedOrMainFrame(); // Do not paste here if the focus was moved somewhere else. - if (m_frame == focusFrame && m_frame->editor()->client()->supportsGlobalSelection()) - return m_frame->editor()->command(ASCIILiteral("PasteGlobalSelection")).execute(); + if (m_frame == focusFrame && m_frame->editor().client()->supportsGlobalSelection()) + return m_frame->editor().command(ASCIILiteral("PasteGlobalSelection")).execute(); return false; } @@ -2035,7 +1983,7 @@ bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Node* dragTa view->resetDeferredRepaintDelay(); RefPtr<MouseEvent> me = MouseEvent::create(eventType, - true, true, m_frame->document()->defaultView(), + true, true, event.timestamp(), m_frame->document()->defaultView(), 0, event.globalPosition().x(), event.globalPosition().y(), event.position().x(), event.position().y(), #if ENABLE(POINTER_LOCK) event.movementDelta().x(), event.movementDelta().y(), @@ -2043,8 +1991,7 @@ bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Node* dragTa event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(), 0, 0, clipboard); - ExceptionCode ec; - dragTarget->dispatchEvent(me.get(), ec); + dragTarget->dispatchEvent(me.get(), IGNORE_EXCEPTION); return me->defaultPrevented(); } @@ -2056,7 +2003,7 @@ static bool targetIsFrame(Node* target, Frame*& frame) if (!target->hasTagName(frameTag) && !target->hasTagName(iframeTag)) return false; - frame = static_cast<HTMLFrameElementBase*>(target)->contentFrame(); + frame = toHTMLFrameElementBase(target)->contentFrame(); return true; } @@ -2104,13 +2051,15 @@ bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard* if (!m_frame->view()) return false; - HitTestRequest request(HitTestRequest::ReadOnly); + HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowShadowContent); MouseEventWithHitTestResults mev = prepareMouseEvent(request, event); // Drag events should never go to text nodes (following IE, and proper mouseover/out dispatch) RefPtr<Node> newTarget = mev.targetNode(); if (newTarget && newTarget->isTextNode()) - newTarget = newTarget->parentNode(); + newTarget = EventPathWalker::parent(newTarget.get()); + + m_autoscrollController->updateDragAndDrop(newTarget.get(), event.position(), event.timestamp()); if (m_dragTarget != newTarget) { // FIXME: this ordering was explicitly chosen to match WinIE. However, @@ -2124,7 +2073,7 @@ bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard* accept = targetFrame->eventHandler()->updateDragAndDrop(event, clipboard); } else if (newTarget) { // As per section 7.9.4 of the HTML 5 spec., we must always fire a drag event before firing a dragenter, dragleave, or dragover event. - if (dragState().m_dragSrc && dragState().shouldDispatchEvents()) { + if (dragState().source && dragState().shouldDispatchEvents) { // for now we don't care if event handler cancels default behavior, since there is none dispatchDragSrcEvent(eventNames().dragEvent, event); } @@ -2151,7 +2100,7 @@ bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard* accept = targetFrame->eventHandler()->updateDragAndDrop(event, clipboard); } else if (newTarget) { // Note, when dealing with sub-frames, we may need to fire only a dragover event as a drag event may have been fired earlier. - if (!m_shouldOnlyFireDragOverEvent && dragState().m_dragSrc && dragState().shouldDispatchEvents()) { + if (!m_shouldOnlyFireDragOverEvent && dragState().source && dragState().shouldDispatchEvents) { // for now we don't care if event handler cancels default behavior, since there is none dispatchDragSrcEvent(eventNames().dragEvent, event); } @@ -2173,7 +2122,7 @@ void EventHandler::cancelDragAndDrop(const PlatformMouseEvent& event, Clipboard* if (targetFrame) targetFrame->eventHandler()->cancelDragAndDrop(event, clipboard); } else if (m_dragTarget.get()) { - if (dragState().m_dragSrc && dragState().shouldDispatchEvents()) + if (dragState().source && dragState().shouldDispatchEvents) dispatchDragSrcEvent(eventNames().dragEvent, event); dispatchDragEvent(eventNames().dragleaveEvent, m_dragTarget.get(), event, clipboard); } @@ -2195,6 +2144,7 @@ bool EventHandler::performDragAndDrop(const PlatformMouseEvent& event, Clipboard void EventHandler::clearDragState() { + stopAutoscrollTimer(); m_dragTarget = 0; m_capturingMouseEventsNode = 0; m_shouldOnlyFireDragOverEvent = false; @@ -2224,7 +2174,7 @@ static inline SVGElementInstance* instanceAssociatedWithShadowTreeElement(Node* if (!referenceNode || !referenceNode->isSVGElement()) return 0; - ShadowRoot* shadowRoot = referenceNode->shadowRoot(); + ShadowRoot* shadowRoot = referenceNode->containingShadowRoot(); if (!shadowRoot) return 0; @@ -2232,7 +2182,7 @@ static inline SVGElementInstance* instanceAssociatedWithShadowTreeElement(Node* if (!shadowTreeParentElement || !shadowTreeParentElement->hasTagName(useTag)) return 0; - return static_cast<SVGUseElement*>(shadowTreeParentElement)->instanceForShadowTreeElement(referenceNode); + return toSVGUseElement(shadowTreeParentElement)->instanceForShadowTreeElement(referenceNode); } #endif @@ -2245,11 +2195,8 @@ void EventHandler::updateMouseEventTargetNode(Node* targetNode, const PlatformMo result = m_capturingMouseEventsNode.get(); else { // If the target node is a text node, dispatch on the parent node - rdar://4196646 - if (result && result->isTextNode()) { - AncestorChainWalker walker(result); - walker.parent(); - result = walker.get(); - } + if (result && result->isTextNode()) + result = EventPathWalker::parent(result); } m_nodeUnderMouse = result; #if ENABLE(SVG) @@ -2374,35 +2321,42 @@ bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targe // Blur current focus node when a link/button is clicked; this // is expected by some sites that rely on onChange handlers running // from form fields before the button click is processed. - Node* node = m_nodeUnderMouse.get(); - // Walk up the DOM tree to search for a node to focus. - while (node) { - if (node->isMouseFocusable()) { + Element* element; + if (m_nodeUnderMouse) + element = m_nodeUnderMouse->isElementNode() ? toElement(m_nodeUnderMouse.get()) : m_nodeUnderMouse->parentOrShadowHostElement(); + else + element = 0; + + // Walk up the DOM tree to search for an element to focus. + while (element) { + if (element->isMouseFocusable()) { // To fix <rdar://problem/4895428> Can't drag selected ToDo, we don't focus a // node on mouse down if it's selected and inside a focused node. It will be // focused if the user does a mouseup over it, however, because the mouseup // will set a selection inside it, which will call setFocuseNodeIfNeeded. - ExceptionCode ec = 0; - Node* n = node->isShadowRoot() ? toShadowRoot(node)->host() : node; if (m_frame->selection()->isRange() - && m_frame->selection()->toNormalizedRange()->compareNode(n, ec) == Range::NODE_INSIDE - && n->isDescendantOf(m_frame->document()->focusedNode())) + && m_frame->selection()->toNormalizedRange()->compareNode(element, IGNORE_EXCEPTION) == Range::NODE_INSIDE + && element->isDescendantOf(m_frame->document()->focusedElement())) return true; break; } - node = node->parentOrHostNode(); + element = element->parentOrShadowHostElement(); } + // Only change the focus when clicking scrollbars if it can transfered to a mouse focusable node. + if ((!element || !element->isMouseFocusable()) && isInsideScrollbar(mouseEvent.position())) + return false; + // If focus shift is blocked, we eat the event. Note we should never clear swallowEvent // if the page already set it (e.g., by canceling default behavior). if (Page* page = m_frame->page()) { - if (node && node->isMouseFocusable()) { - if (!page->focusController()->setFocusedNode(node, m_frame)) + if (element && element->isMouseFocusable()) { + if (!page->focusController()->setFocusedElement(element, m_frame)) swallowEvent = true; - } else if (!node || !node->focused()) { - if (!page->focusController()->setFocusedNode(0, m_frame)) + } else if (!element || !element->focused()) { + if (!page->focusController()->setFocusedElement(0, m_frame)) swallowEvent = true; } } @@ -2411,7 +2365,19 @@ bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targe return !swallowEvent; } -#if !PLATFORM(GTK) && !(PLATFORM(CHROMIUM) && (OS(UNIX) && !OS(DARWIN))) +bool EventHandler::isInsideScrollbar(const IntPoint& windowPoint) const +{ + if (RenderView* renderView = m_frame->contentRenderer()) { + HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowShadowContent); + HitTestResult result(windowPoint); + renderView->hitTest(request, result); + return result.scrollbar(); + } + + return false; +} + +#if !PLATFORM(GTK) bool EventHandler::shouldTurnVerticalTicksIntoHorizontal(const HitTestResult&, const PlatformWheelEvent&) const { return false; @@ -2431,25 +2397,31 @@ bool EventHandler::handleWheelEvent(const PlatformWheelEvent& e) FrameView* view = m_frame->view(); if (!view) return false; + + m_isHandlingWheelEvent = true; setFrameWasScrolledByUser(); LayoutPoint vPoint = view->windowToContents(e.position()); - Node* node; - bool isOverWidget; - - HitTestRequest request(HitTestRequest::ReadOnly); + HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowShadowContent); HitTestResult result(vPoint); doc->renderView()->hitTest(request, result); bool useLatchedWheelEventNode = e.useLatchedEventNode(); + // FIXME: Is the following code different from just calling innerElement? + Node* node = result.innerNode(); + // Wheel events should not dispatch to text nodes. + if (node && node->isTextNode()) + node = EventPathWalker::parent(node); + + bool isOverWidget; if (useLatchedWheelEventNode) { if (!m_latchedWheelEventNode) { - m_latchedWheelEventNode = closestScrollableNodeInDocumentIfPossible(result.innerNode()); + m_latchedWheelEventNode = node; m_widgetIsLatched = result.isOverWidget(); - } + } else + node = m_latchedWheelEventNode.get(); - node = m_latchedWheelEventNode.get(); isOverWidget = m_widgetIsLatched; } else { if (m_latchedWheelEventNode) @@ -2457,7 +2429,6 @@ bool EventHandler::handleWheelEvent(const PlatformWheelEvent& e) if (m_previousWheelScrolledNode) m_previousWheelScrolledNode = 0; - node = result.innerNode(); isOverWidget = result.isOverWidget(); } @@ -2474,21 +2445,24 @@ bool EventHandler::handleWheelEvent(const PlatformWheelEvent& e) if (isOverWidget && target && target->isWidget()) { Widget* widget = toRenderWidget(target)->widget(); - if (widget && passWheelEventToWidget(e, widget)) + if (widget && passWheelEventToWidget(e, widget)) { + m_isHandlingWheelEvent = false; return true; + } } - if (node && !node->dispatchWheelEvent(event)) + if (node && !node->dispatchWheelEvent(event)) { + m_isHandlingWheelEvent = false; return true; + } } // We do another check on the frame view because the event handler can run JS which results in the frame getting destroyed. view = m_frame->view(); - if (!view) - return false; - - return view->wheelEvent(event); + bool didHandleEvent = view ? view->wheelEvent(event) : false; + m_isHandlingWheelEvent = false; + return didHandleEvent; } void EventHandler::defaultWheelEventHandler(Node* startNode, WheelEvent* wheelEvent) @@ -2497,7 +2471,7 @@ void EventHandler::defaultWheelEventHandler(Node* startNode, WheelEvent* wheelEv return; Node* stopNode = m_previousWheelScrolledNode.get(); - ScrollGranularity granularity = wheelGranularityToScrollGranularity(wheelEvent->granularity()); + ScrollGranularity granularity = wheelGranularityToScrollGranularity(wheelEvent->deltaMode()); // Break up into two scrolls if we need to. Diagonal movement on // a MacBook pro is an example of a 2-dimensional mouse wheel event (where both deltaX and deltaY can be set). @@ -2533,14 +2507,11 @@ bool EventHandler::handleGestureTapDown() bool EventHandler::handleGestureEvent(const PlatformGestureEvent& gestureEvent) { - // We don't use DoubleTap at the moment, it's mostly redundant with tap since tap now contains - // a tap count. FIXME: We should probably remove GestureDoubleTap (http://wkb.ug/93045). - if (gestureEvent.type() == PlatformEvent::GestureDoubleTap) - return false; - Node* eventTarget = 0; Scrollbar* scrollbar = 0; - if (gestureEvent.type() == PlatformEvent::GestureScrollEnd || gestureEvent.type() == PlatformEvent::GestureScrollUpdate) { + if (gestureEvent.type() == PlatformEvent::GestureScrollEnd + || gestureEvent.type() == PlatformEvent::GestureScrollUpdate + || gestureEvent.type() == PlatformEvent::GestureScrollUpdateWithoutPropagation) { scrollbar = m_scrollbarHandlingScrollGesture.get(); eventTarget = m_scrollGestureHandlingNode.get(); } @@ -2552,8 +2523,13 @@ bool EventHandler::handleGestureEvent(const PlatformGestureEvent& gestureEvent) adjustGesturePosition(gestureEvent, adjustedPoint); #endif hitType |= HitTestRequest::Active; - } else if (gestureEvent.type() == PlatformEvent::GestureTap || gestureEvent.type() == PlatformEvent::GestureTapDownCancel) + } else if (gestureEvent.type() == PlatformEvent::GestureTapDownCancel) hitType |= HitTestRequest::Release; + else if (gestureEvent.type() == PlatformEvent::GestureTap) { + // The mouseup event synthesized for this gesture will clear the active state of the + // targeted node, so performing a ReadOnly hit test here is fine. + hitType |= HitTestRequest::ReadOnly; + } else hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly; @@ -2562,12 +2538,8 @@ bool EventHandler::handleGestureEvent(const PlatformGestureEvent& gestureEvent) if ((!scrollbar && !eventTarget) || !(hitType & HitTestRequest::ReadOnly)) { IntPoint hitTestPoint = m_frame->view()->windowToContents(adjustedPoint); - HitTestResult result = hitTestResultAtPoint(hitTestPoint, false, false, ShouldHitTestScrollbars, hitType); + HitTestResult result = hitTestResultAtPoint(hitTestPoint, hitType | HitTestRequest::AllowFrameScrollbars); eventTarget = result.targetNode(); - if (!scrollbar) { - FrameView* view = m_frame->view(); - scrollbar = view ? view->scrollbarAtPoint(gestureEvent.position()) : 0; - } if (!scrollbar) scrollbar = result.scrollbar(); } @@ -2585,12 +2557,9 @@ bool EventHandler::handleGestureEvent(const PlatformGestureEvent& gestureEvent) if (eventTarget) { bool eventSwallowed = eventTarget->dispatchGestureEvent(gestureEvent); - - if (gestureEvent.type() == PlatformEvent::GestureScrollBegin) { + if (gestureEvent.type() == PlatformEvent::GestureScrollBegin || gestureEvent.type() == PlatformEvent::GestureScrollEnd) { if (eventSwallowed) m_scrollGestureHandlingNode = eventTarget; - else - m_scrollGestureHandlingNode = 0; } if (eventSwallowed) @@ -2603,9 +2572,13 @@ bool EventHandler::handleGestureEvent(const PlatformGestureEvent& gestureEvent) switch (gestureEvent.type()) { case PlatformEvent::GestureScrollBegin: - return handleGestureScrollCore(gestureEvent, ScrollByPixelWheelEvent, false); + return handleGestureScrollBegin(gestureEvent); case PlatformEvent::GestureScrollUpdate: + case PlatformEvent::GestureScrollUpdateWithoutPropagation: return handleGestureScrollUpdate(gestureEvent); + case PlatformEvent::GestureScrollEnd: + clearGestureScrollNodes(); + return true; case PlatformEvent::GestureTap: return handleGestureTap(gestureEvent); case PlatformEvent::GestureTapDown: @@ -2616,11 +2589,6 @@ bool EventHandler::handleGestureEvent(const PlatformGestureEvent& gestureEvent) return handleGestureLongTap(gestureEvent); case PlatformEvent::GestureTwoFingerTap: return handleGestureTwoFingerTap(gestureEvent); - case PlatformEvent::GestureScrollEnd: - case PlatformEvent::GestureDoubleTap: - case PlatformEvent::GesturePinchBegin: - case PlatformEvent::GesturePinchEnd: - case PlatformEvent::GesturePinchUpdate: case PlatformEvent::GestureTapDownCancel: break; default: @@ -2674,9 +2642,14 @@ bool EventHandler::handleGestureLongPress(const PlatformGestureEvent& gestureEve PlatformMouseEvent mouseDownEvent(adjustedPoint, gestureEvent.globalPosition(), LeftButton, PlatformEvent::MousePressed, 0, false, false, false, false, WTF::currentTime()); handleMousePressEvent(mouseDownEvent); PlatformMouseEvent mouseDragEvent(adjustedPoint, gestureEvent.globalPosition(), LeftButton, PlatformEvent::MouseMoved, 0, false, false, false, false, WTF::currentTime()); - HitTestRequest request(HitTestRequest::ReadOnly); + HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowShadowContent); MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseDragEvent); m_didStartDrag = false; + RefPtr<Frame> subframe = subframeForHitTestResult(mev); + if (subframe && !m_mouseDownMayStartDrag) { + if (subframe->eventHandler()->handleGestureLongPress(gestureEvent)) + return true; + } handleDrag(mev, DontCheckDragHysteresis); if (m_didStartDrag) return true; @@ -2687,25 +2660,15 @@ bool EventHandler::handleGestureLongPress(const PlatformGestureEvent& gestureEve bool EventHandler::handleGestureLongTap(const PlatformGestureEvent& gestureEvent) { -#if ENABLE(CONTEXT_MENUS) && !OS(ANDROID) +#if ENABLE(CONTEXT_MENUS) if (!m_didLongPressInvokeContextMenu) return sendContextMenuEventForGesture(gestureEvent); -#endif +#endif // ENABLE(CONTEXT_MENUS) return false; } bool EventHandler::handleGestureForTextSelectionOrContextMenu(const PlatformGestureEvent& gestureEvent) { -#if OS(ANDROID) - IntPoint hitTestPoint = m_frame->view()->windowToContents(gestureEvent.position()); - HitTestResult result = hitTestResultAtPoint(hitTestPoint, true); - Node* innerNode = result.targetNode(); - if (!result.isLiveLink() && innerNode && (innerNode->isContentEditable() || innerNode->isTextNode())) { - selectClosestWordFromHitTestResult(result, DontAppendTrailingWhitespace); - if (m_frame->selection()->isRange()) - return true; - } -#endif #if ENABLE(CONTEXT_MENUS) m_didLongPressInvokeContextMenu = (gestureEvent.type() == PlatformEvent::GestureLongPress); return sendContextMenuEventForGesture(gestureEvent); @@ -2719,30 +2682,136 @@ bool EventHandler::handleGestureTwoFingerTap(const PlatformGestureEvent& gesture return handleGestureForTextSelectionOrContextMenu(gestureEvent); } -bool EventHandler::handleGestureScrollUpdate(const PlatformGestureEvent& gestureEvent) +bool EventHandler::passGestureEventToWidget(const PlatformGestureEvent& gestureEvent, Widget* widget) { - return handleGestureScrollCore(gestureEvent, ScrollByPixelWheelEvent, true); + if (!widget) + return false; + + if (!widget->isFrameView()) + return false; + + return toFrameView(widget)->frame()->eventHandler()->handleGestureEvent(gestureEvent); } -bool EventHandler::isScrollbarHandlingGestures() const +bool EventHandler::passGestureEventToWidgetIfPossible(const PlatformGestureEvent& gestureEvent, RenderObject* renderer) { - return m_scrollbarHandlingScrollGesture.get(); + if (m_lastHitTestResultOverWidget && renderer && renderer->isWidget()) { + Widget* widget = toRenderWidget(renderer)->widget(); + return widget && passGestureEventToWidget(gestureEvent, widget); + } + return false; +} + +bool EventHandler::handleGestureScrollBegin(const PlatformGestureEvent& gestureEvent) +{ + Document* document = m_frame->document(); + RenderObject* documentRenderer = document->renderer(); + if (!documentRenderer) + return false; + + FrameView* view = m_frame->view(); + if (!view) + return false; + + LayoutPoint viewPoint = view->windowToContents(gestureEvent.position()); + HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowShadowContent); + HitTestResult result(viewPoint); + document->renderView()->hitTest(request, result); + + m_lastHitTestResultOverWidget = result.isOverWidget(); + m_scrollGestureHandlingNode = result.innerNode(); + m_previousGestureScrolledNode = 0; + + Node* node = m_scrollGestureHandlingNode.get(); + if (node) + passGestureEventToWidgetIfPossible(gestureEvent, node->renderer()); + + return node && node->renderer(); +} + +bool EventHandler::handleGestureScrollUpdate(const PlatformGestureEvent& gestureEvent) +{ + FloatSize delta(gestureEvent.deltaX(), gestureEvent.deltaY()); + if (delta.isZero()) + return false; + + const float scaleFactor = m_frame->pageZoomFactor() * m_frame->frameScaleFactor(); + delta.scale(1 / scaleFactor, 1 / scaleFactor); + + Node* node = m_scrollGestureHandlingNode.get(); + if (!node) + return sendScrollEventToView(gestureEvent, delta); + + // Ignore this event if the targeted node does not have a valid renderer. + RenderObject* renderer = node->renderer(); + if (!renderer) + return false; + + RefPtr<FrameView> protector(m_frame->view()); + + // Try to send the event to the correct view. + if (passGestureEventToWidgetIfPossible(gestureEvent, renderer)) + return true; + + Node* stopNode = 0; + bool scrollShouldNotPropagate = gestureEvent.type() == PlatformEvent::GestureScrollUpdateWithoutPropagation; + if (scrollShouldNotPropagate) + stopNode = m_previousGestureScrolledNode.get(); + + // First try to scroll the closest scrollable RenderBox ancestor of |node|. + ScrollGranularity granularity = ScrollByPixel; + bool horizontalScroll = scrollNode(delta.width(), granularity, ScrollLeft, ScrollRight, node, &stopNode); + bool verticalScroll = scrollNode(delta.height(), granularity, ScrollUp, ScrollDown, node, &stopNode); + + if (scrollShouldNotPropagate) + m_previousGestureScrolledNode = stopNode; + + if (horizontalScroll || verticalScroll) { + setFrameWasScrolledByUser(); + return true; + } + + // Otherwise try to scroll the view. + return sendScrollEventToView(gestureEvent, delta); } -bool EventHandler::handleGestureScrollCore(const PlatformGestureEvent& gestureEvent, PlatformWheelEventGranularity granularity, bool latchedWheel) +bool EventHandler::sendScrollEventToView(const PlatformGestureEvent& gestureEvent, const FloatSize& scaledDelta) { - const float tickDivisor = (float)WheelEvent::tickMultiplier; + FrameView* view = m_frame->view(); + if (!view) + return false; + + const float tickDivisor = static_cast<float>(WheelEvent::TickMultiplier); IntPoint point(gestureEvent.position().x(), gestureEvent.position().y()); IntPoint globalPoint(gestureEvent.globalPosition().x(), gestureEvent.globalPosition().y()); PlatformWheelEvent syntheticWheelEvent(point, globalPoint, - gestureEvent.deltaX(), gestureEvent.deltaY(), gestureEvent.deltaX() / tickDivisor, gestureEvent.deltaY() / tickDivisor, - granularity, + scaledDelta.width(), scaledDelta.height(), + scaledDelta.width() / tickDivisor, scaledDelta.height() / tickDivisor, + ScrollByPixelWheelEvent, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey()); - syntheticWheelEvent.setUseLatchedEventNode(latchedWheel); - return handleWheelEvent(syntheticWheelEvent); -} +#if PLATFORM(MAC) + syntheticWheelEvent.setHasPreciseScrollingDeltas(true); #endif + bool scrolledFrame = view->wheelEvent(syntheticWheelEvent); + if (scrolledFrame) + setFrameWasScrolledByUser(); + + return scrolledFrame; +} + +void EventHandler::clearGestureScrollNodes() +{ + m_scrollGestureHandlingNode = 0; + m_previousGestureScrolledNode = 0; +} + +bool EventHandler::isScrollbarHandlingGestures() const +{ + return m_scrollbarHandlingScrollGesture.get(); +} +#endif // ENABLE(GESTURE_EVENTS) + #if ENABLE(TOUCH_ADJUSTMENT) bool EventHandler::shouldApplyTouchAdjustment(const PlatformGestureEvent& event) const { @@ -2754,43 +2823,37 @@ bool EventHandler::shouldApplyTouchAdjustment(const PlatformGestureEvent& event) bool EventHandler::bestClickableNodeForTouchPoint(const IntPoint& touchCenter, const IntSize& touchRadius, IntPoint& targetPoint, Node*& targetNode) { - HitTestRequest::HitTestRequestType hitType = HitTestRequest::ReadOnly | HitTestRequest::Active; IntPoint hitTestPoint = m_frame->view()->windowToContents(touchCenter); - HitTestResult result = hitTestResultAtPoint(hitTestPoint, /*allowShadowContent*/ true, /*ignoreClipping*/ false, DontHitTestScrollbars, hitType, touchRadius); + HitTestResult result = hitTestResultAtPoint(hitTestPoint, HitTestRequest::ReadOnly | HitTestRequest::Active, touchRadius); IntRect touchRect(touchCenter - touchRadius, touchRadius + touchRadius); - RefPtr<StaticHashSetNodeList> nodeList = StaticHashSetNodeList::adopt(result.rectBasedTestResult()); // FIXME: Should be able to handle targetNode being a shadow DOM node to avoid performing uncessary hit tests // in the case where further processing on the node is required. Returning the shadow ancestor prevents a // regression in touchadjustment/html-label.html. Some refinement is required to testing/internals to // handle targetNode being a shadow DOM node. - bool success = findBestClickableCandidate(targetNode, targetPoint, touchCenter, touchRect, *nodeList.get()); + bool success = findBestClickableCandidate(targetNode, targetPoint, touchCenter, touchRect, result.rectBasedTestResult()); if (success && targetNode) - targetNode = targetNode->shadowAncestorNode(); + targetNode = targetNode->deprecatedShadowAncestorNode(); return success; } bool EventHandler::bestContextMenuNodeForTouchPoint(const IntPoint& touchCenter, const IntSize& touchRadius, IntPoint& targetPoint, Node*& targetNode) { - HitTestRequest::HitTestRequestType hitType = HitTestRequest::ReadOnly | HitTestRequest::Active; IntPoint hitTestPoint = m_frame->view()->windowToContents(touchCenter); - HitTestResult result = hitTestResultAtPoint(hitTestPoint, /*allowShadowContent*/ true, /*ignoreClipping*/ false, DontHitTestScrollbars, hitType, touchRadius); + HitTestResult result = hitTestResultAtPoint(hitTestPoint, HitTestRequest::ReadOnly | HitTestRequest::Active, touchRadius); IntRect touchRect(touchCenter - touchRadius, touchRadius + touchRadius); - RefPtr<StaticHashSetNodeList> nodeList = StaticHashSetNodeList::adopt(result.rectBasedTestResult()); - return findBestContextMenuCandidate(targetNode, targetPoint, touchCenter, touchRect, *nodeList.get()); + return findBestContextMenuCandidate(targetNode, targetPoint, touchCenter, touchRect, result.rectBasedTestResult()); } bool EventHandler::bestZoomableAreaForTouchPoint(const IntPoint& touchCenter, const IntSize& touchRadius, IntRect& targetArea, Node*& targetNode) { - HitTestRequest::HitTestRequestType hitType = HitTestRequest::ReadOnly | HitTestRequest::Active; IntPoint hitTestPoint = m_frame->view()->windowToContents(touchCenter); - HitTestResult result = hitTestResultAtPoint(hitTestPoint, /*allowShadowContent*/ false, /*ignoreClipping*/ false, DontHitTestScrollbars, hitType, touchRadius); + HitTestResult result = hitTestResultAtPoint(hitTestPoint, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowShadowContent, touchRadius); IntRect touchRect(touchCenter - touchRadius, touchRadius + touchRadius); - RefPtr<StaticHashSetNodeList> nodeList = StaticHashSetNodeList::adopt(result.rectBasedTestResult()); - return findBestZoomableArea(targetNode, targetArea, touchCenter, touchRect, *nodeList.get()); + return findBestZoomableArea(targetNode, targetArea, touchCenter, touchRect, result.rectBasedTestResult()); } bool EventHandler::adjustGesturePosition(const PlatformGestureEvent& gestureEvent, IntPoint& adjustedPoint) @@ -2829,11 +2892,12 @@ bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event) m_mousePressed = false; bool swallowEvent; LayoutPoint viewportPos = v->windowToContents(event.position()); - HitTestRequest request(HitTestRequest::Active); + HitTestRequest request(HitTestRequest::Active | HitTestRequest::DisallowShadowContent); MouseEventWithHitTestResults mev = doc->prepareMouseEvent(request, viewportPos, event); - if (m_frame->editor()->behavior().shouldSelectOnContextualMenuClick() + if (m_frame->editor().behavior().shouldSelectOnContextualMenuClick() && !m_frame->selection()->contains(viewportPos) + && !mev.scrollbar() // FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse. // If the selection is non-editable, we do word selection to make it easier to use the contextual menu items // available for text selections. But only if we're above text. @@ -2869,20 +2933,20 @@ bool EventHandler::sendContextMenuEventForKey() #endif IntPoint location; - Node* focusedNode = doc->focusedNode(); + Element* focusedElement = doc->focusedElement(); FrameSelection* selection = m_frame->selection(); Position start = selection->selection().start(); if (start.deprecatedNode() && (selection->rootEditableElement() || selection->isRange())) { RefPtr<Range> selectionRange = selection->toNormalizedRange(); - IntRect firstRect = m_frame->editor()->firstRectForRange(selectionRange.get()); + IntRect firstRect = m_frame->editor().firstRectForRange(selectionRange.get()); int x = rightAligned ? firstRect.maxX() : firstRect.x(); // In a multiline edit, firstRect.maxY() would endup on the next line, so -1. int y = firstRect.maxY() ? firstRect.maxY() - 1 : 0; location = IntPoint(x, y); - } else if (focusedNode) { - RenderBoxModelObject* box = focusedNode->renderBoxModelObject(); + } else if (focusedElement) { + RenderBoxModelObject* box = focusedElement->renderBoxModelObject(); if (!box) return false; IntRect clippedRect = box->pixelSnappedAbsoluteClippedOverflowRect(); @@ -2898,17 +2962,15 @@ bool EventHandler::sendContextMenuEventForKey() IntPoint position = view->contentsToRootView(location); IntPoint globalPosition = view->hostWindow()->rootViewToScreen(IntRect(position, IntSize())).location(); - Node* targetNode = doc->focusedNode(); + Node* targetNode = doc->focusedElement(); if (!targetNode) targetNode = doc; // Use the focused node as the target for hover and active. HitTestResult result(position); result.setInnerNode(targetNode); - HitTestRequest request(HitTestRequest::Active); - doc->updateHoverActiveState(request, result); - doc->updateStyleIfNeeded(); - + doc->updateHoverActiveState(HitTestRequest::Active | HitTestRequest::DisallowShadowContent, result.innerElement()); + // The contextmenu event is a mouse event even when invoked using the keyboard. // This is required for web compatibility. @@ -2953,24 +3015,36 @@ void EventHandler::scheduleHoverStateUpdate() m_hoverTimer.startOneShot(0); } +void EventHandler::scheduleCursorUpdate() +{ + if (!m_cursorUpdateTimer.isActive()) + m_cursorUpdateTimer.startOneShot(cursorUpdateInterval); +} + void EventHandler::dispatchFakeMouseMoveEventSoon() { if (m_mousePressed) return; + if (m_mousePositionIsUnknown) + return; + Settings* settings = m_frame->settings(); if (settings && !settings->deviceSupportsMouse()) return; - // Adjust the mouse move throttling so that it's roughly around our running average of the duration of mousemove events. - // This will cause the content to receive these moves only after the user is done scrolling, reducing pauses during the scroll. - // This will only measure the duration of the mousemove event though (not for example layouts), - // so maintain at least a minimum interval. - if (m_mouseMovedDurationRunningAverage > m_fakeMouseMoveEventTimer.delay()) - m_fakeMouseMoveEventTimer.setDelay(m_mouseMovedDurationRunningAverage + fakeMouseMoveIntervalIncrease); - else if (m_mouseMovedDurationRunningAverage < fakeMouseMoveIntervalReductionLimit * m_fakeMouseMoveEventTimer.delay()) - m_fakeMouseMoveEventTimer.setDelay(max(fakeMouseMoveMinimumInterval, fakeMouseMoveIntervalReductionFraction * m_fakeMouseMoveEventTimer.delay())); - m_fakeMouseMoveEventTimer.restart(); + // If the content has ever taken longer than fakeMouseMoveShortInterval we + // reschedule the timer and use a longer time. This will cause the content + // to receive these moves only after the user is done scrolling, reducing + // pauses during the scroll. + if (m_maxMouseMovedDuration > fakeMouseMoveShortInterval) { + if (m_fakeMouseMoveEventTimer.isActive()) + m_fakeMouseMoveEventTimer.stop(); + m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveLongInterval); + } else { + if (!m_fakeMouseMoveEventTimer.isActive()) + m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveShortInterval); + } } void EventHandler::dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad& quad) @@ -2979,7 +3053,7 @@ void EventHandler::dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad& quad) if (!view) return; - if (!quad.containsPoint(view->windowToContents(m_currentMousePosition))) + if (!quad.containsPoint(view->windowToContents(m_lastKnownMousePosition))) return; dispatchFakeMouseMoveEventSoon(); @@ -2990,7 +3064,7 @@ void EventHandler::cancelFakeMouseMoveEvent() m_fakeMouseMoveEventTimer.stop(); } -void EventHandler::fakeMouseMoveEventTimerFired(DeferrableOneShotTimer<EventHandler>* timer) +void EventHandler::fakeMouseMoveEventTimerFired(Timer<EventHandler>* timer) { ASSERT_UNUSED(timer, timer == &m_fakeMouseMoveEventTimer); ASSERT(!m_mousePressed); @@ -3011,7 +3085,7 @@ void EventHandler::fakeMouseMoveEventTimerFired(DeferrableOneShotTimer<EventHand bool altKey; bool metaKey; PlatformKeyboardEvent::getCurrentModifierState(shiftKey, ctrlKey, altKey, metaKey); - PlatformMouseEvent fakeMouseMoveEvent(m_currentMousePosition, m_currentMouseGlobalPosition, NoButton, PlatformEvent::MouseMoved, 0, shiftKey, ctrlKey, altKey, metaKey, currentTime()); + PlatformMouseEvent fakeMouseMoveEvent(m_lastKnownMousePosition, m_lastKnownMouseGlobalPosition, NoButton, PlatformEvent::MouseMoved, 0, shiftKey, ctrlKey, altKey, metaKey, currentTime()); mouseMoved(fakeMouseMoveEvent); } @@ -3035,10 +3109,10 @@ void EventHandler::hoverTimerFired(Timer<EventHandler>*) if (RenderView* renderer = m_frame->contentRenderer()) { if (FrameView* view = m_frame->view()) { - HitTestRequest request(HitTestRequest::Move); - HitTestResult result(view->windowToContents(m_currentMousePosition)); + HitTestRequest request(HitTestRequest::Move | HitTestRequest::DisallowShadowContent); + HitTestResult result(view->windowToContents(m_lastKnownMousePosition)); renderer->hitTest(request, result); - m_frame->document()->updateStyleIfNeeded(); + m_frame->document()->updateHoverActiveState(request, result.innerElement()); } } } @@ -3103,7 +3177,7 @@ bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent) #if ENABLE(PAN_SCROLLING) if (Page* page = m_frame->page()) { - if (page->mainFrame()->eventHandler()->m_panScrollInProgress) { + if (page->mainFrame()->eventHandler()->panScrollInProgress()) { // If a key is pressed while the panScroll is in progress then we want to stop if (initialKeyEvent.type() == PlatformEvent::KeyDown || initialKeyEvent.type() == PlatformEvent::RawKeyDown) stopAutoscrollTimer(); @@ -3144,7 +3218,6 @@ bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent) bool backwardCompatibilityMode = needsKeyboardEventDisambiguationQuirks(); - ExceptionCode ec; PlatformKeyboardEvent keyDownEvent = initialKeyEvent; if (keyDownEvent.type() != PlatformEvent::RawKeyDown) keyDownEvent.disambiguateKeyDownEvent(PlatformEvent::RawKeyDown, backwardCompatibilityMode); @@ -3154,7 +3227,7 @@ bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent) keydown->setTarget(node); if (initialKeyEvent.type() == PlatformEvent::RawKeyDown) { - node->dispatchEvent(keydown, ec); + node->dispatchEvent(keydown, IGNORE_EXCEPTION); // If frame changed as a result of keydown dispatch, then return true to avoid sending a subsequent keypress message to the new frame. bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page()->focusController()->focusedOrMainFrame(); return keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame; @@ -3165,7 +3238,7 @@ bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent) // in order to match IE: // 1. preventing default handling of keydown and keypress events has no effect on IM input; // 2. if an input method handles the event, its keyCode is set to 229 in keydown event. - m_frame->editor()->handleInputMethodKeydown(keydown.get()); + m_frame->editor().handleInputMethodKeydown(keydown.get()); bool handledByInputMethod = keydown->defaultHandled(); @@ -3176,7 +3249,7 @@ bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent) keydown->setDefaultHandled(); } - node->dispatchEvent(keydown, ec); + node->dispatchEvent(keydown, IGNORE_EXCEPTION); // If frame changed as a result of keydown dispatch, then return early to avoid sending a subsequent keypress message to the new frame. bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page()->focusController()->focusedOrMainFrame(); bool keydownResult = keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame; @@ -3202,7 +3275,7 @@ bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent) #if PLATFORM(MAC) keypress->keypressCommands() = keydown->keypressCommands(); #endif - node->dispatchEvent(keypress, ec); + node->dispatchEvent(keypress, IGNORE_EXCEPTION); return keydownResult || keypress->defaultPrevented() || keypress->defaultHandled(); } @@ -3272,7 +3345,7 @@ static void handleKeyboardSelectionMovement(FrameSelection* selection, KeyboardE void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event) { if (event->type() == eventNames().keydownEvent) { - m_frame->editor()->handleKeyboardEvent(event); + m_frame->editor().handleKeyboardEvent(event); if (event->defaultHandled()) return; if (event->keyIdentifier() == "U+0009") @@ -3290,7 +3363,7 @@ void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event) handleKeyboardSelectionMovement(m_frame->selection(), event); } if (event->type() == eventNames().keypressEvent) { - m_frame->editor()->handleKeyboardEvent(event); + m_frame->editor().handleKeyboardEvent(event); if (event->defaultHandled()) return; if (event->charCode() == ' ') @@ -3314,7 +3387,7 @@ bool EventHandler::dragHysteresisExceeded(const FloatPoint& dragViewportLocation IntSize delta = dragLocation - m_mouseDownPos; int threshold = GeneralDragHysteresis; - switch (dragState().m_dragType) { + switch (dragState().type) { case DragSourceActionSelection: threshold = TextDragHysteresis; break; @@ -3336,23 +3409,25 @@ bool EventHandler::dragHysteresisExceeded(const FloatPoint& dragViewportLocation void EventHandler::freeClipboard() { - if (dragState().m_dragClipboard) - dragState().m_dragClipboard->setAccessPolicy(ClipboardNumb); + if (!dragState().clipboard) + return; + dragState().clipboard->setAccessPolicy(ClipboardNumb); + dragState().clipboard = 0; } void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperation operation) { // Send a hit test request so that RenderLayer gets a chance to update the :hover and :active pseudoclasses. - HitTestRequest request(HitTestRequest::Release); + HitTestRequest request(HitTestRequest::Release | HitTestRequest::DisallowShadowContent); prepareMouseEvent(request, event); - if (dragState().m_dragSrc && dragState().shouldDispatchEvents()) { - dragState().m_dragClipboard->setDestinationOperation(operation); - // for now we don't care if event handler cancels default behavior, since there is none + if (dragState().source && dragState().shouldDispatchEvents) { + dragState().clipboard->setDestinationOperation(operation); + // For now we don't care if event handler cancels default behavior, since there is no default behavior. dispatchDragSrcEvent(eventNames().dragendEvent, event); } freeClipboard(); - dragState().m_dragSrc = 0; + dragState().source = 0; // In case the drag was ended due to an escape key press we need to ensure // that consecutive mousemove events don't reinitiate the drag and drop. m_mouseDownMayStartDrag = false; @@ -3360,15 +3435,15 @@ void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperat void EventHandler::updateDragStateAfterEditDragIfNeeded(Element* rootEditableElement) { - // If inserting the dragged contents removed the drag source, we still want to fire dragend at the root editble element. - if (dragState().m_dragSrc && !dragState().m_dragSrc->inDocument()) - dragState().m_dragSrc = rootEditableElement; + // If inserting the dragged contents removed the drag source, we still want to fire dragend at the root editable element. + if (dragState().source && !dragState().source->inDocument()) + dragState().source = rootEditableElement; } -// returns if we should continue "default processing", i.e., whether eventhandler canceled +// Return value indicates if we should continue "default processing", i.e., whether event handler canceled. bool EventHandler::dispatchDragSrcEvent(const AtomicString& eventType, const PlatformMouseEvent& event) { - return !dispatchDragEvent(eventType, dragState().m_dragSrc.get(), event, dragState().m_dragClipboard.get()); + return !dispatchDragEvent(eventType, dragState().source.get(), event, dragState().clipboard.get()); } static bool ExactlyOneBitSet(DragSourceAction n) @@ -3392,48 +3467,42 @@ bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event, CheckDr // Careful that the drag starting logic stays in sync with eventMayStartDrag() - if (m_mouseDownMayStartDrag && !dragState().m_dragSrc) { - dragState().m_eventDispatchPolicy = (updateDragSourceActionsAllowed() & DragSourceActionDHTML) ? DragState::DispatchEvents: DragState::DoNotDispatchEvents; + if (m_mouseDownMayStartDrag && !dragState().source) { + dragState().shouldDispatchEvents = (updateDragSourceActionsAllowed() & DragSourceActionDHTML); // try to find an element that wants to be dragged - HitTestRequest request(HitTestRequest::ReadOnly); + HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowShadowContent); HitTestResult result(m_mouseDownPos); m_frame->contentRenderer()->hitTest(request, result); - Node* node = result.innerNode(); - if (node && m_frame->page()) - dragState().m_dragSrc = m_frame->page()->dragController()->draggableNode(m_frame, node, m_mouseDownPos, dragState()); - else - dragState().m_dragSrc = 0; + if (m_frame->page()) + dragState().source = m_frame->page()->dragController()->draggableElement(m_frame, result.innerElement(), m_mouseDownPos, dragState()); - if (!dragState().m_dragSrc) + if (!dragState().source) m_mouseDownMayStartDrag = false; // no element is draggable else - m_dragMayStartSelectionInstead = (dragState().m_dragType & DragSourceActionSelection); + m_dragMayStartSelectionInstead = (dragState().type & DragSourceActionSelection); } // For drags starting in the selection, the user must wait between the mousedown and mousedrag, // or else we bail on the dragging stuff and allow selection to occur - if (m_mouseDownMayStartDrag && m_dragMayStartSelectionInstead && (dragState().m_dragType & DragSourceActionSelection) && event.event().timestamp() - m_mouseDownTimestamp < TextDragDelay) { + if (m_mouseDownMayStartDrag && m_dragMayStartSelectionInstead && (dragState().type & DragSourceActionSelection) && event.event().timestamp() - m_mouseDownTimestamp < TextDragDelay) { ASSERT(event.event().type() == PlatformEvent::MouseMoved); - if ((dragState().m_dragType & DragSourceActionImage)) { + if ((dragState().type & DragSourceActionImage)) { // ... unless the mouse is over an image, then we start dragging just the image - dragState().m_dragType = DragSourceActionImage; - } else if (!(dragState().m_dragType & (DragSourceActionDHTML | DragSourceActionLink))) { + dragState().type = DragSourceActionImage; + } else if (!(dragState().type & (DragSourceActionDHTML | DragSourceActionLink))) { // ... but only bail if we're not over an unselectable element. m_mouseDownMayStartDrag = false; - dragState().m_dragSrc = 0; + dragState().source = 0; // ... but if this was the first click in the window, we don't even want to start selection if (eventActivatedView(event.event())) m_mouseDownMayStartSelect = false; } else { // Prevent the following case from occuring: // 1. User starts a drag immediately after mouse down over an unselectable element. - // 2. We enter this block and decided that since we're over an unselectable element, - // don't cancel the drag. - // 3. The drag gets resolved as a potential selection drag below /but/ we haven't - // exceeded the drag hysteresis yet. - // 4. We enter this block again, and since it's now marked as a selection drag, we - // cancel the drag. + // 2. We enter this block and decided that since we're over an unselectable element, don't cancel the drag. + // 3. The drag gets resolved as a potential selection drag below /but/ we haven't exceeded the drag hysteresis yet. + // 4. We enter this block again, and since it's now marked as a selection drag, we cancel the drag. m_dragMayStartSelectionInstead = false; } } @@ -3441,12 +3510,12 @@ bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event, CheckDr if (!m_mouseDownMayStartDrag) return !mouseDownMayStartSelect() && !m_mouseDownMayStartAutoscroll; - if (!ExactlyOneBitSet(dragState().m_dragType)) { - ASSERT((dragState().m_dragType & DragSourceActionSelection)); - ASSERT((dragState().m_dragType & ~DragSourceActionSelection) == DragSourceActionDHTML - || (dragState().m_dragType & ~DragSourceActionSelection) == DragSourceActionImage - || (dragState().m_dragType & ~DragSourceActionSelection) == DragSourceActionLink); - dragState().m_dragType = DragSourceActionSelection; + if (!ExactlyOneBitSet(dragState().type)) { + ASSERT((dragState().type & DragSourceActionSelection)); + ASSERT((dragState().type & ~DragSourceActionSelection) == DragSourceActionDHTML + || (dragState().type & ~DragSourceActionSelection) == DragSourceActionImage + || (dragState().type & ~DragSourceActionSelection) == DragSourceActionLink); + dragState().type = DragSourceActionSelection; } // We are starting a text/image/url drag, so the cursor should be an arrow @@ -3463,19 +3532,19 @@ bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event, CheckDr DragOperation srcOp = DragOperationNone; - freeClipboard(); // would only happen if we missed a dragEnd. Do it anyway, just - // to make sure it gets numbified - dragState().m_dragClipboard = createDraggingClipboard(); + // This does work only if we missed a dragEnd. Do it anyway, just to make sure the old clipboard gets numbed. + freeClipboard(); + + dragState().clipboard = createDraggingClipboard(); - if (dragState().shouldDispatchEvents()) { - // Check to see if the is a DOM based drag, if it is get the DOM specified drag - // image and offset - if (dragState().m_dragType == DragSourceActionDHTML) { - if (RenderObject* renderer = dragState().m_dragSrc->renderer()) { + if (dragState().shouldDispatchEvents) { + // Check to see if the is a DOM based drag. If it is, get the DOM specified drag image and offset. + if (dragState().type == DragSourceActionDHTML) { + if (RenderObject* renderer = dragState().source->renderer()) { // FIXME: This doesn't work correctly with transforms. FloatPoint absPos = renderer->localToAbsolute(); IntSize delta = m_mouseDownPos - roundedIntPoint(absPos); - dragState().m_dragClipboard->setDragImageElement(dragState().m_dragSrc.get(), toPoint(delta)); + dragState().clipboard->setDragImage(dragState().source.get(), delta.width(), delta.height()); } else { // The renderer has disappeared, this can happen if the onStartDrag handler has hidden // the element in some way. In this case we just kill the drag. @@ -3489,17 +3558,16 @@ bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event, CheckDr // Invalidate clipboard here against anymore pasteboard writing for security. The drag // image can still be changed as we drag, but not the pasteboard data. - dragState().m_dragClipboard->setAccessPolicy(ClipboardImageWritable); + dragState().clipboard->setAccessPolicy(ClipboardImageWritable); if (m_mouseDownMayStartDrag) { - // gather values from DHTML element, if it set any - srcOp = dragState().m_dragClipboard->sourceOperation(); + // Gather values from DHTML element, if it set any. + srcOp = dragState().clipboard->sourceOperation(); // Yuck, a draggedImage:moveTo: message can be fired as a result of kicking off the - // drag with dragImage! Because of that dumb reentrancy, we may think we've not - // started the drag when that happens. So we have to assume it's started before we - // kick it off. - dragState().m_dragClipboard->setDragHasStarted(); + // drag with dragImage! Because of that dumb reentrancy, we may think we've not + // started the drag when that happens. So we have to assume it's started before we kick it off. + dragState().clipboard->setDragHasStarted(); } } @@ -3507,15 +3575,14 @@ bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event, CheckDr Page* page = m_frame->page(); DragController* dragController = page ? page->dragController() : 0; m_didStartDrag = dragController && dragController->startDrag(m_frame, dragState(), srcOp, event.event(), m_mouseDownPos); - // In WebKit2 we could reenter this code and start another drag. - // On OS X this causes problems with the ownership of the pasteboard - // and the promised types. + // In WebKit2 we could re-enter this code and start another drag. + // On OS X this causes problems with the ownership of the pasteboard and the promised types. if (m_didStartDrag) { m_mouseDownMayStartDrag = false; return true; } - if (dragState().shouldDispatchEvents()) { - // Drag was canned at the last minute - we owe m_dragSrc a DRAGEND event + if (dragState().source && dragState().shouldDispatchEvents) { + // Drag was canned at the last minute. We owe dragSource a dragend event. dispatchDragSrcEvent(eventNames().dragendEvent, event.event()); m_mouseDownMayStartDrag = false; } @@ -3523,9 +3590,9 @@ bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event, CheckDr cleanupDrag: if (!m_mouseDownMayStartDrag) { - // something failed to start the drag, cleanup + // Something failed to start the drag, clean up. freeClipboard(); - dragState().m_dragSrc = 0; + dragState().source = 0; } // No more default handling (like selection), whether we're past the hysteresis bounds or not @@ -3556,8 +3623,7 @@ bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEve RefPtr<TextEvent> event = TextEvent::create(m_frame->document()->domWindow(), text, inputType); event->setUnderlyingEvent(underlyingEvent); - ExceptionCode ec; - target->dispatchEvent(event, ec); + target->dispatchEvent(event, IGNORE_EXCEPTION); return event->defaultHandled(); } @@ -3586,23 +3652,16 @@ bool EventHandler::tabsToLinks(KeyboardEvent* event) const if (!page) return false; - bool tabsToLinksClientCallResult = page->chrome()->client()->keyboardUIMode() & KeyboardAccessTabsToLinks; + bool tabsToLinksClientCallResult = page->chrome().client()->keyboardUIMode() & KeyboardAccessTabsToLinks; return eventInvertsTabsToLinksClientCallResult(event) ? !tabsToLinksClientCallResult : tabsToLinksClientCallResult; } void EventHandler::defaultTextInputEventHandler(TextEvent* event) { - if (m_frame->editor()->handleTextEvent(event)) + if (m_frame->editor().handleTextEvent(event)) event->setDefaultHandled(); } -#if PLATFORM(QT) -// Qt handles the space event in platform-specific WebKit code. -// Eventually it would be good to eliminate that and use the code here instead. -void EventHandler::defaultSpaceEventHandler(KeyboardEvent*) -{ -} -#else void EventHandler::defaultSpaceEventHandler(KeyboardEvent* event) { @@ -3625,8 +3684,6 @@ void EventHandler::defaultSpaceEventHandler(KeyboardEvent* event) event->setDefaultHandled(); } -#endif - void EventHandler::defaultBackspaceEventHandler(KeyboardEvent* event) { ASSERT(event->type() == eventNames().keydownEvent); @@ -3634,7 +3691,7 @@ void EventHandler::defaultBackspaceEventHandler(KeyboardEvent* event) if (event->ctrlKey() || event->metaKey() || event->altKey() || event->altGraphKey()) return; - if (!m_frame->editor()->behavior().shouldNavigateBackOnBackspace()) + if (!m_frame->editor().behavior().shouldNavigateBackOnBackspace()) return; Page* page = m_frame->page(); @@ -3706,19 +3763,14 @@ void EventHandler::defaultTabEventHandler(KeyboardEvent* event) void EventHandler::capsLockStateMayHaveChanged() { Document* d = m_frame->document(); - if (Node* node = d->focusedNode()) { - if (RenderObject* r = node->renderer()) { + if (Element* element = d->focusedElement()) { + if (RenderObject* r = element->renderer()) { if (r->isTextField()) toRenderTextControlSingleLine(r)->capsLockStateMayHaveChanged(); } } } -void EventHandler::sendResizeEvent() -{ - m_frame->document()->enqueueWindowEvent(Event::create(eventNames().resizeEvent, false, false)); -} - void EventHandler::sendScrollEvent() { setFrameWasScrolledByUser(); @@ -3779,6 +3831,21 @@ static const AtomicString& eventNameForTouchPointState(PlatformTouchPoint::State } } +HitTestResult EventHandler::hitTestResultInFrame(Frame* frame, const LayoutPoint& point, HitTestRequest::HitTestRequestType hitType) +{ + HitTestResult result(point); + + if (!frame || !frame->contentRenderer()) + return result; + if (frame->view()) { + IntRect rect = frame->view()->visibleContentRect(); + if (!rect.contains(roundedIntPoint(point))) + return result; + } + frame->contentRenderer()->hitTest(HitTestRequest(hitType), result); + return result; +} + bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event) { // First build up the lists to use for the 'touches', 'targetTouches' and 'changedTouches' attributes @@ -3806,7 +3873,18 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event) UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture); - for (unsigned i = 0; i < points.size(); ++i) { + unsigned i; + bool freshTouchEvents = true; + bool allTouchReleased = true; + for (i = 0; i < points.size(); ++i) { + const PlatformTouchPoint& point = points[i]; + if (point.state() != PlatformTouchPoint::TouchPressed) + freshTouchEvents = false; + if (point.state() != PlatformTouchPoint::TouchReleased && point.state() != PlatformTouchPoint::TouchCancelled) + allTouchReleased = false; + } + + for (i = 0; i < points.size(); ++i) { const PlatformTouchPoint& point = points[i]; PlatformTouchPoint::State pointState = point.state(); LayoutPoint pagePoint = documentPointForWindowPoint(m_frame, point.pos()); @@ -3836,37 +3914,54 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event) break; } -#if ENABLE(GESTURE_EVENTS) if (shouldGesturesTriggerActive()) hitType |= HitTestRequest::ReadOnly; -#endif // Increment the platform touch id by 1 to avoid storing a key of 0 in the hashmap. unsigned touchPointTargetKey = point.id() + 1; RefPtr<EventTarget> touchTarget; if (pointState == PlatformTouchPoint::TouchPressed) { - HitTestResult result = hitTestResultAtPoint(pagePoint, /*allowShadowContent*/ false, false, DontHitTestScrollbars, hitType); + HitTestResult result; + if (freshTouchEvents) { + result = hitTestResultAtPoint(pagePoint, hitType); + m_originatingTouchPointTargetKey = touchPointTargetKey; + } else if (m_originatingTouchPointDocument.get() && m_originatingTouchPointDocument->frame()) { + LayoutPoint pagePointInOriginatingDocument = documentPointForWindowPoint(m_originatingTouchPointDocument->frame(), point.pos()); + result = hitTestResultInFrame(m_originatingTouchPointDocument->frame(), pagePointInOriginatingDocument, hitType); + if (!result.innerNode()) + continue; + } else + continue; + + // FIXME: Is the following code different from just calling innerElement? Node* node = result.innerNode(); ASSERT(node); - // Touch events should not go to text nodes if (node->isTextNode()) - node = node->parentNode(); + node = EventPathWalker::parent(node); if (InspectorInstrumentation::handleTouchEvent(m_frame->page(), node)) return true; Document* doc = node->document(); + // Record the originating touch document even if it does not have a touch listener. + if (freshTouchEvents) { + m_originatingTouchPointDocument = doc; + freshTouchEvents = false; + } if (!doc) continue; - if (!doc->touchEventHandlerCount()) + if (!doc->hasTouchEventHandlers()) continue; - m_originatingTouchPointTargets.set(touchPointTargetKey, node); touchTarget = node; } else if (pointState == PlatformTouchPoint::TouchReleased || pointState == PlatformTouchPoint::TouchCancelled) { - // We only perform a hittest on release or cancel to unset :active or :hover state. - hitTestResultAtPoint(pagePoint, /*allowShadowContent*/ false, false, DontHitTestScrollbars, hitType); + // No need to perform a hit-test since we only need to unset :hover and :active states. + if (!shouldGesturesTriggerActive() && allTouchReleased) + m_frame->document()->updateHoverActiveState(hitType, 0); + if (touchPointTargetKey == m_originatingTouchPointTargetKey) + m_originatingTouchPointTargetKey = 0; + // The target should be the original target for this touch, so get it from the hashmap. As it's a release or cancel // we also remove it from the map. touchTarget = m_originatingTouchPointTargets.take(touchPointTargetKey); @@ -3879,7 +3974,7 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event) Document* doc = touchTarget->toNode()->document(); if (!doc) continue; - if (!doc->touchEventHandlerCount()) + if (!doc->hasTouchEventHandlers()) continue; Frame* targetFrame = doc->frame(); if (!targetFrame) @@ -3927,6 +4022,8 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event) } } m_touchPressed = touches->length() > 0; + if (allTouchReleased) + m_originatingTouchPointDocument.clear(); // Now iterate the changedTouches list and m_targets within it, sending events to the targets as required. bool swallowedEvent = false; @@ -3950,8 +4047,7 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event) TouchEvent::create(effectiveTouches.get(), targetTouches.get(), changedTouches[state].m_touches.get(), stateName, touchEventTarget->toNode()->document()->defaultView(), 0, 0, 0, 0, event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey()); - ExceptionCode ec = 0; - touchEventTarget->dispatchEvent(touchEvent.get(), ec); + touchEventTarget->toNode()->dispatchTouchEvent(touchEvent.get()); swallowedEvent = swallowedEvent || touchEvent->defaultPrevented() || touchEvent->defaultHandled(); } } @@ -3968,13 +4064,26 @@ bool EventHandler::dispatchSyntheticTouchEventIfEnabled(const PlatformMouseEvent if (eventType != PlatformEvent::MouseMoved && eventType != PlatformEvent::MousePressed && eventType != PlatformEvent::MouseReleased) return false; - if (eventType == PlatformEvent::MouseMoved && !m_touchPressed) + HitTestRequest request(HitTestRequest::Active | HitTestRequest::DisallowShadowContent); + MouseEventWithHitTestResults mev = prepareMouseEvent(request, event); + if (mev.scrollbar() || subframeForHitTestResult(mev)) return false; + // The order is important. This check should follow the subframe test: http://webkit.org/b/111292. + if (eventType == PlatformEvent::MouseMoved && !m_touchPressed) + return true; + SyntheticSingleTouchEvent touchEvent(event); return handleTouchEvent(touchEvent); } #endif +void EventHandler::setLastKnownMousePosition(const PlatformMouseEvent& event) +{ + m_mousePositionIsUnknown = false; + m_lastKnownMousePosition = event.position(); + m_lastKnownMouseGlobalPosition = event.globalPosition(); } + +} // namespace WebCore diff --git a/Source/WebCore/page/EventHandler.h b/Source/WebCore/page/EventHandler.h index c15898a02..a72eb97e1 100644 --- a/Source/WebCore/page/EventHandler.h +++ b/Source/WebCore/page/EventHandler.h @@ -28,9 +28,9 @@ #include "Cursor.h" #include "DragActions.h" -#include "DragState.h" #include "FocusDirection.h" #include "HitTestRequest.h" +#include "LayoutPoint.h" #include "PlatformMouseEvent.h" #include "PlatformWheelEvent.h" #include "ScrollTypes.h" @@ -51,7 +51,10 @@ class NSView; namespace WebCore { +class AutoscrollController; class Clipboard; +class Document; +class Element; class Event; class EventTarget; class FloatPoint; @@ -78,6 +81,8 @@ class VisibleSelection; class WheelEvent; class Widget; +struct DragState; + #if ENABLE(GESTURE_EVENTS) class PlatformGestureEvent; #endif @@ -89,7 +94,6 @@ extern const int TextDragHysteresis; extern const int GeneralDragHysteresis; #endif // ENABLE(DRAG_SUPPORT) -enum HitTestScrollbars { ShouldHitTestScrollbars, DontHitTestScrollbars }; enum AppendTrailingWhitespace { ShouldAppendTrailingWhitespace, DontAppendTrailingWhitespace }; enum CheckDragHysteresis { ShouldCheckDragHysteresis, DontCheckDragHysteresis }; @@ -109,20 +113,25 @@ public: Node* mousePressNode() const; void setMousePressNode(PassRefPtr<Node>); +#if ENABLE(PAN_SCROLLING) + void didPanScrollStart(); + void didPanScrollStop(); void startPanScrolling(RenderObject*); +#endif void stopAutoscrollTimer(bool rendererIsBeingDestroyed = false); RenderObject* autoscrollRenderer() const; void updateAutoscrollRenderer(); - bool autoscrollInProgress() const { return m_autoscrollInProgress; } + bool autoscrollInProgress() const; + bool mouseDownWasInSubframe() const { return m_mouseDownWasInSubframe; } + bool panScrollInProgress() const; void dispatchFakeMouseMoveEventSoon(); void dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad&); - HitTestResult hitTestResultAtPoint(const LayoutPoint&, bool allowShadowContent, bool ignoreClipping = false, - HitTestScrollbars scrollbars = DontHitTestScrollbars, - HitTestRequest::HitTestRequestType hitType = HitTestRequest::ReadOnly | HitTestRequest::Active, - const LayoutSize& padding = LayoutSize()); + HitTestResult hitTestResultAtPoint(const LayoutPoint&, + HitTestRequest::HitTestRequestType hitType = HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowShadowContent, + const LayoutSize& padding = LayoutSize()); bool mousePressed() const { return m_mousePressed; } void setMousePressed(bool pressed) { m_mousePressed = pressed; } @@ -137,12 +146,13 @@ public: #endif void scheduleHoverStateUpdate(); + void scheduleCursorUpdate(); void setResizingFrameSet(HTMLFrameSetElement*); void resizeLayerDestroyed(); - IntPoint currentMousePosition() const; + IntPoint lastKnownMousePosition() const; Cursor currentMouseCursor() const { return m_currentMouseCursor; } static Frame* subframeForTargetNode(Node*); @@ -174,6 +184,8 @@ public: bool handleGestureLongTap(const PlatformGestureEvent&); bool handleGestureTwoFingerTap(const PlatformGestureEvent&); bool handleGestureScrollUpdate(const PlatformGestureEvent&); + bool handleGestureScrollBegin(const PlatformGestureEvent&); + void clearGestureScrollNodes(); bool isScrollbarHandlingGestures() const; #endif @@ -217,7 +229,6 @@ public: void capsLockStateMayHaveChanged(); // Only called by FrameSelection - void sendResizeEvent(); // Only called in FrameView void sendScrollEvent(); // Ditto #if PLATFORM(MAC) && defined(__OBJC__) @@ -242,6 +253,9 @@ public: #endif bool useHandCursor(Node*, bool isOverLink, bool shiftKey); + void updateCursor(); + + bool isHandlingWheelEvent() const { return m_isHandlingWheelEvent; } private: #if ENABLE(DRAG_SUPPORT) @@ -268,17 +282,11 @@ private: #endif bool handleMouseReleaseEvent(const MouseEventWithHitTestResults&); - OptionalCursor selectCursor(const MouseEventWithHitTestResults&, Scrollbar*); -#if ENABLE(PAN_SCROLLING) - void updatePanScrollState(); -#endif + OptionalCursor selectCursor(const HitTestResult&, bool shiftKey); void hoverTimerFired(Timer<EventHandler>*); + void cursorUpdateTimerFired(Timer<EventHandler>*); - void handleAutoscroll(RenderObject*); - void startAutoscrollTimer(); - void setAutoscrollRenderer(RenderObject*); - void autoscrollTimerFired(Timer<EventHandler>*); bool logicalScrollOverflow(ScrollLogicalDirection, ScrollGranularity, Node* startingNode = 0); bool shouldTurnVerticalTicksIntoHorizontal(const HitTestResult&, const PlatformWheelEvent&) const; @@ -287,11 +295,14 @@ private: static bool isKeyboardOptionTab(KeyboardEvent*); static bool eventInvertsTabsToLinksClientCallResult(KeyboardEvent*); - void fakeMouseMoveEventTimerFired(DeferrableOneShotTimer<EventHandler>*); + void fakeMouseMoveEventTimerFired(Timer<EventHandler>*); void cancelFakeMouseMoveEvent(); + bool isInsideScrollbar(const IntPoint&) const; + #if ENABLE(TOUCH_EVENTS) bool dispatchSyntheticTouchEventIfEnabled(const PlatformMouseEvent&); + HitTestResult hitTestResultInFrame(Frame*, const LayoutPoint&, HitTestRequest::HitTestRequestType hitType = HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowShadowContent); #endif void invalidateClick(); @@ -372,9 +383,19 @@ private: #endif #if ENABLE(GESTURE_EVENTS) - bool handleGestureScrollCore(const PlatformGestureEvent&, PlatformWheelEventGranularity, bool latchedWheel); bool handleGestureTapDown(); bool handleGestureForTextSelectionOrContextMenu(const PlatformGestureEvent&); + bool passGestureEventToWidget(const PlatformGestureEvent&, Widget*); + bool passGestureEventToWidgetIfPossible(const PlatformGestureEvent&, RenderObject*); + bool sendScrollEventToView(const PlatformGestureEvent&, const FloatSize&); +#endif + + void setLastKnownMousePosition(const PlatformMouseEvent&); + +#if ENABLE(CURSOR_VISIBILITY) + void startAutoHideCursorTimer(); + void cancelAutoHideCursorTimer(); + void autoHideCursorTimerFired(Timer<EventHandler>*); #endif Frame* m_frame; @@ -396,21 +417,16 @@ private: LayoutPoint m_dragStartPos; #endif - IntPoint m_panScrollStartPos; - bool m_panScrollInProgress; - bool m_panScrollButtonPressed; - bool m_springLoadedPanScrollInProgress; Timer<EventHandler> m_hoverTimer; - - Timer<EventHandler> m_autoscrollTimer; - RenderObject* m_autoscrollRenderer; - bool m_autoscrollInProgress; + Timer<EventHandler> m_cursorUpdateTimer; + + OwnPtr<AutoscrollController> m_autoscrollController; bool m_mouseDownMayStartAutoscroll; bool m_mouseDownWasInSubframe; - DeferrableOneShotTimer<EventHandler> m_fakeMouseMoveEventTimer; + Timer<EventHandler> m_fakeMouseMoveEventTimer; #if ENABLE(SVG) bool m_svgPan; @@ -441,8 +457,9 @@ private: LayoutSize m_offsetFromResizeCorner; // In the coords of m_resizeLayer. - IntPoint m_currentMousePosition; - IntPoint m_currentMouseGlobalPosition; + bool m_mousePositionIsUnknown; + IntPoint m_lastKnownMousePosition; + IntPoint m_lastKnownMouseGlobalPosition; IntPoint m_mouseDownPos; // In our view's coords. double m_mouseDownTimestamp; PlatformMouseEvent m_mouseDown; @@ -460,18 +477,27 @@ private: #if ENABLE(TOUCH_EVENTS) typedef HashMap<int, RefPtr<EventTarget> > TouchTargetMap; TouchTargetMap m_originatingTouchPointTargets; + RefPtr<Document> m_originatingTouchPointDocument; + unsigned m_originatingTouchPointTargetKey; bool m_touchPressed; #endif #if ENABLE(GESTURE_EVENTS) RefPtr<Node> m_scrollGestureHandlingNode; + bool m_lastHitTestResultOverWidget; + RefPtr<Node> m_previousGestureScrolledNode; RefPtr<Scrollbar> m_scrollbarHandlingScrollGesture; #endif - double m_mouseMovedDurationRunningAverage; + double m_maxMouseMovedDuration; PlatformEvent::Type m_baseEventType; bool m_didStartDrag; bool m_didLongPressInvokeContextMenu; + bool m_isHandlingWheelEvent; + +#if ENABLE(CURSOR_VISIBILITY) + Timer<EventHandler> m_autoHideCursorTimer; +#endif }; } // namespace WebCore diff --git a/Source/WebCore/page/EventSource.cpp b/Source/WebCore/page/EventSource.cpp index 610170208..77a8e6f33 100644 --- a/Source/WebCore/page/EventSource.cpp +++ b/Source/WebCore/page/EventSource.cpp @@ -1,6 +1,5 @@ /* - * Copyright (C) 2009 Ericsson AB - * All rights reserved. + * Copyright (C) 2009, 2012 Ericsson AB. All rights reserved. * Copyright (C) 2010 Apple Inc. All rights reserved. * Copyright (C) 2011, Code Aurora Forum. All rights reserved. * @@ -36,15 +35,19 @@ #include "ContentSecurityPolicy.h" #include "DOMWindow.h" +#include "Dictionary.h" +#include "Document.h" #include "Event.h" #include "EventException.h" #include "ExceptionCode.h" +#include "Frame.h" #include "MemoryCache.h" #include "MessageEvent.h" #include "ResourceError.h" #include "ResourceRequest.h" #include "ResourceResponse.h" #include "ScriptCallStack.h" +#include "ScriptController.h" #include "ScriptExecutionContext.h" #include "SecurityOrigin.h" #include "SerializedScriptValue.h" @@ -56,20 +59,21 @@ namespace WebCore { const unsigned long long EventSource::defaultReconnectDelay = 3000; -inline EventSource::EventSource(const KURL& url, ScriptExecutionContext* context) - : ActiveDOMObject(context, this) +inline EventSource::EventSource(ScriptExecutionContext* context, const KURL& url, const Dictionary& eventSourceInit) + : ActiveDOMObject(context) , m_url(url) + , m_withCredentials(false) , m_state(CONNECTING) , m_decoder(TextResourceDecoder::create("text/plain", "UTF-8")) - , m_reconnectTimer(this, &EventSource::reconnectTimerFired) + , m_connectTimer(this, &EventSource::connectTimerFired) , m_discardTrailingNewline(false) , m_requestInFlight(false) , m_reconnectDelay(defaultReconnectDelay) - , m_origin(context->securityOrigin()->toString()) { + eventSourceInit.get("withCredentials", m_withCredentials); } -PassRefPtr<EventSource> EventSource::create(ScriptExecutionContext* context, const String& url, ExceptionCode& ec) +PassRefPtr<EventSource> EventSource::create(ScriptExecutionContext* context, const String& url, const Dictionary& eventSourceInit, ExceptionCode& ec) { if (url.isEmpty()) { ec = SYNTAX_ERR; @@ -82,22 +86,22 @@ PassRefPtr<EventSource> EventSource::create(ScriptExecutionContext* context, con return 0; } - // FIXME: Should support at least some cross-origin requests. - if (!context->securityOrigin()->canRequest(fullURL)) { - ec = SECURITY_ERR; - return 0; + // FIXME: Convert this to check the isolated world's Content Security Policy once webkit.org/b/104520 is solved. + bool shouldBypassMainWorldContentSecurityPolicy = false; + if (context->isDocument()) { + Document* document = toDocument(context); + shouldBypassMainWorldContentSecurityPolicy = document->frame()->script()->shouldBypassMainWorldContentSecurityPolicy(); } - - if (!context->contentSecurityPolicy()->allowConnectToSource(fullURL)) { + if (!shouldBypassMainWorldContentSecurityPolicy && !context->contentSecurityPolicy()->allowConnectToSource(fullURL)) { // FIXME: Should this be throwing an exception? ec = SECURITY_ERR; return 0; } - RefPtr<EventSource> source = adoptRef(new EventSource(fullURL, context)); + RefPtr<EventSource> source = adoptRef(new EventSource(context, fullURL, eventSourceInit)); source->setPendingActivity(source.get()); - source->connect(); + source->scheduleInitialConnect(); source->suspendIfNeeded(); return source.release(); @@ -121,11 +125,16 @@ void EventSource::connect() if (!m_lastEventId.isEmpty()) request.setHTTPHeaderField("Last-Event-ID", m_lastEventId); + SecurityOrigin* origin = scriptExecutionContext()->securityOrigin(); + ThreadableLoaderOptions options; options.sendLoadCallbacks = SendCallbacks; options.sniffContent = DoNotSniffContent; - options.allowCredentials = AllowStoredCredentials; - options.shouldBufferData = DoNotBufferData; + options.allowCredentials = (origin->canRequest(m_url) || m_withCredentials) ? AllowStoredCredentials : DoNotAllowStoredCredentials; + options.preflightPolicy = PreventPreflight; + options.crossOriginRequestPolicy = UseAccessControl; + options.dataBufferingPolicy = DoNotBufferData; + options.securityOrigin = origin; m_loader = ThreadableLoader::create(scriptExecutionContext(), this, request, options); @@ -146,14 +155,22 @@ void EventSource::networkRequestEnded() unsetPendingActivity(this); } +void EventSource::scheduleInitialConnect() +{ + ASSERT(m_state == CONNECTING); + ASSERT(!m_requestInFlight); + + m_connectTimer.startOneShot(0); +} + void EventSource::scheduleReconnect() { m_state = CONNECTING; - m_reconnectTimer.startOneShot(m_reconnectDelay / 1000); + m_connectTimer.startOneShot(m_reconnectDelay / 1000.0); dispatchEvent(Event::create(eventNames().errorEvent, false, false)); } -void EventSource::reconnectTimerFired(Timer<EventSource>*) +void EventSource::connectTimerFired(Timer<EventSource>*) { connect(); } @@ -163,6 +180,11 @@ String EventSource::url() const return m_url.string(); } +bool EventSource::withCredentials() const +{ + return m_withCredentials; +} + EventSource::State EventSource::readyState() const { return m_state; @@ -175,16 +197,16 @@ void EventSource::close() return; } - // Stop trying to reconnect if EventSource was explicitly closed or if ActiveDOMObject::stop() was called. - if (m_reconnectTimer.isActive()) { - m_reconnectTimer.stop(); - unsetPendingActivity(this); - } + // Stop trying to connect/reconnect if EventSource was explicitly closed or if ActiveDOMObject::stop() was called. + if (m_connectTimer.isActive()) + m_connectTimer.stop(); if (m_requestInFlight) m_loader->cancel(); - - m_state = CLOSED; + else { + m_state = CLOSED; + unsetPendingActivity(this); + } } const AtomicString& EventSource::interfaceName() const @@ -202,6 +224,7 @@ void EventSource::didReceiveResponse(unsigned long, const ResourceResponse& resp ASSERT(m_state == CONNECTING); ASSERT(m_requestInFlight); + m_eventStreamOrigin = SecurityOrigin::create(response.url())->toString(); int statusCode = response.httpStatusCode(); bool mimeTypeIsValid = response.mimeType() == "text/event-stream"; bool responseIsValid = statusCode == 200 && mimeTypeIsValid; @@ -215,7 +238,7 @@ void EventSource::didReceiveResponse(unsigned long, const ResourceResponse& resp message.append(charset); message.appendLiteral("\") that is not UTF-8. Aborting the connection."); // FIXME: We are missing the source line. - scriptExecutionContext()->addConsoleMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, message.toString()); + scriptExecutionContext()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, message.toString()); } } else { // To keep the signal-to-noise ratio low, we only log 200-response with an invalid MIME type. @@ -225,7 +248,7 @@ void EventSource::didReceiveResponse(unsigned long, const ResourceResponse& resp message.append(response.mimeType()); message.appendLiteral("\") that is not \"text/event-stream\". Aborting the connection."); // FIXME: We are missing the source line. - scriptExecutionContext()->addConsoleMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, message.toString()); + scriptExecutionContext()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, message.toString()); } } @@ -274,12 +297,29 @@ void EventSource::didFail(const ResourceError& error) networkRequestEnded(); } +void EventSource::didFailAccessControlCheck(const ResourceError& error) +{ + String message = makeString("EventSource cannot load ", error.failingURL(), ". ", error.localizedDescription()); + scriptExecutionContext()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, message); + + abortConnectionAttempt(); +} + void EventSource::didFailRedirectCheck() { + abortConnectionAttempt(); +} + +void EventSource::abortConnectionAttempt() +{ ASSERT(m_state == CONNECTING); - ASSERT(m_requestInFlight); - m_loader->cancel(); + if (m_requestInFlight) + m_loader->cancel(); + else { + m_state = CLOSED; + unsetPendingActivity(this); + } ASSERT(m_state == CLOSED); dispatchEvent(Event::create(eventNames().errorEvent, false, false)); @@ -330,7 +370,7 @@ void EventSource::parseEventStream() m_receiveBuf.remove(0, bufPos); } -void EventSource::parseEventStreamLine(unsigned int bufPos, int fieldLength, int lineLength) +void EventSource::parseEventStreamLine(unsigned bufPos, int fieldLength, int lineLength) { if (!lineLength) { if (!m_data.isEmpty()) { @@ -387,7 +427,7 @@ void EventSource::stop() PassRefPtr<MessageEvent> EventSource::createMessageEvent() { RefPtr<MessageEvent> event = MessageEvent::create(); - event->initMessageEvent(m_eventName.isEmpty() ? eventNames().messageEvent : AtomicString(m_eventName), false, false, SerializedScriptValue::create(String::adopt(m_data)), m_origin, m_lastEventId, 0, 0); + event->initMessageEvent(m_eventName.isEmpty() ? eventNames().messageEvent : AtomicString(m_eventName), false, false, SerializedScriptValue::create(String::adopt(m_data)), m_eventStreamOrigin, m_lastEventId, 0, 0); return event.release(); } diff --git a/Source/WebCore/page/EventSource.h b/Source/WebCore/page/EventSource.h index 05181821b..7f91e7bfc 100644 --- a/Source/WebCore/page/EventSource.h +++ b/Source/WebCore/page/EventSource.h @@ -1,6 +1,5 @@ /* - * Copyright (C) 2009 Ericsson AB - * All rights reserved. + * Copyright (C) 2009, 2012 Ericsson AB. All rights reserved. * Copyright (C) 2010 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -43,84 +42,89 @@ namespace WebCore { - class MessageEvent; - class ResourceResponse; - class TextResourceDecoder; - class ThreadableLoader; - - class EventSource : public RefCounted<EventSource>, public EventTarget, private ThreadableLoaderClient, public ActiveDOMObject { - WTF_MAKE_FAST_ALLOCATED; - public: - static PassRefPtr<EventSource> create(ScriptExecutionContext*, const String& url, ExceptionCode&); - virtual ~EventSource(); - - static const unsigned long long defaultReconnectDelay; - - String url() const; - - enum State { - CONNECTING = 0, - OPEN = 1, - CLOSED = 2, - }; - - State readyState() const; - - DEFINE_ATTRIBUTE_EVENT_LISTENER(open); - DEFINE_ATTRIBUTE_EVENT_LISTENER(message); - DEFINE_ATTRIBUTE_EVENT_LISTENER(error); - - void close(); - - using RefCounted<EventSource>::ref; - using RefCounted<EventSource>::deref; - - virtual const AtomicString& interfaceName() const; - virtual ScriptExecutionContext* scriptExecutionContext() const; - - virtual void stop(); - - private: - EventSource(const KURL&, ScriptExecutionContext*); - - virtual void refEventTarget() { ref(); } - virtual void derefEventTarget() { deref(); } - virtual EventTargetData* eventTargetData(); - virtual EventTargetData* ensureEventTargetData(); - - virtual void didReceiveResponse(unsigned long, const ResourceResponse&); - virtual void didReceiveData(const char*, int); - virtual void didFinishLoading(unsigned long, double); - virtual void didFail(const ResourceError&); - virtual void didFailRedirectCheck(); - - void connect(); - void networkRequestEnded(); - void scheduleReconnect(); - void reconnectTimerFired(Timer<EventSource>*); - void parseEventStream(); - void parseEventStreamLine(unsigned int pos, int fieldLength, int lineLength); - PassRefPtr<MessageEvent> createMessageEvent(); - - KURL m_url; - State m_state; - - RefPtr<TextResourceDecoder> m_decoder; - RefPtr<ThreadableLoader> m_loader; - Timer<EventSource> m_reconnectTimer; - Vector<UChar> m_receiveBuf; - bool m_discardTrailingNewline; - bool m_requestInFlight; - - String m_eventName; - Vector<UChar> m_data; - String m_currentlyParsedEventId; - String m_lastEventId; - unsigned long long m_reconnectDelay; - String m_origin; - - EventTargetData m_eventTargetData; - }; +class Dictionary; +class MessageEvent; +class ResourceResponse; +class TextResourceDecoder; +class ThreadableLoader; + +class EventSource : public RefCounted<EventSource>, public EventTarget, private ThreadableLoaderClient, public ActiveDOMObject { + WTF_MAKE_FAST_ALLOCATED; +public: + static PassRefPtr<EventSource> create(ScriptExecutionContext*, const String& url, const Dictionary&, ExceptionCode&); + virtual ~EventSource(); + + static const unsigned long long defaultReconnectDelay; + + String url() const; + bool withCredentials() const; + + typedef short State; + static const State CONNECTING = 0; + static const State OPEN = 1; + static const State CLOSED = 2; + + State readyState() const; + + DEFINE_ATTRIBUTE_EVENT_LISTENER(open); + DEFINE_ATTRIBUTE_EVENT_LISTENER(message); + DEFINE_ATTRIBUTE_EVENT_LISTENER(error); + + void close(); + + using RefCounted<EventSource>::ref; + using RefCounted<EventSource>::deref; + + virtual const AtomicString& interfaceName() const; + virtual ScriptExecutionContext* scriptExecutionContext() const; + + virtual void stop(); + +private: + EventSource(ScriptExecutionContext*, const KURL&, const Dictionary&); + + virtual void refEventTarget() { ref(); } + virtual void derefEventTarget() { deref(); } + virtual EventTargetData* eventTargetData(); + virtual EventTargetData* ensureEventTargetData(); + + virtual void didReceiveResponse(unsigned long, const ResourceResponse&); + virtual void didReceiveData(const char*, int); + virtual void didFinishLoading(unsigned long, double); + virtual void didFail(const ResourceError&); + virtual void didFailAccessControlCheck(const ResourceError&); + virtual void didFailRedirectCheck(); + + void connect(); + void networkRequestEnded(); + void scheduleInitialConnect(); + void scheduleReconnect(); + void connectTimerFired(Timer<EventSource>*); + void abortConnectionAttempt(); + void parseEventStream(); + void parseEventStreamLine(unsigned pos, int fieldLength, int lineLength); + PassRefPtr<MessageEvent> createMessageEvent(); + + KURL m_url; + bool m_withCredentials; + State m_state; + + RefPtr<TextResourceDecoder> m_decoder; + RefPtr<ThreadableLoader> m_loader; + Timer<EventSource> m_connectTimer; + Vector<UChar> m_receiveBuf; + bool m_discardTrailingNewline; + bool m_requestInFlight; + + String m_eventName; + Vector<UChar> m_data; + String m_currentlyParsedEventId; + String m_lastEventId; + unsigned long long m_reconnectDelay; + String m_eventStreamOrigin; + + EventTargetData m_eventTargetData; +}; } // namespace WebCore diff --git a/Source/WebCore/page/EventSource.idl b/Source/WebCore/page/EventSource.idl index 60d36faa0..a291a9beb 100644 --- a/Source/WebCore/page/EventSource.idl +++ b/Source/WebCore/page/EventSource.idl @@ -30,9 +30,10 @@ */ [ + GlobalContext=DOMWindow&WorkerGlobalScope, ActiveDOMObject, - Constructor(in DOMString scriptUrl), - CallWith=ScriptExecutionContext, + Constructor(DOMString url, optional Dictionary eventSourceInit), + ConstructorCallWith=ScriptExecutionContext, ConstructorRaisesException, EventTarget, JSNoStaticTables @@ -40,6 +41,7 @@ readonly attribute DOMString URL; // Lowercased .url is the one in the spec, but leaving .URL for compatibility reasons. readonly attribute DOMString url; + readonly attribute boolean withCredentials; // ready state const unsigned short CONNECTING = 0; @@ -54,13 +56,12 @@ void close(); // EventTarget interface - void addEventListener(in DOMString type, - in EventListener listener, - in [Optional] boolean useCapture); - void removeEventListener(in DOMString type, - in EventListener listener, - in [Optional] boolean useCapture); - boolean dispatchEvent(in Event evt) - raises(EventException); + void addEventListener(DOMString type, + EventListener listener, + optional boolean useCapture); + void removeEventListener(DOMString type, + EventListener listener, + optional boolean useCapture); + [RaisesException] boolean dispatchEvent(Event evt); }; diff --git a/Source/WebCore/page/FeatureObserver.cpp b/Source/WebCore/page/FeatureObserver.cpp index 31d22c55f..f5397abee 100644 --- a/Source/WebCore/page/FeatureObserver.cpp +++ b/Source/WebCore/page/FeatureObserver.cpp @@ -34,29 +34,31 @@ namespace WebCore { FeatureObserver::FeatureObserver() - : m_featureMask(0) { } FeatureObserver::~FeatureObserver() { - // We always log PageDestruction so that we have a scale for the rest of the features. - HistogramSupport::histogramEnumeration("WebCore.FeatureObserver", PageDestruction, NumberOfFeatures); + updateMeasurements(); +} - if (!m_featureMask) +void FeatureObserver::updateMeasurements() +{ + if (!m_featureBits) return; - for (int i = 0; i < NumberOfFeatures; ++i) { - if (m_featureMask & (1 << i)) - HistogramSupport::histogramEnumeration("WebCore.FeatureObserver", i, NumberOfFeatures); - } + // Clearing feature bits is timing sensitive. Ports other than chromium do not use HistogramSupport, + // and pull the results on certain navigation events instead. + m_featureBits->clearAll(); } -void FeatureObserver::observe(DOMWindow* domWindow, Feature feature) +void FeatureObserver::didCommitLoad() { - ASSERT(domWindow); + updateMeasurements(); +} - Document* document = domWindow->document(); +void FeatureObserver::observe(Document* document, Feature feature) +{ if (!document) return; @@ -67,4 +69,10 @@ void FeatureObserver::observe(DOMWindow* domWindow, Feature feature) page->featureObserver()->didObserve(feature); } +void FeatureObserver::observe(DOMWindow* domWindow, Feature feature) +{ + ASSERT(domWindow); + observe(domWindow->document(), feature); +} + } // namespace WebCore diff --git a/Source/WebCore/page/FeatureObserver.h b/Source/WebCore/page/FeatureObserver.h index 531f46f38..d7f4e42f9 100644 --- a/Source/WebCore/page/FeatureObserver.h +++ b/Source/WebCore/page/FeatureObserver.h @@ -26,11 +26,15 @@ #ifndef FeatureObserver_h #define FeatureObserver_h +#include <wtf/BitVector.h> #include <wtf/Noncopyable.h> +#include <wtf/OwnPtr.h> +#include <wtf/PassOwnPtr.h> namespace WebCore { class DOMWindow; +class Document; class FeatureObserver { WTF_MAKE_NONCOPYABLE(FeatureObserver); @@ -41,7 +45,7 @@ public: enum Feature { PageDestruction, LegacyNotifications, - UnusedSlot01, // Prior to 10/2012, we used this slot for LegacyBlobBuilder. + MultipartMainResource, PrefixedIndexedDB, WorkerStart, SharedWorkerStart, @@ -50,29 +54,84 @@ public: PrefixedContentSecurityPolicy, UnprefixedIndexedDB, OpenWebDatabase, - LegacyHTMLNotifications, + UnusedSlot01, // We used this slot for LegacyHTMLNotifications. LegacyTextNotifications, UnprefixedRequestAnimationFrame, PrefixedRequestAnimationFrame, ContentSecurityPolicy, ContentSecurityPolicyReportOnly, PrefixedContentSecurityPolicyReportOnly, - // Add new features above this line. + PrefixedTransitionEndEvent, + UnprefixedTransitionEndEvent, + PrefixedAndUnprefixedTransitionEndEvent, + AutoFocusAttribute, + AutoSaveAttribute, + DataListElement, + FormAttribute, + IncrementalAttribute, + InputTypeColor, + InputTypeDate, + InputTypeDateTime, + InputTypeDateTimeFallback, + InputTypeDateTimeLocal, + InputTypeEmail, + InputTypeMonth, + InputTypeNumber, + InputTypeRange, + InputTypeSearch, + InputTypeTel, + InputTypeTime, + InputTypeURL, + InputTypeWeek, + InputTypeWeekFallback, + ListAttribute, + MaxAttribute, + MinAttribute, + PatternAttribute, + PlaceholderAttribute, + PrecisionAttribute, + PrefixedDirectoryAttribute, + PrefixedSpeechAttribute, + RequiredAttribute, + ResultsAttribute, + StepAttribute, + PageVisits, + HTMLMarqueeElement, + CSSOverflowMarquee, + Reflection, + CursorVisibility, + StorageInfo, + XFrameOptions, + XFrameOptionsSameOrigin, + XFrameOptionsSameOriginWithBadAncestorChain, + DeprecatedFlexboxWebContent, + DeprecatedFlexboxChrome, + DeprecatedFlexboxChromeExtension, + // Add new features above this line. Don't change assigned numbers of each items. NumberOfFeatures, // This enum value must be last. }; + static void observe(Document*, Feature); static void observe(DOMWindow*, Feature); + void didCommitLoad(); + + const BitVector* accumulatedFeatureBits() const { return m_featureBits.get(); } private: void didObserve(Feature feature) { - COMPILE_ASSERT(sizeof(m_featureMask) * 8 >= NumberOfFeatures, FeaturesMustNotOverflowBitmask); ASSERT(feature != PageDestruction); // PageDestruction is reserved as a scaling factor. ASSERT(feature < NumberOfFeatures); - m_featureMask |= 1 << static_cast<int>(feature); + if (!m_featureBits) { + m_featureBits = adoptPtr(new BitVector(NumberOfFeatures)); + m_featureBits->clearAll(); + } + m_featureBits->quickSet(feature); } - int m_featureMask; + void updateMeasurements(); + + OwnPtr<BitVector> m_featureBits; }; } // namespace WebCore diff --git a/Source/WebCore/page/FocusController.cpp b/Source/WebCore/page/FocusController.cpp index bc20169c9..bc83e7f8c 100644 --- a/Source/WebCore/page/FocusController.cpp +++ b/Source/WebCore/page/FocusController.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2013 Apple Inc. All rights reserved. * Copyright (C) 2008 Nuanti Ltd. * * Redistribution and use in source and binary forms, with or without @@ -29,7 +29,6 @@ #include "AXObjectCache.h" #include "Chrome.h" -#include "ComposedShadowTreeWalker.h" #include "Document.h" #include "Editor.h" #include "EditorClient.h" @@ -45,9 +44,13 @@ #include "FrameView.h" #include "HTMLAreaElement.h" #include "HTMLImageElement.h" +#include "HTMLInputElement.h" #include "HTMLNames.h" +#include "HTMLTextAreaElement.h" #include "HitTestResult.h" #include "KeyboardEvent.h" +#include "NodeRenderingTraversal.h" +#include "NodeTraversal.h" #include "Page.h" #include "Range.h" #include "RenderObject.h" @@ -65,50 +68,20 @@ namespace WebCore { using namespace HTMLNames; using namespace std; -static inline ComposedShadowTreeWalker walkerFrom(const Node* node) -{ - return ComposedShadowTreeWalker(node, ComposedShadowTreeWalker::DoNotCrossUpperBoundary); -} - -static inline ComposedShadowTreeWalker walkerFromNext(const Node* node) -{ - ComposedShadowTreeWalker walker = ComposedShadowTreeWalker(node, ComposedShadowTreeWalker::DoNotCrossUpperBoundary); - walker.next(); - return walker; -} - -static inline ComposedShadowTreeWalker walkerFromPrevious(const Node* node) -{ - ComposedShadowTreeWalker walker = ComposedShadowTreeWalker(node, ComposedShadowTreeWalker::DoNotCrossUpperBoundary); - walker.previous(); - return walker; -} - -static inline Node* nextNode(const Node* node) -{ - return walkerFromNext(node).get(); -} - -static inline Node* previousNode(const Node* node) -{ - return walkerFromPrevious(node).get(); -} - FocusNavigationScope::FocusNavigationScope(TreeScope* treeScope) : m_rootTreeScope(treeScope) { ASSERT(treeScope); - ASSERT(!treeScope->rootNode()->isShadowRoot() || toShadowRoot(treeScope->rootNode())->isYoungest()); } -Node* FocusNavigationScope::rootNode() const +ContainerNode* FocusNavigationScope::rootNode() const { return m_rootTreeScope->rootNode(); } Element* FocusNavigationScope::owner() const { - Node* root = rootNode(); + ContainerNode* root = rootNode(); if (root->isShadowRoot()) return toShadowRoot(root)->host(); if (Frame* frame = root->document()->frame()) @@ -119,12 +92,9 @@ Element* FocusNavigationScope::owner() const FocusNavigationScope FocusNavigationScope::focusNavigationScopeOf(Node* node) { ASSERT(node); - ComposedShadowTreeWalker walker(node, ComposedShadowTreeWalker::DoNotCrossUpperBoundary); Node* root = node; - while (walker.get()) { - root = walker.get(); - walker.parent(); - } + for (Node* n = node; n; n = NodeRenderingTraversal::parentInScope(n)) + root = n; // The result is not always a ShadowRoot nor a DocumentNode since // a starting node is in an orphaned tree in composed shadow tree. return FocusNavigationScope(root->treeScope()); @@ -133,7 +103,7 @@ FocusNavigationScope FocusNavigationScope::focusNavigationScopeOf(Node* node) FocusNavigationScope FocusNavigationScope::focusNavigationScopeOwnedByShadowHost(Node* node) { ASSERT(isShadowHost(node)); - return FocusNavigationScope(toElement(node)->shadow()->youngestShadowRoot()); + return FocusNavigationScope(toElement(node)->shadow()->shadowRoot()); } FocusNavigationScope FocusNavigationScope::focusNavigationScopeOwnedByIFrame(HTMLFrameOwnerElement* frame) @@ -142,7 +112,7 @@ FocusNavigationScope FocusNavigationScope::focusNavigationScopeOwnedByIFrame(HTM return FocusNavigationScope(frame->contentFrame()->document()); } -static inline void dispatchEventsOnWindowAndFocusedNode(Document* document, bool focused) +static inline void dispatchEventsOnWindowAndFocusedElement(Document* document, bool focused) { // If we have a focused node we should dispatch blur on it before we blur the window. // If we have a focused node we should dispatch focus on it after we focus the window. @@ -154,11 +124,11 @@ static inline void dispatchEventsOnWindowAndFocusedNode(Document* document, bool return; } - if (!focused && document->focusedNode()) - document->focusedNode()->dispatchBlurEvent(0); + if (!focused && document->focusedElement()) + document->focusedElement()->dispatchBlurEvent(0); document->dispatchWindowEvent(Event::create(focused ? eventNames().focusEvent : eventNames().blurEvent, false, false)); - if (focused && document->focusedNode()) - document->focusedNode()->dispatchFocusEvent(0); + if (focused && document->focusedElement()) + document->focusedElement()->dispatchFocusEvent(0, FocusDirectionNone); } static inline bool hasCustomFocusLogic(Node* node) @@ -166,28 +136,30 @@ static inline bool hasCustomFocusLogic(Node* node) return node->isHTMLElement() && toHTMLElement(node)->hasCustomFocusLogic(); } -static inline bool isNonFocusableShadowHost(Node* node, KeyboardEvent* event) +static inline bool isNonFocusableShadowHost(Element* element, KeyboardEvent* event) { - ASSERT(node); - return !node->isKeyboardFocusable(event) && isShadowHost(node) && !hasCustomFocusLogic(node); + ASSERT(element); + return !element->isKeyboardFocusable(event) && isShadowHost(element) && !hasCustomFocusLogic(element); } static inline bool isFocusableShadowHost(Node* node, KeyboardEvent* event) { ASSERT(node); - return node->isKeyboardFocusable(event) && isShadowHost(node) && !hasCustomFocusLogic(node); + return node->isElementNode() && toElement(node)->isKeyboardFocusable(event) && isShadowHost(node) && !hasCustomFocusLogic(node); } static inline int adjustedTabIndex(Node* node, KeyboardEvent* event) { ASSERT(node); - return isNonFocusableShadowHost(node, event) ? 0 : node->tabIndex(); + if (!node->isElementNode()) + return 0; + return isNonFocusableShadowHost(toElement(node), event) ? 0 : toElement(node)->tabIndex(); } -static inline bool shouldVisit(Node* node, KeyboardEvent* event) +static inline bool shouldVisit(Element* element, KeyboardEvent* event) { - ASSERT(node); - return node->isKeyboardFocusable(event) || isNonFocusableShadowHost(node, event); + ASSERT(element); + return element->isKeyboardFocusable(event) || isNonFocusableShadowHost(element, event); } FocusController::FocusController(Page* page) @@ -228,7 +200,7 @@ void FocusController::setFocusedFrame(PassRefPtr<Frame> frame) newFrame->document()->dispatchWindowEvent(Event::create(eventNames().focusEvent, false, false)); } - m_page->chrome()->focusedFrameChanged(newFrame.get()); + m_page->chrome().focusedFrameChanged(newFrame.get()); m_isChangingFocusedFrame = false; } @@ -255,26 +227,26 @@ void FocusController::setFocused(bool focused) if (m_focusedFrame->view()) { m_focusedFrame->selection()->setFocused(focused); - dispatchEventsOnWindowAndFocusedNode(m_focusedFrame->document(), focused); + dispatchEventsOnWindowAndFocusedElement(m_focusedFrame->document(), focused); } } -Node* FocusController::findFocusableNodeDecendingDownIntoFrameDocument(FocusDirection direction, Node* node, KeyboardEvent* event) +Element* FocusController::findFocusableElementDescendingDownIntoFrameDocument(FocusDirection direction, Element* element, KeyboardEvent* event) { // The node we found might be a HTMLFrameOwnerElement, so descend down the tree until we find either: // 1) a focusable node, or // 2) the deepest-nested HTMLFrameOwnerElement. - while (node && node->isFrameOwnerElement()) { - HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(node); + while (element && element->isFrameOwnerElement()) { + HTMLFrameOwnerElement* owner = toFrameOwnerElement(element); if (!owner->contentFrame()) break; - Node* foundNode = findFocusableNode(direction, FocusNavigationScope::focusNavigationScopeOwnedByIFrame(owner), 0, event); - if (!foundNode) + Element* foundElement = findFocusableElement(direction, FocusNavigationScope::focusNavigationScopeOwnedByIFrame(owner), 0, event); + if (!foundElement) break; - ASSERT(node != foundNode); - node = foundNode; + ASSERT(element != foundElement); + element = foundElement; } - return node; + return element; } bool FocusController::setInitialFocus(FocusDirection direction, KeyboardEvent* event) @@ -284,8 +256,8 @@ bool FocusController::setInitialFocus(FocusDirection direction, KeyboardEvent* e // If focus is being set initially, accessibility needs to be informed that system focus has moved // into the web area again, even if focus did not change within WebCore. PostNotification is called instead // of handleFocusedUIElementChanged, because this will send the notification even if the element is the same. - if (AXObjectCache::accessibilityEnabled()) - focusedOrMainFrame()->document()->axObjectCache()->postNotification(focusedOrMainFrame()->document(), AXObjectCache::AXFocusedUIElementChanged, true); + if (AXObjectCache* cache = focusedOrMainFrame()->document()->existingAXObjectCache()) + cache->postNotification(focusedOrMainFrame()->document(), AXObjectCache::AXFocusedUIElementChanged, true); return didAdvanceFocus; } @@ -314,7 +286,7 @@ bool FocusController::advanceFocusInDocumentOrder(FocusDirection direction, Keyb ASSERT(frame); Document* document = frame->document(); - Node* currentNode = document->focusedNode(); + Node* currentNode = document->focusedElement(); // FIXME: Not quite correct when it comes to focus transitions leaving/entering the WebView itself bool caretBrowsing = frame->settings() && frame->settings()->caretBrowsingEnabled(); @@ -323,84 +295,82 @@ bool FocusController::advanceFocusInDocumentOrder(FocusDirection direction, Keyb document->updateLayoutIgnorePendingStylesheets(); - RefPtr<Node> node = findFocusableNodeAcrossFocusScope(direction, FocusNavigationScope::focusNavigationScopeOf(currentNode ? currentNode : document), currentNode, event); + RefPtr<Element> element = findFocusableElementAcrossFocusScope(direction, FocusNavigationScope::focusNavigationScopeOf(currentNode ? currentNode : document), currentNode, event); - if (!node) { + if (!element) { // We didn't find a node to focus, so we should try to pass focus to Chrome. - if (!initialFocus && m_page->chrome()->canTakeFocus(direction)) { - document->setFocusedNode(0); + if (!initialFocus && m_page->chrome().canTakeFocus(direction)) { + document->setFocusedElement(0); setFocusedFrame(0); - m_page->chrome()->takeFocus(direction); + m_page->chrome().takeFocus(direction); return true; } // Chrome doesn't want focus, so we should wrap focus. - node = findFocusableNodeRecursively(direction, FocusNavigationScope::focusNavigationScopeOf(m_page->mainFrame()->document()), 0, event); - node = findFocusableNodeDecendingDownIntoFrameDocument(direction, node.get(), event); + element = findFocusableElementRecursively(direction, FocusNavigationScope::focusNavigationScopeOf(m_page->mainFrame()->document()), 0, event); + element = findFocusableElementDescendingDownIntoFrameDocument(direction, element.get(), event); - if (!node) + if (!element) return false; } - ASSERT(node); + ASSERT(element); - if (node == document->focusedNode()) - // Focus wrapped around to the same node. + if (element == document->focusedElement()) { + // Focus wrapped around to the same Element. return true; + } - if (!node->isElementNode()) - // FIXME: May need a way to focus a document here. - return false; - - if (node->isFrameOwnerElement() && (!node->isPluginElement() || !node->isKeyboardFocusable(event))) { + if (element->isFrameOwnerElement() && (!element->isPluginElement() || !element->isKeyboardFocusable(event))) { // We focus frames rather than frame owners. // FIXME: We should not focus frames that have no scrollbars, as focusing them isn't useful to the user. - HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(node.get()); + HTMLFrameOwnerElement* owner = toFrameOwnerElement(element.get()); if (!owner->contentFrame()) return false; - document->setFocusedNode(0); + document->setFocusedElement(0); setFocusedFrame(owner->contentFrame()); return true; } - // FIXME: It would be nice to just be able to call setFocusedNode(node) here, but we can't do + // FIXME: It would be nice to just be able to call setFocusedElement(node) here, but we can't do // that because some elements (e.g. HTMLInputElement and HTMLTextAreaElement) do extra work in // their focus() methods. - Document* newDocument = node->document(); + Document* newDocument = element->document(); - if (newDocument != document) + if (newDocument != document) { // Focus is going away from this document, so clear the focused node. - document->setFocusedNode(0); + document->setFocusedElement(0); + } if (newDocument) setFocusedFrame(newDocument->frame()); if (caretBrowsing) { - Position position = firstPositionInOrBeforeNode(node.get()); + Position position = firstPositionInOrBeforeNode(element.get()); VisibleSelection newSelection(position, position, DOWNSTREAM); if (frame->selection()->shouldChangeSelection(newSelection)) frame->selection()->setSelection(newSelection); } - static_cast<Element*>(node.get())->focus(false); + element->focus(false, direction); return true; } -Node* FocusController::findFocusableNodeAcrossFocusScope(FocusDirection direction, FocusNavigationScope scope, Node* currentNode, KeyboardEvent* event) +Element* FocusController::findFocusableElementAcrossFocusScope(FocusDirection direction, FocusNavigationScope scope, Node* currentNode, KeyboardEvent* event) { - ASSERT(!currentNode || !isNonFocusableShadowHost(currentNode, event)); - Node* found; + ASSERT(!currentNode || !currentNode->isElementNode() || !isNonFocusableShadowHost(toElement(currentNode), event)); + Element* found; if (currentNode && direction == FocusDirectionForward && isFocusableShadowHost(currentNode, event)) { - Node* foundInInnerFocusScope = findFocusableNodeRecursively(direction, FocusNavigationScope::focusNavigationScopeOwnedByShadowHost(currentNode), 0, event); - found = foundInInnerFocusScope ? foundInInnerFocusScope : findFocusableNodeRecursively(direction, scope, currentNode, event); + Element* foundInInnerFocusScope = findFocusableElementRecursively(direction, FocusNavigationScope::focusNavigationScopeOwnedByShadowHost(currentNode), 0, event); + found = foundInInnerFocusScope ? foundInInnerFocusScope : findFocusableElementRecursively(direction, scope, currentNode, event); } else - found = findFocusableNodeRecursively(direction, scope, currentNode, event); + found = findFocusableElementRecursively(direction, scope, currentNode, event); // If there's no focusable node to advance to, move up the focus scopes until we find one. while (!found) { - Node* owner = scope.owner(); + Element* owner = scope.owner(); if (!owner) break; scope = FocusNavigationScope::focusNavigationScopeOf(owner); @@ -408,99 +378,112 @@ Node* FocusController::findFocusableNodeAcrossFocusScope(FocusDirection directio found = owner; break; } - found = findFocusableNodeRecursively(direction, scope, owner, event); + found = findFocusableElementRecursively(direction, scope, owner, event); } - found = findFocusableNodeDecendingDownIntoFrameDocument(direction, found, event); + found = findFocusableElementDescendingDownIntoFrameDocument(direction, found, event); return found; } -Node* FocusController::findFocusableNodeRecursively(FocusDirection direction, FocusNavigationScope scope, Node* start, KeyboardEvent* event) +Element* FocusController::findFocusableElementRecursively(FocusDirection direction, FocusNavigationScope scope, Node* start, KeyboardEvent* event) { // Starting node is exclusive. - Node* found = findFocusableNode(direction, scope, start, event); + Element* found = findFocusableElement(direction, scope, start, event); if (!found) return 0; if (direction == FocusDirectionForward) { if (!isNonFocusableShadowHost(found, event)) return found; - Node* foundInInnerFocusScope = findFocusableNodeRecursively(direction, FocusNavigationScope::focusNavigationScopeOwnedByShadowHost(found), 0, event); - return foundInInnerFocusScope ? foundInInnerFocusScope : findFocusableNodeRecursively(direction, scope, found, event); + Element* foundInInnerFocusScope = findFocusableElementRecursively(direction, FocusNavigationScope::focusNavigationScopeOwnedByShadowHost(found), 0, event); + return foundInInnerFocusScope ? foundInInnerFocusScope : findFocusableElementRecursively(direction, scope, found, event); } ASSERT(direction == FocusDirectionBackward); if (isFocusableShadowHost(found, event)) { - Node* foundInInnerFocusScope = findFocusableNodeRecursively(direction, FocusNavigationScope::focusNavigationScopeOwnedByShadowHost(found), 0, event); + Element* foundInInnerFocusScope = findFocusableElementRecursively(direction, FocusNavigationScope::focusNavigationScopeOwnedByShadowHost(found), 0, event); return foundInInnerFocusScope ? foundInInnerFocusScope : found; } if (isNonFocusableShadowHost(found, event)) { - Node* foundInInnerFocusScope = findFocusableNodeRecursively(direction, FocusNavigationScope::focusNavigationScopeOwnedByShadowHost(found), 0, event); - return foundInInnerFocusScope ? foundInInnerFocusScope :findFocusableNodeRecursively(direction, scope, found, event); + Element* foundInInnerFocusScope = findFocusableElementRecursively(direction, FocusNavigationScope::focusNavigationScopeOwnedByShadowHost(found), 0, event); + return foundInInnerFocusScope ? foundInInnerFocusScope :findFocusableElementRecursively(direction, scope, found, event); } return found; } -Node* FocusController::findFocusableNode(FocusDirection direction, FocusNavigationScope scope, Node* node, KeyboardEvent* event) +Element* FocusController::findFocusableElement(FocusDirection direction, FocusNavigationScope scope, Node* node, KeyboardEvent* event) { return (direction == FocusDirectionForward) - ? nextFocusableNode(scope, node, event) - : previousFocusableNode(scope, node, event); + ? nextFocusableElement(scope, node, event) + : previousFocusableElement(scope, node, event); } -Node* FocusController::findNodeWithExactTabIndex(Node* start, int tabIndex, KeyboardEvent* event, FocusDirection direction) +Element* FocusController::findElementWithExactTabIndex(Node* start, int tabIndex, KeyboardEvent* event, FocusDirection direction) { // Search is inclusive of start - for (ComposedShadowTreeWalker walker = walkerFrom(start); walker.get(); direction == FocusDirectionForward ? walker.next() : walker.previous()) { - if (shouldVisit(walker.get(), event) && adjustedTabIndex(walker.get(), event) == tabIndex) - return walker.get(); + using namespace NodeRenderingTraversal; + for (Node* node = start; node; node = direction == FocusDirectionForward ? nextInScope(node) : previousInScope(node)) { + if (!node->isElementNode()) + continue; + Element* element = toElement(node); + if (shouldVisit(element, event) && adjustedTabIndex(element, event) == tabIndex) + return element; } return 0; } -static Node* nextNodeWithGreaterTabIndex(Node* start, int tabIndex, KeyboardEvent* event) +static Element* nextElementWithGreaterTabIndex(Node* start, int tabIndex, KeyboardEvent* event) { // Search is inclusive of start int winningTabIndex = std::numeric_limits<short>::max() + 1; - Node* winner = 0; - for (ComposedShadowTreeWalker walker = walkerFrom(start); walker.get(); walker.next()) { - Node* node = walker.get(); - if (shouldVisit(node, event) && node->tabIndex() > tabIndex && node->tabIndex() < winningTabIndex) { - winner = node; - winningTabIndex = node->tabIndex(); + Element* winner = 0; + for (Node* node = start; node; node = NodeRenderingTraversal::nextInScope(node)) { + if (!node->isElementNode()) + continue; + Element* element = toElement(node); + if (shouldVisit(element, event) && element->tabIndex() > tabIndex && element->tabIndex() < winningTabIndex) { + winner = element; + winningTabIndex = element->tabIndex(); } } return winner; } -static Node* previousNodeWithLowerTabIndex(Node* start, int tabIndex, KeyboardEvent* event) +static Element* previousElementWithLowerTabIndex(Node* start, int tabIndex, KeyboardEvent* event) { // Search is inclusive of start int winningTabIndex = 0; - Node* winner = 0; - for (ComposedShadowTreeWalker walker = walkerFrom(start); walker.get(); walker.previous()) { - Node* node = walker.get(); - int currentTabIndex = adjustedTabIndex(node, event); - if ((shouldVisit(node, event) || isNonFocusableShadowHost(node, event)) && currentTabIndex < tabIndex && currentTabIndex > winningTabIndex) { - winner = node; + Element* winner = 0; + for (Node* node = start; node; node = NodeRenderingTraversal::previousInScope(node)) { + if (!node->isElementNode()) + continue; + Element* element = toElement(node); + int currentTabIndex = adjustedTabIndex(element, event); + if ((shouldVisit(element, event) || isNonFocusableShadowHost(element, event)) && currentTabIndex < tabIndex && currentTabIndex > winningTabIndex) { + winner = element; winningTabIndex = currentTabIndex; } } return winner; } -Node* FocusController::nextFocusableNode(FocusNavigationScope scope, Node* start, KeyboardEvent* event) +Element* FocusController::nextFocusableElement(FocusNavigationScope scope, Node* start, KeyboardEvent* event) { + using namespace NodeRenderingTraversal; + if (start) { int tabIndex = adjustedTabIndex(start, event); // If a node is excluded from the normal tabbing cycle, the next focusable node is determined by tree order if (tabIndex < 0) { - for (ComposedShadowTreeWalker walker = walkerFromNext(start); walker.get(); walker.next()) { - if (shouldVisit(walker.get(), event) && adjustedTabIndex(walker.get(), event) >= 0) - return walker.get(); + for (Node* node = nextInScope(start); node; node = nextInScope(node)) { + if (!node->isElementNode()) + continue; + Element* element = toElement(node); + if (shouldVisit(element, event) && adjustedTabIndex(element, event) >= 0) + return element; } } // First try to find a node with the same tabindex as start that comes after start in the scope. - if (Node* winner = findNodeWithExactTabIndex(nextNode(start), tabIndex, event, FocusDirectionForward)) + if (Element* winner = findElementWithExactTabIndex(nextInScope(start), tabIndex, event, FocusDirectionForward)) return winner; if (!tabIndex) @@ -508,22 +491,24 @@ Node* FocusController::nextFocusableNode(FocusNavigationScope scope, Node* start return 0; } - // Look for the first node in the scope that: + // Look for the first Element in the scope that: // 1) has the lowest tabindex that is higher than start's tabindex (or 0, if start is null), and // 2) comes first in the scope, if there's a tie. - if (Node* winner = nextNodeWithGreaterTabIndex(scope.rootNode(), start ? adjustedTabIndex(start, event) : 0, event)) + if (Element* winner = nextElementWithGreaterTabIndex(scope.rootNode(), start ? adjustedTabIndex(start, event) : 0, event)) return winner; // There are no nodes with a tabindex greater than start's tabindex, // so find the first node with a tabindex of 0. - return findNodeWithExactTabIndex(scope.rootNode(), 0, event, FocusDirectionForward); + return findElementWithExactTabIndex(scope.rootNode(), 0, event, FocusDirectionForward); } -Node* FocusController::previousFocusableNode(FocusNavigationScope scope, Node* start, KeyboardEvent* event) +Element* FocusController::previousFocusableElement(FocusNavigationScope scope, Node* start, KeyboardEvent* event) { + using namespace NodeRenderingTraversal; + Node* last = 0; - for (ComposedShadowTreeWalker walker = walkerFrom(scope.rootNode()); walker.get(); walker.lastChild()) - last = walker.get(); + for (Node* node = scope.rootNode(); node; node = lastChildInScope(node)) + last = node; ASSERT(last); // First try to find the last node in the scope that comes before start and has the same tabindex as start. @@ -531,7 +516,7 @@ Node* FocusController::previousFocusableNode(FocusNavigationScope scope, Node* s Node* startingNode; int startingTabIndex; if (start) { - startingNode = previousNode(start); + startingNode = previousInScope(start); startingTabIndex = adjustedTabIndex(start, event); } else { startingNode = last; @@ -540,20 +525,23 @@ Node* FocusController::previousFocusableNode(FocusNavigationScope scope, Node* s // However, if a node is excluded from the normal tabbing cycle, the previous focusable node is determined by tree order if (startingTabIndex < 0) { - for (ComposedShadowTreeWalker walker = walkerFrom(startingNode); walker.get(); walker.previous()) { - if (shouldVisit(walker.get(), event) && adjustedTabIndex(walker.get(), event) >= 0) - return walker.get(); + for (Node* node = startingNode; node; node = previousInScope(node)) { + if (!node->isElementNode()) + continue; + Element* element = toElement(node); + if (shouldVisit(element, event) && adjustedTabIndex(element, event) >= 0) + return element; } } - if (Node* winner = findNodeWithExactTabIndex(startingNode, startingTabIndex, event, FocusDirectionBackward)) + if (Element* winner = findElementWithExactTabIndex(startingNode, startingTabIndex, event, FocusDirectionBackward)) return winner; // There are no nodes before start with the same tabindex as start, so look for a node that: // 1) has the highest non-zero tabindex (that is less than start's tabindex), and // 2) comes last in the scope, if there's a tie. startingTabIndex = (start && startingTabIndex) ? startingTabIndex : std::numeric_limits<short>::max(); - return previousNodeWithLowerTabIndex(last, startingTabIndex, event); + return previousElementWithLowerTabIndex(last, startingTabIndex, event); } static bool relinquishesEditingFocus(Node *node) @@ -566,7 +554,7 @@ static bool relinquishesEditingFocus(Node *node) if (!frame || !root) return false; - return frame->editor()->shouldEndEditing(rangeOfContents(root).get()); + return frame->editor().shouldEndEditing(rangeOfContents(root).get()); } static void clearSelectionIfNeeded(Frame* oldFocusedFrame, Frame* newFocusedFrame, Node* newFocusedNode) @@ -586,7 +574,7 @@ static void clearSelectionIfNeeded(Frame* oldFocusedFrame, Frame* newFocusedFram return; Node* selectionStartNode = s->selection().start().deprecatedNode(); - if (selectionStartNode == newFocusedNode || selectionStartNode->isDescendantOf(newFocusedNode) || selectionStartNode->shadowAncestorNode() == newFocusedNode) + if (selectionStartNode == newFocusedNode || selectionStartNode->isDescendantOf(newFocusedNode) || selectionStartNode->deprecatedShadowAncestorNode() == newFocusedNode) return; if (Node* mousePressNode = newFocusedFrame->eventHandler()->mousePressNode()) { @@ -596,8 +584,8 @@ static void clearSelectionIfNeeded(Frame* oldFocusedFrame, Frame* newFocusedFram if (!root) return; - if (Node* shadowAncestorNode = root->shadowAncestorNode()) { - if (!shadowAncestorNode->hasTagName(inputTag) && !shadowAncestorNode->hasTagName(textareaTag)) + if (Node* shadowAncestorNode = root->deprecatedShadowAncestorNode()) { + if (!isHTMLInputElement(shadowAncestorNode) && !isHTMLTextAreaElement(shadowAncestorNode)) return; } } @@ -606,52 +594,55 @@ static void clearSelectionIfNeeded(Frame* oldFocusedFrame, Frame* newFocusedFram s->clear(); } -bool FocusController::setFocusedNode(Node* node, PassRefPtr<Frame> newFocusedFrame) +bool FocusController::setFocusedElement(Element* element, PassRefPtr<Frame> newFocusedFrame, FocusDirection direction) { RefPtr<Frame> oldFocusedFrame = focusedFrame(); RefPtr<Document> oldDocument = oldFocusedFrame ? oldFocusedFrame->document() : 0; - Node* oldFocusedNode = oldDocument ? oldDocument->focusedNode() : 0; - if (oldFocusedNode == node) + Element* oldFocusedElement = oldDocument ? oldDocument->focusedElement() : 0; + if (oldFocusedElement == element) return true; // FIXME: Might want to disable this check for caretBrowsing - if (oldFocusedNode && oldFocusedNode->isRootEditableElement() && !relinquishesEditingFocus(oldFocusedNode)) + if (oldFocusedElement && oldFocusedElement->isRootEditableElement() && !relinquishesEditingFocus(oldFocusedElement)) return false; m_page->editorClient()->willSetInputMethodState(); - clearSelectionIfNeeded(oldFocusedFrame.get(), newFocusedFrame.get(), node); + clearSelectionIfNeeded(oldFocusedFrame.get(), newFocusedFrame.get(), element); - if (!node) { + if (!element) { if (oldDocument) - oldDocument->setFocusedNode(0); + oldDocument->setFocusedElement(0); m_page->editorClient()->setInputMethodState(false); return true; } - RefPtr<Document> newDocument = node->document(); + RefPtr<Document> newDocument = element->document(); - if (newDocument && newDocument->focusedNode() == node) { - m_page->editorClient()->setInputMethodState(node->shouldUseInputMethod()); + if (newDocument && newDocument->focusedElement() == element) { + m_page->editorClient()->setInputMethodState(element->shouldUseInputMethod()); return true; } if (oldDocument && oldDocument != newDocument) - oldDocument->setFocusedNode(0); - + oldDocument->setFocusedElement(0); + + if (newFocusedFrame && !newFocusedFrame->page()) { + setFocusedFrame(0); + return false; + } setFocusedFrame(newFocusedFrame); - // Setting the focused node can result in losing our last reft to node when JS event handlers fire. - RefPtr<Node> protect = node; + RefPtr<Element> protect(element); if (newDocument) { - bool successfullyFocused = newDocument->setFocusedNode(node); + bool successfullyFocused = newDocument->setFocusedElement(element, direction); if (!successfullyFocused) return false; } - if (newDocument->focusedNode() == node) - m_page->editorClient()->setInputMethodState(node->shouldUseInputMethod()); + if (newDocument->focusedElement() == element) + m_page->editorClient()->setInputMethodState(element->shouldUseInputMethod()); return true; } @@ -673,7 +664,7 @@ void FocusController::setActive(bool active) focusedOrMainFrame()->selection()->pageActivationChanged(); if (m_focusedFrame && isFocused()) - dispatchEventsOnWindowAndFocusedNode(m_focusedFrame->document(), active); + dispatchEventsOnWindowAndFocusedElement(m_focusedFrame->document(), active); } static void contentAreaDidShowOrHide(ScrollableArea* scrollableArea, bool didShow) @@ -745,7 +736,7 @@ static void updateFocusCandidateIfNeeded(FocusDirection direction, const FocusCa // If 2 nodes are intersecting, do hit test to find which node in on top. LayoutUnit x = intersectionRect.x() + intersectionRect.width() / 2; LayoutUnit y = intersectionRect.y() + intersectionRect.height() / 2; - HitTestResult result = candidate.visibleNode->document()->page()->mainFrame()->eventHandler()->hitTestResultAtPoint(IntPoint(x, y), false, true); + HitTestResult result = candidate.visibleNode->document()->page()->mainFrame()->eventHandler()->hitTestResultAtPoint(IntPoint(x, y), HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::IgnoreClipping | HitTestRequest::DisallowShadowContent); if (candidate.visibleNode->contains(result.innerNode())) { closest = candidate; return; @@ -767,25 +758,24 @@ static void updateFocusCandidateIfNeeded(FocusDirection direction, const FocusCa void FocusController::findFocusCandidateInContainer(Node* container, const LayoutRect& startingRect, FocusDirection direction, KeyboardEvent* event, FocusCandidate& closest) { ASSERT(container); - Node* focusedNode = (focusedFrame() && focusedFrame()->document()) ? focusedFrame()->document()->focusedNode() : 0; + Node* focusedNode = (focusedFrame() && focusedFrame()->document()) ? focusedFrame()->document()->focusedElement() : 0; - Node* node = container->firstChild(); + Element* element = ElementTraversal::firstWithin(container); FocusCandidate current; current.rect = startingRect; current.focusableNode = focusedNode; current.visibleNode = focusedNode; - for (; node; node = (node->isFrameOwnerElement() || canScrollInDirection(node, direction)) ? node->traverseNextSibling(container) : node->traverseNextNode(container)) { - if (node == focusedNode) - continue; - - if (!node->isElementNode()) + for (; element; element = (element->isFrameOwnerElement() || canScrollInDirection(element, direction)) + ? ElementTraversal::nextSkippingChildren(element, container) + : ElementTraversal::next(element, container)) { + if (element == focusedNode) continue; - if (!node->isKeyboardFocusable(event) && !node->isFrameOwnerElement() && !canScrollInDirection(node, direction)) + if (!element->isKeyboardFocusable(event) && !element->isFrameOwnerElement() && !canScrollInDirection(element, direction)) continue; - FocusCandidate candidate = FocusCandidate(node, direction); + FocusCandidate candidate = FocusCandidate(element, direction); if (candidate.isNull()) continue; @@ -827,9 +817,9 @@ bool FocusController::advanceFocusDirectionallyInContainer(Node* container, cons } // Navigate into a new frame. LayoutRect rect; - Node* focusedNode = focusedOrMainFrame()->document()->focusedNode(); - if (focusedNode && !hasOffscreenRect(focusedNode)) - rect = nodeRectInAbsoluteCoordinates(focusedNode, true /* ignore border */); + Element* focusedElement = focusedOrMainFrame()->document()->focusedElement(); + if (focusedElement && !hasOffscreenRect(focusedElement)) + rect = nodeRectInAbsoluteCoordinates(focusedElement, true /* ignore border */); frameElement->contentFrame()->document()->updateLayoutIgnorePendingStylesheets(); if (!advanceFocusDirectionallyInContainer(frameElement->contentFrame()->document(), rect, direction, event)) { // The new frame had nothing interesting, need to find another candidate. @@ -845,9 +835,9 @@ bool FocusController::advanceFocusDirectionallyInContainer(Node* container, cons } // Navigate into a new scrollable container. LayoutRect startingRect; - Node* focusedNode = focusedOrMainFrame()->document()->focusedNode(); - if (focusedNode && !hasOffscreenRect(focusedNode)) - startingRect = nodeRectInAbsoluteCoordinates(focusedNode, true); + Element* focusedElement = focusedOrMainFrame()->document()->focusedElement(); + if (focusedElement && !hasOffscreenRect(focusedElement)) + startingRect = nodeRectInAbsoluteCoordinates(focusedElement, true); return advanceFocusDirectionallyInContainer(focusCandidate.visibleNode, startingRect, direction, event); } if (focusCandidate.isOffscreenAfterScrolling) { @@ -860,7 +850,7 @@ bool FocusController::advanceFocusDirectionallyInContainer(Node* container, cons Element* element = toElement(focusCandidate.focusableNode); ASSERT(element); - element->focus(false); + element->focus(false, direction); return true; } @@ -873,20 +863,20 @@ bool FocusController::advanceFocusDirectionally(FocusDirection direction, Keyboa if (!focusedDocument) return false; - Node* focusedNode = focusedDocument->focusedNode(); + Element* focusedElement = focusedDocument->focusedElement(); Node* container = focusedDocument; if (container->isDocumentNode()) - static_cast<Document*>(container)->updateLayoutIgnorePendingStylesheets(); + toDocument(container)->updateLayoutIgnorePendingStylesheets(); // Figure out the starting rect. LayoutRect startingRect; - if (focusedNode) { - if (!hasOffscreenRect(focusedNode)) { - container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(direction, focusedNode); - startingRect = nodeRectInAbsoluteCoordinates(focusedNode, true /* ignore border */); - } else if (focusedNode->hasTagName(areaTag)) { - HTMLAreaElement* area = static_cast<HTMLAreaElement*>(focusedNode); + if (focusedElement) { + if (!hasOffscreenRect(focusedElement)) { + container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(direction, focusedElement); + startingRect = nodeRectInAbsoluteCoordinates(focusedElement, true /* ignore border */); + } else if (isHTMLAreaElement(focusedElement)) { + HTMLAreaElement* area = toHTMLAreaElement(focusedElement); container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(direction, area->imageElement()); startingRect = virtualRectForAreaElementAndDirection(area, direction); } @@ -898,7 +888,7 @@ bool FocusController::advanceFocusDirectionally(FocusDirection direction, Keyboa startingRect = nodeRectInAbsoluteCoordinates(container, true /* ignore border */); container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(direction, container); if (container && container->isDocumentNode()) - static_cast<Document*>(container)->updateLayoutIgnorePendingStylesheets(); + toDocument(container)->updateLayoutIgnorePendingStylesheets(); } while (!consumed && container); return consumed; diff --git a/Source/WebCore/page/FocusController.h b/Source/WebCore/page/FocusController.h index 4f5986d96..549778653 100644 --- a/Source/WebCore/page/FocusController.h +++ b/Source/WebCore/page/FocusController.h @@ -35,6 +35,7 @@ namespace WebCore { struct FocusCandidate; +class ContainerNode; class Document; class Element; class Frame; @@ -47,7 +48,7 @@ class TreeScope; class FocusNavigationScope { public: - Node* rootNode() const; + ContainerNode* rootNode() const; Element* owner() const; static FocusNavigationScope focusNavigationScopeOf(Node*); static FocusNavigationScope focusNavigationScopeOwnedByShadowHost(Node*); @@ -69,8 +70,8 @@ public: bool setInitialFocus(FocusDirection, KeyboardEvent*); bool advanceFocus(FocusDirection, KeyboardEvent*, bool initialFocus = false); - - bool setFocusedNode(Node*, PassRefPtr<Frame>); + + bool setFocusedElement(Element*, PassRefPtr<Frame>, FocusDirection = FocusDirectionNone); void setActive(bool); bool isActive() const { return m_isActive; } @@ -87,9 +88,9 @@ private: bool advanceFocusDirectionally(FocusDirection, KeyboardEvent*); bool advanceFocusInDocumentOrder(FocusDirection, KeyboardEvent*, bool initialFocus); - Node* findFocusableNodeAcrossFocusScope(FocusDirection, FocusNavigationScope startScope, Node* start, KeyboardEvent*); - Node* findFocusableNodeRecursively(FocusDirection, FocusNavigationScope, Node* start, KeyboardEvent*); - Node* findFocusableNodeDecendingDownIntoFrameDocument(FocusDirection, Node*, KeyboardEvent*); + Element* findFocusableElementAcrossFocusScope(FocusDirection, FocusNavigationScope startScope, Node* start, KeyboardEvent*); + Element* findFocusableElementRecursively(FocusDirection, FocusNavigationScope, Node* start, KeyboardEvent*); + Element* findFocusableElementDescendingDownIntoFrameDocument(FocusDirection, Element*, KeyboardEvent*); // Searches through the given tree scope, starting from start node, for the next/previous selectable element that comes after/before start node. // The order followed is as specified in section 17.11.1 of the HTML4 spec, which is elements with tab indexes @@ -100,12 +101,12 @@ private: // @return The focus node that comes after/before start node. // // See http://www.w3.org/TR/html4/interact/forms.html#h-17.11.1 - inline Node* findFocusableNode(FocusDirection, FocusNavigationScope, Node* start, KeyboardEvent*); + Element* findFocusableElement(FocusDirection, FocusNavigationScope, Node* start, KeyboardEvent*); - Node* nextFocusableNode(FocusNavigationScope, Node* start, KeyboardEvent*); - Node* previousFocusableNode(FocusNavigationScope, Node* start, KeyboardEvent*); + Element* nextFocusableElement(FocusNavigationScope, Node* start, KeyboardEvent*); + Element* previousFocusableElement(FocusNavigationScope, Node* start, KeyboardEvent*); - Node* findNodeWithExactTabIndex(Node* start, int tabIndex, KeyboardEvent*, FocusDirection); + Element* findElementWithExactTabIndex(Node* start, int tabIndex, KeyboardEvent*, FocusDirection); bool advanceFocusDirectionallyInContainer(Node* container, const LayoutRect& startingRect, FocusDirection, KeyboardEvent*); void findFocusCandidateInContainer(Node* container, const LayoutRect& startingRect, FocusDirection, KeyboardEvent*, FocusCandidate& closest); diff --git a/Source/WebCore/page/Frame.cpp b/Source/WebCore/page/Frame.cpp index ac794691d..5f587d432 100644 --- a/Source/WebCore/page/Frame.cpp +++ b/Source/WebCore/page/Frame.cpp @@ -30,23 +30,28 @@ #include "config.h" #include "Frame.h" +#include "AnimationController.h" #include "ApplyStyleCommand.h" #include "BackForwardController.h" #include "CSSComputedStyleDeclaration.h" #include "CSSPropertyNames.h" #include "CachedCSSStyleSheet.h" +#include "CachedResourceLoader.h" #include "Chrome.h" #include "ChromeClient.h" #include "DOMWindow.h" -#include "CachedResourceLoader.h" #include "DocumentType.h" +#include "Editor.h" #include "EditorClient.h" +#include "Event.h" +#include "EventHandler.h" #include "EventNames.h" #include "FloatQuad.h" #include "FocusController.h" #include "FrameDestructionObserver.h" #include "FrameLoader.h" #include "FrameLoaderClient.h" +#include "FrameSelection.h" #include "FrameView.h" #include "GraphicsContext.h" #include "GraphicsLayer.h" @@ -59,10 +64,13 @@ #include "HitTestResult.h" #include "ImageBuffer.h" #include "InspectorInstrumentation.h" +#include "JSDOMWindowShell.h" #include "Logging.h" +#include "MathMLNames.h" #include "MediaFeatureNames.h" #include "Navigator.h" #include "NodeList.h" +#include "NodeTraversal.h" #include "Page.h" #include "PageCache.h" #include "PageGroup.h" @@ -73,22 +81,27 @@ #include "RenderTheme.h" #include "RenderView.h" #include "RuntimeEnabledFeatures.h" +#include "SVGNames.h" #include "ScriptController.h" #include "ScriptSourceCode.h" #include "ScriptValue.h" +#include "ScrollingCoordinator.h" #include "Settings.h" #include "StylePropertySet.h" #include "TextIterator.h" #include "TextResourceDecoder.h" #include "UserContentURLPattern.h" #include "UserTypingGestureIndicator.h" +#include "VisibleUnits.h" #include "WebKitFontFamilyNames.h" +#include "XLinkNames.h" #include "XMLNSNames.h" #include "XMLNames.h" #include "htmlediting.h" #include "markup.h" #include "npruntime_impl.h" -#include "visible_units.h" +#include "runtime_root.h" +#include <wtf/PassOwnPtr.h> #include <wtf/RefCountedLeakCounter.h> #include <wtf/StdLibExtras.h> @@ -96,15 +109,6 @@ #include "RenderLayerCompositor.h" #endif -#if USE(JSC) -#include "JSDOMWindowShell.h" -#include "runtime_root.h" -#endif - -#include "MathMLNames.h" -#include "SVGNames.h" -#include "XLinkNames.h" - #if ENABLE(SVG) #include "SVGDocument.h" #include "SVGDocumentExtensions.h" @@ -151,11 +155,11 @@ inline Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoader , m_loader(this, frameLoaderClient) , m_navigationScheduler(this) , m_ownerElement(ownerElement) - , m_script(this) - , m_editor(this) - , m_selection(this) - , m_eventHandler(this) - , m_animationController(this) + , m_script(adoptPtr(new ScriptController(this))) + , m_editor(adoptPtr(new Editor(this))) + , m_selection(adoptPtr(new FrameSelection(this))) + , m_eventHandler(adoptPtr(new EventHandler(this))) + , m_animationController(adoptPtr(new AnimationController(this))) , m_pageZoomFactor(parentPageZoomFactor(this)) , m_textZoomFactor(parentTextZoomFactor(this)) #if ENABLE(ORIENTATION_EVENTS) @@ -220,11 +224,6 @@ Frame::~Frame() HashSet<FrameDestructionObserver*>::iterator stop = m_destructionObservers.end(); for (HashSet<FrameDestructionObserver*>::iterator it = m_destructionObservers.begin(); it != stop; ++it) (*it)->frameDestroyed(); - - if (m_view) { - m_view->hide(); - m_view->clearFrame(); - } } bool Frame::inScope(TreeScope* scope) const @@ -255,7 +254,7 @@ void Frame::setView(PassRefPtr<FrameView> view) // from messing with the view such that its scroll bars won't be torn down. // FIXME: We should revisit this. if (m_view) - m_view->detachCustomScrollbars(); + m_view->prepareForDetach(); // Prepare for destruction now, so any unload event handlers get run and the DOMWindow is // notified. If we wait until the view is destroyed, then things won't be hooked up enough for @@ -295,28 +294,26 @@ void Frame::setDocument(PassRefPtr<Document> newDoc) ASSERT(!m_doc || m_doc->domWindow()); ASSERT(!m_doc || m_doc->domWindow()->frame() == this); - selection()->updateSecureKeyboardEntryIfActive(); - if (m_doc && !m_doc->attached()) m_doc->attach(); if (m_doc) { - m_script.updateDocument(); + m_script->updateDocument(); m_doc->updateViewportArguments(); } if (m_page && m_page->mainFrame() == this) { notifyChromeClientWheelEventHandlerCountChanged(); #if ENABLE(TOUCH_EVENTS) - if (m_doc && m_doc->touchEventHandlerCount()) - m_page->chrome()->client()->needTouchEvents(true); + if (m_doc && m_doc->hasTouchEventHandlers()) + m_page->chrome().client()->needTouchEvents(true); #endif } // Suspend document if this frame was created in suspended state. if (m_doc && activeDOMObjectsAndAnimationsSuspended()) { m_doc->suspendScriptedAnimationControllerCallbacks(); - m_animationController.suspendAnimationsForDocument(m_doc.get()); + m_animationController->suspendAnimationsForDocument(m_doc.get()); m_doc->suspendActiveDOMObjects(ActiveDOMObject::PageWillBeSuspended); } } @@ -375,7 +372,7 @@ String Frame::searchForLabelsAboveCell(RegularExpression* regExp, HTMLTableCellE if (aboveCell) { // search within the above cell we found for a match size_t lengthSearched = 0; - for (Node* n = aboveCell->firstChild(); n; n = n->traverseNextNode(aboveCell)) { + for (Node* n = aboveCell->firstChild(); n; n = NodeTraversal::next(n, aboveCell)) { if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) { // For each text chunk, run the regexp String nodeString = n->nodeValue(); @@ -416,16 +413,12 @@ String Frame::searchForLabelsBeforeElement(const Vector<String>& labels, Element // walk backwards in the node tree, until another element, or form, or end of tree int unsigned lengthSearched = 0; Node* n; - for (n = element->traversePreviousNode(); - n && lengthSearched < charsSearchedThreshold; - n = n->traversePreviousNode()) - { - if (n->hasTagName(formTag) - || (n->isHTMLElement() && static_cast<Element*>(n)->isFormControlElement())) - { - // We hit another form element or the start of the form - bail out + for (n = NodeTraversal::previous(element); n && lengthSearched < charsSearchedThreshold; n = NodeTraversal::previous(n)) { + // We hit another form element or the start of the form - bail out + if (isHTMLFormElement(n) || (n->isHTMLElement() && toElement(n)->isFormControlElement())) break; - } else if (n->hasTagName(tdTag) && !startingTableCell) { + + if (n->hasTagName(tdTag) && !startingTableCell) { startingTableCell = static_cast<HTMLTableCellElement*>(n); } else if (n->hasTagName(trTag) && startingTableCell) { String result = searchForLabelsAboveCell(regExp.get(), startingTableCell, resultDistance); @@ -531,7 +524,7 @@ void Frame::setPrinting(bool printing, const FloatSize& pageSize, const FloatSiz } // Subframes of the one we're printing don't lay out to the page size. - for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling()) + for (RefPtr<Frame> child = tree()->firstChild(); child; child = child->tree()->nextSibling()) child->setPrinting(printing, FloatSize(), FloatSize(), 0, shouldAdjustViewSize); } @@ -596,7 +589,7 @@ void Frame::injectUserScriptsForWorld(DOMWrapperWorld* world, const UserScriptVe continue; if (script->injectionTime() == injectionTime && UserContentURLPattern::matchesPatterns(doc->url(), script->whitelist(), script->blacklist())) - m_script.evaluateInWorld(ScriptSourceCode(script->source(), script->url()), world); + m_script->evaluateInWorld(ScriptSourceCode(script->source(), script->url()), world); } } @@ -632,8 +625,8 @@ Frame* Frame::frameForWidget(const Widget* widget) // Assume all widgets are either a FrameView or owned by a RenderWidget. // FIXME: That assumption is not right for scroll bars! - ASSERT(widget->isFrameView()); - return static_cast<const FrameView*>(widget)->frame(); + ASSERT_WITH_SECURITY_IMPLICATION(widget->isFrameView()); + return toFrameView(widget)->frame(); } void Frame::clearTimers(FrameView *view, Document *document) @@ -667,13 +660,6 @@ void Frame::dispatchVisibilityStateChangeEvent() } #endif -void Frame::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const -{ - MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::DOM); - info.addMember(m_doc.get()); - info.addMember(m_loader); -} - void Frame::willDetachPage() { if (Frame* parent = tree()->parent()) @@ -688,6 +674,9 @@ void Frame::willDetachPage() if (page() && page()->focusController()->focusedFrame() == this) page()->focusController()->setFocusedFrame(0); + if (page() && page()->scrollingCoordinator() && m_view) + page()->scrollingCoordinator()->willDestroyScrollableArea(m_view.get()); + script()->clearScriptObjects(); script()->updatePlatformScriptObjects(); } @@ -696,7 +685,7 @@ void Frame::disconnectOwnerElement() { if (m_ownerElement) { if (Document* doc = document()) - doc->clearAXObjectCache(); + doc->topDocument()->clearAXObjectCache(); m_ownerElement->clearContentFrame(); if (m_page) m_page->decrementSubframeCount(); @@ -719,7 +708,7 @@ String Frame::displayStringModifiedByEncoding(const String& str) const VisiblePosition Frame::visiblePositionForPoint(const IntPoint& framePoint) { - HitTestResult result = eventHandler()->hitTestResultAtPoint(framePoint, true); + HitTestResult result = eventHandler()->hitTestResultAtPoint(framePoint, HitTestRequest::ReadOnly | HitTestRequest::Active); Node* node = result.innerNonSharedNode(); if (!node) return VisiblePosition(); @@ -741,7 +730,7 @@ Document* Frame::documentAtPoint(const IntPoint& point) HitTestResult result = HitTestResult(pt); if (contentRenderer()) - result = eventHandler()->hitTestResultAtPoint(pt, false); + result = eventHandler()->hitTestResultAtPoint(pt); return result.innerNode() ? result.innerNode()->document() : 0; } @@ -754,14 +743,14 @@ PassRefPtr<Range> Frame::rangeForPoint(const IntPoint& framePoint) VisiblePosition previous = position.previous(); if (previous.isNotNull()) { RefPtr<Range> previousCharacterRange = makeRange(previous, position); - LayoutRect rect = editor()->firstRectForRange(previousCharacterRange.get()); + LayoutRect rect = editor().firstRectForRange(previousCharacterRange.get()); if (rect.contains(framePoint)) return previousCharacterRange.release(); } VisiblePosition next = position.next(); if (RefPtr<Range> nextCharacterRange = makeRange(position, next)) { - LayoutRect rect = editor()->firstRectForRange(nextCharacterRange.get()); + LayoutRect rect = editor().firstRectForRange(nextCharacterRange.get()); if (rect.contains(framePoint)) return nextCharacterRange.release(); } @@ -820,6 +809,7 @@ void Frame::setTiledBackingStoreEnabled(bool enabled) if (m_tiledBackingStore) return; m_tiledBackingStore = adoptPtr(new TiledBackingStore(this)); + m_tiledBackingStore->setCommitTileUpdatesOnIdleEventLoop(true); if (m_view) m_view->setPaintsEntireContents(true); } @@ -846,7 +836,7 @@ void Frame::tiledBackingStorePaintEnd(const Vector<IntRect>& paintedArea) unsigned size = paintedArea.size(); // Request repaint from the system for (unsigned n = 0; n < size; ++n) - m_page->chrome()->invalidateContentsAndRootView(m_view->contentsToRootView(paintedArea[n]), false); + m_page->chrome().invalidateContentsAndRootView(m_view->contentsToRootView(paintedArea[n]), false); } IntRect Frame::tiledBackingStoreContentsRect() @@ -860,7 +850,7 @@ IntRect Frame::tiledBackingStoreVisibleRect() { if (!m_page) return IntRect(); - return m_page->chrome()->client()->visibleRectForTiledBackingStore(); + return m_page->chrome().client()->visibleRectForTiledBackingStore(); } Color Frame::tiledBackingStoreBackgroundColor() const @@ -916,13 +906,13 @@ void Frame::setPageAndTextZoomFactors(float pageZoomFactor, float textZoomFactor if (!document) return; - m_editor.dismissCorrectionPanelAsIgnored(); + m_editor->dismissCorrectionPanelAsIgnored(); #if ENABLE(SVG) // Respect SVGs zoomAndPan="disabled" property in standalone SVG documents. // FIXME: How to handle compound documents + zoomAndPan="disabled"? Needs SVG WG clarification. if (document->isSVGDocument()) { - if (!static_cast<SVGDocument*>(document)->zoomAndPanEnabled()) + if (!toSVGDocument(document)->zoomAndPanEnabled()) return; } #endif @@ -941,7 +931,7 @@ void Frame::setPageAndTextZoomFactors(float pageZoomFactor, float textZoomFactor document->recalcStyle(Node::Force); - for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling()) + for (RefPtr<Frame> child = tree()->firstChild(); child; child = child->tree()->nextSibling()) child->setPageAndTextZoomFactors(m_pageZoomFactor, m_textZoomFactor); if (FrameView* view = this->view()) { @@ -990,16 +980,19 @@ void Frame::resumeActiveDOMObjectsAndAnimations() return; if (document()) { - document()->resumeActiveDOMObjects(); + document()->resumeActiveDOMObjects(ActiveDOMObject::PageWillBeSuspended); animation()->resumeAnimationsForDocument(document()); document()->resumeScriptedAnimationControllerCallbacks(); } + + if (m_view) + m_view->resumeAnimatingImages(); } #if USE(ACCELERATED_COMPOSITING) void Frame::deviceOrPageScaleFactorChanged() { - for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling()) + for (RefPtr<Frame> child = tree()->firstChild(); child; child = child->tree()->nextSibling()) child->deviceOrPageScaleFactorChanged(); RenderView* root = contentRenderer(); @@ -1018,7 +1011,7 @@ void Frame::notifyChromeClientWheelEventHandlerCountChanged() const count += frame->document()->wheelEventHandlerCount(); } - m_page->chrome()->client()->numWheelEventHandlersChanged(count); + m_page->chrome().client()->numWheelEventHandlersChanged(count); } bool Frame::isURLAllowed(const KURL& url) const @@ -1076,7 +1069,7 @@ DragImageRef Frame::nodeImage(Node* node) m_view->setPaintBehavior(state.paintBehavior | PaintBehaviorFlattenCompositingLayers); // When generating the drag image for an element, ignore the document background. - m_view->setBaseBackgroundColor(colorWithOverrideAlpha(Color::white, 1.0)); + m_view->setBaseBackgroundColor(Color::transparent); m_doc->updateLayout(); m_view->setNodeToDraw(node); // Enable special sub-tree drawing mode. diff --git a/Source/WebCore/page/Frame.h b/Source/WebCore/page/Frame.h index 7053eb240..3c2bade92 100644 --- a/Source/WebCore/page/Frame.h +++ b/Source/WebCore/page/Frame.h @@ -29,16 +29,14 @@ #define Frame_h #include "AdjustViewSizeOrNot.h" -#include "AnimationController.h" #include "DragImage.h" -#include "Editor.h" -#include "EventHandler.h" #include "FrameLoader.h" -#include "FrameSelection.h" #include "FrameTree.h" +#include "IntRect.h" #include "NavigationScheduler.h" -#include "ScriptController.h" +#include "ScrollTypes.h" #include "UserScriptTypes.h" +#include <wtf/RefCounted.h> #if PLATFORM(WIN) #include "FrameWin.h" @@ -48,39 +46,44 @@ #include "TiledBackingStoreClient.h" #endif -#if PLATFORM(MAC) -#ifndef __OBJC__ -class NSArray; -class NSMutableDictionary; -class NSString; -#endif -#endif - #if PLATFORM(WIN) typedef struct HBITMAP__* HBITMAP; #endif namespace WebCore { + class AnimationController; + class Color; class Document; + class Editor; + class Element; + class EventHandler; class FrameDestructionObserver; + class FrameSelection; class FrameView; class HTMLTableCellElement; + class IntRect; + class Node; class RegularExpression; class RenderPart; + class RenderView; + class ScriptController; + class Settings; class TiledBackingStore; + class TreeScope; + class VisiblePosition; #if !USE(TILED_BACKING_STORE) class TiledBackingStoreClient { }; #endif - class TreeScope; enum { LayerTreeFlagsIncludeDebugInfo = 1 << 0, LayerTreeFlagsIncludeVisibleRects = 1 << 1, LayerTreeFlagsIncludeTileCaches = 1 << 2, - LayerTreeFlagsIncludeRepaintRects = 1 << 3 + LayerTreeFlagsIncludeRepaintRects = 1 << 3, + LayerTreeFlagsIncludePaintingPhases = 1 << 4 }; typedef unsigned LayerTreeFlags; @@ -110,7 +113,7 @@ namespace WebCore { Document* document() const; FrameView* view() const; - Editor* editor() const; + Editor& editor() const; EventHandler* eventHandler() const; FrameLoader* loader() const; NavigationScheduler* navigationScheduler() const; @@ -126,8 +129,6 @@ namespace WebCore { void dispatchVisibilityStateChangeEvent(); #endif - void reportMemoryUsage(MemoryObjectInfo*) const; - // ======== All public functions below this point are candidates to move out of Frame into another class. ======== bool inScope(TreeScope*) const; @@ -189,12 +190,6 @@ namespace WebCore { String searchForLabelsBeforeElement(const Vector<String>& labels, Element*, size_t* resultDistance, bool* resultIsInCellAbove); String matchLabelsAgainstElement(const Vector<String>& labels, Element*); -#if PLATFORM(MAC) - NSImage* selectionImage(bool forceBlackText = false) const; - NSImage* rangeImage(Range*, bool forceBlackText = false) const; - NSImage* snapshotDragImage(Node*, NSRect* imageRect, NSRect* elementRect) const; - NSImage* imageFromRect(NSRect) const; -#endif void suspendActiveDOMObjectsAndAnimations(); void resumeActiveDOMObjectsAndAnimations(); bool activeDOMObjectsAndAnimationsSuspended() const { return m_activeDOMObjectsAndAnimationsSuspendedCount > 0; } @@ -222,12 +217,11 @@ namespace WebCore { RefPtr<FrameView> m_view; RefPtr<Document> m_doc; - ScriptController m_script; - - mutable Editor m_editor; - mutable FrameSelection m_selection; - mutable EventHandler m_eventHandler; - mutable AnimationController m_animationController; + OwnPtr<ScriptController> m_script; + const OwnPtr<Editor> m_editor; + OwnPtr<FrameSelection> m_selection; + OwnPtr<EventHandler> m_eventHandler; + OwnPtr<AnimationController> m_animationController; float m_pageZoomFactor; float m_textZoomFactor; @@ -282,7 +276,7 @@ namespace WebCore { inline ScriptController* Frame::script() { - return &m_script; + return m_script.get(); } inline Document* Frame::document() const @@ -292,17 +286,17 @@ namespace WebCore { inline FrameSelection* Frame::selection() const { - return &m_selection; + return m_selection.get(); } - inline Editor* Frame::editor() const + inline Editor& Frame::editor() const { - return &m_editor; + return *m_editor; } inline AnimationController* Frame::animation() const { - return &m_animationController; + return m_animationController.get(); } inline HTMLFrameOwnerElement* Frame::ownerElement() const @@ -337,7 +331,7 @@ namespace WebCore { inline EventHandler* Frame::eventHandler() const { - return &m_eventHandler; + return m_eventHandler.get(); } } // namespace WebCore diff --git a/Source/WebCore/page/FrameActionScheduler.cpp b/Source/WebCore/page/FrameActionScheduler.cpp index cf193cc84..42b50b710 100644 --- a/Source/WebCore/page/FrameActionScheduler.cpp +++ b/Source/WebCore/page/FrameActionScheduler.cpp @@ -27,6 +27,7 @@ #include "FrameActionScheduler.h" #include "Event.h" +#include "ExceptionCodePlaceholder.h" #include "Node.h" #include <wtf/Vector.h> @@ -43,9 +44,8 @@ public: virtual void fire() { // Only dispatch events to nodes that are in the document - ExceptionCode ec = 0; if (m_eventTarget->inDocument()) - m_eventTarget->dispatchEvent(m_event, ec); + m_eventTarget->dispatchEvent(m_event, IGNORE_EXCEPTION); } private: diff --git a/Source/WebCore/page/FrameTree.h b/Source/WebCore/page/FrameTree.h index c8653305a..5ee71718e 100644 --- a/Source/WebCore/page/FrameTree.h +++ b/Source/WebCore/page/FrameTree.h @@ -20,7 +20,6 @@ #ifndef FrameTree_h #define FrameTree_h -#include <wtf/NotFound.h> #include <wtf/text/AtomicString.h> namespace WebCore { @@ -31,7 +30,7 @@ namespace WebCore { class FrameTree { WTF_MAKE_NONCOPYABLE(FrameTree); public: - const static unsigned invalidCount = static_cast<unsigned>(WTF::notFound); + const static unsigned invalidCount = static_cast<unsigned>(-1); FrameTree(Frame* thisFrame, Frame* parentFrame) : m_thisFrame(thisFrame) @@ -94,7 +93,6 @@ namespace WebCore { AtomicString m_name; // The actual frame name (may be empty). AtomicString m_uniqueName; - // FIXME: use ListRefPtr? RefPtr<Frame> m_nextSibling; Frame* m_previousSibling; RefPtr<Frame> m_firstChild; diff --git a/Source/WebCore/page/FrameView.cpp b/Source/WebCore/page/FrameView.cpp index 083b83ad5..209030309 100644 --- a/Source/WebCore/page/FrameView.cpp +++ b/Source/WebCore/page/FrameView.cpp @@ -28,19 +28,24 @@ #include "FrameView.h" #include "AXObjectCache.h" +#include "AnimationController.h" #include "BackForwardController.h" +#include "CachedImage.h" #include "CachedResourceLoader.h" #include "Chrome.h" #include "ChromeClient.h" +#include "DOMWindow.h" #include "DocumentMarkerController.h" #include "EventHandler.h" #include "FloatRect.h" #include "FocusController.h" #include "FontCache.h" +#include "FontLoader.h" #include "Frame.h" #include "FrameActionScheduler.h" #include "FrameLoader.h" #include "FrameLoaderClient.h" +#include "FrameSelection.h" #include "FrameTree.h" #include "GraphicsContext.h" #include "HTMLDocument.h" @@ -52,14 +57,17 @@ #include "InspectorController.h" #include "InspectorInstrumentation.h" #include "OverflowEvent.h" +#include "ProgressTracker.h" #include "RenderArena.h" #include "RenderEmbeddedObject.h" #include "RenderFullScreen.h" #include "RenderIFrame.h" #include "RenderLayer.h" +#include "RenderLayerBacking.h" #include "RenderPart.h" #include "RenderScrollbar.h" #include "RenderScrollbarPart.h" +#include "RenderStyle.h" #include "RenderTheme.h" #include "RenderView.h" #include "ScrollAnimator.h" @@ -71,7 +79,6 @@ #include <wtf/CurrentTime.h> #include <wtf/TemporaryChange.h> -#include <wtf/UnusedParam.h> #if USE(ACCELERATED_COMPOSITING) #include "RenderLayerCompositor.h" @@ -123,16 +130,13 @@ double FrameView::s_deferredRepaintDelayIncrementDuringLoading = 0; // The maximum number of updateWidgets iterations that should be done before returning. static const unsigned maxUpdateWidgetsIterations = 2; -static inline RenderView* rootRenderer(const FrameView* view) -{ - return view->frame() ? view->frame()->contentRenderer() : 0; -} - static RenderLayer::UpdateLayerPositionsFlags updateLayerPositionFlags(RenderLayer* layer, bool isRelayoutingSubtree, bool didFullRepaint) { RenderLayer::UpdateLayerPositionsFlags flags = RenderLayer::defaultFlags; - if (didFullRepaint) + if (didFullRepaint) { flags &= ~RenderLayer::CheckForRepaint; + flags |= RenderLayer::NeedsFullRepaintInBacking; + } if (isRelayoutingSubtree && layer->isPaginated()) flags |= RenderLayer::UpdatePagination; return flags; @@ -168,7 +172,6 @@ Pagination::Mode paginationModeForRenderStyle(RenderStyle* style) FrameView::FrameView(Frame* frame) : m_frame(frame) , m_canHaveScrollbars(true) - , m_slowRepaintObjectCount(0) , m_layoutTimer(this, &FrameView::layoutTimerFired) , m_layoutRoot(0) , m_inSynchronousPostLayout(false) @@ -192,9 +195,14 @@ FrameView::FrameView(Frame* frame) , m_shouldAutoSize(false) , m_inAutoSize(false) , m_didRunAutosize(false) + , m_headerHeight(0) + , m_footerHeight(0) + , m_milestonesPendingPaint(0) #if ENABLE(CSS_FILTERS) , m_hasSoftwareFilters(false) #endif + , m_visualUpdatesAllowedByClient(true) + , m_scrollPinningBehavior(DoNotPin) { init(); @@ -234,9 +242,7 @@ FrameView::~FrameView() m_actionScheduler->clear(); } - if (AXObjectCache::accessibilityEnabled() && axObjectCache()) - axObjectCache()->remove(this); - + removeFromAXObjectCache(); resetScrollbars(); // Custom scrollbars should already be destroyed at this point @@ -299,9 +305,10 @@ void FrameView::reset() m_disableRepaints = 0; } -bool FrameView::isFrameView() const -{ - return true; +void FrameView::removeFromAXObjectCache() +{ + if (AXObjectCache* cache = axObjectCache()) + cache->remove(this); } void FrameView::clearFrame() @@ -340,7 +347,7 @@ void FrameView::init() // Propagate the marginwidth/height and scrolling modes to the view. Element* ownerElement = m_frame ? m_frame->ownerElement() : 0; if (ownerElement && (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag))) { - HTMLFrameElementBase* frameElt = static_cast<HTMLFrameElementBase*>(ownerElement); + HTMLFrameElementBase* frameElt = toHTMLFrameElementBase(ownerElement); if (frameElt->scrollingMode() == ScrollbarAlwaysOff) setCanHaveScrollbars(false); LayoutUnit marginWidth = frameElt->marginWidth(); @@ -350,6 +357,23 @@ void FrameView::init() if (marginHeight != -1) setMarginHeight(marginHeight); } + + Page* page = frame() ? frame()->page() : 0; + if (page && page->chrome().client()->shouldPaintEntireContents()) + setPaintsEntireContents(true); +} + +void FrameView::prepareForDetach() +{ + detachCustomScrollbars(); + // When the view is no longer associated with a frame, it needs to be removed from the ax object cache + // right now, otherwise it won't be able to reach the topDocument()'s axObject cache later. + removeFromAXObjectCache(); + + if (m_frame && m_frame->page()) { + if (ScrollingCoordinator* scrollingCoordinator = m_frame->page()->scrollingCoordinator()) + scrollingCoordinator->willDestroyScrollableArea(this); + } } void FrameView::detachCustomScrollbars() @@ -374,20 +398,13 @@ void FrameView::recalculateScrollbarOverlayStyle() ScrollbarOverlayStyle overlayStyle = ScrollbarOverlayStyleDefault; Color backgroundColor = documentBackgroundColor(); -#if USE(ACCELERATED_COMPOSITING) - if (RenderView* root = rootRenderer(this)) { - RenderLayerCompositor* compositor = root->compositor(); - compositor->documentBackgroundColorDidChange(); - } -#endif - if (backgroundColor.isValid()) { // Reduce the background color from RGB to a lightness value // and determine which scrollbar style to use based on a lightness // heuristic. double hue, saturation, lightness; backgroundColor.getHSL(hue, saturation, lightness); - if (lightness <= .5) + if (lightness <= .5 && backgroundColor.alpha() > 0) overlayStyle = ScrollbarOverlayStyleLight; } @@ -417,8 +434,8 @@ bool FrameView::didFirstLayout() const void FrameView::invalidateRect(const IntRect& rect) { if (!parent()) { - if (hostWindow()) - hostWindow()->invalidateContentsAndRootView(rect, false /*immediate*/); + if (HostWindow* window = hostWindow()) + window->invalidateContentsAndRootView(rect, false /*immediate*/); return; } @@ -441,23 +458,37 @@ void FrameView::setFrameRect(const IntRect& newRect) if (newRect == oldRect) return; +#if ENABLE(TEXT_AUTOSIZING) + // Autosized font sizes depend on the width of the viewing area. + if (newRect.width() != oldRect.width()) { + Page* page = m_frame ? m_frame->page() : 0; + if (page && page->mainFrame() == m_frame && page->settings()->textAutosizingEnabled()) { + for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext()) + m_frame->document()->textAutosizer()->recalculateMultipliers(); + } + } +#endif + ScrollView::setFrameRect(newRect); updateScrollableAreaSet(); #if USE(ACCELERATED_COMPOSITING) - if (RenderView* root = rootRenderer(this)) { - if (root->usesCompositing()) - root->compositor()->frameViewDidChangeSize(); + if (RenderView* renderView = this->renderView()) { + if (renderView->usesCompositing()) + renderView->compositor()->frameViewDidChangeSize(); } #endif + + if (!frameFlatteningEnabled()) + sendResizeEventIfNeeded(); } #if ENABLE(REQUEST_ANIMATION_FRAME) bool FrameView::scheduleAnimation() { - if (hostWindow()) { - hostWindow()->scheduleAnimation(); + if (HostWindow* window = hostWindow()) { + window->scheduleAnimation(); return true; } return false; @@ -476,21 +507,35 @@ void FrameView::setMarginHeight(LayoutUnit h) m_margins.setHeight(h); } -bool FrameView::avoidScrollbarCreation() const +bool FrameView::frameFlatteningEnabled() const { - ASSERT(m_frame); + Settings* settings = frame() ? frame()->settings() : 0; + if (!settings) + return false; - // with frame flattening no subframe can have scrollbars - // but we also cannot turn scrollbars off as we determine - // our flattening policy using that. + return settings->frameFlatteningEnabled(); +} - if (!m_frame->ownerElement()) +bool FrameView::isFrameFlatteningValidForThisFrame() const +{ + if (!frameFlatteningEnabled()) return false; - if (!m_frame->settings() || m_frame->settings()->frameFlatteningEnabled()) - return true; + HTMLFrameOwnerElement* owner = frame() ? frame()->ownerElement() : 0; + if (!owner) + return false; - return false; + // Frame flattening is valid only for <frame> and <iframe>. + return owner->hasTagName(frameTag) || owner->hasTagName(iframeTag); +} + +bool FrameView::avoidScrollbarCreation() const +{ + ASSERT(m_frame); + // with frame flattening no subframe can have scrollbars + // but we also cannot turn scrollbars off as we determine + // our flattening policy using that. + return isFrameFlatteningValidForThisFrame(); } void FrameView::setCanHaveScrollbars(bool canHaveScrollbars) @@ -555,7 +600,7 @@ void FrameView::setContentsSize(const IntSize& size) updateScrollableAreaSet(); - page->chrome()->contentsSizeChanged(frame(), size); //notify only + page->chrome().contentsSizeChanged(frame(), size); // Notify only. m_deferSetNeedsLayouts--; @@ -565,13 +610,13 @@ void FrameView::setContentsSize(const IntSize& size) void FrameView::adjustViewSize() { - RenderView* root = rootRenderer(this); - if (!root) + RenderView* renderView = this->renderView(); + if (!renderView) return; ASSERT(m_frame->view() == this); - const IntRect rect = root->documentRect(); + const IntRect rect = renderView->documentRect(); const IntSize& size = rect.size(); ScrollView::setScrollOrigin(IntPoint(-rect.x(), -rect.y()), !m_frame->document()->printing(), size == contentsSize()); @@ -586,9 +631,11 @@ void FrameView::applyOverflowToViewport(RenderObject* o, ScrollbarMode& hMode, S // use the root element. // To combat the inability to scroll on a page with overflow:hidden on the root when scaled, disregard hidden when - // there is a frameScaleFactor that is greater than one on the main frame. + // there is a frameScaleFactor that is greater than one on the main frame. Also disregard hidden if there is a + // header or footer. - bool overrideHidden = m_frame->page() && m_frame->page()->mainFrame() == m_frame && m_frame->frameScaleFactor() > 1; + bool overrideHidden = (m_frame->page() && m_frame->page()->mainFrame() == m_frame && m_frame->frameScaleFactor() > 1) + || (m_frame->page() && m_frame->page()->mainFrame() == m_frame && (headerHeight() || footerHeight())); EOverflow overflowX = o->style()->overflowX(); EOverflow overflowY = o->style()->overflowY(); @@ -683,7 +730,11 @@ void FrameView::calculateScrollbarModesForLayout(ScrollbarMode& hMode, Scrollbar if (m_canHaveScrollbars || strategy == RulesFromWebContentOnly) { hMode = ScrollbarAuto; - vMode = ScrollbarAuto; + // Seamless documents begin with heights of 0; we special case that here + // to correctly render documents that don't need scrollbars. + IntSize fullVisibleSize = visibleContentRect(IncludeScrollbars).size(); + bool isSeamlessDocument = frame() && frame()->document() && frame()->document()->shouldDisplaySeamlesslyWithParent(); + vMode = (isSeamlessDocument && !fullVisibleSize.height()) ? ScrollbarAlwaysOff : ScrollbarAuto; } else { hMode = ScrollbarAlwaysOff; vMode = ScrollbarAlwaysOff; @@ -695,7 +746,7 @@ void FrameView::calculateScrollbarModesForLayout(ScrollbarMode& hMode, Scrollbar RenderObject* rootRenderer = documentElement ? documentElement->renderer() : 0; Node* body = document->body(); if (body && body->renderer()) { - if (body->hasTagName(framesetTag) && m_frame->settings() && !m_frame->settings()->frameFlatteningEnabled()) { + if (body->hasTagName(framesetTag) && !frameFlatteningEnabled()) { vMode = ScrollbarAlwaysOff; hMode = ScrollbarAlwaysOff; } else if (body->hasTagName(bodyTag)) { @@ -712,37 +763,37 @@ void FrameView::calculateScrollbarModesForLayout(ScrollbarMode& hMode, Scrollbar #if USE(ACCELERATED_COMPOSITING) void FrameView::updateCompositingLayersAfterStyleChange() { - RenderView* root = rootRenderer(this); - if (!root) + RenderView* renderView = this->renderView(); + if (!renderView) return; // If we expect to update compositing after an incipient layout, don't do so here. - if (m_doingPreLayoutStyleUpdate || layoutPending() || root->needsLayout()) + if (m_doingPreLayoutStyleUpdate || layoutPending() || renderView->needsLayout()) return; // This call will make sure the cached hasAcceleratedCompositing is updated from the pref - root->compositor()->cacheAcceleratedCompositingFlags(); - root->compositor()->updateCompositingLayers(CompositingUpdateAfterStyleChange); + renderView->compositor()->cacheAcceleratedCompositingFlags(); + renderView->compositor()->updateCompositingLayers(CompositingUpdateAfterStyleChange); } void FrameView::updateCompositingLayersAfterLayout() { - RenderView* root = rootRenderer(this); - if (!root) + RenderView* renderView = this->renderView(); + if (!renderView) return; // This call will make sure the cached hasAcceleratedCompositing is updated from the pref - root->compositor()->cacheAcceleratedCompositingFlags(); - root->compositor()->updateCompositingLayers(CompositingUpdateAfterLayout); + renderView->compositor()->cacheAcceleratedCompositingFlags(); + renderView->compositor()->updateCompositingLayers(CompositingUpdateAfterLayout); } void FrameView::clearBackingStores() { - RenderView* root = rootRenderer(this); - if (!root) + RenderView* renderView = this->renderView(); + if (!renderView) return; - RenderLayerCompositor* compositor = root->compositor(); + RenderLayerCompositor* compositor = renderView->compositor(); ASSERT(compositor->inCompositingMode()); compositor->enableCompositingMode(false); compositor->clearBackingForAllLayers(); @@ -750,46 +801,64 @@ void FrameView::clearBackingStores() void FrameView::restoreBackingStores() { - RenderView* root = rootRenderer(this); - if (!root) + RenderView* renderView = this->renderView(); + if (!renderView) return; - RenderLayerCompositor* compositor = root->compositor(); + RenderLayerCompositor* compositor = renderView->compositor(); compositor->enableCompositingMode(true); compositor->updateCompositingLayers(CompositingUpdateAfterLayout); } +bool FrameView::usesCompositedScrolling() const +{ + RenderView* renderView = this->renderView(); + if (!renderView) + return false; + if (m_frame->settings() && m_frame->settings()->compositedScrollingForFramesEnabled()) + return renderView->compositor()->inForcedCompositingMode(); + return false; +} + +GraphicsLayer* FrameView::layerForScrolling() const +{ + RenderView* renderView = this->renderView(); + if (!renderView) + return 0; + return renderView->compositor()->scrollLayer(); +} + GraphicsLayer* FrameView::layerForHorizontalScrollbar() const { - RenderView* root = rootRenderer(this); - if (!root) + RenderView* renderView = this->renderView(); + if (!renderView) return 0; - return root->compositor()->layerForHorizontalScrollbar(); + return renderView->compositor()->layerForHorizontalScrollbar(); } GraphicsLayer* FrameView::layerForVerticalScrollbar() const { - RenderView* root = rootRenderer(this); - if (!root) + RenderView* renderView = this->renderView(); + if (!renderView) return 0; - return root->compositor()->layerForVerticalScrollbar(); + return renderView->compositor()->layerForVerticalScrollbar(); } GraphicsLayer* FrameView::layerForScrollCorner() const { - RenderView* root = rootRenderer(this); - if (!root) + RenderView* renderView = this->renderView(); + if (!renderView) return 0; - return root->compositor()->layerForScrollCorner(); + return renderView->compositor()->layerForScrollCorner(); } TiledBacking* FrameView::tiledBacking() { - RenderView* root = rootRenderer(this); - if (!root) + RenderView* renderView = this->renderView(); + if (!renderView) return 0; - RenderLayerBacking* backing = root->layer()->backing(); + RenderLayerBacking* backing = renderView->layer()->backing(); if (!backing) return 0; @@ -798,11 +867,11 @@ TiledBacking* FrameView::tiledBacking() uint64_t FrameView::scrollLayerID() const { - RenderView* root = rootRenderer(this); - if (!root) + RenderView* renderView = this->renderView(); + if (!renderView) return 0; - RenderLayerBacking* backing = root->layer()->backing(); + RenderLayerBacking* backing = renderView->layer()->backing(); if (!backing) return 0; @@ -812,17 +881,44 @@ uint64_t FrameView::scrollLayerID() const #if ENABLE(RUBBER_BANDING) GraphicsLayer* FrameView::layerForOverhangAreas() const { - RenderView* root = rootRenderer(this); - if (!root) + RenderView* renderView = this->renderView(); + if (!renderView) return 0; - return root->compositor()->layerForOverhangAreas(); + return renderView->compositor()->layerForOverhangAreas(); +} + +GraphicsLayer* FrameView::setWantsLayerForTopOverHangArea(bool wantsLayer) const +{ + RenderView* renderView = this->renderView(); + if (!renderView) + return 0; + + return renderView->compositor()->updateLayerForTopOverhangArea(wantsLayer); +} + +GraphicsLayer* FrameView::setWantsLayerForBottomOverHangArea(bool wantsLayer) const +{ + RenderView* renderView = this->renderView(); + if (!renderView) + return 0; + + return renderView->compositor()->updateLayerForBottomOverhangArea(wantsLayer); +} + +#endif // ENABLE(RUBBER_BANDING) + +bool FrameView::scrollbarAnimationsAreSuppressed() const +{ + Page* page = frame() ? frame()->page() : 0; + if (!page) + return true; + return page->shouldSuppressScrollbarAnimations(); } -#endif bool FrameView::flushCompositingStateForThisFrame(Frame* rootFrameForFlush) { - RenderView* root = rootRenderer(this); - if (!root) + RenderView* renderView = this->renderView(); + if (!renderView) return true; // We don't want to keep trying to update layers if we have no renderer. ASSERT(m_frame->view() == this); @@ -836,7 +932,7 @@ bool FrameView::flushCompositingStateForThisFrame(Frame* rootFrameForFlush) // visible flash to occur. Instead, stop the deferred repaint timer and repaint immediately. flushDeferredRepaints(); - root->compositor()->flushPendingLayerChanges(rootFrameForFlush == m_frame); + renderView->compositor()->flushPendingLayerChanges(rootFrameForFlush == m_frame); return true; } @@ -845,16 +941,36 @@ void FrameView::setNeedsOneShotDrawingSynchronization() { Page* page = frame() ? frame()->page() : 0; if (page) - page->chrome()->client()->setNeedsOneShotDrawingSynchronization(); + page->chrome().client()->setNeedsOneShotDrawingSynchronization(); } #endif // USE(ACCELERATED_COMPOSITING) +void FrameView::setHeaderHeight(int headerHeight) +{ + if (m_frame && m_frame->page()) + ASSERT(m_frame == m_frame->page()->mainFrame()); + m_headerHeight = headerHeight; + + if (RenderView* renderView = this->renderView()) + renderView->setNeedsLayout(true); +} + +void FrameView::setFooterHeight(int footerHeight) +{ + if (m_frame && m_frame->page()) + ASSERT(m_frame == m_frame->page()->mainFrame()); + m_footerHeight = footerHeight; + + if (RenderView* renderView = this->renderView()) + renderView->setNeedsLayout(true); +} + bool FrameView::hasCompositedContent() const { #if USE(ACCELERATED_COMPOSITING) - if (RenderView* root = rootRenderer(this)) - return root->compositor()->inCompositingMode(); + if (RenderView* renderView = this->renderView()) + return renderView->compositor()->inCompositingMode(); #endif return false; } @@ -894,10 +1010,10 @@ bool FrameView::hasCompositingAncestor() const void FrameView::enterCompositingMode() { #if USE(ACCELERATED_COMPOSITING) - if (RenderView* root = rootRenderer(this)) { - root->compositor()->enableCompositingMode(); + if (RenderView* renderView = this->renderView()) { + renderView->compositor()->enableCompositingMode(); if (!needsLayout()) - root->compositor()->scheduleCompositingLayerUpdate(); + renderView->compositor()->scheduleCompositingLayerUpdate(); } #endif } @@ -933,11 +1049,8 @@ bool FrameView::flushCompositingStateIncludingSubframes() bool FrameView::isSoftwareRenderable() const { #if USE(ACCELERATED_COMPOSITING) - RenderView* root = rootRenderer(this); - if (!root) - return true; - - return !root->compositor()->has3DContent(); + RenderView* renderView = this->renderView(); + return !renderView || !renderView->compositor()->has3DContent(); #else return true; #endif @@ -945,18 +1058,31 @@ bool FrameView::isSoftwareRenderable() const void FrameView::didMoveOnscreen() { - if (RenderView* root = rootRenderer(this)) - root->didMoveOnscreen(); contentAreaDidShow(); } void FrameView::willMoveOffscreen() { - if (RenderView* root = rootRenderer(this)) - root->willMoveOffscreen(); contentAreaDidHide(); } +void FrameView::setIsInWindow(bool isInWindow) +{ + if (RenderView* renderView = this->renderView()) + renderView->setIsInWindow(isInWindow); + + if (isInWindow) + resumeAnimatingImages(); +} + +void FrameView::resumeAnimatingImages() +{ + // Drawing models which cache painted content while out-of-window (WebKit2's composited drawing areas, etc.) + // require that we repaint animated images to kickstart the animation loop. + + CachedImage::resumeAnimatingImagesForLoader(frame()->document()->cachedResourceLoader()); +} + RenderObject* FrameView::layoutRoot(bool onlyDuringLayout) const { return onlyDuringLayout && layoutPending() ? 0 : m_layoutRoot; @@ -971,7 +1097,7 @@ static inline void collectFrameViewChildren(FrameView* frameView, Vector<RefPtr< for (HashSet<RefPtr<Widget> >::iterator current = viewChildren->begin(); current != end; ++current) { Widget* widget = (*current).get(); if (widget->isFrameView()) - frameViews.append(static_cast<FrameView*>(widget)); + frameViews.append(toFrameView(widget)); } } @@ -1016,6 +1142,9 @@ void FrameView::layout(bool allowSubtree) // Protect the view from being deleted during layout (in recalcStyle) RefPtr<FrameView> protector(this); + // Every scroll that happens during layout is programmatic. + TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true); + bool inChildFrameLayoutWithFrameFlattening = isInChildFrameWithFrameFlattening(); if (inChildFrameLayoutWithFrameFlattening) { @@ -1065,9 +1194,10 @@ void FrameView::layout(bool allowSubtree) } // Viewport-dependent media queries may cause us to need completely different style information. - // Check that here. - if (document->styleResolver()->affectedByViewportChange()) { - document->styleResolverChanged(RecalcStyleImmediately); + if (!document->styleResolverIfExists() || document->styleResolverIfExists()->affectedByViewportChange()) { + document->styleResolverChanged(DeferRecalcStyle); + // FIXME: This instrumentation event is not strictly accurate since cached media query results + // do not persist across StyleResolver rebuilds. InspectorInstrumentation::mediaQueryResultChanged(document); } else document->evaluateMediaQueryList(); @@ -1108,7 +1238,7 @@ void FrameView::layout(bool allowSubtree) Document* document = m_frame->document(); Node* body = document->body(); if (body && body->renderer()) { - if (body->hasTagName(framesetTag) && m_frame->settings() && !m_frame->settings()->frameFlatteningEnabled()) { + if (body->hasTagName(framesetTag) && !frameFlatteningEnabled()) { body->renderer()->setChildNeedsLayout(true); } else if (body->hasTagName(bodyTag)) { if (!m_firstLayout && m_size.height() != layoutHeight() && body->renderer()->enclosingBox()->stretchesToViewport()) @@ -1144,7 +1274,7 @@ void FrameView::layout(bool allowSubtree) if (useFixedLayout() && !fixedLayoutSize().isEmpty() && delegatesScrolling()) m_lastViewportSize = fixedLayoutSize(); else - m_lastViewportSize = visibleContentRect(true /*includeScrollbars*/).size(); + m_lastViewportSize = visibleContentRect(IncludeScrollbars).size(); m_lastZoomFactor = root->style()->zoom(); // Set the initial vMode to AlwaysOn if we're auto. @@ -1208,16 +1338,20 @@ void FrameView::layout(bool allowSubtree) m_layoutRoot = 0; } // Reset m_layoutSchedulingEnabled to its previous value. + bool neededFullRepaint = m_doFullRepaint; + if (!subtree && !toRenderView(root)->printing()) adjustViewSize(); + m_doFullRepaint = neededFullRepaint; + // Now update the positions of all layers. beginDeferredRepaints(); if (m_doFullRepaint) root->view()->repaint(); // FIXME: This isn't really right, since the RenderView doesn't fully encompass the visibleContentRect(). It just happens // to work out most of the time, since first layouts and printing don't have you scrolled anywhere. - layer->updateLayerPositionsAfterLayout(rootRenderer(this)->layer(), updateLayerPositionFlags(layer, subtree, m_doFullRepaint)); + layer->updateLayerPositionsAfterLayout(renderView()->layer(), updateLayerPositionFlags(layer, subtree, m_doFullRepaint)); endDeferredRepaints(); @@ -1227,9 +1361,9 @@ void FrameView::layout(bool allowSubtree) m_layoutCount++; -#if PLATFORM(MAC) || PLATFORM(CHROMIUM) - if (AXObjectCache::accessibilityEnabled()) - root->document()->axObjectCache()->postNotification(root, AXObjectCache::AXLayoutComplete, true); +#if PLATFORM(MAC) || PLATFORM(WIN) + if (AXObjectCache* cache = root->document()->existingAXObjectCache()) + cache->postNotification(root, AXObjectCache::AXLayoutComplete, true); #endif #if ENABLE(DASHBOARD_SUPPORT) || ENABLE(DRAGGABLE_REGION) updateAnnotatedRegions(); @@ -1246,8 +1380,8 @@ void FrameView::layout(bool allowSubtree) if (!m_postLayoutTasksTimer.isActive()) { if (!m_inSynchronousPostLayout) { if (inChildFrameLayoutWithFrameFlattening) { - if (RenderView* root = rootRenderer(this)) - root->updateWidgetPositions(); + if (RenderView* renderView = this->renderView()) + renderView->updateWidgetPositions(); } else { m_inSynchronousPostLayout = true; // Calls resumeScheduledEvents() @@ -1281,44 +1415,45 @@ void FrameView::layout(bool allowSubtree) if (!page) return; - page->chrome()->client()->layoutUpdated(frame()); + page->chrome().client()->layoutUpdated(frame()); } RenderBox* FrameView::embeddedContentBox() const { #if ENABLE(SVG) - RenderView* root = rootRenderer(this); - if (!root) + RenderView* renderView = this->renderView(); + if (!renderView) return 0; - RenderObject* rootChild = root->firstChild(); - if (!rootChild || !rootChild->isBox()) + RenderObject* firstChild = renderView->firstChild(); + if (!firstChild || !firstChild->isBox()) return 0; // Curently only embedded SVG documents participate in the size-negotiation logic. - if (rootChild->isSVGRoot()) - return toRenderBox(rootChild); + if (firstChild->isSVGRoot()) + return toRenderBox(firstChild); #endif return 0; } -void FrameView::addWidgetToUpdate(RenderEmbeddedObject* object) +void FrameView::addWidgetToUpdate(RenderObject* object) { if (!m_widgetUpdateSet) - m_widgetUpdateSet = adoptPtr(new RenderEmbeddedObjectSet); + m_widgetUpdateSet = adoptPtr(new RenderObjectSet); // Tell the DOM element that it needs a widget update. Node* node = object->node(); if (node->hasTagName(objectTag) || node->hasTagName(embedTag)) { - HTMLPlugInImageElement* pluginElement = static_cast<HTMLPlugInImageElement*>(node); - pluginElement->setNeedsWidgetUpdate(true); + HTMLPlugInImageElement* pluginElement = toHTMLPlugInImageElement(node); + if (!pluginElement->needsCheckForSizeChange()) + pluginElement->setNeedsWidgetUpdate(true); } m_widgetUpdateSet->add(object); } -void FrameView::removeWidgetToUpdate(RenderEmbeddedObject* object) +void FrameView::removeWidgetToUpdate(RenderObject* object) { if (!m_widgetUpdateSet) return; @@ -1335,6 +1470,7 @@ String FrameView::mediaType() const { // See if we have an override type. String overrideType = m_frame->loader()->client()->overrideMediaType(); + InspectorInstrumentation::applyEmulatedMedia(m_frame.get(), &overrideType); if (!overrideType.isNull()) return overrideType; return m_mediaType; @@ -1355,7 +1491,7 @@ void FrameView::adjustMediaTypeForPrinting(bool printing) bool FrameView::useSlowRepaints(bool considerOverlap) const { - bool mustBeSlow = m_slowRepaintObjectCount > 0 || (platformWidget() && hasViewportConstrainedObjects()); + bool mustBeSlow = hasSlowRepaintObjects() || (platformWidget() && hasViewportConstrainedObjects()); // FIXME: WidgetMac.mm makes the assumption that useSlowRepaints == // m_contentIsOpaque, so don't take the fast path for composited layers @@ -1364,13 +1500,6 @@ bool FrameView::useSlowRepaints(bool considerOverlap) const if (contentsInCompositedLayer() && !platformWidget()) return mustBeSlow; -#if PLATFORM(CHROMIUM) - // The chromium compositor does not support scrolling a non-composited frame within a composited page through - // the fast scrolling path, so force slow scrolling in that case. - if (m_frame->ownerElement() && !hasCompositedContent() && m_frame->page() && m_frame->page()->mainFrame()->view()->hasCompositedContent()) - return true; -#endif - bool isOverlapped = m_isOverlapped && considerOverlap; if (mustBeSlow || m_cannotBlitToWindow || isOverlapped || !m_contentIsOpaque) @@ -1398,9 +1527,9 @@ void FrameView::updateCanBlitOnScrollRecursively() bool FrameView::contentsInCompositedLayer() const { #if USE(ACCELERATED_COMPOSITING) - RenderView* root = rootRenderer(this); - if (root && root->isComposited()) { - GraphicsLayer* layer = root->layer()->backing()->graphicsLayer(); + RenderView* renderView = this->renderView(); + if (renderView && renderView->isComposited()) { + GraphicsLayer* layer = renderView->layer()->backing()->graphicsLayer(); if (layer && layer->drawsContent()) return true; } @@ -1414,9 +1543,16 @@ void FrameView::setCannotBlitToWindow() updateCanBlitOnScrollRecursively(); } -void FrameView::addSlowRepaintObject() +void FrameView::addSlowRepaintObject(RenderObject* o) { - if (!m_slowRepaintObjectCount++) { + bool hadSlowRepaintObjects = hasSlowRepaintObjects(); + + if (!m_slowRepaintObjects) + m_slowRepaintObjects = adoptPtr(new RenderObjectSet); + + m_slowRepaintObjects->add(o); + + if (!hadSlowRepaintObjects) { updateCanBlitOnScrollRecursively(); if (Page* page = m_frame->page()) { @@ -1426,11 +1562,14 @@ void FrameView::addSlowRepaintObject() } } -void FrameView::removeSlowRepaintObject() +void FrameView::removeSlowRepaintObject(RenderObject* o) { - ASSERT(m_slowRepaintObjectCount > 0); - m_slowRepaintObjectCount--; - if (!m_slowRepaintObjectCount) { + if (!m_slowRepaintObjects) + return; + + m_slowRepaintObjects->remove(o); + if (m_slowRepaintObjects->isEmpty()) { + m_slowRepaintObjects = nullptr; updateCanBlitOnScrollRecursively(); if (Page* page = m_frame->page()) { @@ -1472,14 +1611,61 @@ void FrameView::removeViewportConstrainedObject(RenderObject* object) } } +LayoutRect FrameView::viewportConstrainedVisibleContentRect() const +{ + LayoutRect viewportRect = visibleContentRect(); + viewportRect.setLocation(toPoint(scrollOffsetForFixedPosition())); + return viewportRect; +} + +IntSize FrameView::scrollOffsetForFixedPosition(const IntRect& visibleContentRect, const IntSize& totalContentsSize, const IntPoint& scrollPosition, const IntPoint& scrollOrigin, float frameScaleFactor, bool fixedElementsLayoutRelativeToFrame, int headerHeight, int footerHeight) +{ + IntPoint constrainedPosition = ScrollableArea::constrainScrollPositionForOverhang(visibleContentRect, totalContentsSize, scrollPosition, scrollOrigin, headerHeight, footerHeight); + + IntSize maxSize = totalContentsSize - visibleContentRect.size(); + + float dragFactorX = (fixedElementsLayoutRelativeToFrame || !maxSize.width()) ? 1 : (totalContentsSize.width() - visibleContentRect.width() * frameScaleFactor) / maxSize.width(); + float dragFactorY = (fixedElementsLayoutRelativeToFrame || !maxSize.height()) ? 1 : (totalContentsSize.height() - visibleContentRect.height() * frameScaleFactor) / maxSize.height(); + + return IntSize(constrainedPosition.x() * dragFactorX / frameScaleFactor, constrainedPosition.y() * dragFactorY / frameScaleFactor); +} + IntSize FrameView::scrollOffsetForFixedPosition() const { IntRect visibleContentRect = this->visibleContentRect(); - IntSize contentsSize = this->contentsSize(); + IntSize totalContentsSize = this->totalContentsSize(); IntPoint scrollPosition = this->scrollPosition(); IntPoint scrollOrigin = this->scrollOrigin(); float frameScaleFactor = m_frame ? m_frame->frameScaleFactor() : 1; - return WebCore::scrollOffsetForFixedPosition(visibleContentRect, contentsSize, scrollPosition, scrollOrigin, frameScaleFactor, fixedElementsLayoutRelativeToFrame()); + return scrollOffsetForFixedPosition(visibleContentRect, totalContentsSize, scrollPosition, scrollOrigin, frameScaleFactor, fixedElementsLayoutRelativeToFrame(), headerHeight(), footerHeight()); +} + +IntPoint FrameView::minimumScrollPosition() const +{ + IntPoint minimumPosition(ScrollView::minimumScrollPosition()); + + if (!m_frame || !m_frame->page()) + return minimumPosition; + + if (m_frame == m_frame->page()->mainFrame() && m_scrollPinningBehavior == PinToBottom) + minimumPosition.setY(maximumScrollPosition().y()); + + return minimumPosition; +} + +IntPoint FrameView::maximumScrollPosition() const +{ + IntPoint maximumOffset(contentsWidth() - visibleWidth() - scrollOrigin().x(), totalContentsSize().height() - visibleHeight() - scrollOrigin().y()); + + maximumOffset.clampNegativeToZero(); + + if (!m_frame || !m_frame->page()) + return maximumOffset; + + if (m_frame == m_frame->page()->mainFrame() && m_scrollPinningBehavior == PinToTop) + maximumOffset.setY(minimumScrollPosition().y()); + + return maximumOffset; } bool FrameView::fixedElementsLayoutRelativeToFrame() const @@ -1491,9 +1677,20 @@ bool FrameView::fixedElementsLayoutRelativeToFrame() const return m_frame->settings()->fixedElementsLayoutRelativeToFrame(); } -IntPoint FrameView::currentMousePosition() const +IntPoint FrameView::lastKnownMousePosition() const { - return m_frame ? m_frame->eventHandler()->currentMousePosition() : IntPoint(); + return m_frame ? m_frame->eventHandler()->lastKnownMousePosition() : IntPoint(); +} + +bool FrameView::isHandlingWheelEvent() const +{ + return m_frame ? m_frame->eventHandler()->isHandlingWheelEvent() : false; +} + +bool FrameView::shouldSetCursor() const +{ + Page* page = frame()->page(); + return page && page->isOnscreen() && page->focusController()->isActive(); } bool FrameView::scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect) @@ -1520,7 +1717,15 @@ bool FrameView::scrollContentsFastPath(const IntSize& scrollDelta, const IntRect // Fixed items should always have layers. ASSERT(renderer->hasLayer()); RenderLayer* layer = toRenderBoxModelObject(renderer)->layer(); - + +#if USE(ACCELERATED_COMPOSITING) + if (layer->viewportConstrainedNotCompositedReason() == RenderLayer::NotCompositedForBoundsOutOfView + || layer->viewportConstrainedNotCompositedReason() == RenderLayer::NotCompositedForNoVisibleContent) { + // Don't invalidate for invisible fixed layers. + continue; + } +#endif + #if ENABLE(CSS_FILTERS) if (layer->hasAncestorWithFilterOutsets()) { // If the fixed layer has a blur/drop-shadow filter applied on at least one of its parents, we cannot @@ -1550,9 +1755,8 @@ bool FrameView::scrollContentsFastPath(const IntSize& scrollDelta, const IntRect #if USE(ACCELERATED_COMPOSITING) if (isCompositedContentLayer) { updateRect = rootViewToContents(updateRect); - RenderView* root = rootRenderer(this); - ASSERT(root); - root->layer()->setBackingNeedsRepaintInRect(updateRect); + ASSERT(renderView()); + renderView()->layer()->setBackingNeedsRepaintInRect(updateRect); continue; } #endif @@ -1568,17 +1772,18 @@ void FrameView::scrollContentsSlowPath(const IntRect& updateRect) { #if USE(ACCELERATED_COMPOSITING) if (contentsInCompositedLayer()) { - RenderView* root = rootRenderer(this); - ASSERT(root); - IntRect updateRect = visibleContentRect(); // Make sure to "apply" the scale factor here since we're converting from frame view // coordinates to layer backing coordinates. updateRect.scale(1 / m_frame->frameScaleFactor()); - root->layer()->setBackingNeedsRepaintInRect(updateRect); + ASSERT(renderView()); + renderView()->layer()->setBackingNeedsRepaintInRect(updateRect); } + + repaintSlowRepaintObjects(); + if (RenderPart* frameRenderer = m_frame->ownerRenderer()) { if (isEnclosedInCompositingLayer()) { LayoutRect rect(frameRenderer->borderLeft() + frameRenderer->paddingLeft(), @@ -1593,6 +1798,20 @@ void FrameView::scrollContentsSlowPath(const IntRect& updateRect) ScrollView::scrollContentsSlowPath(updateRect); } +void FrameView::repaintSlowRepaintObjects() +{ + if (!m_slowRepaintObjects) + return; + + // Renderers with fixed backgrounds may be in compositing layers, so we need to explicitly + // repaint them after scrolling. + RenderObjectSet::const_iterator end = m_slowRepaintObjects->end(); + for (RenderObjectSet::const_iterator it = m_slowRepaintObjects->begin(); it != end; ++it) { + RenderObject* renderer = *it; + renderer->repaint(); + } +} + // Note that this gets called at painting time. void FrameView::setIsOverlapped(bool isOverlapped) { @@ -1687,26 +1906,31 @@ bool FrameView::scrollToAnchor(const String& name) m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(false); - Element* anchorNode = m_frame->document()->findAnchor(name); + Element* anchorElement = m_frame->document()->findAnchor(name); // Setting to null will clear the current target. - m_frame->document()->setCSSTarget(anchorNode); + m_frame->document()->setCSSTarget(anchorElement); #if ENABLE(SVG) if (m_frame->document()->isSVGDocument()) { - if (SVGSVGElement* svg = static_cast<SVGDocument*>(m_frame->document())->rootElement()) { - svg->setupInitialView(name, anchorNode); - if (!anchorNode) + if (SVGSVGElement* svg = toSVGDocument(m_frame->document())->rootElement()) { + svg->setupInitialView(name, anchorElement); + if (!anchorElement) return true; } } #endif // Implement the rule that "" and "top" both mean top of page as in other browsers. - if (!anchorNode && !(name.isEmpty() || equalIgnoringCase(name, "top"))) + if (!anchorElement && !(name.isEmpty() || equalIgnoringCase(name, "top"))) return false; - maintainScrollPositionAtAnchor(anchorNode ? static_cast<Node*>(anchorNode) : m_frame->document()); + maintainScrollPositionAtAnchor(anchorElement ? static_cast<Node*>(anchorElement) : m_frame->document()); + + // If the anchor accepts keyboard focus, move focus there to aid users relying on keyboard navigation. + if (anchorElement && anchorElement->isFocusable()) + m_frame->document()->setFocusedElement(anchorElement); + return true; } @@ -1720,8 +1944,8 @@ void FrameView::maintainScrollPositionAtAnchor(Node* anchorNode) // really mess things up if an anchor scroll comes at a bad moment. m_frame->document()->updateStyleIfNeeded(); // Only do a layout if changes have occurred that make it necessary. - RenderView* root = rootRenderer(this); - if (root && root->needsLayout()) + RenderView* renderView = this->renderView(); + if (renderView && renderView->needsLayout()) layout(); else scrollToAnchor(); @@ -1741,10 +1965,6 @@ void FrameView::setScrollPosition(const IntPoint& scrollPoint) { TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true); m_maintainScrollPositionAnchor = 0; - - if (requestScrollPositionUpdate(scrollPoint)) - return; - ScrollView::setScrollPosition(scrollPoint); } @@ -1770,6 +1990,7 @@ void FrameView::setFixedVisibleContentRect(const IntRect& visibleContentRect) IntSize offset = scrollOffset(); ScrollView::setFixedVisibleContentRect(visibleContentRect); if (offset != scrollOffset()) { + repaintFixedElementsAfterScrolling(); if (m_frame->page()->settings()->acceleratedCompositingForFixedPositionEnabled()) updateFixedElementsAfterScrolling(); scrollAnimator()->setCurrentPosition(scrollPosition()); @@ -1794,11 +2015,11 @@ void FrameView::setViewportConstrainedObjectsNeedLayout() } } - void FrameView::scrollPositionChangedViaPlatformWidget() { repaintFixedElementsAfterScrolling(); updateFixedElementsAfterScrolling(); + repaintSlowRepaintObjects(); scrollPositionChanged(); } @@ -1808,21 +2029,22 @@ void FrameView::scrollPositionChanged() frame()->eventHandler()->dispatchFakeMouseMoveEventSoon(); #if USE(ACCELERATED_COMPOSITING) - if (RenderView* root = rootRenderer(this)) { - if (root->usesCompositing()) - root->compositor()->frameViewDidScroll(); + if (RenderView* renderView = this->renderView()) { + if (renderView->usesCompositing()) + renderView->compositor()->frameViewDidScroll(); } #endif } +// FIXME: this function is misnamed; its primary purpose is to update RenderLayer positions. void FrameView::repaintFixedElementsAfterScrolling() { // For fixed position elements, update widget positions and compositing layers after scrolling, // but only if we're not inside of layout. - if (!m_nestedLayoutCount && hasViewportConstrainedObjects()) { - if (RenderView* root = rootRenderer(this)) { - root->updateWidgetPositions(); - root->layer()->updateLayerPositionsAfterDocumentScroll(); + if (m_nestedLayoutCount <= 1 && hasViewportConstrainedObjects()) { + if (RenderView* renderView = this->renderView()) { + renderView->updateWidgetPositions(); + renderView->layer()->updateLayerPositionsAfterDocumentScroll(); } } } @@ -1863,8 +2085,8 @@ void FrameView::updateFixedElementsAfterScrolling() return; if (m_nestedLayoutCount <= 1 && hasViewportConstrainedObjects()) { - if (RenderView* root = rootRenderer(this)) - root->compositor()->updateCompositingLayers(CompositingUpdateOnScroll); + if (RenderView* renderView = this->renderView()) + renderView->compositor()->updateCompositingLayers(CompositingUpdateOnScroll); } #endif } @@ -1874,12 +2096,40 @@ bool FrameView::shouldRubberBandInDirection(ScrollDirection direction) const Page* page = frame() ? frame()->page() : 0; if (!page) return ScrollView::shouldRubberBandInDirection(direction); - return page->chrome()->client()->shouldRubberBandInDirection(direction); + return page->chrome().client()->shouldRubberBandInDirection(direction); +} + +bool FrameView::isRubberBandInProgress() const +{ + if (scrollbarsSuppressed()) + return false; + + // If the scrolling thread updates the scroll position for this FrameView, then we should return + // ScrollingCoordinator::isRubberBandInProgress(). + if (Page* page = m_frame->page()) { + if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) { + if (!scrollingCoordinator->shouldUpdateScrollLayerPositionOnMainThread()) + return scrollingCoordinator->isRubberBandInProgress(); + } + } + + // If the main thread updates the scroll position for this FrameView, we should return + // ScrollAnimator::isRubberBandInProgress(). + if (ScrollAnimator* scrollAnimator = existingScrollAnimator()) + return scrollAnimator->isRubberBandInProgress(); + + return false; } bool FrameView::requestScrollPositionUpdate(const IntPoint& position) { #if ENABLE(THREADED_SCROLLING) + if (TiledBacking* tiledBacking = this->tiledBacking()) { + IntRect visibleRect = visibleContentRect(); + visibleRect.setLocation(position); + tiledBacking->prepopulateRect(visibleRect); + } + if (Page* page = m_frame->page()) { if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) return scrollingCoordinator->requestScrollPositionUpdate(this, position); @@ -1896,7 +2146,7 @@ HostWindow* FrameView::hostWindow() const Page* page = frame() ? frame()->page() : 0; if (!page) return 0; - return page->chrome(); + return &page->chrome(); } const unsigned cRepaintRectUnionThreshold = 25; @@ -1955,6 +2205,15 @@ void FrameView::contentsResized() setNeedsLayout(); } +void FrameView::fixedLayoutSizeChanged() +{ + // Can be triggered before the view is set, see comment in FrameView::visibleContentsResized(). + // An ASSERT is triggered when a view schedules a layout before being attached to a frame. + if (!frame()->view()) + return; + ScrollView::fixedLayoutSizeChanged(); +} + void FrameView::visibleContentsResized() { // We check to make sure the view is attached to a frame() as this method can @@ -1964,13 +2223,13 @@ void FrameView::visibleContentsResized() if (!frame()->view()) return; - if (needsLayout()) + if (!useFixedLayout() && needsLayout()) layout(); #if USE(ACCELERATED_COMPOSITING) - if (RenderView* root = rootRenderer(this)) { - if (root->usesCompositing()) - root->compositor()->frameViewDidChangeSize(); + if (RenderView* renderView = this->renderView()) { + if (renderView->usesCompositing()) + renderView->compositor()->frameViewDidChangeSize(); } #endif } @@ -2100,6 +2359,10 @@ void FrameView::resetDeferredRepaintDelay() if (!m_deferringRepaints) doDeferredRepaints(); } +#if USE(ACCELERATED_COMPOSITING) + if (RenderView* view = renderView()) + view->compositor()->disableLayerFlushThrottlingTemporarilyForInteraction(); +#endif } double FrameView::adjustedDeferredRepaintDelay() const @@ -2127,6 +2390,26 @@ void FrameView::endDisableRepaints() m_disableRepaints--; } +void FrameView::updateLayerFlushThrottlingInAllFrames() +{ +#if USE(ACCELERATED_COMPOSITING) + bool isMainLoadProgressing = m_frame->page()->progress()->isMainLoadProgressing(); + for (Frame* frame = m_frame.get(); frame; frame = frame->tree()->traverseNext(m_frame.get())) { + if (RenderView* renderView = frame->contentRenderer()) + renderView->compositor()->setLayerFlushThrottlingEnabled(isMainLoadProgressing); + } +#endif +} + +void FrameView::adjustTiledBackingCoverage() +{ +#if USE(ACCELERATED_COMPOSITING) + RenderView* renderView = this->renderView(); + if (renderView && renderView->layer()->backing()) + renderView->layer()->backing()->adjustTiledBackingCoverage(); +#endif +} + void FrameView::layoutTimerFired(Timer<FrameView>*) { #ifdef INSTRUMENT_LAYOUT_SCHEDULING @@ -2187,8 +2470,8 @@ void FrameView::scheduleRelayoutOfSubtree(RenderObject* relayoutRoot) { ASSERT(m_frame->view() == this); - RenderView* root = rootRenderer(this); - if (root && root->needsLayout()) { + RenderView* renderView = this->renderView(); + if (renderView && renderView->needsLayout()) { if (relayoutRoot) relayoutRoot->markContainingBlocksForLayout(false); return; @@ -2238,9 +2521,9 @@ bool FrameView::needsLayout() const if (!m_frame) return false; - RenderView* root = rootRenderer(this); + RenderView* renderView = this->renderView(); return layoutPending() - || (root && root->needsLayout()) + || (renderView && renderView->needsLayout()) || m_layoutRoot || (m_deferSetNeedsLayouts && m_setNeedsLayoutWasDeferred); } @@ -2252,8 +2535,8 @@ void FrameView::setNeedsLayout() return; } - if (RenderView* root = rootRenderer(this)) - root->setNeedsLayout(true); + if (RenderView* renderView = this->renderView()) + renderView->setNeedsLayout(true); } void FrameView::unscheduleRelayout() @@ -2297,6 +2580,11 @@ void FrameView::setTransparent(bool isTransparent) m_isTransparent = isTransparent; } +bool FrameView::hasOpaqueBackground() const +{ + return !m_isTransparent && !m_baseBackgroundColor.hasAlpha(); +} + Color FrameView::baseBackgroundColor() const { return m_baseBackgroundColor; @@ -2371,45 +2659,60 @@ void FrameView::scrollToAnchor() // Align to the top and to the closest side (this matches other browsers). anchorNode->renderer()->scrollRectToVisible(rect, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways); - if (AXObjectCache::accessibilityEnabled()) - m_frame->document()->axObjectCache()->handleScrolledToAnchor(anchorNode.get()); + if (AXObjectCache* cache = m_frame->document()->existingAXObjectCache()) + cache->handleScrolledToAnchor(anchorNode.get()); // scrollRectToVisible can call into setScrollPosition(), which resets m_maintainScrollPositionAnchor. m_maintainScrollPositionAnchor = anchorNode; } -void FrameView::updateWidget(RenderEmbeddedObject* object) +void FrameView::updateWidget(RenderObject* object) { ASSERT(!object->node() || object->node()->isElementNode()); - Element* ownerElement = static_cast<Element*>(object->node()); + Element* ownerElement = toElement(object->node()); // The object may have already been destroyed (thus node cleared), // but FrameView holds a manual ref, so it won't have been deleted. ASSERT(m_widgetUpdateSet->contains(object)); if (!ownerElement) return; - // No need to update if it's already crashed or known to be missing. - if (object->showsUnavailablePluginIndicator()) - return; + if (object->isEmbeddedObject()) { + RenderEmbeddedObject* embeddedObject = static_cast<RenderEmbeddedObject*>(object); + // No need to update if it's already crashed or known to be missing. + if (embeddedObject->isPluginUnavailable()) + return; - // FIXME: This could turn into a real virtual dispatch if we defined - // updateWidget(PluginCreationOption) on HTMLElement. - if (ownerElement->hasTagName(objectTag) || ownerElement->hasTagName(embedTag) || ownerElement->hasTagName(appletTag)) { - HTMLPlugInImageElement* pluginElement = static_cast<HTMLPlugInImageElement*>(ownerElement); - if (pluginElement->needsWidgetUpdate()) - pluginElement->updateWidget(CreateAnyWidgetType); - } - // FIXME: It is not clear that Media elements need or want this updateWidget() call. + if (object->isSnapshottedPlugIn()) { + if (ownerElement->hasTagName(objectTag) || ownerElement->hasTagName(embedTag)) { + HTMLPlugInImageElement* pluginElement = toHTMLPlugInImageElement(ownerElement); + pluginElement->checkSnapshotStatus(); + } + return; + } + + // FIXME: This could turn into a real virtual dispatch if we defined + // updateWidget(PluginCreationOption) on HTMLElement. + if (ownerElement->hasTagName(objectTag) || ownerElement->hasTagName(embedTag) || ownerElement->hasTagName(appletTag)) { + HTMLPlugInImageElement* pluginElement = toHTMLPlugInImageElement(ownerElement); + if (pluginElement->needsCheckForSizeChange()) { + pluginElement->checkSnapshotStatus(); + return; + } + if (pluginElement->needsWidgetUpdate()) + pluginElement->updateWidget(CreateAnyWidgetType); + } + // FIXME: It is not clear that Media elements need or want this updateWidget() call. #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) - else if (ownerElement->isMediaElement()) - static_cast<HTMLMediaElement*>(ownerElement)->updateWidget(CreateAnyWidgetType); + else if (ownerElement->isMediaElement()) + toHTMLMediaElement(ownerElement)->updateWidget(CreateAnyWidgetType); #endif - else - ASSERT_NOT_REACHED(); + else + ASSERT_NOT_REACHED(); - // Caution: it's possible the object was destroyed again, since loading a - // plugin may run any arbitrary javascript. - object->updateWidgetPosition(); + // Caution: it's possible the object was destroyed again, since loading a + // plugin may run any arbitrary JavaScript. + embeddedObject->updateWidgetPosition(); + } } bool FrameView::updateWidgets() @@ -2419,24 +2722,34 @@ bool FrameView::updateWidgets() size_t size = m_widgetUpdateSet->size(); - Vector<RenderEmbeddedObject*> objects; - objects.reserveCapacity(size); - - RenderEmbeddedObjectSet::const_iterator end = m_widgetUpdateSet->end(); - for (RenderEmbeddedObjectSet::const_iterator it = m_widgetUpdateSet->begin(); it != end; ++it) { - objects.uncheckedAppend(*it); - (*it)->ref(); + Vector<RenderObject*> objects; + objects.reserveInitialCapacity(size); + // Protect RendereArena from getting wiped out, when Document is detached during updateWidget(). + RefPtr<RenderArena> protectedArena = m_frame->document()->renderArena(); + + RenderObjectSet::const_iterator end = m_widgetUpdateSet->end(); + for (RenderObjectSet::const_iterator it = m_widgetUpdateSet->begin(); it != end; ++it) { + RenderObject* object = *it; + objects.uncheckedAppend(object); + if (object->isEmbeddedObject()) { + RenderEmbeddedObject* embeddedObject = static_cast<RenderEmbeddedObject*>(object); + embeddedObject->ref(); + } } for (size_t i = 0; i < size; ++i) { - RenderEmbeddedObject* object = objects[i]; + RenderObject* object = objects[i]; updateWidget(object); m_widgetUpdateSet->remove(object); } - RenderArena* arena = m_frame->document()->renderArena(); - for (size_t i = 0; i < size; ++i) - objects[i]->deref(arena); + for (size_t i = 0; i < size; ++i) { + RenderObject* object = objects[i]; + if (object->isEmbeddedObject()) { + RenderEmbeddedObject* embeddedObject = static_cast<RenderEmbeddedObject*>(object); + embeddedObject->deref(protectedArena.get()); + } + } return m_widgetUpdateSet->isEmpty(); } @@ -2456,46 +2769,50 @@ void FrameView::performPostLayoutTasks() m_frame->selection()->setCaretRectNeedsUpdate(); m_frame->selection()->updateAppearance(); - LayoutMilestones milestonesOfInterest = 0; + LayoutMilestones requestedMilestones = 0; LayoutMilestones milestonesAchieved = 0; Page* page = m_frame->page(); if (page) - milestonesOfInterest = page->layoutMilestones(); + requestedMilestones = page->requestedLayoutMilestones(); - if (m_nestedLayoutCount <= 1) { + if (m_nestedLayoutCount <= 1 && m_frame->document()->documentElement()) { if (m_firstLayoutCallbackPending) { m_firstLayoutCallbackPending = false; m_frame->loader()->didFirstLayout(); - if (milestonesOfInterest & DidFirstLayout) + if (requestedMilestones & DidFirstLayout) milestonesAchieved |= DidFirstLayout; if (page) { if (page->mainFrame() == m_frame) page->startCountingRelevantRepaintedObjects(); } } - - // Ensure that we always send this eventually. - if (!m_frame->document()->parsing() && m_frame->loader()->stateMachine()->committedFirstRealDocumentLoad()) - m_isVisuallyNonEmpty = true; + updateIsVisuallyNonEmpty(); // If the layout was done with pending sheets, we are not in fact visually non-empty yet. if (m_isVisuallyNonEmpty && !m_frame->document()->didLayoutWithPendingStylesheets() && m_firstVisuallyNonEmptyLayoutCallbackPending) { m_firstVisuallyNonEmptyLayoutCallbackPending = false; - if (milestonesOfInterest & DidFirstVisuallyNonEmptyLayout) + if (requestedMilestones & DidFirstVisuallyNonEmptyLayout) milestonesAchieved |= DidFirstVisuallyNonEmptyLayout; } } - m_frame->loader()->didLayout(milestonesAchieved); + if (milestonesAchieved) + m_frame->loader()->didLayout(milestonesAchieved); +#if ENABLE(FONT_LOAD_EVENTS) + if (RuntimeEnabledFeatures::fontLoadEventsEnabled()) + m_frame->document()->fontloader()->didLayout(); +#endif // FIXME: We should consider adding DidLayout as a LayoutMilestone. That would let us merge this // with didLayout(LayoutMilestones). m_frame->loader()->client()->dispatchDidLayout(); - RenderView* root = rootRenderer(this); - if (root) - root->updateWidgetPositions(); + if (RenderView* renderView = this->renderView()) + renderView->updateWidgetPositions(); + // layout() protects FrameView, but it still can get destroyed when updateWidgets() + // is called through the post layout timer. + RefPtr<FrameView> protector(this); for (unsigned i = 0; i < maxUpdateWidgetsIterations; i++) { if (updateWidgets()) break; @@ -2507,9 +2824,9 @@ void FrameView::performPostLayoutTasks() } #if USE(ACCELERATED_COMPOSITING) - if (RenderView* root = rootRenderer(this)) { - if (root->usesCompositing()) - root->compositor()->frameViewDidLayout(); + if (RenderView* renderView = this->renderView()) { + if (renderView->usesCompositing()) + renderView->compositor()->frameViewDidLayout(); } #endif @@ -2517,31 +2834,61 @@ void FrameView::performPostLayoutTasks() m_actionScheduler->resume(); - if (root && !root->printing()) { - IntSize currentSize; - if (useFixedLayout() && !fixedLayoutSize().isEmpty() && delegatesScrolling()) - currentSize = fixedLayoutSize(); - else - currentSize = visibleContentRect(true /*includeScrollbars*/).size(); - float currentZoomFactor = root->style()->zoom(); - bool resized = !m_firstLayout && (currentSize != m_lastViewportSize || currentZoomFactor != m_lastZoomFactor); - m_lastViewportSize = currentSize; - m_lastZoomFactor = currentZoomFactor; - if (resized) { - m_frame->eventHandler()->sendResizeEvent(); + sendResizeEventIfNeeded(); +} + +void FrameView::sendResizeEventIfNeeded() +{ + ASSERT(m_frame); + + RenderView* renderView = this->renderView(); + if (!renderView || renderView->printing()) + return; + + Page* page = m_frame->page(); + IntSize currentSize; + if (useFixedLayout() && !fixedLayoutSize().isEmpty() && delegatesScrolling()) + currentSize = fixedLayoutSize(); + else + currentSize = visibleContentRect(IncludeScrollbars).size(); + + float currentZoomFactor = renderView->style()->zoom(); + bool shouldSendResizeEvent = !m_firstLayout && (currentSize != m_lastViewportSize || currentZoomFactor != m_lastZoomFactor); + + m_lastViewportSize = currentSize; + m_lastZoomFactor = currentZoomFactor; + + if (!shouldSendResizeEvent) + return; + + bool isMainFrame = page && page->mainFrame() == m_frame; + bool canSendResizeEventSynchronously = isMainFrame && !isInLayout(); + + // If we resized during layout, queue up a resize event for later, otherwise fire it right away. + RefPtr<Event> resizeEvent = Event::create(eventNames().resizeEvent, false, false); + if (canSendResizeEventSynchronously) + m_frame->document()->dispatchWindowEvent(resizeEvent.release(), m_frame->document()->domWindow()); + else + m_frame->document()->enqueueWindowEvent(resizeEvent.release()); #if ENABLE(INSPECTOR) - if (InspectorInstrumentation::hasFrontends()) { - if (page) { - if (page->mainFrame() == m_frame) { - if (InspectorClient* inspectorClient = page->inspectorController()->inspectorClient()) - inspectorClient->didResizeMainFrame(m_frame.get()); - } - } - } -#endif - } + if (InspectorInstrumentation::hasFrontends() && isMainFrame) { + if (InspectorClient* inspectorClient = page ? page->inspectorController()->inspectorClient() : 0) + inspectorClient->didResizeMainFrame(m_frame.get()); } +#endif +} + +void FrameView::willStartLiveResize() +{ + ScrollView::willStartLiveResize(); + adjustTiledBackingCoverage(); +} + +void FrameView::willEndLiveResize() +{ + ScrollView::willEndLiveResize(); + adjustTiledBackingCoverage(); } void FrameView::postLayoutTimerFired(Timer<FrameView>*) @@ -2568,14 +2915,8 @@ void FrameView::autoSizeIfEnabled() if (!documentView || !documentElement) return; - RenderBox* documentRenderBox = documentElement->renderBox(); - if (!documentRenderBox) - return; - - // If this is the first time we run autosize, start from small height and - // allow it to grow. - if (!m_didRunAutosize) - resize(frameRect().width(), m_minAutoSize.height()); + // Start from the minimum size and allow it to grow. + resize(m_minAutoSize.width(), m_minAutoSize.height()); IntSize size = frameRect().size(); @@ -2585,7 +2926,7 @@ void FrameView::autoSizeIfEnabled() // Update various sizes including contentsSize, scrollHeight, etc. document->updateLayoutIgnorePendingStylesheets(); int width = documentView->minPreferredLogicalWidth(); - int height = documentRenderBox->scrollHeight(); + int height = documentView->documentRect().height(); IntSize newSize(width, height); // Check to see if a scrollbar is needed for a given dimension and @@ -2701,10 +3042,10 @@ IntRect FrameView::windowClipRect(bool clipToContents) const ASSERT(m_frame->view() == this); if (paintsEntireContents()) - return IntRect(IntPoint(), contentsSize()); + return IntRect(IntPoint(), totalContentsSize()); // Set our clip rect to be our contents. - IntRect clipRect = contentsToWindow(visibleContentRect(!clipToContents)); + IntRect clipRect = contentsToWindow(visibleContentRect(clipToContents ? ExcludeScrollbars : IncludeScrollbars)); if (!m_frame || !m_frame->ownerElement()) return clipRect; @@ -2771,7 +3112,18 @@ IntRect FrameView::windowResizerRect() const Page* page = frame() ? frame()->page() : 0; if (!page) return IntRect(); - return page->chrome()->windowResizerRect(); + return page->chrome().windowResizerRect(); +} + +float FrameView::visibleContentScaleFactor() const +{ + if (!m_frame || !m_frame->page()) + return 1; + + if (!m_frame->settings()->applyPageScaleFactorInCompositor() || m_frame != m_frame->page()->mainFrame()) + return 1; + + return m_frame->page()->pageScaleFactor(); } void FrameView::setVisibleScrollerThumbRect(const IntRect& scrollerThumb) @@ -2781,7 +3133,7 @@ void FrameView::setVisibleScrollerThumbRect(const IntRect& scrollerThumb) return; if (page->mainFrame() != m_frame) return; - page->chrome()->client()->notifyScrollerThumbIsVisibleInRect(scrollerThumb); + page->chrome().client()->notifyScrollerThumbIsVisibleInRect(scrollerThumb); } bool FrameView::scrollbarsCanBeActive() const @@ -2811,45 +3163,55 @@ ScrollableArea* FrameView::enclosingScrollableArea() const IntRect FrameView::scrollableAreaBoundingBox() const { - // FIXME: This isn't correct for transformed frames. We probably need to ask the renderer instead. - return frameRect(); + RenderPart* ownerRenderer = frame()->ownerRenderer(); + if (!ownerRenderer) + return frameRect(); + + return ownerRenderer->absoluteContentQuad().enclosingBoundingBox(); } -void FrameView::updateScrollableAreaSet() +bool FrameView::isScrollable() { - // That ensures that only inner frames are cached. - if (!parentFrameView()) - return; - // Check for: - // 1) display:none or visibility:hidden set to self or inherited. - // 2) overflow{-x,-y}: hidden; - // 3) scrolling: no; - - // Covers #1. - HTMLFrameOwnerElement* owner = m_frame->ownerElement(); - if (!owner || !owner->renderer() || !owner->renderer()->visibleToHitTesting()) { - parentFrameView()->removeScrollableArea(this); - return; - } + // 1) If there an actual overflow. + // 2) display:none or visibility:hidden set to self or inherited. + // 3) overflow{-x,-y}: hidden; + // 4) scrolling: no; - IntSize contentSize = contentsSize(); + // Covers #1 + IntSize totalContentsSize = this->totalContentsSize(); IntSize visibleContentSize = visibleContentRect().size(); - if ((contentSize.height() <= visibleContentSize.height() && contentSize.width() <= visibleContentSize.width())) { - parentFrameView()->removeScrollableArea(this); - return; - } + if ((totalContentsSize.height() <= visibleContentSize.height() && totalContentsSize.width() <= visibleContentSize.width())) + return false; - // Cover #2 and #3. + // Covers #2. + HTMLFrameOwnerElement* owner = m_frame->ownerElement(); + if (owner && (!owner->renderer() || !owner->renderer()->visibleToHitTesting())) + return false; + + // Cover #3 and #4. ScrollbarMode horizontalMode; ScrollbarMode verticalMode; calculateScrollbarModesForLayout(horizontalMode, verticalMode, RulesFromWebContentOnly); - if (horizontalMode == ScrollbarAlwaysOff && verticalMode == ScrollbarAlwaysOff) { - parentFrameView()->removeScrollableArea(this); + if (horizontalMode == ScrollbarAlwaysOff && verticalMode == ScrollbarAlwaysOff) + return false; + + return true; +} + +void FrameView::updateScrollableAreaSet() +{ + // That ensures that only inner frames are cached. + FrameView* parentFrameView = this->parentFrameView(); + if (!parentFrameView) + return; + + if (!isScrollable()) { + parentFrameView->removeScrollableArea(this); return; } - parentFrameView()->addScrollableArea(this); + parentFrameView->addScrollableArea(this); } bool FrameView::shouldSuspendScrollAnimations() const @@ -2864,7 +3226,7 @@ void FrameView::scrollbarStyleChanged(int newStyle, bool forceUpdate) return; if (page->mainFrame() != m_frame) return; - page->chrome()->client()->recommendedScrollbarStyleDidChange(newStyle); + page->chrome().client()->recommendedScrollbarStyleDidChange(newStyle); if (forceUpdate) ScrollView::scrollbarStyleChanged(newStyle, forceUpdate); @@ -2935,7 +3297,7 @@ void FrameView::updateAnnotatedRegions() Page* page = m_frame->page(); if (!page) return; - page->chrome()->client()->annotatedRegionsChanged(); + page->chrome().client()->annotatedRegionsChanged(); } #endif @@ -2951,7 +3313,7 @@ void FrameView::updateScrollCorner() Element* body = doc ? doc->body() : 0; if (body && body->renderer()) { renderer = body->renderer(); - cornerStyle = renderer->getUncachedPseudoStyle(SCROLLBAR_CORNER, renderer->style()); + cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), renderer->style()); } if (!cornerStyle) { @@ -2959,20 +3321,20 @@ void FrameView::updateScrollCorner() Element* docElement = doc ? doc->documentElement() : 0; if (docElement && docElement->renderer()) { renderer = docElement->renderer(); - cornerStyle = renderer->getUncachedPseudoStyle(SCROLLBAR_CORNER, renderer->style()); + cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), renderer->style()); } } if (!cornerStyle) { // If we have an owning iframe/frame element, then it can set the custom scrollbar also. if (RenderPart* renderer = m_frame->ownerRenderer()) - cornerStyle = renderer->getUncachedPseudoStyle(SCROLLBAR_CORNER, renderer->style()); + cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), renderer->style()); } } if (cornerStyle) { if (!m_scrollCorner) - m_scrollCorner = new (renderer->renderArena()) RenderScrollbarPart(renderer->document()); + m_scrollCorner = RenderScrollbarPart::createAnonymous(renderer->document()); m_scrollCorner->setStyle(cornerStyle.release()); invalidateScrollCorner(cornerRect); } else if (m_scrollCorner) { @@ -3060,7 +3422,7 @@ bool FrameView::hasCustomScrollbars() const for (HashSet<RefPtr<Widget> >::const_iterator current = viewChildren->begin(); current != end; ++current) { Widget* widget = current->get(); if (widget->isFrameView()) { - if (static_cast<FrameView*>(widget)->hasCustomScrollbars()) + if (toFrameView(widget)->hasCustomScrollbars()) return true; } else if (widget->isScrollbar()) { Scrollbar* scrollbar = static_cast<Scrollbar*>(widget); @@ -3096,7 +3458,7 @@ bool FrameView::isInChildFrameWithFrameFlattening() const return true; } - if (!m_frame->settings() || !m_frame->settings()->frameFlatteningEnabled()) + if (!frameFlatteningEnabled()) return false; if (m_frame->ownerElement()->hasTagName(frameTag)) @@ -3143,8 +3505,8 @@ void FrameView::updateControlTints() if (!m_frame || m_frame->document()->url().isEmpty()) return; - RenderView* root = rootRenderer(this); - if ((root && root->theme()->supportsControlTints()) || hasCustomScrollbars()) + RenderView* renderView = this->renderView(); + if ((renderView && renderView->theme()->supportsControlTints()) || hasCustomScrollbars()) paintControlTints(); } @@ -3171,7 +3533,10 @@ void FrameView::setWasScrolledByUser(bool wasScrolledByUser) if (m_inProgrammaticScroll) return; m_maintainScrollPositionAnchor = 0; + if (m_wasScrolledByUser == wasScrolledByUser) + return; m_wasScrolledByUser = wasScrolledByUser; + adjustTiledBackingCoverage(); } void FrameView::paintContents(GraphicsContext* p, const IntRect& rect) @@ -3179,8 +3544,6 @@ void FrameView::paintContents(GraphicsContext* p, const IntRect& rect) if (!frame()) return; - InspectorInstrumentationCookie cookie = InspectorInstrumentation::willPaint(m_frame.get()); - Document* document = m_frame->document(); #ifndef NDEBUG @@ -3202,8 +3565,8 @@ void FrameView::paintContents(GraphicsContext* p, const IntRect& rect) p->fillRect(rect, Color(0xFF, 0, 0), ColorSpaceDeviceRGB); #endif - RenderView* root = rootRenderer(this); - if (!root) { + RenderView* renderView = this->renderView(); + if (!renderView) { LOG_ERROR("called FrameView::paint with nil renderer"); return; } @@ -3212,6 +3575,9 @@ void FrameView::paintContents(GraphicsContext* p, const IntRect& rect) if (needsLayout()) return; + if (!p->paintingDisabled()) + InspectorInstrumentation::willPaint(renderView); + bool isTopLevelPainter = !sCurrentPaintTimeStamp; if (isTopLevelPainter) sCurrentPaintTimeStamp = currentTime(); @@ -3246,7 +3612,7 @@ void FrameView::paintContents(GraphicsContext* p, const IntRect& rect) // m_nodeToDraw is used to draw only one element (and its descendants) RenderObject* eltRenderer = m_nodeToDraw ? m_nodeToDraw->renderer() : 0; - RenderLayer* rootLayer = root->layer(); + RenderLayer* rootLayer = renderView->layer(); #ifndef NDEBUG RenderObject::SetLayoutNeededForbiddenScope forbidSetNeedsLayout(rootLayer->renderer()); @@ -3274,7 +3640,11 @@ void FrameView::paintContents(GraphicsContext* p, const IntRect& rect) if (isTopLevelPainter) sCurrentPaintTimeStamp = 0; - InspectorInstrumentation::didPaint(cookie, p, rect); + if (!p->paintingDisabled()) { + InspectorInstrumentation::didPaint(renderView, p, rect); + // FIXME: should probably not fire milestones for snapshot painting. https://bugs.webkit.org/show_bug.cgi?id=117623 + firePaintRelatedMilestones(); + } } void FrameView::setPaintBehavior(PaintBehavior behavior) @@ -3292,6 +3662,7 @@ bool FrameView::isPainting() const return m_isPainting; } +// FIXME: change this to use the subtreePaint terminology. void FrameView::setNodeToDraw(Node* node) { m_nodeToDraw = node; @@ -3343,7 +3714,7 @@ void FrameView::paintOverhangAreas(GraphicsContext* context, const IntRect& hori Page* page = m_frame->page(); if (page->mainFrame() == m_frame) { - if (page->chrome()->client()->paintCustomOverhangArea(context, horizontalOverhangArea, verticalOverhangArea, dirtyRect)) + if (page->chrome().client()->paintCustomOverhangArea(context, horizontalOverhangArea, verticalOverhangArea, dirtyRect)) return; } @@ -3386,6 +3757,41 @@ void FrameView::updateLayoutAndStyleIfNeededRecursive() ASSERT(!needsLayout()); } +bool FrameView::qualifiesAsVisuallyNonEmpty() const +{ + // No content yet. + Element* documentElement = m_frame->document()->documentElement(); + if (!documentElement || !documentElement->renderer()) + return false; + + // Ensure that we always get marked visually non-empty eventually. + if (!m_frame->document()->parsing() && m_frame->loader()->stateMachine()->committedFirstRealDocumentLoad()) + return true; + + // Require the document to grow a bit. + static const int documentHeightThreshold = 200; + if (documentElement->renderBox()->layoutOverflowRect().pixelSnappedHeight() < documentHeightThreshold) + return false; + + // The first few hundred characters rarely contain the interesting content of the page. + if (m_visuallyNonEmptyCharacterCount > visualCharacterThreshold) + return true; + // Use a threshold value to prevent very small amounts of visible content from triggering didFirstVisuallyNonEmptyLayout + if (m_visuallyNonEmptyPixelCount > visualPixelThreshold) + return true; + return false; +} + +void FrameView::updateIsVisuallyNonEmpty() +{ + if (m_isVisuallyNonEmpty) + return; + if (!qualifiesAsVisuallyNonEmpty()) + return; + m_isVisuallyNonEmpty = true; + adjustTiledBackingCoverage(); +} + void FrameView::enableAutoSizeMode(bool enable, const IntSize& minSize, const IntSize& maxSize) { ASSERT(!enable || !minSize.isEmpty()); @@ -3420,23 +3826,23 @@ void FrameView::forceLayoutForPagination(const FloatSize& pageSize, const FloatS { // Dumping externalRepresentation(m_frame->renderer()).ascii() is a good trick to see // the state of things before and after the layout - if (RenderView* root = rootRenderer(this)) { - float pageLogicalWidth = root->style()->isHorizontalWritingMode() ? pageSize.width() : pageSize.height(); - float pageLogicalHeight = root->style()->isHorizontalWritingMode() ? pageSize.height() : pageSize.width(); + if (RenderView* renderView = this->renderView()) { + float pageLogicalWidth = renderView->style()->isHorizontalWritingMode() ? pageSize.width() : pageSize.height(); + float pageLogicalHeight = renderView->style()->isHorizontalWritingMode() ? pageSize.height() : pageSize.width(); LayoutUnit flooredPageLogicalWidth = static_cast<LayoutUnit>(pageLogicalWidth); LayoutUnit flooredPageLogicalHeight = static_cast<LayoutUnit>(pageLogicalHeight); - root->setLogicalWidth(flooredPageLogicalWidth); - root->setPageLogicalHeight(flooredPageLogicalHeight); - root->setNeedsLayoutAndPrefWidthsRecalc(); + renderView->setLogicalWidth(flooredPageLogicalWidth); + renderView->setPageLogicalHeight(flooredPageLogicalHeight); + renderView->setNeedsLayoutAndPrefWidthsRecalc(); forceLayout(); // If we don't fit in the given page width, we'll lay out again. If we don't fit in the // page width when shrunk, we will lay out at maximum shrink and clip extra content. // FIXME: We are assuming a shrink-to-fit printing implementation. A cropping // implementation should not do this! - bool horizontalWritingMode = root->style()->isHorizontalWritingMode(); - const LayoutRect& documentRect = root->documentRect(); + bool horizontalWritingMode = renderView->style()->isHorizontalWritingMode(); + const LayoutRect& documentRect = renderView->documentRect(); LayoutUnit docLogicalWidth = horizontalWritingMode ? documentRect.width() : documentRect.height(); if (docLogicalWidth > pageLogicalWidth) { int expectedPageWidth = std::min<float>(documentRect.width(), pageSize.width() * maximumShrinkFactor); @@ -3447,24 +3853,24 @@ void FrameView::forceLayoutForPagination(const FloatSize& pageSize, const FloatS flooredPageLogicalWidth = static_cast<LayoutUnit>(pageLogicalWidth); flooredPageLogicalHeight = static_cast<LayoutUnit>(pageLogicalHeight); - root->setLogicalWidth(flooredPageLogicalWidth); - root->setPageLogicalHeight(flooredPageLogicalHeight); - root->setNeedsLayoutAndPrefWidthsRecalc(); + renderView->setLogicalWidth(flooredPageLogicalWidth); + renderView->setPageLogicalHeight(flooredPageLogicalHeight); + renderView->setNeedsLayoutAndPrefWidthsRecalc(); forceLayout(); - const LayoutRect& updatedDocumentRect = root->documentRect(); + const LayoutRect& updatedDocumentRect = renderView->documentRect(); LayoutUnit docLogicalHeight = horizontalWritingMode ? updatedDocumentRect.height() : updatedDocumentRect.width(); LayoutUnit docLogicalTop = horizontalWritingMode ? updatedDocumentRect.y() : updatedDocumentRect.x(); LayoutUnit docLogicalRight = horizontalWritingMode ? updatedDocumentRect.maxX() : updatedDocumentRect.maxY(); LayoutUnit clippedLogicalLeft = 0; - if (!root->style()->isLeftToRightDirection()) + if (!renderView->style()->isLeftToRightDirection()) clippedLogicalLeft = docLogicalRight - pageLogicalWidth; LayoutRect overflow(clippedLogicalLeft, docLogicalTop, pageLogicalWidth, docLogicalHeight); if (!horizontalWritingMode) overflow = overflow.transposedRect(); - root->clearLayoutOverflow(); - root->addLayoutOverflow(overflow); // This is how we clip in case we overflow again. + renderView->clearLayoutOverflow(); + renderView->addLayoutOverflow(overflow); // This is how we clip in case we overflow again. } } @@ -3474,28 +3880,31 @@ void FrameView::forceLayoutForPagination(const FloatSize& pageSize, const FloatS void FrameView::adjustPageHeightDeprecated(float *newBottom, float oldTop, float oldBottom, float /*bottomLimit*/) { - if (RenderView* root = rootRenderer(this)) { - // Use a context with painting disabled. - GraphicsContext context((PlatformGraphicsContext*)0); - root->setTruncatedAt(static_cast<int>(floorf(oldBottom))); - IntRect dirtyRect(0, static_cast<int>(floorf(oldTop)), root->layoutOverflowRect().maxX(), static_cast<int>(ceilf(oldBottom - oldTop))); - root->setPrintRect(dirtyRect); - root->layer()->paint(&context, dirtyRect); - *newBottom = root->bestTruncatedAt(); - if (*newBottom == 0) - *newBottom = oldBottom; - root->setPrintRect(IntRect()); - } else + RenderView* renderView = this->renderView(); + if (!renderView) { + *newBottom = oldBottom; + return; + + } + // Use a context with painting disabled. + GraphicsContext context((PlatformGraphicsContext*)0); + renderView->setTruncatedAt(static_cast<int>(floorf(oldBottom))); + IntRect dirtyRect(0, static_cast<int>(floorf(oldTop)), renderView->layoutOverflowRect().maxX(), static_cast<int>(ceilf(oldBottom - oldTop))); + renderView->setPrintRect(dirtyRect); + renderView->layer()->paint(&context, dirtyRect); + *newBottom = renderView->bestTruncatedAt(); + if (!*newBottom) *newBottom = oldBottom; + renderView->setPrintRect(IntRect()); } IntRect FrameView::convertFromRenderer(const RenderObject* renderer, const IntRect& rendererRect) const { - IntRect rect = renderer->localToAbsoluteQuad(FloatRect(rendererRect), SnapOffsetForTransforms).enclosingBoundingBox(); + IntRect rect = pixelSnappedIntRect(enclosingLayoutRect(renderer->localToAbsoluteQuad(FloatRect(rendererRect)).boundingBox())); // Convert from page ("absolute") to FrameView coordinates. if (!delegatesScrolling()) - rect.moveBy(-scrollPosition()); + rect.moveBy(-scrollPosition() + IntPoint(0, headerHeight())); return rect; } @@ -3506,21 +3915,21 @@ IntRect FrameView::convertToRenderer(const RenderObject* renderer, const IntRect // Convert from FrameView coords into page ("absolute") coordinates. if (!delegatesScrolling()) - rect.moveBy(scrollPosition()); + rect.moveBy(scrollPositionRelativeToDocument()); // FIXME: we don't have a way to map an absolute rect down to a local quad, so just // move the rect for now. - rect.setLocation(roundedIntPoint(renderer->absoluteToLocal(rect.location(), UseTransforms | SnapOffsetForTransforms))); + rect.setLocation(roundedIntPoint(renderer->absoluteToLocal(rect.location(), UseTransforms))); return rect; } IntPoint FrameView::convertFromRenderer(const RenderObject* renderer, const IntPoint& rendererPoint) const { - IntPoint point = roundedIntPoint(renderer->localToAbsolute(rendererPoint, UseTransforms | SnapOffsetForTransforms)); + IntPoint point = roundedIntPoint(renderer->localToAbsolute(rendererPoint, UseTransforms)); // Convert from page ("absolute") to FrameView coordinates. if (!delegatesScrolling()) - point.moveBy(-scrollPosition()); + point.moveBy(-scrollPosition() + IntPoint(0, headerHeight())); return point; } @@ -3530,16 +3939,16 @@ IntPoint FrameView::convertToRenderer(const RenderObject* renderer, const IntPoi // Convert from FrameView coords into page ("absolute") coordinates. if (!delegatesScrolling()) - point += IntSize(scrollX(), scrollY()); + point = point + scrollPositionRelativeToDocument(); - return roundedIntPoint(renderer->absoluteToLocal(point, UseTransforms | SnapOffsetForTransforms)); + return roundedIntPoint(renderer->absoluteToLocal(point, UseTransforms)); } IntRect FrameView::convertToContainingView(const IntRect& localRect) const { if (const ScrollView* parentScrollView = parent()) { if (parentScrollView->isFrameView()) { - const FrameView* parentView = static_cast<const FrameView*>(parentScrollView); + const FrameView* parentView = toFrameView(parentScrollView); // Get our renderer in the parent view RenderPart* renderer = m_frame->ownerRenderer(); if (!renderer) @@ -3562,7 +3971,7 @@ IntRect FrameView::convertFromContainingView(const IntRect& parentRect) const { if (const ScrollView* parentScrollView = parent()) { if (parentScrollView->isFrameView()) { - const FrameView* parentView = static_cast<const FrameView*>(parentScrollView); + const FrameView* parentView = toFrameView(parentScrollView); // Get our renderer in the parent view RenderPart* renderer = m_frame->ownerRenderer(); @@ -3586,7 +3995,7 @@ IntPoint FrameView::convertToContainingView(const IntPoint& localPoint) const { if (const ScrollView* parentScrollView = parent()) { if (parentScrollView->isFrameView()) { - const FrameView* parentView = static_cast<const FrameView*>(parentScrollView); + const FrameView* parentView = toFrameView(parentScrollView); // Get our renderer in the parent view RenderPart* renderer = m_frame->ownerRenderer(); @@ -3611,7 +4020,7 @@ IntPoint FrameView::convertFromContainingView(const IntPoint& parentPoint) const { if (const ScrollView* parentScrollView = parent()) { if (parentScrollView->isFrameView()) { - const FrameView* parentView = static_cast<const FrameView*>(parentScrollView); + const FrameView* parentView = toFrameView(parentScrollView); // Get our renderer in the parent view RenderPart* renderer = m_frame->ownerRenderer(); @@ -3660,6 +4069,12 @@ void FrameView::setTracksRepaints(bool trackRepaints) if (trackRepaints == m_isTrackingRepaints) return; + // Force layout to flush out any pending repaints. + if (trackRepaints) { + if (frame() && frame()->document()) + frame()->document()->updateLayout(); + } + #if USE(ACCELERATED_COMPOSITING) for (Frame* frame = m_frame->tree()->top(); frame; frame = frame->tree()->traverseNext()) { if (RenderView* renderView = frame->contentRenderer()) @@ -3675,15 +4090,16 @@ void FrameView::resetTrackedRepaints() { m_trackedRepaintRects.clear(); #if USE(ACCELERATED_COMPOSITING) - if (RenderView* root = rootRenderer(this)) { - RenderLayerCompositor* compositor = root->compositor(); - compositor->resetTrackedRepaintRects(); - } + if (RenderView* renderView = this->renderView()) + renderView->compositor()->resetTrackedRepaintRects(); #endif } String FrameView::trackedRepaintRectsAsText() const { + if (frame() && frame()->document()) + frame()->document()->updateLayout(); + TextStream ts; if (!m_trackedRepaintRects.isEmpty()) { ts << "(repaint rects\n"; @@ -3694,18 +4110,24 @@ String FrameView::trackedRepaintRectsAsText() const return ts.release(); } -void FrameView::addScrollableArea(ScrollableArea* scrollableArea) +bool FrameView::addScrollableArea(ScrollableArea* scrollableArea) { if (!m_scrollableAreas) m_scrollableAreas = adoptPtr(new ScrollableAreaSet); - m_scrollableAreas->add(scrollableArea); + return m_scrollableAreas->add(scrollableArea).isNewEntry; } -void FrameView::removeScrollableArea(ScrollableArea* scrollableArea) +bool FrameView::removeScrollableArea(ScrollableArea* scrollableArea) { if (!m_scrollableAreas) - return; - m_scrollableAreas->remove(scrollableArea); + return false; + + ScrollableAreaSet::iterator it = m_scrollableAreas->find(scrollableArea); + if (it == m_scrollableAreas->end()) + return false; + + m_scrollableAreas->remove(it); + return true; } bool FrameView::containsScrollableArea(ScrollableArea* scrollableArea) const @@ -3718,21 +4140,37 @@ bool FrameView::containsScrollableArea(ScrollableArea* scrollableArea) const void FrameView::removeChild(Widget* widget) { if (widget->isFrameView()) - removeScrollableArea(static_cast<FrameView*>(widget)); + removeScrollableArea(toFrameView(widget)); ScrollView::removeChild(widget); } bool FrameView::wheelEvent(const PlatformWheelEvent& wheelEvent) { + // Note that to allow for rubber-band over-scroll behavior, even non-scrollable views + // should handle wheel events. +#if !ENABLE(RUBBER_BANDING) + if (!isScrollable()) + return false; +#endif + + if (delegatesScrolling()) { + IntSize offset = scrollOffset(); + IntSize newOffset = IntSize(offset.width() - wheelEvent.deltaX(), offset.height() - wheelEvent.deltaY()); + if (offset != newOffset) { + ScrollView::scrollTo(newOffset); + scrollPositionChanged(); + frame()->loader()->client()->didChangeScrollOffset(); + } + return true; + } + // We don't allow mouse wheeling to happen in a ScrollView that has had its scrollbars explicitly disabled. if (!canHaveScrollbars()) return false; -#if !PLATFORM(WX) if (platformWidget()) return false; -#endif #if ENABLE(THREADED_SCROLLING) if (Page* page = m_frame->page()) { @@ -3749,20 +4187,20 @@ bool FrameView::wheelEvent(const PlatformWheelEvent& wheelEvent) bool FrameView::isVerticalDocument() const { - RenderView* root = rootRenderer(this); - if (!root) + RenderView* renderView = this->renderView(); + if (!renderView) return true; - return root->style()->isHorizontalWritingMode(); + return renderView->style()->isHorizontalWritingMode(); } bool FrameView::isFlippedDocument() const { - RenderView* root = rootRenderer(this); - if (!root) + RenderView* renderView = this->renderView(); + if (!renderView) return false; - return root->style()->isFlippedBlocksWritingMode(); + return renderView->style()->isFlippedBlocksWritingMode(); } void FrameView::notifyWidgetsInAllFrames(WidgetNotification notification) @@ -3775,8 +4213,8 @@ void FrameView::notifyWidgetsInAllFrames(WidgetNotification notification) AXObjectCache* FrameView::axObjectCache() const { - if (frame() && frame()->document() && frame()->document()->axObjectCacheExists()) - return frame()->document()->axObjectCache(); + if (frame() && frame()->document()) + return frame()->document()->existingAXObjectCache(); return 0; } @@ -3790,4 +4228,72 @@ void FrameView::setScrollingPerformanceLoggingEnabled(bool flag) #endif } +void FrameView::didAddScrollbar(Scrollbar* scrollbar, ScrollbarOrientation orientation) +{ + ScrollableArea::didAddScrollbar(scrollbar, orientation); + if (AXObjectCache* cache = axObjectCache()) + cache->handleScrollbarUpdate(this); +} + +void FrameView::willRemoveScrollbar(Scrollbar* scrollbar, ScrollbarOrientation orientation) +{ + ScrollableArea::willRemoveScrollbar(scrollbar, orientation); + if (AXObjectCache* cache = axObjectCache()) { + cache->remove(scrollbar); + cache->handleScrollbarUpdate(this); + } +} + +void FrameView::addPaintPendingMilestones(LayoutMilestones milestones) +{ + m_milestonesPendingPaint |= milestones; +} + +void FrameView::firePaintRelatedMilestones() +{ + Page* page = m_frame->page(); + if (!page) + return; + + LayoutMilestones milestonesAchieved = 0; + + // Make sure the pending paint milestones have actually been requested before we send them. + if (m_milestonesPendingPaint & DidFirstFlushForHeaderLayer) { + if (page->requestedLayoutMilestones() & DidFirstFlushForHeaderLayer) + milestonesAchieved |= DidFirstFlushForHeaderLayer; + } + + if (m_milestonesPendingPaint & DidFirstPaintAfterSuppressedIncrementalRendering) { + if (page->requestedLayoutMilestones() & DidFirstPaintAfterSuppressedIncrementalRendering) + milestonesAchieved |= DidFirstPaintAfterSuppressedIncrementalRendering; + } + + m_milestonesPendingPaint = 0; + + if (milestonesAchieved) { + if (Frame* frame = page->mainFrame()) + frame->loader()->didLayout(milestonesAchieved); + } +} + +void FrameView::setVisualUpdatesAllowedByClient(bool visualUpdatesAllowed) +{ + if (m_visualUpdatesAllowedByClient == visualUpdatesAllowed) + return; + + m_visualUpdatesAllowedByClient = visualUpdatesAllowed; + + m_frame->document()->setVisualUpdatesAllowedByClient(visualUpdatesAllowed); +} + +void FrameView::setScrollPinningBehavior(ScrollPinningBehavior pinning) +{ + m_scrollPinningBehavior = pinning; + + if (ScrollingCoordinator* scrollingCoordinator = m_frame->page()->scrollingCoordinator()) + scrollingCoordinator->setScrollPinningBehavior(pinning); + + updateScrollbars(scrollOffset()); +} + } // namespace WebCore diff --git a/Source/WebCore/page/FrameView.h b/Source/WebCore/page/FrameView.h index dab46ae31..37d1897bd 100644 --- a/Source/WebCore/page/FrameView.h +++ b/Source/WebCore/page/FrameView.h @@ -38,11 +38,10 @@ namespace WebCore { -class Color; +class AXObjectCache; class Element; class Event; class FloatSize; -class Frame; class FrameActionScheduler; class KURL; class Node; @@ -52,6 +51,7 @@ class RenderEmbeddedObject; class RenderLayer; class RenderObject; class RenderScrollbarPart; +class RenderStyle; Pagination::Mode paginationModeForRenderStyle(RenderStyle*); @@ -79,6 +79,8 @@ public: Frame* frame() const { return m_frame.get(); } void clearFrame(); + RenderView* renderView() const { return m_frame ? m_frame->contentRenderer() : 0; } + int mapFromLayoutToCSSUnits(LayoutUnit); LayoutUnit mapFromCSSToLayoutUnits(int); @@ -111,6 +113,7 @@ public: bool needsLayout() const; void setNeedsLayout(); + void setViewportConstrainedObjectsNeedLayout(); bool needsFullRepaint() const { return m_doFullRepaint; } @@ -153,9 +156,11 @@ public: void didMoveOnscreen(); void willMoveOffscreen(); + void setIsInWindow(bool); void resetScrollbars(); void resetScrollbarsAndClearContentsSize(); + void prepareForDetach(); void detachCustomScrollbars(); virtual void recalculateScrollbarOverlayStyle(); @@ -163,6 +168,9 @@ public: bool isTransparent() const; void setTransparent(bool isTransparent); + + // True if the FrameView is not transparent, and the base background color is opaque. + bool hasOpaqueBackground() const; Color baseBackgroundColor() const; void setBaseBackgroundColor(const Color&); @@ -179,6 +187,8 @@ public: virtual IntRect windowResizerRect() const; + virtual float visibleContentScaleFactor() const OVERRIDE; + virtual void setFixedVisibleContentRect(const IntRect&) OVERRIDE; virtual void setScrollPosition(const IntPoint&) OVERRIDE; void scrollPositionChangedViaPlatformWidget(); @@ -186,6 +196,13 @@ public: virtual void updateFixedElementsAfterScrolling(); virtual bool shouldRubberBandInDirection(ScrollDirection) const; virtual bool requestScrollPositionUpdate(const IntPoint&) OVERRIDE; + virtual bool isRubberBandInProgress() const OVERRIDE; + virtual IntPoint minimumScrollPosition() const OVERRIDE; + virtual IntPoint maximumScrollPosition() const OVERRIDE; + + // This is different than visibleContentRect() in that it ignores negative (or overly positive) + // offsets from rubber-banding, and it takes zooming into account. + LayoutRect viewportConstrainedVisibleContentRect() const; String mediaType() const; void setMediaType(const String&); @@ -197,9 +214,10 @@ public: bool isOverlappedIncludingAncestors() const; void setContentIsOpaque(bool); - void addSlowRepaintObject(); - void removeSlowRepaintObject(); - bool hasSlowRepaintObjects() const { return m_slowRepaintObjectCount; } + void addSlowRepaintObject(RenderObject*); + void removeSlowRepaintObject(RenderObject*); + bool hasSlowRepaintObject(RenderObject* o) const { return m_slowRepaintObjects && m_slowRepaintObjects->contains(o); } + bool hasSlowRepaintObjects() const { return m_slowRepaintObjects && m_slowRepaintObjects->size(); } // Includes fixed- and sticky-position objects. typedef HashSet<RenderObject*> ViewportConstrainedObjectSet; @@ -211,6 +229,8 @@ public: // Functions for querying the current scrolled position, negating the effects of overhang // and adjusting for page scale. IntSize scrollOffsetForFixedPosition() const; + // Static function can be called from another thread. + static IntSize scrollOffsetForFixedPosition(const IntRect& visibleContentRect, const IntSize& totalContentsSize, const IntPoint& scrollPosition, const IntPoint& scrollOrigin, float frameScaleFactor, bool fixedElementsLayoutRelativeToFrame, int headerHeight, int footerHeight); bool fixedElementsLayoutRelativeToFrame() const; @@ -221,6 +241,9 @@ public: void startDeferredRepaintTimer(double delay); void resetDeferredRepaintDelay(); + void updateLayerFlushThrottlingInAllFrames(); + void adjustTiledBackingCoverage(); + void beginDisableRepaints(); void endDisableRepaints(); bool repaintsDisabled() { return m_disableRepaints > 0; } @@ -243,8 +266,8 @@ public: bool safeToPropagateScrollToParent() const { return m_safeToPropagateScrollToParent; } void setSafeToPropagateScrollToParent(bool isSafe) { m_safeToPropagateScrollToParent = isSafe; } - void addWidgetToUpdate(RenderEmbeddedObject*); - void removeWidgetToUpdate(RenderEmbeddedObject*); + void addWidgetToUpdate(RenderObject*); + void removeWidgetToUpdate(RenderObject*); virtual void paintContents(GraphicsContext*, const IntRect& damageRect); void setPaintBehavior(PaintBehavior); @@ -272,7 +295,7 @@ public: void incrementVisuallyNonEmptyCharacterCount(unsigned); void incrementVisuallyNonEmptyPixelCount(const IntSize&); - void setIsVisuallyNonEmpty() { m_isVisuallyNonEmpty = true; } + void updateIsVisuallyNonEmpty(); bool isVisuallyNonEmpty() const { return m_isVisuallyNonEmpty; } void enableAutoSizeMode(bool enable, const IntSize& minSize, const IntSize& maxSize); @@ -310,6 +333,8 @@ public: bool isFrameViewScrollCorner(RenderScrollbarPart* scrollCorner) const { return m_scrollCorner == scrollCorner; } + bool isScrollable(); + enum ScrollbarModesCalculationStrategy { RulesFromWebContentOnly, AnyRule }; void calculateScrollbarModesForLayout(ScrollbarMode& hMode, ScrollbarMode& vMode, ScrollbarModesCalculationStrategy = AnyRule); @@ -322,7 +347,9 @@ public: // On each repaint the delay increses by this amount static void setRepaintThrottlingDeferredRepaintDelayIncrementDuringLoading(double p); - virtual IntPoint currentMousePosition() const; + virtual IntPoint lastKnownMousePosition() const; + virtual bool isHandlingWheelEvent() const OVERRIDE; + bool shouldSetCursor() const; virtual bool scrollbarsCanBeActive() const OVERRIDE; @@ -343,8 +370,10 @@ public: String trackedRepaintRectsAsText() const; typedef HashSet<ScrollableArea*> ScrollableAreaSet; - void addScrollableArea(ScrollableArea*); - void removeScrollableArea(ScrollableArea*); + // Returns whether the scrollable area has just been newly added. + bool addScrollableArea(ScrollableArea*); + // Returns whether the scrollable area has just been removed. + bool removeScrollableArea(ScrollableArea*); bool containsScrollableArea(ScrollableArea*) const; const ScrollableAreaSet* scrollableAreas() const { return m_scrollableAreas.get(); } @@ -373,10 +402,46 @@ public: void setHasSoftwareFilters(bool hasSoftwareFilters) { m_hasSoftwareFilters = hasSoftwareFilters; } bool hasSoftwareFilters() const { return m_hasSoftwareFilters; } #endif +#if ENABLE(CSS_DEVICE_ADAPTATION) + IntSize initialViewportSize() const { return m_initialViewportSize; } + void setInitialViewportSize(const IntSize& size) { m_initialViewportSize = size; } +#endif + + virtual bool isActive() const OVERRIDE; + +#if ENABLE(RUBBER_BANDING) + GraphicsLayer* setWantsLayerForTopOverHangArea(bool) const; + GraphicsLayer* setWantsLayerForBottomOverHangArea(bool) const; +#endif + + virtual int headerHeight() const OVERRIDE { return m_headerHeight; } + void setHeaderHeight(int); + virtual int footerHeight() const OVERRIDE { return m_footerHeight; } + void setFooterHeight(int); + + virtual void willStartLiveResize() OVERRIDE; + virtual void willEndLiveResize() OVERRIDE; + +#if USE(ACCELERATED_COMPOSITING) + virtual bool scrollbarAnimationsAreSuppressed() const OVERRIDE; +#endif + + void addPaintPendingMilestones(LayoutMilestones); + void firePaintRelatedMilestones(); + LayoutMilestones milestonesPendingPaint() const { return m_milestonesPendingPaint; } + + bool visualUpdatesAllowedByClient() const { return m_visualUpdatesAllowedByClient; } + void setVisualUpdatesAllowedByClient(bool); + + void resumeAnimatingImages(); + + void setScrollPinningBehavior(ScrollPinningBehavior); protected: virtual bool scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect); virtual void scrollContentsSlowPath(const IntRect& updateRect); + + void repaintSlowRepaintObjects(); virtual bool isVerticalDocument() const; virtual bool isFlippedDocument() const; @@ -387,7 +452,7 @@ private: void reset(); void init(); - virtual bool isFrameView() const; + virtual bool isFrameView() const OVERRIDE { return true; } friend class RenderWidget; bool useSlowRepaints(bool considerOverlap = true) const; @@ -411,6 +476,7 @@ private: virtual void repaintContentRectangle(const IntRect&, bool immediate); virtual void contentsResized() OVERRIDE; virtual void visibleContentsResized(); + virtual void fixedLayoutSizeChanged() OVERRIDE; virtual void delegatesScrollingDidChange(); @@ -423,7 +489,6 @@ private: // ScrollableArea interface virtual void invalidateScrollbarRect(Scrollbar*, const IntRect&) OVERRIDE; - virtual bool isActive() const OVERRIDE; virtual void getTickmarks(Vector<IntRect>&) const OVERRIDE; virtual void scrollTo(const IntSize&) OVERRIDE; virtual void setVisibleScrollerThumbRect(const IntRect&) OVERRIDE; @@ -431,6 +496,8 @@ private: virtual IntRect scrollableAreaBoundingBox() const OVERRIDE; virtual bool scrollAnimatorEnabled() const OVERRIDE; #if USE(ACCELERATED_COMPOSITING) + virtual bool usesCompositedScrolling() const OVERRIDE; + virtual GraphicsLayer* layerForScrolling() const OVERRIDE; virtual GraphicsLayer* layerForHorizontalScrollbar() const OVERRIDE; virtual GraphicsLayer* layerForVerticalScrollbar() const OVERRIDE; virtual GraphicsLayer* layerForScrollCorner() const OVERRIDE; @@ -439,6 +506,12 @@ private: #endif #endif + // Override scrollbar notifications to update the AXObject cache. + virtual void didAddScrollbar(Scrollbar*, ScrollbarOrientation) OVERRIDE; + virtual void willRemoveScrollbar(Scrollbar*, ScrollbarOrientation) OVERRIDE; + + void sendResizeEventIfNeeded(); + void updateScrollableAreaSet(); virtual void notifyPageThatContentAreaWillPaint() const; @@ -450,7 +523,7 @@ private: double adjustedDeferredRepaintDelay() const; bool updateWidgets(); - void updateWidget(RenderEmbeddedObject*); + void updateWidget(RenderObject*); void scrollToAnchor(); void scrollPositionChanged(); @@ -461,28 +534,33 @@ private: FrameView* parentFrameView() const; bool doLayoutWithFrameFlattening(bool allowSubtree); + bool frameFlatteningEnabled() const; + bool isFrameFlatteningValidForThisFrame() const; - void setViewportConstrainedObjectsNeedLayout(); + bool qualifiesAsVisuallyNonEmpty() const; virtual AXObjectCache* axObjectCache() const; void notifyWidgetsInAllFrames(WidgetNotification); + void removeFromAXObjectCache(); static double sCurrentPaintTimeStamp; // used for detecting decoded resource thrash in the cache LayoutSize m_size; LayoutSize m_margins; - typedef HashSet<RenderEmbeddedObject*> RenderEmbeddedObjectSet; - OwnPtr<RenderEmbeddedObjectSet> m_widgetUpdateSet; + typedef HashSet<RenderObject*> RenderObjectSet; + OwnPtr<RenderObjectSet> m_widgetUpdateSet; RefPtr<Frame> m_frame; + OwnPtr<RenderObjectSet> m_slowRepaintObjects; + bool m_doFullRepaint; bool m_canHaveScrollbars; bool m_cannotBlitToWindow; bool m_isOverlapped; bool m_contentIsOpaque; - unsigned m_slowRepaintObjectCount; + int m_borderX; int m_borderY; @@ -565,14 +643,31 @@ private: OwnPtr<ScrollableAreaSet> m_scrollableAreas; OwnPtr<ViewportConstrainedObjectSet> m_viewportConstrainedObjects; + int m_headerHeight; + int m_footerHeight; + + LayoutMilestones m_milestonesPendingPaint; + static double s_normalDeferredRepaintDelay; static double s_initialDeferredRepaintDelayDuringLoading; static double s_maxDeferredRepaintDelayDuringLoading; static double s_deferredRepaintDelayIncrementDuringLoading; + static const unsigned visualCharacterThreshold = 200; + static const unsigned visualPixelThreshold = 32 * 32; + #if ENABLE(CSS_FILTERS) bool m_hasSoftwareFilters; #endif +#if ENABLE(CSS_DEVICE_ADAPTATION) + // Size of viewport before any UA or author styles have overridden + // the viewport given by the window or viewing area of the UA. + IntSize m_initialViewportSize; +#endif + + bool m_visualUpdatesAllowedByClient; + + ScrollPinningBehavior m_scrollPinningBehavior; }; inline void FrameView::incrementVisuallyNonEmptyCharacterCount(unsigned count) @@ -580,11 +675,9 @@ inline void FrameView::incrementVisuallyNonEmptyCharacterCount(unsigned count) if (m_isVisuallyNonEmpty) return; m_visuallyNonEmptyCharacterCount += count; - // Use a threshold value to prevent very small amounts of visible content from triggering didFirstVisuallyNonEmptyLayout. - // The first few hundred characters rarely contain the interesting content of the page. - static const unsigned visualCharacterThreshold = 200; - if (m_visuallyNonEmptyCharacterCount > visualCharacterThreshold) - setIsVisuallyNonEmpty(); + if (m_visuallyNonEmptyCharacterCount <= visualCharacterThreshold) + return; + updateIsVisuallyNonEmpty(); } inline void FrameView::incrementVisuallyNonEmptyPixelCount(const IntSize& size) @@ -592,10 +685,9 @@ inline void FrameView::incrementVisuallyNonEmptyPixelCount(const IntSize& size) if (m_isVisuallyNonEmpty) return; m_visuallyNonEmptyPixelCount += size.width() * size.height(); - // Use a threshold value to prevent very small amounts of visible content from triggering didFirstVisuallyNonEmptyLayout - static const unsigned visualPixelThreshold = 32 * 32; - if (m_visuallyNonEmptyPixelCount > visualPixelThreshold) - setIsVisuallyNonEmpty(); + if (m_visuallyNonEmptyPixelCount <= visualPixelThreshold) + return; + updateIsVisuallyNonEmpty(); } inline int FrameView::mapFromLayoutToCSSUnits(LayoutUnit value) @@ -608,6 +700,21 @@ inline LayoutUnit FrameView::mapFromCSSToLayoutUnits(int value) return value * m_frame->pageZoomFactor() * m_frame->frameScaleFactor(); } +inline FrameView* toFrameView(Widget* widget) +{ + ASSERT(!widget || widget->isFrameView()); + return static_cast<FrameView*>(widget); +} + +inline const FrameView* toFrameView(const Widget* widget) +{ + ASSERT(!widget || widget->isFrameView()); + return static_cast<const FrameView*>(widget); +} + +// This will catch anyone doing an unnecessary cast. +void toFrameView(const FrameView*); + } // namespace WebCore #endif // FrameView_h diff --git a/Source/WebCore/page/History.cpp b/Source/WebCore/page/History.cpp index 66831c433..79bf90bfe 100644 --- a/Source/WebCore/page/History.cpp +++ b/Source/WebCore/page/History.cpp @@ -32,6 +32,7 @@ #include "Frame.h" #include "FrameLoader.h" #include "FrameLoaderClient.h" +#include "HistoryController.h" #include "HistoryItem.h" #include "Page.h" #include "SecurityOrigin.h" @@ -55,13 +56,13 @@ unsigned History::length() const return m_frame->page()->backForward()->count(); } -SerializedScriptValue* History::state() +PassRefPtr<SerializedScriptValue> History::state() { m_lastStateObjectRequested = stateInternal(); return m_lastStateObjectRequested; } -SerializedScriptValue* History::stateInternal() const +PassRefPtr<SerializedScriptValue> History::stateInternal() const { if (!m_frame) return 0; @@ -79,7 +80,7 @@ bool History::stateChanged() const bool History::isSameAsCurrentState(SerializedScriptValue* state) const { - return state == stateInternal(); + return state == stateInternal().get(); } void History::back() @@ -116,7 +117,7 @@ void History::go(ScriptExecutionContext* context, int distance) return; ASSERT(isMainThread()); - Document* activeDocument = static_cast<Document*>(context); + Document* activeDocument = toDocument(context); if (!activeDocument) return; diff --git a/Source/WebCore/page/History.h b/Source/WebCore/page/History.h index d7c7a28ba..ca976a96c 100644 --- a/Source/WebCore/page/History.h +++ b/Source/WebCore/page/History.h @@ -29,6 +29,7 @@ #include "DOMWindowProperty.h" #include "KURL.h" #include "ScriptWrappable.h" +#include "SerializedScriptValue.h" #include <wtf/Forward.h> #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> @@ -37,7 +38,6 @@ namespace WebCore { class Frame; class ScriptExecutionContext; -class SerializedScriptValue; typedef int ExceptionCode; class History : public ScriptWrappable, public RefCounted<History>, public DOMWindowProperty { @@ -45,7 +45,7 @@ public: static PassRefPtr<History> create(Frame* frame) { return adoptRef(new History(frame)); } unsigned length() const; - SerializedScriptValue* state(); + PassRefPtr<SerializedScriptValue> state(); void back(); void forward(); void go(int distance); @@ -68,9 +68,9 @@ private: KURL urlForState(const String& url); - SerializedScriptValue* stateInternal() const; + PassRefPtr<SerializedScriptValue> stateInternal() const; - SerializedScriptValue* m_lastStateObjectRequested; + RefPtr<SerializedScriptValue> m_lastStateObjectRequested; }; } // namespace WebCore diff --git a/Source/WebCore/page/History.idl b/Source/WebCore/page/History.idl index 99a9dbeea..2fc8c07f0 100644 --- a/Source/WebCore/page/History.idl +++ b/Source/WebCore/page/History.idl @@ -24,25 +24,19 @@ */ [ -#if defined(V8_BINDING) && V8_BINDING - CheckSecurity, -#endif JSCustomGetOwnPropertySlotAndDescriptor, CustomNamedSetter, - JSGenerateIsReachable=ImplFrame, + GenerateIsReachable=ImplFrame, CustomDeleteProperty, CustomEnumerateProperty, - OmitConstructor ] interface History { readonly attribute unsigned long length; [CachedAttribute, Custom] readonly attribute SerializedScriptValue state; [DoNotCheckSecurity, CallWith=ScriptExecutionContext] void back(); [DoNotCheckSecurity, CallWith=ScriptExecutionContext] void forward(); - [DoNotCheckSecurity, CallWith=ScriptExecutionContext] void go(in [Optional=DefaultIsUndefined] long distance); + [DoNotCheckSecurity, CallWith=ScriptExecutionContext] void go([Default=Undefined] optional long distance); - [Custom, V8EnabledPerContext=pushState] void pushState(in any data, in DOMString title, in [Optional] DOMString url) - raises(DOMException); - [Custom, V8EnabledPerContext=pushState] void replaceState(in any data, in DOMString title, in [Optional] DOMString url) - raises(DOMException); + [Custom, RaisesException] void pushState(any data, DOMString title, optional DOMString url); + [Custom, RaisesException] void replaceState(any data, DOMString title, optional DOMString url); }; diff --git a/Source/WebCore/page/LayoutMilestones.h b/Source/WebCore/page/LayoutMilestones.h index dbfcf143b..7007434bf 100644 --- a/Source/WebCore/page/LayoutMilestones.h +++ b/Source/WebCore/page/LayoutMilestones.h @@ -28,10 +28,16 @@ namespace WebCore { +// FIXME: Some of these milestones are about layout, and others are about painting. +// We should either re-name them to something more generic, or split them into +// two enums -- one for painting and one for layout. enum LayoutMilestoneFlag { DidFirstLayout = 1 << 0, DidFirstVisuallyNonEmptyLayout = 1 << 1, - DidHitRelevantRepaintedObjectsAreaThreshold = 1 << 2 + DidHitRelevantRepaintedObjectsAreaThreshold = 1 << 2, + DidFirstFlushForHeaderLayer = 1 << 3, + DidFirstLayoutAfterSuppressedIncrementalRendering = 1 << 4, + DidFirstPaintAfterSuppressedIncrementalRendering = 1 << 5 }; typedef unsigned LayoutMilestones; diff --git a/Source/WebCore/page/Location.idl b/Source/WebCore/page/Location.idl index 0707f0758..07545a48b 100644 --- a/Source/WebCore/page/Location.idl +++ b/Source/WebCore/page/Location.idl @@ -27,26 +27,22 @@ */ [ -#if defined(V8_BINDING) && V8_BINDING - CheckSecurity, -#endif JSCustomGetOwnPropertySlotAndDescriptor, CustomNamedSetter, - JSGenerateIsReachable=ImplFrame, + GenerateIsReachable=ImplFrame, CustomDeleteProperty, CustomEnumerateProperty, JSCustomDefineOwnProperty, JSCustomNamedGetterOnPrototype, JSCustomDefineOwnPropertyOnPrototype, - OmitConstructor ] interface Location { #if !defined(LANGUAGE_CPP) || !LANGUAGE_CPP - [DoNotCheckSecurityOnSetter, CustomSetter, V8Unforgeable] attribute DOMString href; + [DoNotCheckSecurityOnSetter, CustomSetter] attribute DOMString href; #endif - [Custom, V8Unforgeable] void assign(in [Optional=DefaultIsUndefined] DOMString url); - [Custom, V8Unforgeable] void replace(in [Optional=DefaultIsUndefined] DOMString url); - [Custom, V8Unforgeable] void reload(); + [Custom] void assign([Default=Undefined] optional DOMString url); + [Custom] void replace([Default=Undefined] optional DOMString url); + [Custom] void reload(); // URI decomposition attributes #if !defined(LANGUAGE_CPP) || !LANGUAGE_CPP @@ -64,10 +60,7 @@ readonly attribute DOMStringList ancestorOrigins; #if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT - [NotEnumerable, Custom, V8Unforgeable, V8ReadOnly, ImplementedAs=toStringFunction] DOMString toString(); -#endif -#if defined(V8_BINDING) && V8_BINDING - [NotEnumerable, Custom, V8Unforgeable, V8ReadOnly] DOMObject valueOf(); + [NotEnumerable, Custom, ImplementedAs=toStringFunction] DOMString toString(); #endif }; diff --git a/Source/WebCore/page/MemoryInfo.cpp b/Source/WebCore/page/MemoryInfo.cpp deleted file mode 100644 index 836ec3328..000000000 --- a/Source/WebCore/page/MemoryInfo.cpp +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "MemoryInfo.h" - -#include "Frame.h" -#include "ScriptGCEvent.h" -#include "Settings.h" -#include <limits> -#include <wtf/CurrentTime.h> -#include <wtf/MainThread.h> - -namespace WebCore { - -#if ENABLE(INSPECTOR) - -class HeapSizeCache { - WTF_MAKE_NONCOPYABLE(HeapSizeCache); WTF_MAKE_FAST_ALLOCATED; -public: - HeapSizeCache() - : m_lastUpdateTime(0) - { - } - - void getCachedHeapSize(HeapInfo& info) - { - maybeUpdate(); - info = m_info; - } - -private: - void maybeUpdate() - { - // We rate-limit queries to once every twenty minutes to make it more difficult - // for attackers to compare memory usage before and after some event. - const double TwentyMinutesInSeconds = 20 * 60; - - double now = monotonicallyIncreasingTime(); - if (now - m_lastUpdateTime >= TwentyMinutesInSeconds) { - update(); - m_lastUpdateTime = now; - } - } - - void update() - { - ScriptGCEvent::getHeapSize(m_info); - m_info.usedJSHeapSize = quantizeMemorySize(m_info.usedJSHeapSize); - m_info.totalJSHeapSize = quantizeMemorySize(m_info.totalJSHeapSize); - m_info.jsHeapSizeLimit = quantizeMemorySize(m_info.jsHeapSizeLimit); - } - - double m_lastUpdateTime; - - HeapInfo m_info; -}; - -// We quantize the sizes to make it more difficult for an attacker to see precise -// impact of operations on memory. The values are used for performance tuning, -// and hence don't need to be as refined when the value is large, so we threshold -// at a list of exponentially separated buckets. -size_t quantizeMemorySize(size_t size) -{ - const int numberOfBuckets = 100; - DEFINE_STATIC_LOCAL(Vector<size_t>, bucketSizeList, ()); - - ASSERT(isMainThread()); - if (bucketSizeList.isEmpty()) { - bucketSizeList.resize(numberOfBuckets); - - float sizeOfNextBucket = 10000000.0; // First bucket size is roughly 10M. - const float largestBucketSize = 4000000000.0; // Roughly 4GB. - // We scale with the Nth root of the ratio, so that we use all the bucktes. - const float scalingFactor = exp(log(largestBucketSize / sizeOfNextBucket) / numberOfBuckets); - - size_t nextPowerOfTen = static_cast<size_t>(pow(10, floor(log10(sizeOfNextBucket)) + 1) + 0.5); - size_t granularity = nextPowerOfTen / 1000; // We want 3 signficant digits. - - for (int i = 0; i < numberOfBuckets; ++i) { - size_t currentBucketSize = static_cast<size_t>(sizeOfNextBucket); - bucketSizeList[i] = currentBucketSize - (currentBucketSize % granularity); - - sizeOfNextBucket *= scalingFactor; - if (sizeOfNextBucket >= nextPowerOfTen) { - if (std::numeric_limits<size_t>::max() / 10 <= nextPowerOfTen) - nextPowerOfTen = std::numeric_limits<size_t>::max(); - else { - nextPowerOfTen *= 10; - granularity *= 10; - } - } - - // Watch out for overflow, if the range is too large for size_t. - if (i > 0 && bucketSizeList[i] < bucketSizeList[i - 1]) - bucketSizeList[i] = std::numeric_limits<size_t>::max(); - } - } - - for (int i = 0; i < numberOfBuckets; ++i) { - if (size <= bucketSizeList[i]) - return bucketSizeList[i]; - } - - return bucketSizeList[numberOfBuckets - 1]; -} - -#endif - -MemoryInfo::MemoryInfo(Frame* frame) -{ - if (!frame || !frame->settings()) - return; - -#if ENABLE(INSPECTOR) - if (frame->settings()->memoryInfoEnabled()) - ScriptGCEvent::getHeapSize(m_info); - else if (true || frame->settings()->quantizedMemoryInfoEnabled()) { - DEFINE_STATIC_LOCAL(HeapSizeCache, heapSizeCache, ()); - heapSizeCache.getCachedHeapSize(m_info); - } -#endif -} - -} // namespace WebCore diff --git a/Source/WebCore/page/MemoryInfo.h b/Source/WebCore/page/MemoryInfo.h deleted file mode 100644 index a6557b3b8..000000000 --- a/Source/WebCore/page/MemoryInfo.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef MemoryInfo_h -#define MemoryInfo_h - -#include "ScriptGCEvent.h" -#include <wtf/PassRefPtr.h> -#include <wtf/RefCounted.h> - -namespace WebCore { - -class Frame; - -class MemoryInfo : public RefCounted<MemoryInfo> { -public: - static PassRefPtr<MemoryInfo> create(Frame* frame) { return adoptRef(new MemoryInfo(frame)); } - - size_t totalJSHeapSize() const { return m_info.totalJSHeapSize; } - size_t usedJSHeapSize() const { return m_info.usedJSHeapSize; } - size_t jsHeapSizeLimit() const { return m_info.jsHeapSizeLimit; } - -private: - explicit MemoryInfo(Frame*); - - HeapInfo m_info; -}; - -size_t quantizeMemorySize(size_t); - -} // namespace WebCore - -#endif // MemoryInfo_h diff --git a/Source/WebCore/page/MemoryInfo.idl b/Source/WebCore/page/MemoryInfo.idl deleted file mode 100644 index df50b4804..000000000 --- a/Source/WebCore/page/MemoryInfo.idl +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -[ - OmitConstructor -] interface MemoryInfo { - - readonly attribute unsigned long totalJSHeapSize; - readonly attribute unsigned long usedJSHeapSize; - [JSCustomGetter] readonly attribute unsigned long jsHeapSizeLimit; - -}; - diff --git a/Source/WebCore/page/MouseEventWithHitTestResults.cpp b/Source/WebCore/page/MouseEventWithHitTestResults.cpp index e33ddce24..e0305687d 100644 --- a/Source/WebCore/page/MouseEventWithHitTestResults.cpp +++ b/Source/WebCore/page/MouseEventWithHitTestResults.cpp @@ -35,7 +35,7 @@ MouseEventWithHitTestResults::MouseEventWithHitTestResults(const PlatformMouseEv bool MouseEventWithHitTestResults::isOverLink() const { - return m_hitTestResult.URLElement() && m_hitTestResult.URLElement()->isLink(); + return m_hitTestResult.isOverLink(); } } diff --git a/Source/WebCore/page/Navigator.cpp b/Source/WebCore/page/Navigator.cpp index 7bf2b5b4b..84269ef31 100644 --- a/Source/WebCore/page/Navigator.cpp +++ b/Source/WebCore/page/Navigator.cpp @@ -34,6 +34,7 @@ #include "Language.h" #include "Page.h" #include "PluginData.h" +#include "ScriptController.h" #include "SecurityOrigin.h" #include "Settings.h" #include "StorageNamespace.h" diff --git a/Source/WebCore/page/Navigator.idl b/Source/WebCore/page/Navigator.idl index 0c676ebe5..acc51ac86 100644 --- a/Source/WebCore/page/Navigator.idl +++ b/Source/WebCore/page/Navigator.idl @@ -18,8 +18,7 @@ */ [ - JSGenerateIsReachable=ImplFrame, - OmitConstructor + GenerateIsReachable=ImplFrame, ] interface Navigator { readonly attribute DOMString appCodeName; readonly attribute DOMString appName; diff --git a/Source/WebCore/page/Page.cpp b/Source/WebCore/page/Page.cpp index 5d62e0e96..b4c963a4f 100644 --- a/Source/WebCore/page/Page.cpp +++ b/Source/WebCore/page/Page.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All Rights Reserved. + * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All Rights Reserved. * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * * This library is free software; you can redistribute it and/or @@ -21,20 +21,24 @@ #include "Page.h" #include "AlternativeTextClient.h" +#include "AnimationController.h" #include "BackForwardController.h" #include "BackForwardList.h" #include "Chrome.h" #include "ChromeClient.h" +#include "ClientRectList.h" #include "ContextMenuClient.h" #include "ContextMenuController.h" #include "DOMWindow.h" #include "DocumentMarkerController.h" #include "DocumentStyleSheetCollection.h" #include "DragController.h" +#include "Editor.h" #include "EditorClient.h" #include "Event.h" #include "EventNames.h" #include "ExceptionCode.h" +#include "ExceptionCodePlaceholder.h" #include "FileSystem.h" #include "FocusController.h" #include "Frame.h" @@ -44,6 +48,7 @@ #include "FrameTree.h" #include "FrameView.h" #include "HTMLElement.h" +#include "HistoryController.h" #include "HistoryItem.h" #include "InspectorController.h" #include "InspectorInstrumentation.h" @@ -51,18 +56,24 @@ #include "MediaCanStartListener.h" #include "Navigator.h" #include "NetworkStateNotifier.h" +#include "PageActivityAssertionToken.h" #include "PageCache.h" +#include "PageConsole.h" #include "PageGroup.h" +#include "PageThrottler.h" +#include "PlugInClient.h" #include "PluginData.h" #include "PluginView.h" #include "PointerLockController.h" #include "ProgressTracker.h" #include "RenderArena.h" +#include "RenderLayerCompositor.h" #include "RenderTheme.h" #include "RenderView.h" #include "RenderWidget.h" #include "RuntimeEnabledFeatures.h" #include "SchemeRegistry.h" +#include "ScriptController.h" #include "ScrollingCoordinator.h" #include "Settings.h" #include "SharedBuffer.h" @@ -70,8 +81,8 @@ #include "StorageNamespace.h" #include "StyleResolver.h" #include "TextResourceDecoder.h" +#include "VisitedLinkState.h" #include "VoidCallback.h" -#include "WebCoreMemoryInstrumentation.h" #include "Widget.h" #include <wtf/HashMap.h> #include <wtf/RefCountedLeakCounter.h> @@ -82,11 +93,10 @@ namespace WebCore { static HashSet<Page*>* allPages; -static const double hiddenPageTimerAlignmentInterval = 1.0; // once a second DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, pageCounter, ("Page")); -static void networkStateChanged() +static void networkStateChanged(bool isOnLine) { Vector<RefPtr<Frame> > frames; @@ -98,7 +108,7 @@ static void networkStateChanged() InspectorInstrumentation::networkStateChanged(*it); } - AtomicString eventName = networkStateNotifier().onLine() ? eventNames().onlineEvent : eventNames().offlineEvent; + AtomicString eventName = isOnLine ? eventNames().onlineEvent : eventNames().offlineEvent; for (unsigned i = 0; i < frames.size(); i++) frames[i]->document()->dispatchWindowEvent(Event::create(eventName, false, false)); } @@ -134,6 +144,7 @@ Page::Page(PageClients& pageClients) , m_backForwardController(BackForwardController::create(this, pageClients.backForwardClient)) , m_theme(RenderTheme::themeForPage(this)) , m_editorClient(pageClients.editorClient) + , m_plugInClient(pageClients.plugInClient) , m_validationMessageClient(pageClients.validationMessageClient) , m_subframeCount(0) , m_openedByDOM(false) @@ -154,29 +165,36 @@ Page::Page(PageClients& pageClients) , m_customHTMLTokenizerTimeDelay(-1) , m_customHTMLTokenizerChunkSize(-1) , m_canStartMedia(true) +#if ENABLE(VIEW_MODE_CSS_MEDIA) , m_viewMode(ViewModeWindowed) +#endif // ENABLE(VIEW_MODE_CSS_MEDIA) , m_minimumTimerInterval(Settings::defaultMinDOMTimerInterval()) , m_timerAlignmentInterval(Settings::defaultDOMTimerAlignmentInterval()) , m_isEditable(false) , m_isOnscreen(true) + , m_isInWindow(true) #if ENABLE(PAGE_VISIBILITY_API) , m_visibilityState(PageVisibilityStateVisible) #endif - , m_displayID(0) - , m_layoutMilestones(0) + , m_requestedLayoutMilestones(0) + , m_headerHeight(0) + , m_footerHeight(0) , m_isCountingRelevantRepaintedObjects(false) #ifndef NDEBUG , m_isPainting(false) #endif , m_alternativeTextClient(pageClients.alternativeTextClient) , m_scriptedAnimationsSuspended(false) + , m_pageThrottler(PageThrottler::create(this)) + , m_console(PageConsole::create(this)) + , m_framesHandlingBeforeUnloadEvent(0) { ASSERT(m_editorClient); if (!allPages) { allPages = new HashSet<Page*>; - networkStateNotifier().setNetworkStateChangedFunction(networkStateChanged); + networkStateNotifier().addNetworkStateChangeListener(networkStateChanged); } ASSERT(!allPages->contains(this)); @@ -199,6 +217,8 @@ Page::~Page() } m_editorClient->pageDestroyed(); + if (m_plugInClient) + m_plugInClient->pageDestroyed(); if (m_alternativeTextClient) m_alternativeTextClient->pageDestroyed(); @@ -215,6 +235,7 @@ Page::~Page() pageCounter.decrement(); #endif + m_pageThrottler.clear(); } ArenaSize Page::renderTreeSize() const @@ -255,6 +276,33 @@ String Page::scrollingStateTreeAsText() return String(); } +String Page::mainThreadScrollingReasonsAsText() +{ + if (Document* document = m_mainFrame->document()) + document->updateLayout(); + + if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) + return scrollingCoordinator->mainThreadScrollingReasonsAsText(); + + return String(); +} + +PassRefPtr<ClientRectList> Page::nonFastScrollableRects(const Frame* frame) +{ + if (Document* document = m_mainFrame->document()) + document->updateLayout(); + + Vector<IntRect> rects; + if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) + rects = scrollingCoordinator->computeNonFastScrollableRegion(frame, IntPoint()).rects(); + + Vector<FloatQuad> quads(rects.size()); + for (size_t i = 0; i < rects.size(); ++i) + quads[i] = FloatRect(rects[i]); + return ClientRectList::create(quads); +} + +#if ENABLE(VIEW_MODE_CSS_MEDIA) struct ViewModeInfo { const char* name; Page::ViewMode type; @@ -293,6 +341,7 @@ void Page::setViewMode(ViewMode viewMode) if (m_mainFrame->document()) m_mainFrame->document()->styleResolverChanged(RecalcStyleImmediately); } +#endif // ENABLE(VIEW_MODE_CSS_MEDIA) void Page::setMainFrame(PassRefPtr<Frame> mainFrame) { @@ -406,9 +455,7 @@ void Page::setGroupName(const String& name) const String& Page::groupName() const { - DEFINE_STATIC_LOCAL(String, nullString, ()); - // FIXME: Why not just return String()? - return m_group ? m_group->name() : nullString; + return m_group ? m_group->name() : nullAtom.string(); } void Page::initGroup() @@ -419,14 +466,20 @@ void Page::initGroup() m_group = m_singlePageGroup.get(); } -void Page::scheduleForcedStyleRecalcForAllPages() +void Page::updateStyleForAllPagesAfterGlobalChangeInEnvironment() { if (!allPages) return; HashSet<Page*>::iterator end = allPages->end(); for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) - for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) + for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) { + // If a change in the global environment has occurred, we need to + // make sure all the properties a recomputed, therefore we invalidate + // the properties cache. + if (StyleResolver* styleResolver = frame->document()->styleResolverIfExists()) + styleResolver->invalidateMatchedPropertiesCache(); frame->document()->scheduleForcedStyleRecalc(); + } } void Page::setNeedsRecalcStyleInAllFrames() @@ -467,8 +520,6 @@ void Page::refreshPlugins(bool reload) PluginData* Page::pluginData() const { - if (!mainFrame()->loader()->subframeLoader()->allowPlugins(NotAboutToInstantiatePlugin)) - return 0; if (!m_pluginData) m_pluginData = PluginData::create(this); return m_pluginData.get(); @@ -519,7 +570,7 @@ bool Page::findString(const String& target, FindOptions options) Frame* frame = focusController()->focusedOrMainFrame(); Frame* startFrame = frame; do { - if (frame->editor()->findString(target, (options & ~WrapAround) | StartInSelection)) { + if (frame->editor().findString(target, (options & ~WrapAround) | StartInSelection)) { if (frame != startFrame) startFrame->selection()->clear(); focusController()->setFocusedFrame(frame); @@ -531,7 +582,7 @@ bool Page::findString(const String& target, FindOptions options) // Search contents of startFrame, on the other side of the selection that we did earlier. // We cheat a bit and just research with wrap on if (shouldWrap && !startFrame->selection()->isNone()) { - bool found = startFrame->editor()->findString(target, options | WrapAround | StartInSelection); + bool found = startFrame->editor().findString(target, options | WrapAround | StartInSelection); focusController()->setFocusedFrame(frame); return found; } @@ -539,6 +590,50 @@ bool Page::findString(const String& target, FindOptions options) return false; } +void Page::findStringMatchingRanges(const String& target, FindOptions options, int limit, Vector<RefPtr<Range> >* matchRanges, int& indexForSelection) +{ + indexForSelection = 0; + if (!mainFrame()) + return; + + Frame* frame = mainFrame(); + Frame* frameWithSelection = 0; + do { + frame->editor().countMatchesForText(target, 0, options, limit ? (limit - matchRanges->size()) : 0, true, matchRanges); + if (frame->selection()->isRange()) + frameWithSelection = frame; + frame = incrementFrame(frame, true, false); + } while (frame); + + if (matchRanges->isEmpty()) + return; + + if (frameWithSelection) { + indexForSelection = NoMatchAfterUserSelection; + RefPtr<Range> selectedRange = frameWithSelection->selection()->selection().firstRange(); + if (options & Backwards) { + for (size_t i = matchRanges->size(); i > 0; --i) { + if (selectedRange->compareBoundaryPoints(Range::END_TO_START, matchRanges->at(i - 1).get(), IGNORE_EXCEPTION) > 0) { + indexForSelection = i - 1; + break; + } + } + } else { + for (size_t i = 0; i < matchRanges->size(); ++i) { + if (selectedRange->compareBoundaryPoints(Range::START_TO_END, matchRanges->at(i).get(), IGNORE_EXCEPTION) < 0) { + indexForSelection = i; + break; + } + } + } + } else { + if (options & Backwards) + indexForSelection = matchRanges->size() - 1; + else + indexForSelection = 0; + } +} + PassRefPtr<Range> Page::rangeOfString(const String& target, Range* referenceRange, FindOptions options) { if (target.isEmpty() || !mainFrame()) @@ -551,7 +646,7 @@ PassRefPtr<Range> Page::rangeOfString(const String& target, Range* referenceRang Frame* frame = referenceRange ? referenceRange->ownerDocument()->frame() : mainFrame(); Frame* startFrame = frame; do { - if (RefPtr<Range> resultRange = frame->editor()->rangeOfString(target, frame == startFrame ? referenceRange : 0, options & ~WrapAround)) + if (RefPtr<Range> resultRange = frame->editor().rangeOfString(target, frame == startFrame ? referenceRange : 0, options & ~WrapAround)) return resultRange.release(); frame = incrementFrame(frame, !(options & Backwards), shouldWrap); @@ -560,33 +655,39 @@ PassRefPtr<Range> Page::rangeOfString(const String& target, Range* referenceRang // Search contents of startFrame, on the other side of the reference range that we did earlier. // We cheat a bit and just search again with wrap on. if (shouldWrap && referenceRange) { - if (RefPtr<Range> resultRange = startFrame->editor()->rangeOfString(target, referenceRange, options | WrapAround | StartInSelection)) + if (RefPtr<Range> resultRange = startFrame->editor().rangeOfString(target, referenceRange, options | WrapAround | StartInSelection)) return resultRange.release(); } return 0; } -unsigned int Page::markAllMatchesForText(const String& target, TextCaseSensitivity caseSensitivity, bool shouldHighlight, unsigned limit) -{ - return markAllMatchesForText(target, caseSensitivity == TextCaseInsensitive ? CaseInsensitive : 0, shouldHighlight, limit); -} - -unsigned int Page::markAllMatchesForText(const String& target, FindOptions options, bool shouldHighlight, unsigned limit) +unsigned Page::findMatchesForText(const String& target, FindOptions options, unsigned maxMatchCount, ShouldHighlightMatches shouldHighlightMatches, ShouldMarkMatches shouldMarkMatches) { if (target.isEmpty() || !mainFrame()) return 0; - unsigned matches = 0; + unsigned matchCount = 0; Frame* frame = mainFrame(); do { - frame->editor()->setMarkedTextMatchesAreHighlighted(shouldHighlight); - matches += frame->editor()->countMatchesForText(target, options, limit ? (limit - matches) : 0, true); + if (shouldMarkMatches == MarkMatches) + frame->editor().setMarkedTextMatchesAreHighlighted(shouldHighlightMatches == HighlightMatches); + matchCount += frame->editor().countMatchesForText(target, 0, options, maxMatchCount ? (maxMatchCount - matchCount) : 0, shouldMarkMatches == MarkMatches, 0); frame = incrementFrame(frame, true, false); } while (frame); - return matches; + return matchCount; +} + +unsigned Page::markAllMatchesForText(const String& target, FindOptions options, bool shouldHighlight, unsigned maxMatchCount) +{ + return findMatchesForText(target, options, maxMatchCount, shouldHighlight ? HighlightMatches : DoNotHighlightMatches, MarkMatches); +} + +unsigned Page::countFindMatches(const String& target, FindOptions options, unsigned maxMatchCount) +{ + return findMatchesForText(target, options, maxMatchCount, DoNotHighlightMatches, DoNotMarkMatches); } void Page::unmarkAllTextMatches() @@ -664,7 +765,8 @@ void Page::setPageScaleFactor(float scale, const IntPoint& origin) if (scale == m_pageScaleFactor) { if (view && (view->scrollPosition() != origin || view->delegatesScrolling())) { - document->updateLayoutIgnorePendingStylesheets(); + if (!m_settings->applyPageScaleFactorInCompositor()) + document->updateLayoutIgnorePendingStylesheets(); view->setScrollPosition(origin); } return; @@ -672,20 +774,25 @@ void Page::setPageScaleFactor(float scale, const IntPoint& origin) m_pageScaleFactor = scale; - if (document->renderer()) - document->renderer()->setNeedsLayout(true); + if (!m_settings->applyPageScaleFactorInCompositor()) { + if (document->renderer()) + document->renderer()->setNeedsLayout(true); - document->recalcStyle(Node::Force); + document->recalcStyle(Node::Force); - // Transform change on RenderView doesn't trigger repaint on non-composited contents. - mainFrame()->view()->invalidateRect(IntRect(LayoutRect::infiniteRect())); + // Transform change on RenderView doesn't trigger repaint on non-composited contents. + mainFrame()->view()->invalidateRect(IntRect(LayoutRect::infiniteRect())); + } #if USE(ACCELERATED_COMPOSITING) mainFrame()->deviceOrPageScaleFactorChanged(); #endif + if (view && view->fixedElementsLayoutRelativeToFrame()) + view->setViewportConstrainedObjectsNeedLayout(); + if (view && view->scrollPosition() != origin) { - if (document->renderer() && document->renderer()->needsLayout() && view->didFirstLayout()) + if (!m_settings->applyPageScaleFactorInCompositor() && document->renderer() && document->renderer()->needsLayout() && view->didFirstLayout()) view->layout(); view->setScrollPosition(origin); } @@ -703,10 +810,12 @@ void Page::setDeviceScaleFactor(float scaleFactor) #if USE(ACCELERATED_COMPOSITING) if (mainFrame()) mainFrame()->deviceOrPageScaleFactorChanged(); + + pageCache()->markPagesForDeviceScaleChanged(this); #endif for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) - frame->editor()->deviceScaleFactorChanged(); + frame->editor().deviceScaleFactorChanged(); pageCache()->markPagesForFullStyleRecalc(this); } @@ -751,6 +860,34 @@ void Page::setShouldSuppressScrollbarAnimations(bool suppressAnimations) m_suppressScrollbarAnimations = suppressAnimations; } +bool Page::rubberBandsAtBottom() +{ + if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) + return scrollingCoordinator->rubberBandsAtBottom(); + + return false; +} + +void Page::setRubberBandsAtBottom(bool rubberBandsAtBottom) +{ + if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) + scrollingCoordinator->setRubberBandsAtBottom(rubberBandsAtBottom); +} + +bool Page::rubberBandsAtTop() +{ + if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) + return scrollingCoordinator->rubberBandsAtTop(); + + return false; +} + +void Page::setRubberBandsAtTop(bool rubberBandsAtTop) +{ + if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) + scrollingCoordinator->setRubberBandsAtTop(rubberBandsAtTop); +} + void Page::setPagination(const Pagination& pagination) { if (m_pagination == pagination) @@ -767,9 +904,8 @@ unsigned Page::pageCount() const if (m_pagination.mode == Pagination::Unpaginated) return 0; - FrameView* frameView = mainFrame()->view(); - if (frameView->needsLayout()) - frameView->layout(); + if (Document* document = mainFrame()->document()) + document->updateLayoutIgnorePendingStylesheets(); RenderView* contentRenderer = mainFrame()->contentRenderer(); return contentRenderer ? contentRenderer->columnCount(contentRenderer->columnInfo()) : 0; @@ -799,13 +935,16 @@ void Page::willMoveOffscreen() suspendScriptedAnimations(); } -void Page::windowScreenDidChange(PlatformDisplayID displayID) +void Page::setIsInWindow(bool isInWindow) { - m_displayID = displayID; - + if (m_isInWindow == isInWindow) + return; + + m_isInWindow = isInWindow; + for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) { - if (frame->document()) - frame->document()->windowScreenDidChange(displayID); + if (FrameView* frameView = frame->view()) + frameView->setIsInWindow(isInWindow); } } @@ -827,6 +966,11 @@ void Page::resumeScriptedAnimations() } } +void Page::setThrottled(bool throttled) +{ + m_pageThrottler->setThrottled(throttled); +} + void Page::userStyleSheetLocationChanged() { // FIXME: Eventually we will move to a model of just being handed the sheet @@ -855,7 +999,7 @@ void Page::userStyleSheetLocationChanged() for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) { if (frame->document()) - frame->document()->styleSheetCollection()->updatePageUserStyleSheet(); + frame->document()->styleSheetCollection()->updatePageUserSheet(); } } @@ -926,14 +1070,12 @@ void Page::allVisitedStateChanged(PageGroup* group) Page* page = *it; if (page->m_group != group) continue; - for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) { - if (StyleResolver* styleResolver = frame->document()->styleResolver()) - styleResolver->allVisitedStateChanged(); - } + for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) + frame->document()->visitedLinkState()->invalidateStyleForAllLinks(); } } -void Page::visitedStateChanged(PageGroup* group, LinkHash visitedLinkHash) +void Page::visitedStateChanged(PageGroup* group, LinkHash linkHash) { ASSERT(group); if (!allPages) @@ -944,10 +1086,8 @@ void Page::visitedStateChanged(PageGroup* group, LinkHash visitedLinkHash) Page* page = *it; if (page->m_group != group) continue; - for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) { - if (StyleResolver* styleResolver = frame->document()->styleResolver()) - styleResolver->visitedStateChanged(visitedLinkHash); - } + for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) + frame->document()->visitedLinkState()->invalidateStyleForLink(linkHash); } } @@ -974,7 +1114,7 @@ void Page::setDebugger(JSC::Debugger* debugger) StorageNamespace* Page::sessionStorage(bool optionalCreate) { if (!m_sessionStorage && optionalCreate) - m_sessionStorage = StorageNamespace::sessionStorageNamespace(this, m_settings->sessionStorageQuota()); + m_sessionStorage = StorageNamespace::sessionStorageNamespace(this); return m_sessionStorage.get(); } @@ -1067,7 +1207,7 @@ void Page::collectPluginViews(Vector<RefPtr<PluginViewBase>, 32>& pluginViewBase for (HashSet<RefPtr<Widget> >::const_iterator it = children->begin(); it != end; ++it) { Widget* widget = (*it).get(); if (widget->isPluginViewBase()) - pluginViewBases.append(static_cast<PluginViewBase*>(widget)); + pluginViewBases.append(toPluginViewBase(widget)); } } } @@ -1115,6 +1255,22 @@ void Page::checkSubframeCountConsistency() const } #endif +void Page::throttleTimers() +{ +#if ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING) + if (m_settings->hiddenPageDOMTimerThrottlingEnabled()) + setTimerAlignmentInterval(Settings::hiddenPageDOMTimerAlignmentInterval()); +#endif +} + +void Page::unthrottleTimers() +{ +#if ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING) + if (m_settings->hiddenPageDOMTimerThrottlingEnabled()) + setTimerAlignmentInterval(Settings::defaultDOMTimerAlignmentInterval()); +#endif +} + #if ENABLE(PAGE_VISIBILITY_API) || ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING) void Page::setVisibilityState(PageVisibilityState visibilityState, bool isInitialState) { @@ -1129,15 +1285,19 @@ void Page::setVisibilityState(PageVisibilityState visibilityState, bool isInitia m_mainFrame->dispatchVisibilityStateChangeEvent(); #endif -#if ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING) - if (visibilityState == WebCore::PageVisibilityStateHidden) - setTimerAlignmentInterval(hiddenPageTimerAlignmentInterval); - else - setTimerAlignmentInterval(Settings::defaultDOMTimerAlignmentInterval()); + if (visibilityState == WebCore::PageVisibilityStateHidden) { + if (m_pageThrottler->shouldThrottleTimers()) + throttleTimers(); + if (m_settings->hiddenPageCSSAnimationSuspensionEnabled()) + mainFrame()->animation()->suspendAnimations(); + } else { + unthrottleTimers(); + if (m_settings->hiddenPageCSSAnimationSuspensionEnabled()) + mainFrame()->animation()->resumeAnimations(); + } #if !ENABLE(PAGE_VISIBILITY_API) UNUSED_PARAM(isInitialState); #endif -#endif } #endif // ENABLE(PAGE_VISIBILITY_API) || ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING) @@ -1148,10 +1308,49 @@ PageVisibilityState Page::visibilityState() const } #endif +#if ENABLE(RUBBER_BANDING) +void Page::addHeaderWithHeight(int headerHeight) +{ + m_headerHeight = headerHeight; + + FrameView* frameView = mainFrame() ? mainFrame()->view() : 0; + if (!frameView) + return; + + RenderView* renderView = frameView->renderView(); + if (!renderView) + return; + + frameView->setHeaderHeight(m_headerHeight); + renderView->compositor()->updateLayerForHeader(m_headerHeight); +} + +void Page::addFooterWithHeight(int footerHeight) +{ + m_footerHeight = footerHeight; + + FrameView* frameView = mainFrame() ? mainFrame()->view() : 0; + if (!frameView) + return; + + RenderView* renderView = frameView->renderView(); + if (!renderView) + return; + + frameView->setFooterHeight(m_footerHeight); + renderView->compositor()->updateLayerForFooter(m_footerHeight); +} +#endif + void Page::addLayoutMilestones(LayoutMilestones milestones) { // In the future, we may want a function that replaces m_layoutMilestones instead of just adding to it. - m_layoutMilestones |= milestones; + m_requestedLayoutMilestones |= milestones; +} + +void Page::removeLayoutMilestones(LayoutMilestones milestones) +{ + m_requestedLayoutMilestones &= ~milestones; } // These are magical constants that might be tweaked over time. @@ -1160,7 +1359,7 @@ static double gMaximumUnpaintedAreaRatio = 0.04; bool Page::isCountingRelevantRepaintedObjects() const { - return m_isCountingRelevantRepaintedObjects && (m_layoutMilestones & DidHitRelevantRepaintedObjectsAreaThreshold); + return m_isCountingRelevantRepaintedObjects && (m_requestedLayoutMilestones & DidHitRelevantRepaintedObjectsAreaThreshold); } void Page::startCountingRelevantRepaintedObjects() @@ -1175,20 +1374,46 @@ void Page::resetRelevantPaintedObjectCounter() { m_isCountingRelevantRepaintedObjects = false; m_relevantUnpaintedRenderObjects.clear(); - m_relevantPaintedRegion = Region(); + m_topRelevantPaintedRegion = Region(); + m_bottomRelevantPaintedRegion = Region(); m_relevantUnpaintedRegion = Region(); } +static LayoutRect relevantViewRect(RenderView* view) +{ + // DidHitRelevantRepaintedObjectsAreaThreshold is a LayoutMilestone intended to indicate that + // a certain relevant amount of content has been drawn to the screen. This is the rect that + // has been determined to be relevant in the context of this goal. We may choose to tweak + // the rect over time, much like we may choose to tweak gMinimumPaintedAreaRatio and + // gMaximumUnpaintedAreaRatio. But this seems to work well right now. + LayoutRect relevantViewRect = LayoutRect(0, 0, 980, 1300); + + LayoutRect viewRect = view->viewRect(); + // If the viewRect is wider than the relevantViewRect, center the relevantViewRect. + if (viewRect.width() > relevantViewRect.width()) + relevantViewRect.setX((viewRect.width() - relevantViewRect.width()) / 2); + + return relevantViewRect; +} + void Page::addRelevantRepaintedObject(RenderObject* object, const LayoutRect& objectPaintRect) { if (!isCountingRelevantRepaintedObjects()) return; + // Objects inside sub-frames are not considered to be relevant. + if (object->document()->frame() != mainFrame()) + return; + + RenderView* view = object->view(); + if (!view) + return; + + LayoutRect relevantRect = relevantViewRect(view); + // The objects are only relevant if they are being painted within the viewRect(). - if (RenderView* view = object->view()) { - if (!objectPaintRect.intersects(pixelSnappedIntRect(view->viewRect()))) - return; - } + if (!objectPaintRect.intersects(pixelSnappedIntRect(relevantRect))) + return; IntRect snappedPaintRect = pixelSnappedIntRect(objectPaintRect); @@ -1200,17 +1425,38 @@ void Page::addRelevantRepaintedObject(RenderObject* object, const LayoutRect& ob m_relevantUnpaintedRegion.subtract(snappedPaintRect); } - m_relevantPaintedRegion.unite(snappedPaintRect); + // Split the relevantRect into a top half and a bottom half. Making sure we have coverage in + // both halves helps to prevent cases where we have a fully loaded menu bar or masthead with + // no content beneath that. + LayoutRect topRelevantRect = relevantRect; + topRelevantRect.contract(LayoutSize(0, relevantRect.height() / 2)); + LayoutRect bottomRelevantRect = topRelevantRect; + bottomRelevantRect.setY(relevantRect.height() / 2); + + // If the rect straddles both Regions, split it appropriately. + if (topRelevantRect.intersects(snappedPaintRect) && bottomRelevantRect.intersects(snappedPaintRect)) { + IntRect topIntersection = snappedPaintRect; + topIntersection.intersect(pixelSnappedIntRect(topRelevantRect)); + m_topRelevantPaintedRegion.unite(topIntersection); + + IntRect bottomIntersection = snappedPaintRect; + bottomIntersection.intersect(pixelSnappedIntRect(bottomRelevantRect)); + m_bottomRelevantPaintedRegion.unite(bottomIntersection); + } else if (topRelevantRect.intersects(snappedPaintRect)) + m_topRelevantPaintedRegion.unite(snappedPaintRect); + else + m_bottomRelevantPaintedRegion.unite(snappedPaintRect); - RenderView* view = object->view(); - if (!view) - return; - - float viewArea = view->viewRect().width() * view->viewRect().height(); - float ratioOfViewThatIsPainted = m_relevantPaintedRegion.totalArea() / viewArea; + float topPaintedArea = m_topRelevantPaintedRegion.totalArea(); + float bottomPaintedArea = m_bottomRelevantPaintedRegion.totalArea(); + float viewArea = relevantRect.width() * relevantRect.height(); + + float ratioThatIsPaintedOnTop = topPaintedArea / viewArea; + float ratioThatIsPaintedOnBottom = bottomPaintedArea / viewArea; float ratioOfViewThatIsUnpainted = m_relevantUnpaintedRegion.totalArea() / viewArea; - if (ratioOfViewThatIsPainted > gMinimumPaintedAreaRatio && ratioOfViewThatIsUnpainted < gMaximumUnpaintedAreaRatio) { + if (ratioThatIsPaintedOnTop > (gMinimumPaintedAreaRatio / 2) && ratioThatIsPaintedOnBottom > (gMinimumPaintedAreaRatio / 2) + && ratioOfViewThatIsUnpainted < gMaximumUnpaintedAreaRatio) { m_isCountingRelevantRepaintedObjects = false; resetRelevantPaintedObjectCounter(); if (Frame* frame = mainFrame()) @@ -1223,9 +1469,9 @@ void Page::addRelevantUnpaintedObject(RenderObject* object, const LayoutRect& ob if (!isCountingRelevantRepaintedObjects()) return; - // The objects are only relevant if they are being painted within the viewRect(). + // The objects are only relevant if they are being painted within the relevantViewRect(). if (RenderView* view = object->view()) { - if (!objectPaintRect.intersects(pixelSnappedIntRect(view->viewRect()))) + if (!objectPaintRect.intersects(pixelSnappedIntRect(relevantViewRect(view)))) return; } @@ -1285,47 +1531,58 @@ void Page::resetSeenMediaEngines() m_seenMediaEngines.clear(); } -void Page::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const +PassOwnPtr<PageActivityAssertionToken> Page::createActivityToken() { - MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::Page); - info.addMember(m_chrome); - info.addMember(m_dragCaretController); + return adoptPtr(new PageActivityAssertionToken(m_pageThrottler.get())); +} -#if ENABLE(DRAG_SUPPORT) - info.addMember(m_dragController); +#if ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING) +void Page::hiddenPageDOMTimerThrottlingStateChanged() +{ + if (m_settings->hiddenPageDOMTimerThrottlingEnabled()) { +#if ENABLE(PAGE_VISIBILITY_API) + if (m_pageThrottler->shouldThrottleTimers()) + setTimerAlignmentInterval(Settings::hiddenPageDOMTimerAlignmentInterval()); #endif - info.addMember(m_focusController); -#if ENABLE(CONTEXT_MENUS) - info.addMember(m_contextMenuController); + } else + setTimerAlignmentInterval(Settings::defaultDOMTimerAlignmentInterval()); +} #endif -#if ENABLE(INSPECTOR) - info.addMember(m_inspectorController); + +#if (ENABLE_PAGE_VISIBILITY_API) +void Page::hiddenPageCSSAnimationSuspensionStateChanged() +{ + if (m_visibilityState == WebCore::PageVisibilityStateHidden) { + if (m_settings->hiddenPageCSSAnimationSuspensionEnabled()) + mainFrame()->animation()->suspendAnimations(); + else + mainFrame()->animation()->resumeAnimations(); + } +} #endif -#if ENABLE(POINTER_LOCK) - info.addMember(m_pointerLockController); + +#if ENABLE(VIDEO_TRACK) +void Page::captionPreferencesChanged() +{ + for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) + frame->document()->captionPreferencesChanged(); +} #endif - info.addMember(m_scrollingCoordinator); - info.addMember(m_settings); - info.addMember(m_progress); - info.addMember(m_backForwardController); - info.addMember(m_mainFrame); - info.addMember(m_pluginData); - info.addMember(m_theme); - info.addWeakPointer(m_editorClient); - info.addMember(m_featureObserver); - info.addMember(m_groupName); - info.addMember(m_pagination); - info.addMember(m_userStyleSheetPath); - info.addMember(m_userStyleSheet); - info.addMember(m_singlePageGroup); - info.addMember(m_group); - info.addWeakPointer(m_debugger); - info.addMember(m_sessionStorage); - info.addMember(m_relevantUnpaintedRenderObjects); - info.addMember(m_relevantPaintedRegion); - info.addMember(m_relevantUnpaintedRegion); - info.addWeakPointer(m_alternativeTextClient); - info.addMember(m_seenPlugins); + +void Page::incrementFrameHandlingBeforeUnloadEventCount() +{ + ++m_framesHandlingBeforeUnloadEvent; +} + +void Page::decrementFrameHandlingBeforeUnloadEventCount() +{ + ASSERT(m_framesHandlingBeforeUnloadEvent); + --m_framesHandlingBeforeUnloadEvent; +} + +bool Page::isAnyFrameHandlingBeforeUnloadEvent() +{ + return m_framesHandlingBeforeUnloadEvent; } Page::PageClients::PageClients() @@ -1337,6 +1594,7 @@ Page::PageClients::PageClients() , editorClient(0) , dragClient(0) , inspectorClient(0) + , plugInClient(0) , validationMessageClient(0) { } diff --git a/Source/WebCore/page/Page.h b/Source/WebCore/page/Page.h index 443ab260b..d95565ab9 100644 --- a/Source/WebCore/page/Page.h +++ b/Source/WebCore/page/Page.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2013 Apple Inc. All rights reserved. * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * * This library is free software; you can redistribute it and/or @@ -22,8 +22,8 @@ #define Page_h #include "FeatureObserver.h" -#include "FrameLoaderTypes.h" #include "FindOptions.h" +#include "FrameLoaderTypes.h" #include "LayoutMilestones.h" #include "LayoutRect.h" #include "PageVisibilityState.h" @@ -36,6 +36,7 @@ #include <wtf/HashMap.h> #include <wtf/HashSet.h> #include <wtf/Noncopyable.h> +#include <wtf/RefCounted.h> #include <wtf/text/WTFString.h> #if OS(SOLARIS) @@ -43,440 +44,518 @@ #endif #if PLATFORM(MAC) -#include "SchedulePair.h" +#include <wtf/SchedulePair.h> #endif namespace JSC { - class Debugger; +class Debugger; } namespace WebCore { - class AlternativeTextClient; - class BackForwardController; - class BackForwardList; - class Chrome; - class ChromeClient; -#if ENABLE(CONTEXT_MENUS) - class ContextMenuClient; - class ContextMenuController; -#endif - class Document; - class DragCaretController; - class DragClient; - class DragController; - class EditorClient; - class FocusController; - class Frame; - class FrameSelection; - class HaltablePlugin; - class HistoryItem; - class InspectorClient; - class InspectorController; - class MediaCanStartListener; - class Node; - class PageGroup; - class PluginData; - class PluginViewBase; - class PointerLockController; - class ProgressTracker; - class Range; - class RenderObject; - class RenderTheme; - class VisibleSelection; - class ScrollableArea; - class ScrollingCoordinator; - class Settings; - class StorageNamespace; - class ValidationMessageClient; - - typedef uint64_t LinkHash; - - enum FindDirection { FindDirectionForward, FindDirectionBackward }; - - float deviceScaleFactor(Frame*); - - struct ArenaSize { - ArenaSize(size_t treeSize, size_t allocated) - : treeSize(treeSize) - , allocated(allocated) - { - } - size_t treeSize; - size_t allocated; - }; - - class Page : public Supplementable<Page> { - WTF_MAKE_NONCOPYABLE(Page); - friend class Settings; +class AlternativeTextClient; +class BackForwardController; +class BackForwardList; +class Chrome; +class ChromeClient; +class ClientRectList; +class ContextMenuClient; +class ContextMenuController; +class Document; +class DragCaretController; +class DragClient; +class DragController; +class EditorClient; +class FocusController; +class Frame; +class FrameSelection; +class HaltablePlugin; +class HistoryItem; +class InspectorClient; +class InspectorController; +class MediaCanStartListener; +class Node; +class PageActivityAssertionToken; +class PageConsole; +class PageGroup; +class PageThrottler; +class PlugInClient; +class PluginData; +class PluginViewBase; +class PointerLockController; +class ProgressTracker; +class Range; +class RenderObject; +class RenderTheme; +class VisibleSelection; +class ScrollableArea; +class ScrollingCoordinator; +class Settings; +class StorageNamespace; +class ValidationMessageClient; + +typedef uint64_t LinkHash; + +enum FindDirection { FindDirectionForward, FindDirectionBackward }; + +float deviceScaleFactor(Frame*); + +struct ArenaSize { + ArenaSize(size_t treeSize, size_t allocated) + : treeSize(treeSize) + , allocated(allocated) + { + } + size_t treeSize; + size_t allocated; +}; + +class Page : public Supplementable<Page> { + WTF_MAKE_NONCOPYABLE(Page); + friend class Settings; + friend class PageThrottler; + +public: + static void updateStyleForAllPagesAfterGlobalChangeInEnvironment(); + + // It is up to the platform to ensure that non-null clients are provided where required. + struct PageClients { + WTF_MAKE_NONCOPYABLE(PageClients); WTF_MAKE_FAST_ALLOCATED; public: - static void scheduleForcedStyleRecalcForAllPages(); - - // It is up to the platform to ensure that non-null clients are provided where required. - struct PageClients { - WTF_MAKE_NONCOPYABLE(PageClients); WTF_MAKE_FAST_ALLOCATED; - public: - PageClients(); - ~PageClients(); + PageClients(); + ~PageClients(); - AlternativeTextClient* alternativeTextClient; - ChromeClient* chromeClient; + AlternativeTextClient* alternativeTextClient; + ChromeClient* chromeClient; #if ENABLE(CONTEXT_MENUS) - ContextMenuClient* contextMenuClient; + ContextMenuClient* contextMenuClient; #endif - EditorClient* editorClient; - DragClient* dragClient; - InspectorClient* inspectorClient; - RefPtr<BackForwardList> backForwardClient; - ValidationMessageClient* validationMessageClient; - }; + EditorClient* editorClient; + DragClient* dragClient; + InspectorClient* inspectorClient; + PlugInClient* plugInClient; + RefPtr<BackForwardList> backForwardClient; + ValidationMessageClient* validationMessageClient; + }; - explicit Page(PageClients&); - ~Page(); + explicit Page(PageClients&); + ~Page(); - ArenaSize renderTreeSize() const; + ArenaSize renderTreeSize() const; - void setNeedsRecalcStyleInAllFrames(); + void setNeedsRecalcStyleInAllFrames(); - RenderTheme* theme() const { return m_theme.get(); }; + RenderTheme* theme() const { return m_theme.get(); } - ViewportArguments viewportArguments() const; + ViewportArguments viewportArguments() const; - static void refreshPlugins(bool reload); - PluginData* pluginData() const; + static void refreshPlugins(bool reload); + PluginData* pluginData() const; - void setCanStartMedia(bool); - bool canStartMedia() const { return m_canStartMedia; } + void setCanStartMedia(bool); + bool canStartMedia() const { return m_canStartMedia; } - EditorClient* editorClient() const { return m_editorClient; } + EditorClient* editorClient() const { return m_editorClient; } + PlugInClient* plugInClient() const { return m_plugInClient; } - void setMainFrame(PassRefPtr<Frame>); - Frame* mainFrame() const { return m_mainFrame.get(); } + void setMainFrame(PassRefPtr<Frame>); + Frame* mainFrame() const { return m_mainFrame.get(); } - bool openedByDOM() const; - void setOpenedByDOM(); + bool openedByDOM() const; + void setOpenedByDOM(); - // DEPRECATED. Use backForward() instead of the following 6 functions. - BackForwardList* backForwardList() const; - bool goBack(); - bool goForward(); - bool canGoBackOrForward(int distance) const; - void goBackOrForward(int distance); - int getHistoryLength(); + // DEPRECATED. Use backForward() instead of the following 6 functions. + BackForwardList* backForwardList() const; + bool goBack(); + bool goForward(); + bool canGoBackOrForward(int distance) const; + void goBackOrForward(int distance); + int getHistoryLength(); - void goToItem(HistoryItem*, FrameLoadType); + void goToItem(HistoryItem*, FrameLoadType); - void setGroupName(const String&); - const String& groupName() const; + void setGroupName(const String&); + const String& groupName() const; - PageGroup& group() { if (!m_group) initGroup(); return *m_group; } - PageGroup* groupPtr() { return m_group; } // can return 0 + PageGroup& group(); + PageGroup* groupPtr() { return m_group; } // can return 0 - void incrementSubframeCount() { ++m_subframeCount; } - void decrementSubframeCount() { ASSERT(m_subframeCount); --m_subframeCount; } - int subframeCount() const { checkSubframeCountConsistency(); return m_subframeCount; } + void incrementSubframeCount() { ++m_subframeCount; } + void decrementSubframeCount() { ASSERT(m_subframeCount); --m_subframeCount; } + int subframeCount() const { checkSubframeCountConsistency(); return m_subframeCount; } - Chrome* chrome() const { return m_chrome.get(); } - DragCaretController* dragCaretController() const { return m_dragCaretController.get(); } + Chrome& chrome() const { return *m_chrome; } + DragCaretController* dragCaretController() const { return m_dragCaretController.get(); } #if ENABLE(DRAG_SUPPORT) - DragController* dragController() const { return m_dragController.get(); } + DragController* dragController() const { return m_dragController.get(); } #endif - FocusController* focusController() const { return m_focusController.get(); } + FocusController* focusController() const { return m_focusController.get(); } #if ENABLE(CONTEXT_MENUS) - ContextMenuController* contextMenuController() const { return m_contextMenuController.get(); } + ContextMenuController* contextMenuController() const { return m_contextMenuController.get(); } #endif #if ENABLE(INSPECTOR) - InspectorController* inspectorController() const { return m_inspectorController.get(); } + InspectorController* inspectorController() const { return m_inspectorController.get(); } #endif #if ENABLE(POINTER_LOCK) - PointerLockController* pointerLockController() const { return m_pointerLockController.get(); } + PointerLockController* pointerLockController() const { return m_pointerLockController.get(); } #endif - ValidationMessageClient* validationMessageClient() const { return m_validationMessageClient; } + ValidationMessageClient* validationMessageClient() const { return m_validationMessageClient; } - ScrollingCoordinator* scrollingCoordinator(); + ScrollingCoordinator* scrollingCoordinator(); - String scrollingStateTreeAsText(); + String scrollingStateTreeAsText(); + String mainThreadScrollingReasonsAsText(); + PassRefPtr<ClientRectList> nonFastScrollableRects(const Frame*); - Settings* settings() const { return m_settings.get(); } - ProgressTracker* progress() const { return m_progress.get(); } - BackForwardController* backForward() const { return m_backForwardController.get(); } + Settings* settings() const { return m_settings.get(); } + ProgressTracker* progress() const { return m_progress.get(); } + BackForwardController* backForward() const { return m_backForwardController.get(); } - FeatureObserver* featureObserver() { return &m_featureObserver; } + FeatureObserver* featureObserver() { return &m_featureObserver; } - enum ViewMode { - ViewModeInvalid, - ViewModeWindowed, - ViewModeFloating, - ViewModeFullscreen, - ViewModeMaximized, - ViewModeMinimized - }; - static ViewMode stringToViewMode(const String&); +#if ENABLE(VIEW_MODE_CSS_MEDIA) + enum ViewMode { + ViewModeInvalid, + ViewModeWindowed, + ViewModeFloating, + ViewModeFullscreen, + ViewModeMaximized, + ViewModeMinimized + }; + static ViewMode stringToViewMode(const String&); - ViewMode viewMode() const { return m_viewMode; } - void setViewMode(ViewMode); - - void setTabKeyCyclesThroughElements(bool b) { m_tabKeyCyclesThroughElements = b; } - bool tabKeyCyclesThroughElements() const { return m_tabKeyCyclesThroughElements; } + ViewMode viewMode() const { return m_viewMode; } + void setViewMode(ViewMode); +#endif // ENABLE(VIEW_MODE_CSS_MEDIA) - bool findString(const String&, FindOptions); - // FIXME: Switch callers over to the FindOptions version and retire this one. - bool findString(const String&, TextCaseSensitivity, FindDirection, bool shouldWrap); + void setTabKeyCyclesThroughElements(bool b) { m_tabKeyCyclesThroughElements = b; } + bool tabKeyCyclesThroughElements() const { return m_tabKeyCyclesThroughElements; } - PassRefPtr<Range> rangeOfString(const String&, Range*, FindOptions); + bool findString(const String&, FindOptions); + // FIXME: Switch callers over to the FindOptions version and retire this one. + bool findString(const String&, TextCaseSensitivity, FindDirection, bool shouldWrap); - unsigned markAllMatchesForText(const String&, FindOptions, bool shouldHighlight, unsigned); - // FIXME: Switch callers over to the FindOptions version and retire this one. - unsigned markAllMatchesForText(const String&, TextCaseSensitivity, bool shouldHighlight, unsigned); - void unmarkAllTextMatches(); + PassRefPtr<Range> rangeOfString(const String&, Range*, FindOptions); + unsigned countFindMatches(const String&, FindOptions, unsigned maxMatchCount); + unsigned markAllMatchesForText(const String&, FindOptions, bool shouldHighlight, unsigned maxMatchCount); + + void unmarkAllTextMatches(); + + // find all the Ranges for the matching text. + // Upon return, indexForSelection will be one of the following: + // 0 if there is no user selection + // the index of the first range after the user selection + // NoMatchAfterUserSelection if there is no matching text after the user selection. + enum { NoMatchAfterUserSelection = -1 }; + void findStringMatchingRanges(const String&, FindOptions, int maxCount, Vector<RefPtr<Range> >*, int& indexForSelection); #if PLATFORM(MAC) - void addSchedulePair(PassRefPtr<SchedulePair>); - void removeSchedulePair(PassRefPtr<SchedulePair>); - SchedulePairHashSet* scheduledRunLoopPairs() { return m_scheduledRunLoopPairs.get(); } + void addSchedulePair(PassRefPtr<SchedulePair>); + void removeSchedulePair(PassRefPtr<SchedulePair>); + SchedulePairHashSet* scheduledRunLoopPairs() { return m_scheduledRunLoopPairs.get(); } - OwnPtr<SchedulePairHashSet> m_scheduledRunLoopPairs; + OwnPtr<SchedulePairHashSet> m_scheduledRunLoopPairs; #endif - const VisibleSelection& selection() const; + const VisibleSelection& selection() const; + + void setDefersLoading(bool); + bool defersLoading() const { return m_defersLoading; } + + void clearUndoRedoOperations(); - void setDefersLoading(bool); - bool defersLoading() const { return m_defersLoading; } - - void clearUndoRedoOperations(); + bool inLowQualityImageInterpolationMode() const; + void setInLowQualityImageInterpolationMode(bool = true); - bool inLowQualityImageInterpolationMode() const; - void setInLowQualityImageInterpolationMode(bool = true); + float mediaVolume() const { return m_mediaVolume; } + void setMediaVolume(float); - float mediaVolume() const { return m_mediaVolume; } - void setMediaVolume(float volume); + void setPageScaleFactor(float scale, const IntPoint& origin); + float pageScaleFactor() const { return m_pageScaleFactor; } - void setPageScaleFactor(float scale, const IntPoint& origin); - float pageScaleFactor() const { return m_pageScaleFactor; } + float deviceScaleFactor() const { return m_deviceScaleFactor; } + void setDeviceScaleFactor(float); - float deviceScaleFactor() const { return m_deviceScaleFactor; } - void setDeviceScaleFactor(float); + bool shouldSuppressScrollbarAnimations() const { return m_suppressScrollbarAnimations; } + void setShouldSuppressScrollbarAnimations(bool suppressAnimations); - bool shouldSuppressScrollbarAnimations() const { return m_suppressScrollbarAnimations; } - void setShouldSuppressScrollbarAnimations(bool suppressAnimations); + bool rubberBandsAtBottom(); + void setRubberBandsAtBottom(bool); + bool rubberBandsAtTop(); + void setRubberBandsAtTop(bool); - // Page and FrameView both store a Pagination value. Page::pagination() is set only by API, - // and FrameView::pagination() is set only by CSS. Page::pagination() will affect all - // FrameViews in the page cache, but FrameView::pagination() only affects the current - // FrameView. - const Pagination& pagination() const { return m_pagination; } - void setPagination(const Pagination&); + // Page and FrameView both store a Pagination value. Page::pagination() is set only by API, + // and FrameView::pagination() is set only by CSS. Page::pagination() will affect all + // FrameViews in the page cache, but FrameView::pagination() only affects the current + // FrameView. + const Pagination& pagination() const { return m_pagination; } + void setPagination(const Pagination&); - unsigned pageCount() const; + unsigned pageCount() const; - // Notifications when the Page starts and stops being presented via a native window. - void didMoveOnscreen(); - void willMoveOffscreen(); - bool isOnscreen() const { return m_isOnscreen; } + // Notifications when the Page starts and stops being presented via a native window. + void didMoveOnscreen(); + void willMoveOffscreen(); + bool isOnscreen() const { return m_isOnscreen; } - void windowScreenDidChange(PlatformDisplayID); - - void suspendScriptedAnimations(); - void resumeScriptedAnimations(); - bool scriptedAnimationsSuspended() const { return m_scriptedAnimationsSuspended; } - - void userStyleSheetLocationChanged(); - const String& userStyleSheet() const; + // Notification that this Page was moved into or out of a native window. + void setIsInWindow(bool); + bool isInWindow() const { return m_isInWindow; } - void dnsPrefetchingStateChanged(); - void storageBlockingStateChanged(); - void privateBrowsingStateChanged(); + void suspendScriptedAnimations(); + void resumeScriptedAnimations(); + bool scriptedAnimationsSuspended() const { return m_scriptedAnimationsSuspended; } + void setThrottled(bool); - static void setDebuggerForAllPages(JSC::Debugger*); - void setDebugger(JSC::Debugger*); - JSC::Debugger* debugger() const { return m_debugger; } + void userStyleSheetLocationChanged(); + const String& userStyleSheet() const; - static void removeAllVisitedLinks(); + void dnsPrefetchingStateChanged(); + void storageBlockingStateChanged(); + void privateBrowsingStateChanged(); - static void allVisitedStateChanged(PageGroup*); - static void visitedStateChanged(PageGroup*, LinkHash visitedHash); + static void setDebuggerForAllPages(JSC::Debugger*); + void setDebugger(JSC::Debugger*); + JSC::Debugger* debugger() const { return m_debugger; } - StorageNamespace* sessionStorage(bool optionalCreate = true); - void setSessionStorage(PassRefPtr<StorageNamespace>); + static void removeAllVisitedLinks(); - void setCustomHTMLTokenizerTimeDelay(double); - bool hasCustomHTMLTokenizerTimeDelay() const { return m_customHTMLTokenizerTimeDelay != -1; } - double customHTMLTokenizerTimeDelay() const { ASSERT(m_customHTMLTokenizerTimeDelay != -1); return m_customHTMLTokenizerTimeDelay; } + static void allVisitedStateChanged(PageGroup*); + static void visitedStateChanged(PageGroup*, LinkHash visitedHash); - void setCustomHTMLTokenizerChunkSize(int); - bool hasCustomHTMLTokenizerChunkSize() const { return m_customHTMLTokenizerChunkSize != -1; } - int customHTMLTokenizerChunkSize() const { ASSERT(m_customHTMLTokenizerChunkSize != -1); return m_customHTMLTokenizerChunkSize; } + StorageNamespace* sessionStorage(bool optionalCreate = true); + void setSessionStorage(PassRefPtr<StorageNamespace>); - void setMemoryCacheClientCallsEnabled(bool); - bool areMemoryCacheClientCallsEnabled() const { return m_areMemoryCacheClientCallsEnabled; } + void setCustomHTMLTokenizerTimeDelay(double); + bool hasCustomHTMLTokenizerTimeDelay() const { return m_customHTMLTokenizerTimeDelay != -1; } + double customHTMLTokenizerTimeDelay() const { ASSERT(m_customHTMLTokenizerTimeDelay != -1); return m_customHTMLTokenizerTimeDelay; } - // Don't allow more than a certain number of frames in a page. - // This seems like a reasonable upper bound, and otherwise mutually - // recursive frameset pages can quickly bring the program to its knees - // with exponential growth in the number of frames. - static const int maxNumberOfFrames = 1000; + void setCustomHTMLTokenizerChunkSize(int); + bool hasCustomHTMLTokenizerChunkSize() const { return m_customHTMLTokenizerChunkSize != -1; } + int customHTMLTokenizerChunkSize() const { ASSERT(m_customHTMLTokenizerChunkSize != -1); return m_customHTMLTokenizerChunkSize; } - void setEditable(bool isEditable) { m_isEditable = isEditable; } - bool isEditable() { return m_isEditable; } + void setMemoryCacheClientCallsEnabled(bool); + bool areMemoryCacheClientCallsEnabled() const { return m_areMemoryCacheClientCallsEnabled; } + + // Don't allow more than a certain number of frames in a page. + // This seems like a reasonable upper bound, and otherwise mutually + // recursive frameset pages can quickly bring the program to its knees + // with exponential growth in the number of frames. + static const int maxNumberOfFrames = 1000; + + void setEditable(bool isEditable) { m_isEditable = isEditable; } + bool isEditable() { return m_isEditable; } #if ENABLE(PAGE_VISIBILITY_API) - PageVisibilityState visibilityState() const; + PageVisibilityState visibilityState() const; #endif #if ENABLE(PAGE_VISIBILITY_API) || ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING) - void setVisibilityState(PageVisibilityState, bool); + void setVisibilityState(PageVisibilityState, bool); #endif - PlatformDisplayID displayID() const { return m_displayID; } + void addLayoutMilestones(LayoutMilestones); + void removeLayoutMilestones(LayoutMilestones); + LayoutMilestones requestedLayoutMilestones() const { return m_requestedLayoutMilestones; } + +#if ENABLE(RUBBER_BANDING) + void addHeaderWithHeight(int); + void addFooterWithHeight(int); +#endif - void addLayoutMilestones(LayoutMilestones); - LayoutMilestones layoutMilestones() const { return m_layoutMilestones; } + int headerHeight() const { return m_headerHeight; } + int footerHeight() const { return m_footerHeight; } - bool isCountingRelevantRepaintedObjects() const; - void startCountingRelevantRepaintedObjects(); - void resetRelevantPaintedObjectCounter(); - void addRelevantRepaintedObject(RenderObject*, const LayoutRect& objectPaintRect); - void addRelevantUnpaintedObject(RenderObject*, const LayoutRect& objectPaintRect); + bool isCountingRelevantRepaintedObjects() const; + void startCountingRelevantRepaintedObjects(); + void resetRelevantPaintedObjectCounter(); + void addRelevantRepaintedObject(RenderObject*, const LayoutRect& objectPaintRect); + void addRelevantUnpaintedObject(RenderObject*, const LayoutRect& objectPaintRect); - void suspendActiveDOMObjectsAndAnimations(); - void resumeActiveDOMObjectsAndAnimations(); + void suspendActiveDOMObjectsAndAnimations(); + void resumeActiveDOMObjectsAndAnimations(); #ifndef NDEBUG - void setIsPainting(bool painting) { m_isPainting = painting; } - bool isPainting() const { return m_isPainting; } + void setIsPainting(bool painting) { m_isPainting = painting; } + bool isPainting() const { return m_isPainting; } #endif - AlternativeTextClient* alternativeTextClient() const { return m_alternativeTextClient; } + AlternativeTextClient* alternativeTextClient() const { return m_alternativeTextClient; } - bool hasSeenPlugin(const String& serviceType) const; - bool hasSeenAnyPlugin() const; - void sawPlugin(const String& serviceType); - void resetSeenPlugins(); + bool hasSeenPlugin(const String& serviceType) const; + bool hasSeenAnyPlugin() const; + void sawPlugin(const String& serviceType); + void resetSeenPlugins(); - bool hasSeenMediaEngine(const String& engineName) const; - bool hasSeenAnyMediaEngine() const; - void sawMediaEngine(const String& engineName); - void resetSeenMediaEngines(); + bool hasSeenMediaEngine(const String& engineName) const; + bool hasSeenAnyMediaEngine() const; + void sawMediaEngine(const String& engineName); + void resetSeenMediaEngines(); - void reportMemoryUsage(MemoryObjectInfo*) const; + PageThrottler* pageThrottler() { return m_pageThrottler.get(); } + PassOwnPtr<PageActivityAssertionToken> createActivityToken(); - private: - void initGroup(); + PageConsole* console() { return m_console.get(); } + +#if ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING) + void hiddenPageDOMTimerThrottlingStateChanged(); +#endif +#if ENABLE(PAGE_VISIBILITY_API) + void hiddenPageCSSAnimationSuspensionStateChanged(); +#endif + +#if ENABLE(VIDEO_TRACK) + void captionPreferencesChanged(); +#endif + + void incrementFrameHandlingBeforeUnloadEventCount(); + void decrementFrameHandlingBeforeUnloadEventCount(); + bool isAnyFrameHandlingBeforeUnloadEvent(); + +private: + void initGroup(); #if ASSERT_DISABLED - void checkSubframeCountConsistency() const { } + void checkSubframeCountConsistency() const { } #else - void checkSubframeCountConsistency() const; + void checkSubframeCountConsistency() const; #endif - MediaCanStartListener* takeAnyMediaCanStartListener(); + enum ShouldHighlightMatches { DoNotHighlightMatches, HighlightMatches }; + enum ShouldMarkMatches { DoNotMarkMatches, MarkMatches }; + + unsigned findMatchesForText(const String&, FindOptions, unsigned maxMatchCount, ShouldHighlightMatches, ShouldMarkMatches); - void setMinimumTimerInterval(double); - double minimumTimerInterval() const; + MediaCanStartListener* takeAnyMediaCanStartListener(); - void setTimerAlignmentInterval(double); - double timerAlignmentInterval() const; + void setMinimumTimerInterval(double); + double minimumTimerInterval() const; - void collectPluginViews(Vector<RefPtr<PluginViewBase>, 32>& pluginViewBases); + void setTimerAlignmentInterval(double); + double timerAlignmentInterval() const; - OwnPtr<Chrome> m_chrome; - OwnPtr<DragCaretController> m_dragCaretController; + void collectPluginViews(Vector<RefPtr<PluginViewBase>, 32>& pluginViewBases); + + void throttleTimers(); + void unthrottleTimers(); + + const OwnPtr<Chrome> m_chrome; + OwnPtr<DragCaretController> m_dragCaretController; #if ENABLE(DRAG_SUPPORT) - OwnPtr<DragController> m_dragController; + OwnPtr<DragController> m_dragController; #endif - OwnPtr<FocusController> m_focusController; + OwnPtr<FocusController> m_focusController; #if ENABLE(CONTEXT_MENUS) - OwnPtr<ContextMenuController> m_contextMenuController; + OwnPtr<ContextMenuController> m_contextMenuController; #endif #if ENABLE(INSPECTOR) - OwnPtr<InspectorController> m_inspectorController; + OwnPtr<InspectorController> m_inspectorController; #endif #if ENABLE(POINTER_LOCK) - OwnPtr<PointerLockController> m_pointerLockController; + OwnPtr<PointerLockController> m_pointerLockController; #endif - RefPtr<ScrollingCoordinator> m_scrollingCoordinator; + RefPtr<ScrollingCoordinator> m_scrollingCoordinator; - OwnPtr<Settings> m_settings; - OwnPtr<ProgressTracker> m_progress; - - OwnPtr<BackForwardController> m_backForwardController; - RefPtr<Frame> m_mainFrame; + OwnPtr<Settings> m_settings; + OwnPtr<ProgressTracker> m_progress; - mutable RefPtr<PluginData> m_pluginData; + OwnPtr<BackForwardController> m_backForwardController; + RefPtr<Frame> m_mainFrame; - RefPtr<RenderTheme> m_theme; + mutable RefPtr<PluginData> m_pluginData; - EditorClient* m_editorClient; - ValidationMessageClient* m_validationMessageClient; + RefPtr<RenderTheme> m_theme; - FeatureObserver m_featureObserver; + EditorClient* m_editorClient; + PlugInClient* m_plugInClient; + ValidationMessageClient* m_validationMessageClient; - int m_subframeCount; - String m_groupName; - bool m_openedByDOM; + FeatureObserver m_featureObserver; - bool m_tabKeyCyclesThroughElements; - bool m_defersLoading; - unsigned m_defersLoadingCallCount; + int m_subframeCount; + String m_groupName; + bool m_openedByDOM; - bool m_inLowQualityInterpolationMode; - bool m_cookieEnabled; - bool m_areMemoryCacheClientCallsEnabled; - float m_mediaVolume; + bool m_tabKeyCyclesThroughElements; + bool m_defersLoading; + unsigned m_defersLoadingCallCount; - float m_pageScaleFactor; - float m_deviceScaleFactor; + bool m_inLowQualityInterpolationMode; + bool m_cookieEnabled; + bool m_areMemoryCacheClientCallsEnabled; + float m_mediaVolume; - bool m_suppressScrollbarAnimations; + float m_pageScaleFactor; + float m_deviceScaleFactor; - Pagination m_pagination; + bool m_suppressScrollbarAnimations; - String m_userStyleSheetPath; - mutable String m_userStyleSheet; - mutable bool m_didLoadUserStyleSheet; - mutable time_t m_userStyleSheetModificationTime; + Pagination m_pagination; - OwnPtr<PageGroup> m_singlePageGroup; - PageGroup* m_group; + String m_userStyleSheetPath; + mutable String m_userStyleSheet; + mutable bool m_didLoadUserStyleSheet; + mutable time_t m_userStyleSheetModificationTime; - JSC::Debugger* m_debugger; + OwnPtr<PageGroup> m_singlePageGroup; + PageGroup* m_group; - double m_customHTMLTokenizerTimeDelay; - int m_customHTMLTokenizerChunkSize; + JSC::Debugger* m_debugger; - bool m_canStartMedia; + double m_customHTMLTokenizerTimeDelay; + int m_customHTMLTokenizerChunkSize; - RefPtr<StorageNamespace> m_sessionStorage; + bool m_canStartMedia; - ViewMode m_viewMode; + RefPtr<StorageNamespace> m_sessionStorage; - double m_minimumTimerInterval; +#if ENABLE(VIEW_MODE_CSS_MEDIA) + ViewMode m_viewMode; +#endif // ENABLE(VIEW_MODE_CSS_MEDIA) - double m_timerAlignmentInterval; + double m_minimumTimerInterval; - bool m_isEditable; - bool m_isOnscreen; + double m_timerAlignmentInterval; + + bool m_isEditable; + bool m_isOnscreen; + bool m_isInWindow; #if ENABLE(PAGE_VISIBILITY_API) - PageVisibilityState m_visibilityState; + PageVisibilityState m_visibilityState; #endif - PlatformDisplayID m_displayID; - LayoutMilestones m_layoutMilestones; + LayoutMilestones m_requestedLayoutMilestones; + + int m_headerHeight; + int m_footerHeight; - HashSet<RenderObject*> m_relevantUnpaintedRenderObjects; - Region m_relevantPaintedRegion; - Region m_relevantUnpaintedRegion; - bool m_isCountingRelevantRepaintedObjects; + HashSet<RenderObject*> m_relevantUnpaintedRenderObjects; + Region m_topRelevantPaintedRegion; + Region m_bottomRelevantPaintedRegion; + Region m_relevantUnpaintedRegion; + bool m_isCountingRelevantRepaintedObjects; #ifndef NDEBUG - bool m_isPainting; + bool m_isPainting; #endif - AlternativeTextClient* m_alternativeTextClient; + AlternativeTextClient* m_alternativeTextClient; - bool m_scriptedAnimationsSuspended; + bool m_scriptedAnimationsSuspended; + OwnPtr<PageThrottler> m_pageThrottler; - HashSet<String> m_seenPlugins; - HashSet<String> m_seenMediaEngines; - }; + OwnPtr<PageConsole> m_console; + + HashSet<String> m_seenPlugins; + HashSet<String> m_seenMediaEngines; + + unsigned m_framesHandlingBeforeUnloadEvent; +}; + +inline PageGroup& Page::group() +{ + if (!m_group) + initGroup(); + return *m_group; +} } // namespace WebCore diff --git a/Source/WebCore/page/PageActivityAssertionToken.cpp b/Source/WebCore/page/PageActivityAssertionToken.cpp new file mode 100644 index 000000000..61d35c14d --- /dev/null +++ b/Source/WebCore/page/PageActivityAssertionToken.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2013 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "PageActivityAssertionToken.h" + +#include "PageThrottler.h" + +namespace WebCore { + +PageActivityAssertionToken::PageActivityAssertionToken(PageThrottler* throttler) + :m_throttler(throttler) +{ + if (m_throttler) + m_throttler->addActivityToken(this); +} + +PageActivityAssertionToken::~PageActivityAssertionToken() +{ + if (m_throttler) + m_throttler->removeActivityToken(this); +} + +void PageActivityAssertionToken::invalidate() +{ + m_throttler = 0; +} + +} + + diff --git a/Source/WebCore/page/PageActivityAssertionToken.h b/Source/WebCore/page/PageActivityAssertionToken.h new file mode 100644 index 000000000..fe516e8ac --- /dev/null +++ b/Source/WebCore/page/PageActivityAssertionToken.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2013 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PageActivityAssertionToken_h +#define PageActivityAssertionToken_h + +#include <wtf/Noncopyable.h> + +namespace WebCore { + +class PageThrottler; + +class PageActivityAssertionToken { + WTF_MAKE_NONCOPYABLE(PageActivityAssertionToken); +public: + ~PageActivityAssertionToken(); + + void invalidate(); + +private: + friend class Page; + PageActivityAssertionToken(PageThrottler*); + + PageThrottler* m_throttler; +}; + +} + +#endif // PageActivityAssertionToken_h diff --git a/Source/WebCore/page/PageConsole.cpp b/Source/WebCore/page/PageConsole.cpp new file mode 100644 index 000000000..890c4b8f2 --- /dev/null +++ b/Source/WebCore/page/PageConsole.cpp @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2013 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "PageConsole.h" + +#include "Chrome.h" +#include "ChromeClient.h" +#include "ConsoleAPITypes.h" +#include "ConsoleTypes.h" +#include "Document.h" +#include "Frame.h" +#include "InspectorConsoleInstrumentation.h" +#include "InspectorController.h" +#include "Page.h" +#include "ScriptArguments.h" +#include "ScriptCallStack.h" +#include "ScriptCallStackFactory.h" +#include "ScriptValue.h" +#include "ScriptableDocumentParser.h" +#include "Settings.h" +#include <stdio.h> +#include <wtf/text/CString.h> +#include <wtf/text/WTFString.h> + +namespace WebCore { + +namespace { + int muteCount = 0; +} + +PageConsole::PageConsole(Page* page) : m_page(page) { } + +PageConsole::~PageConsole() { } + +void PageConsole::printSourceURLAndLine(const String& sourceURL, unsigned lineNumber) +{ + if (!sourceURL.isEmpty()) { + if (lineNumber > 0) + printf("%s:%d: ", sourceURL.utf8().data(), lineNumber); + else + printf("%s: ", sourceURL.utf8().data()); + } +} + +void PageConsole::printMessageSourceAndLevelPrefix(MessageSource source, MessageLevel level) +{ + const char* sourceString; + switch (source) { + case XMLMessageSource: + sourceString = "XML"; + break; + case JSMessageSource: + sourceString = "JS"; + break; + case NetworkMessageSource: + sourceString = "NETWORK"; + break; + case ConsoleAPIMessageSource: + sourceString = "CONSOLEAPI"; + break; + case StorageMessageSource: + sourceString = "STORAGE"; + break; + case AppCacheMessageSource: + sourceString = "APPCACHE"; + break; + case RenderingMessageSource: + sourceString = "RENDERING"; + break; + case CSSMessageSource: + sourceString = "CSS"; + break; + case SecurityMessageSource: + sourceString = "SECURITY"; + break; + case OtherMessageSource: + sourceString = "OTHER"; + break; + default: + ASSERT_NOT_REACHED(); + sourceString = "UNKNOWN"; + break; + } + + const char* levelString; + switch (level) { + case DebugMessageLevel: + levelString = "DEBUG"; + break; + case LogMessageLevel: + levelString = "LOG"; + break; + case WarningMessageLevel: + levelString = "WARN"; + break; + case ErrorMessageLevel: + levelString = "ERROR"; + break; + default: + ASSERT_NOT_REACHED(); + levelString = "UNKNOWN"; + break; + } + + printf("%s %s:", sourceString, levelString); +} + +void PageConsole::addMessage(MessageSource source, MessageLevel level, const String& message, unsigned long requestIdentifier, Document* document) +{ + String url; + if (document) + url = document->url().string(); + // FIXME: <http://webkit.org/b/114319> PageConsole::addMessage should automatically determine column number alongside line number + unsigned line = 0; + if (document && document->parsing() && !document->isInDocumentWrite() && document->scriptableDocumentParser()) { + ScriptableDocumentParser* parser = document->scriptableDocumentParser(); + if (!parser->isWaitingForScripts() && !parser->isExecutingScript()) + line = parser->lineNumber().oneBasedInt(); + } + addMessage(source, level, message, url, line, 0, 0, 0, requestIdentifier); +} + +void PageConsole::addMessage(MessageSource source, MessageLevel level, const String& message, PassRefPtr<ScriptCallStack> callStack) +{ + addMessage(source, level, message, String(), 0, 0, callStack, 0); +} + +void PageConsole::addMessage(MessageSource source, MessageLevel level, const String& message, const String& url, unsigned lineNumber, unsigned columnNumber, PassRefPtr<ScriptCallStack> callStack, ScriptState* state, unsigned long requestIdentifier) +{ + if (muteCount && source != ConsoleAPIMessageSource) + return; + + Page* page = this->page(); + if (!page) + return; + + if (callStack) + InspectorInstrumentation::addMessageToConsole(page, source, LogMessageType, level, message, callStack, requestIdentifier); + else + InspectorInstrumentation::addMessageToConsole(page, source, LogMessageType, level, message, url, lineNumber, columnNumber, state, requestIdentifier); + + if (source == CSSMessageSource) + return; + + if (page->settings()->privateBrowsingEnabled()) + return; + + page->chrome().client()->addMessageToConsole(source, level, message, lineNumber, columnNumber, url); + + if (!page->settings()->logsPageMessagesToSystemConsoleEnabled() && !shouldPrintExceptions()) + return; + + printSourceURLAndLine(url, lineNumber); + printMessageSourceAndLevelPrefix(source, level); + + printf(" %s\n", message.utf8().data()); +} + +// static +void PageConsole::mute() +{ + muteCount++; +} + +// static +void PageConsole::unmute() +{ + ASSERT(muteCount > 0); + muteCount--; +} + +static bool printExceptions = false; + +bool PageConsole::shouldPrintExceptions() +{ + return printExceptions; +} + +void PageConsole::setShouldPrintExceptions(bool print) +{ + printExceptions = print; +} + +} // namespace WebCore diff --git a/Source/WebCore/page/WebKitAnimation.idl b/Source/WebCore/page/PageConsole.h index 2618be085..cf9974663 100644 --- a/Source/WebCore/page/WebKitAnimation.idl +++ b/Source/WebCore/page/PageConsole.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Apple Inc. All rights reserved. + * Copyright (C) 2013 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,30 +26,46 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -interface WebKitAnimation { +#ifndef PageConsole_h +#define PageConsole_h - readonly attribute DOMString name; +#include "ConsoleTypes.h" +#include "ScriptCallStack.h" +#include "ScriptState.h" +#include <wtf/Forward.h> +#include <wtf/PassOwnPtr.h> - readonly attribute double duration; - attribute double elapsedTime; +namespace WebCore { - readonly attribute double delay; - [Custom] readonly attribute long iterationCount; +class Document; +class Page; - readonly attribute boolean paused; - readonly attribute boolean ended; +class PageConsole { +public: + static PassOwnPtr<PageConsole> create(Page* page) { return adoptPtr(new PageConsole(page)); } + virtual ~PageConsole(); - const unsigned short DIRECTION_NORMAL = 0; - const unsigned short DIRECTION_ALTERNATE = 1; - readonly attribute unsigned short direction; + static void printSourceURLAndLine(const String& sourceURL, unsigned lineNumber); + static void printMessageSourceAndLevelPrefix(MessageSource, MessageLevel); - const unsigned short FILL_NONE = 0; - const unsigned short FILL_BACKWARDS = 1; - const unsigned short FILL_FORWARDS = 2; - const unsigned short FILL_BOTH = 3; - readonly attribute unsigned short fillMode; + void addMessage(MessageSource, MessageLevel, const String& message, const String& sourceURL, unsigned lineNumber, unsigned columnNumber, PassRefPtr<ScriptCallStack> = 0, ScriptState* = 0, unsigned long requestIdentifier = 0); + void addMessage(MessageSource, MessageLevel, const String& message, PassRefPtr<ScriptCallStack>); + void addMessage(MessageSource, MessageLevel, const String& message, unsigned long requestIdentifier = 0, Document* = 0); - void play(); - void pause(); + static void mute(); + static void unmute(); + + static bool shouldPrintExceptions(); + static void setShouldPrintExceptions(bool); + +private: + PageConsole(Page*); + + Page* page() { return m_page; }; + + Page* m_page; }; +} // namespace WebCore + +#endif // PageConsole_h diff --git a/Source/WebCore/page/PageGroup.cpp b/Source/WebCore/page/PageGroup.cpp index f93c0b734..fe9be7350 100644 --- a/Source/WebCore/page/PageGroup.cpp +++ b/Source/WebCore/page/PageGroup.cpp @@ -28,6 +28,7 @@ #include "Chrome.h" #include "ChromeClient.h" +#include "DOMWrapperWorld.h" #include "Document.h" #include "DocumentStyleSheetCollection.h" #include "Frame.h" @@ -39,17 +40,13 @@ #include "StorageNamespace.h" #if ENABLE(VIDEO_TRACK) -#if PLATFORM(MAC) -#include "CaptionUserPreferencesMac.h" +#if (PLATFORM(MAC) && !PLATFORM(IOS)) || HAVE(MEDIA_ACCESSIBILITY_FRAMEWORK) +#include "CaptionUserPreferencesMediaAF.h" #else #include "CaptionUserPreferences.h" #endif #endif -#if PLATFORM(CHROMIUM) -#include "VisitedLinks.h" -#endif - namespace WebCore { static unsigned getUniqueIdentifier() @@ -144,9 +141,21 @@ void PageGroup::clearLocalStorageForOrigin(SecurityOrigin* origin) for (PageGroupMap::iterator it = pageGroups->begin(); it != end; ++it) { if (it->value->hasLocalStorage()) it->value->localStorage()->clearOriginForDeletion(origin); - } + } } - + +void PageGroup::closeIdleLocalStorageDatabases() +{ + if (!pageGroups) + return; + + PageGroupMap::iterator end = pageGroups->end(); + for (PageGroupMap::iterator it = pageGroups->begin(); it != end; ++it) { + if (it->value->hasLocalStorage()) + it->value->localStorage()->closeIdleLocalStorageDatabases(); + } +} + void PageGroup::syncLocalStorage() { if (!pageGroups) @@ -183,17 +192,12 @@ void PageGroup::removePage(Page* page) bool PageGroup::isLinkVisited(LinkHash visitedLinkHash) { -#if PLATFORM(CHROMIUM) - // Use Chromium's built-in visited link database. - return VisitedLinks::isLinkVisited(visitedLinkHash); -#else if (!m_visitedLinksPopulated) { m_visitedLinksPopulated = true; ASSERT(!m_pages.isEmpty()); - (*m_pages.begin())->chrome()->client()->populateVisitedLinks(); + (*m_pages.begin())->chrome().client()->populateVisitedLinks(); } return m_visitedLinkHashes.contains(visitedLinkHash); -#endif } void PageGroup::addVisitedLinkHash(LinkHash hash) @@ -205,10 +209,8 @@ void PageGroup::addVisitedLinkHash(LinkHash hash) inline void PageGroup::addVisitedLink(LinkHash hash) { ASSERT(shouldTrackVisitedLinks); -#if !PLATFORM(CHROMIUM) if (!m_visitedLinkHashes.add(hash).isNewEntry) return; -#endif Page::visitedStateChanged(this, hash); pageCache()->markPagesForVistedLinkStyleRecalc(); } @@ -255,20 +257,22 @@ void PageGroup::setShouldTrackVisitedLinks(bool shouldTrack) StorageNamespace* PageGroup::localStorage() { - if (!m_localStorage) { - // Need a page in this page group to query the settings for the local storage database path. - // Having these parameters attached to the page settings is unfortunate since these settings are - // not per-page (and, in fact, we simply grab the settings from some page at random), but - // at this point we're stuck with it. - Page* page = *m_pages.begin(); - const String& path = page->settings()->localStorageDatabasePath(); - unsigned quota = m_groupSettings->localStorageQuotaBytes(); - m_localStorage = StorageNamespace::localStorageNamespace(path, quota); - } + if (!m_localStorage) + m_localStorage = StorageNamespace::localStorageNamespace(this); return m_localStorage.get(); } +StorageNamespace* PageGroup::transientLocalStorage(SecurityOrigin* topOrigin) +{ + HashMap<RefPtr<SecurityOrigin>, RefPtr<StorageNamespace> >::AddResult result = m_transientLocalStorageMap.add(topOrigin, 0); + + if (result.isNewEntry) + result.iterator->value = StorageNamespace::transientLocalStorageNamespace(this, topOrigin); + + return result.iterator->value.get(); +} + void PageGroup::addUserScriptToWorld(DOMWrapperWorld* world, const String& source, const KURL& url, const Vector<String>& whitelist, const Vector<String>& blacklist, UserScriptInjectionTime injectionTime, UserContentInjectedFrames injectedFrames) @@ -405,44 +409,24 @@ void PageGroup::invalidatedInjectedStyleSheetCacheInAllFrames() } #if ENABLE(VIDEO_TRACK) +void PageGroup::captionPreferencesChanged() +{ + for (HashSet<Page*>::iterator i = m_pages.begin(); i != m_pages.end(); ++i) + (*i)->captionPreferencesChanged(); + pageCache()->markPagesForCaptionPreferencesChanged(); +} + CaptionUserPreferences* PageGroup::captionPreferences() { if (!m_captionPreferences) -#if PLATFORM(MAC) - m_captionPreferences = CaptionUserPreferencesMac::create(this); +#if (PLATFORM(MAC) && !PLATFORM(IOS)) || HAVE(MEDIA_ACCESSIBILITY_FRAMEWORK) + m_captionPreferences = CaptionUserPreferencesMediaAF::create(this); #else m_captionPreferences = CaptionUserPreferences::create(this); #endif return m_captionPreferences.get(); } - -void PageGroup::registerForCaptionPreferencesChangedCallbacks(CaptionPreferencesChangedListener* listener) -{ - captionPreferences()->registerForCaptionPreferencesChangedCallbacks(listener); -} - -void PageGroup::unregisterForCaptionPreferencesChangedCallbacks(CaptionPreferencesChangedListener* listener) -{ - if (!m_captionPreferences) - return; - captionPreferences()->unregisterForCaptionPreferencesChangedCallbacks(listener); -} - -bool PageGroup::userPrefersCaptions() -{ - return captionPreferences()->userPrefersCaptions(); -} - -bool PageGroup::userHasCaptionPreferences() -{ - return captionPreferences()->userPrefersCaptions(); -} - -float PageGroup::captionFontSizeScale() -{ - return captionPreferences()->captionFontSizeScale(); -} #endif diff --git a/Source/WebCore/page/PageGroup.h b/Source/WebCore/page/PageGroup.h index 6284fa8ff..301ca44ad 100644 --- a/Source/WebCore/page/PageGroup.h +++ b/Source/WebCore/page/PageGroup.h @@ -26,13 +26,13 @@ #ifndef PageGroup_h #define PageGroup_h -#include <wtf/HashSet.h> -#include <wtf/Noncopyable.h> #include "LinkHash.h" +#include "SecurityOriginHash.h" #include "Supplementable.h" #include "UserScript.h" #include "UserStyleSheet.h" -#include <wtf/text/StringHash.h> +#include <wtf/HashSet.h> +#include <wtf/Noncopyable.h> namespace WebCore { @@ -60,6 +60,7 @@ namespace WebCore { static void clearLocalStorageForAllOrigins(); static void clearLocalStorageForOrigin(SecurityOrigin*); + static void closeIdleLocalStorageDatabases(); // DumpRenderTree helper that triggers a StorageArea sync. static void syncLocalStorage(); @@ -86,6 +87,8 @@ namespace WebCore { StorageNamespace* localStorage(); bool hasLocalStorage() { return m_localStorage; } + StorageNamespace* transientLocalStorage(SecurityOrigin* topOrigin); + void addUserScriptToWorld(DOMWrapperWorld*, const String& source, const KURL&, const Vector<String>& whitelist, const Vector<String>& blacklist, UserScriptInjectionTime, UserContentInjectedFrames); @@ -108,22 +111,16 @@ namespace WebCore { GroupSettings* groupSettings() const { return m_groupSettings.get(); } #if ENABLE(VIDEO_TRACK) - bool userPrefersCaptions(); - bool userHasCaptionPreferences(); - float captionFontSizeScale(); - void registerForCaptionPreferencesChangedCallbacks(CaptionPreferencesChangedListener*); - void unregisterForCaptionPreferencesChangedCallbacks(CaptionPreferencesChangedListener*); + void captionPreferencesChanged(); + CaptionUserPreferences* captionPreferences(); #endif private: PageGroup(Page*); - void addVisitedLink(LinkHash stringHash); + void addVisitedLink(LinkHash); void invalidatedInjectedStyleSheetCacheInAllFrames(); - -#if ENABLE(VIDEO_TRACK) - CaptionUserPreferences* captionPreferences(); -#endif + String m_name; HashSet<Page*> m_pages; @@ -133,6 +130,7 @@ namespace WebCore { unsigned m_identifier; RefPtr<StorageNamespace> m_localStorage; + HashMap<RefPtr<SecurityOrigin>, RefPtr<StorageNamespace> > m_transientLocalStorageMap; OwnPtr<UserScriptMap> m_userScripts; OwnPtr<UserStyleSheetMap> m_userStyleSheets; diff --git a/Source/WebCore/page/PageGroupLoadDeferrer.cpp b/Source/WebCore/page/PageGroupLoadDeferrer.cpp index 751a79844..936e5c8f5 100644 --- a/Source/WebCore/page/PageGroupLoadDeferrer.cpp +++ b/Source/WebCore/page/PageGroupLoadDeferrer.cpp @@ -65,7 +65,7 @@ PageGroupLoadDeferrer::~PageGroupLoadDeferrer() page->setDefersLoading(false); for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext()) - frame->document()->resumeScheduledTasks(); + frame->document()->resumeScheduledTasks(ActiveDOMObject::WillDeferLoading); } } } diff --git a/Source/WebCore/page/PagePopup.h b/Source/WebCore/page/PagePopup.h deleted file mode 100644 index 26713cb82..000000000 --- a/Source/WebCore/page/PagePopup.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2012 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef PagePopup_h -#define PagePopup_h - -#if ENABLE(PAGE_POPUP) -namespace WebCore { - -// A PagePopup object is created by ChromeClient::openPagePopup(), and deleted -// by ChromeClient::closePagePopup(). -class PagePopup { -protected: - virtual ~PagePopup() { } -}; - -} -#endif -#endif diff --git a/Source/WebCore/page/PagePopupClient.cpp b/Source/WebCore/page/PagePopupClient.cpp deleted file mode 100644 index 7dab828b7..000000000 --- a/Source/WebCore/page/PagePopupClient.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2012 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "PagePopupClient.h" - -#if ENABLE(PAGE_POPUP) - -#include <wtf/text/StringBuilder.h> - -namespace WebCore { - -#define addLiteral(literal, writer) writer.addData(literal, sizeof(literal) - 1) - -void PagePopupClient::addJavaScriptString(const String& str, DocumentWriter& writer) -{ - addLiteral("\"", writer); - StringBuilder builder; - builder.reserveCapacity(str.length()); - for (unsigned i = 0; i < str.length(); ++i) { - if (str[i] == '\\' || str[i] == '"') - builder.append('\\'); - builder.append(str[i]); - } - addString(builder.toString(), writer); - addLiteral("\"", writer); -} - -void PagePopupClient::addProperty(const char* name, const String& value, DocumentWriter& writer) -{ - writer.addData(name, strlen(name)); - addLiteral(": ", writer); - addJavaScriptString(value, writer); - addLiteral(",\n", writer); -} - -void PagePopupClient::addProperty(const char* name, int value, DocumentWriter& writer) -{ - writer.addData(name, strlen(name)); - addLiteral(": ", writer); - addString(String::number(value), writer); - addLiteral(",\n", writer); -} - -void PagePopupClient::addProperty(const char* name, unsigned value, DocumentWriter& writer) -{ - writer.addData(name, strlen(name)); - addLiteral(": ", writer); - addString(String::number(value), writer); - addLiteral(",\n", writer); -} - -void PagePopupClient::addProperty(const char* name, bool value, DocumentWriter& writer) -{ - writer.addData(name, strlen(name)); - addLiteral(": ", writer); - if (value) - addLiteral("true", writer); - else - addLiteral("false", writer); - addLiteral(",\n", writer); -} - -void PagePopupClient::addProperty(const char* name, const Vector<String>& values, DocumentWriter& writer) -{ - writer.addData(name, strlen(name)); - addLiteral(": [", writer); - for (unsigned i = 0; i < values.size(); ++i) { - if (i) - addLiteral(",", writer); - addJavaScriptString(values[i], writer); - } - addLiteral("],\n", writer); -} - -void PagePopupClient::addProperty(const char* name, const IntRect& rect, DocumentWriter& writer) -{ - writer.addData(name, strlen(name)); - addLiteral(": {", writer); - addProperty("x", rect.x(), writer); - addProperty("y", rect.y(), writer); - addProperty("width", rect.width(), writer); - addProperty("height", rect.height(), writer); - addLiteral("},\n", writer); -} - -} // namespace WebCore - -#endif // ENABLE(PAGE_POPUP) diff --git a/Source/WebCore/page/PagePopupClient.h b/Source/WebCore/page/PagePopupClient.h deleted file mode 100644 index 391c8f83e..000000000 --- a/Source/WebCore/page/PagePopupClient.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2012 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef PagePopupClient_h -#define PagePopupClient_h - -#if ENABLE(PAGE_POPUP) - -#include "DocumentWriter.h" -#include "IntRect.h" -#include <wtf/text/WTFString.h> - -namespace WebCore { - -class DocumentWriter; -class Locale; - -class PagePopupClient { -public: - virtual IntSize contentSize() = 0; - - // Provide an HTML source through the specified DocumentWriter. The HTML - // source is rendered in a PagePopup. - // The content HTML supports: - // - No <select> popups - // - window.setValueAndClosePopup(number, string). - virtual void writeDocument(DocumentWriter&) = 0; - - // Returns a Locale object associated to the client. - virtual Locale& locale() = 0; - - // This is called by the content HTML of a PagePopup. - // An implementation of this function should call ChromeClient::closePagePopup(). - virtual void setValueAndClosePopup(int numValue, const String& stringValue) = 0; - - // This is called whenever a PagePopup was closed. - virtual void didClosePopup() = 0; - - virtual ~PagePopupClient() { } - - // Helper functions to be used in PagePopupClient::writeDocument(). - static void addString(const String&, DocumentWriter&); - static void addJavaScriptString(const String&, DocumentWriter&); - static void addProperty(const char* name, const String& value, DocumentWriter&); - static void addProperty(const char* name, int value, DocumentWriter&); - static void addProperty(const char* name, unsigned value, DocumentWriter&); - static void addProperty(const char* name, bool value, DocumentWriter&); - static void addProperty(const char* name, const Vector<String>& values, DocumentWriter&); - static void addProperty(const char* name, const IntRect&, DocumentWriter&); -}; - -inline void PagePopupClient::addString(const String& str, DocumentWriter& writer) -{ - CString str8 = str.utf8(); - writer.addData(str8.data(), str8.length()); -} - -} -#endif -#endif diff --git a/Source/WebCore/page/PagePopupController.cpp b/Source/WebCore/page/PagePopupController.cpp deleted file mode 100644 index 6e7cdb3ea..000000000 --- a/Source/WebCore/page/PagePopupController.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2012 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "PagePopupController.h" - -#if ENABLE(PAGE_POPUP) -#include "PagePopupClient.h" -#include "PlatformLocale.h" - -namespace WebCore { - -PagePopupController::PagePopupController(PagePopupClient* client) - : m_popupClient(client) -{ - ASSERT(client); -} - -PassRefPtr<PagePopupController> PagePopupController::create(PagePopupClient* client) -{ - return adoptRef(new PagePopupController(client)); -} - -void PagePopupController::setValueAndClosePopup(int numValue, const String& stringValue) -{ - if (m_popupClient) - m_popupClient->setValueAndClosePopup(numValue, stringValue); -} - -String PagePopupController::localizeNumberString(const String& numberString) -{ - if (m_popupClient) - return m_popupClient->locale().convertToLocalizedNumber(numberString); - return numberString; -} - -#if ENABLE(CALENDAR_PICKER) -String PagePopupController::formatMonth(int year, int zeroBaseMonth) -{ - if (!m_popupClient) - return emptyString(); - DateComponents date; - date.setMonthsSinceEpoch((year - 1970) * 12.0 + zeroBaseMonth); - return m_popupClient->locale().formatDateTime(date); -} -#endif - -void PagePopupController::clearPagePopupClient() -{ - m_popupClient = 0; -} - -} -#endif diff --git a/Source/WebCore/page/PagePopupController.h b/Source/WebCore/page/PagePopupController.h deleted file mode 100644 index 2edacbce2..000000000 --- a/Source/WebCore/page/PagePopupController.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2012 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef PagePopupController_h -#define PagePopupController_h - -#if ENABLE(PAGE_POPUP) - -#include <wtf/Forward.h> -#include <wtf/RefCounted.h> - -namespace WebCore { - -class PagePopupClient; - -class PagePopupController : public RefCounted<PagePopupController> { -public: - static PassRefPtr<PagePopupController> create(PagePopupClient*); - void setValueAndClosePopup(int numValue, const String& stringValue); - String localizeNumberString(const String&); -#if ENABLE(CALENDAR_PICKER) - String formatMonth(int year, int zeroBaseMonth); -#endif - void clearPagePopupClient(); - -private: - explicit PagePopupController(PagePopupClient*); - - PagePopupClient* m_popupClient; -}; - -} -#endif -#endif diff --git a/Source/WebCore/page/PagePopupController.idl b/Source/WebCore/page/PagePopupController.idl deleted file mode 100644 index f1d6e475b..000000000 --- a/Source/WebCore/page/PagePopupController.idl +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2012 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -[ - Conditional=PAGE_POPUP -] interface PagePopupController { - void setValueAndClosePopup(in long numberValue, in DOMString stringValue); - DOMString localizeNumberString(in DOMString numberString); - [Conditional=CALENDAR_PICKER] DOMString formatMonth(in long year, in long zeroBaseMonth); -}; diff --git a/Source/WebCore/page/PagePopupDriver.h b/Source/WebCore/page/PagePopupDriver.h deleted file mode 100644 index 695d622c8..000000000 --- a/Source/WebCore/page/PagePopupDriver.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2012 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef PagePopupDriver_h -#define PagePopupDriver_h - -namespace WebCore { - -class IntRect; -class PagePopup; -class PagePopupClient; - -class PagePopupDriver { -public: - virtual PagePopup* openPagePopup(PagePopupClient*, const IntRect& originBoundsInRootView) = 0; - virtual void closePagePopup(PagePopup*) = 0; - virtual ~PagePopupDriver() { } -}; - -} -#endif diff --git a/Source/WebCore/page/PageSerializer.cpp b/Source/WebCore/page/PageSerializer.cpp index 63dbd174e..32facf60c 100644 --- a/Source/WebCore/page/PageSerializer.cpp +++ b/Source/WebCore/page/PageSerializer.cpp @@ -52,6 +52,7 @@ #include "Page.h" #include "StyleCachedImage.h" #include "StyleImage.h" +#include "StylePropertySet.h" #include "StyleRule.h" #include "StyleSheetContents.h" #include "Text.h" @@ -149,7 +150,7 @@ void SerializerMarkupAccumulator::appendCustomAttributes(StringBuilder& out, Ele if (!element->isFrameOwnerElement()) return; - HTMLFrameOwnerElement* frameOwner = static_cast<HTMLFrameOwnerElement*>(element); + HTMLFrameOwnerElement* frameOwner = toFrameOwnerElement(element); Frame* frame = frameOwner->contentFrame(); if (!frame) return; @@ -230,8 +231,8 @@ void PageSerializer::serializeFrame(Frame* frame) if (element->isStyledElement()) retrieveResourcesForProperties(static_cast<StyledElement*>(element)->inlineStyle(), document); - if (element->hasTagName(HTMLNames::imgTag)) { - HTMLImageElement* imageElement = static_cast<HTMLImageElement*>(element); + if (isHTMLImageElement(element)) { + HTMLImageElement* imageElement = toHTMLImageElement(element); KURL url = document->completeURL(imageElement->getAttribute(HTMLNames::srcAttr)); CachedImage* cachedImage = imageElement->cachedImage(); addImageToResources(cachedImage, imageElement->renderer(), url); @@ -242,9 +243,8 @@ void PageSerializer::serializeFrame(Frame* frame) serializeCSSStyleSheet(sheet, url); ASSERT(m_resourceURLs.contains(url)); } - } else if (element->hasTagName(HTMLNames::styleTag)) { - HTMLStyleElement* styleElement = static_cast<HTMLStyleElement*>(element); - if (CSSStyleSheet* sheet = styleElement->sheet()) + } else if (isHTMLStyleElement(element)) { + if (CSSStyleSheet* sheet = toHTMLStyleElement(element)->sheet()) serializeCSSStyleSheet(sheet, KURL()); } } diff --git a/Source/WebCore/page/PageThrottler.cpp b/Source/WebCore/page/PageThrottler.cpp new file mode 100644 index 000000000..61ba2f1c1 --- /dev/null +++ b/Source/WebCore/page/PageThrottler.cpp @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2013 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "PageThrottler.h" + +#include "Chrome.h" +#include "ChromeClient.h" +#include "Frame.h" +#include "Page.h" +#include "PageActivityAssertionToken.h" + +namespace WebCore { + +static const double kThrottleHysteresisSeconds = 2.0; + +PageThrottler::PageThrottler(Page* page) + : m_page(page) + , m_throttleState(PageNotThrottledState) + , m_throttleHysteresisTimer(this, &PageThrottler::throttleHysteresisTimerFired) +{ + if (ChromeClient* chromeClient = m_page->chrome().client()) + chromeClient->incrementActivePageCount(); +} + +PageThrottler::~PageThrottler() +{ + setThrottled(false); + + for (HashSet<PageActivityAssertionToken*>::iterator i = m_activityTokens.begin(); i != m_activityTokens.end(); ++i) + (*i)->invalidate(); + + if (m_throttleState != PageThrottledState) { + if (ChromeClient* chromeClient = m_page->chrome().client()) + chromeClient->decrementActivePageCount(); + } +} + +void PageThrottler::throttlePage() +{ + m_throttleState = PageThrottledState; + + if (ChromeClient* chromeClient = m_page->chrome().client()) + chromeClient->decrementActivePageCount(); + + for (Frame* frame = m_page->mainFrame(); frame; frame = frame->tree()->traverseNext()) { + if (frame->document()) + frame->document()->scriptedAnimationControllerSetThrottled(true); + } + + m_page->throttleTimers(); +} + +void PageThrottler::unthrottlePage() +{ + PageThrottleState oldState = m_throttleState; + m_throttleState = PageNotThrottledState; + + if (oldState == PageNotThrottledState) + return; + + if (oldState == PageThrottledState) { + if (ChromeClient* chromeClient = m_page->chrome().client()) + chromeClient->incrementActivePageCount(); + } + + for (Frame* frame = m_page->mainFrame(); frame; frame = frame->tree()->traverseNext()) { + if (frame->document()) + frame->document()->scriptedAnimationControllerSetThrottled(false); + } + + m_page->unthrottleTimers(); +} + +void PageThrottler::setThrottled(bool isThrottled) +{ + if (isThrottled) { + m_throttleState = PageWaitingToThrottleState; + startThrottleHysteresisTimer(); + } else { + unthrottlePage(); + stopThrottleHysteresisTimer(); + } +} + +void PageThrottler::stopThrottleHysteresisTimer() +{ + m_throttleHysteresisTimer.stop(); +} + +void PageThrottler::reportInterestingEvent() +{ + if (m_throttleState == PageNotThrottledState) + return; + if (m_throttleState == PageThrottledState) + unthrottlePage(); + m_throttleState = PageWaitingToThrottleState; + startThrottleHysteresisTimer(); +} + +void PageThrottler::startThrottleHysteresisTimer() +{ + if (m_throttleHysteresisTimer.isActive()) + m_throttleHysteresisTimer.stop(); + if (!m_activityTokens.size()) + m_throttleHysteresisTimer.startOneShot(kThrottleHysteresisSeconds); +} + +void PageThrottler::throttleHysteresisTimerFired(Timer<PageThrottler>*) +{ + ASSERT(!m_activityTokens.size()); + throttlePage(); +} + +void PageThrottler::addActivityToken(PageActivityAssertionToken* token) +{ + ASSERT(token && !m_activityTokens.contains(token)); + + m_activityTokens.add(token); + + // If we've already got events that block throttling we can return early + if (m_activityTokens.size() > 1) + return; + + if (m_throttleState == PageNotThrottledState) + return; + + if (m_throttleState == PageThrottledState) + unthrottlePage(); + + m_throttleState = PageWaitingToThrottleState; + stopThrottleHysteresisTimer(); +} + +void PageThrottler::removeActivityToken(PageActivityAssertionToken* token) +{ + ASSERT(token && m_activityTokens.contains(token)); + + m_activityTokens.remove(token); + + if (m_activityTokens.size()) + return; + + if (m_throttleState == PageNotThrottledState) + return; + + ASSERT(m_throttleState == PageWaitingToThrottleState); + startThrottleHysteresisTimer(); +} + +} diff --git a/Source/WebCore/page/PageThrottler.h b/Source/WebCore/page/PageThrottler.h new file mode 100644 index 000000000..26dc8fab5 --- /dev/null +++ b/Source/WebCore/page/PageThrottler.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2013 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PageThrottler_h +#define PageThrottler_h + +#include "Timer.h" + +#include <wtf/HashSet.h> +#include <wtf/OwnPtr.h> +#include <wtf/PassOwnPtr.h> + +namespace WebCore { + +class Page; +class PageActivityAssertionToken; + +class PageThrottler { +public: + static PassOwnPtr<PageThrottler> create(Page* page) + { + return adoptPtr(new PageThrottler(page)); + } + + bool shouldThrottleAnimations() const { return m_throttleState != PageNotThrottledState; } + bool shouldThrottleTimers() const { return m_throttleState != PageNotThrottledState; } + + void setThrottled(bool); + + void reportInterestingEvent(); + + ~PageThrottler(); + +private: + enum PageThrottleState { + PageNotThrottledState, + PageWaitingToThrottleState, + PageThrottledState + }; + + friend class PageActivityAssertionToken; + void addActivityToken(PageActivityAssertionToken*); + void removeActivityToken(PageActivityAssertionToken*); + + PageThrottler(Page*); + void startThrottleHysteresisTimer(); + void stopThrottleHysteresisTimer(); + void throttleHysteresisTimerFired(Timer<PageThrottler>*); + + Page* m_page; + + void throttlePage(); + void unthrottlePage(); + + PageThrottleState m_throttleState; + Timer<PageThrottler> m_throttleHysteresisTimer; + HashSet<PageActivityAssertionToken*> m_activityTokens; +}; + +} +#endif diff --git a/Source/WebCore/page/Performance.cpp b/Source/WebCore/page/Performance.cpp index e6871b7b7..9dcf46e13 100644 --- a/Source/WebCore/page/Performance.cpp +++ b/Source/WebCore/page/Performance.cpp @@ -34,7 +34,6 @@ #include "Document.h" #include "DocumentLoader.h" -#include "MemoryInfo.h" #include "PerformanceEntry.h" #include "PerformanceNavigation.h" #include "PerformanceResourceTiming.h" @@ -80,11 +79,6 @@ ScriptExecutionContext* Performance::scriptExecutionContext() const return frame()->document(); } -PassRefPtr<MemoryInfo> Performance::memory() const -{ - return MemoryInfo::create(m_frame); -} - PerformanceNavigation* Performance::navigation() const { if (!m_navigation) @@ -102,7 +96,6 @@ PerformanceTiming* Performance::timing() const } #if ENABLE(PERFORMANCE_TIMELINE) - PassRefPtr<PerformanceEntryList> Performance::webkitGetEntries() const { RefPtr<PerformanceEntryList> entries = PerformanceEntryList::create(); diff --git a/Source/WebCore/page/Performance.h b/Source/WebCore/page/Performance.h index 44db7c817..9f4e60285 100644 --- a/Source/WebCore/page/Performance.h +++ b/Source/WebCore/page/Performance.h @@ -36,7 +36,6 @@ #include "DOMWindowProperty.h" #include "EventTarget.h" -#include "MemoryInfo.h" #include "PerformanceEntryList.h" #include "PerformanceNavigation.h" #include "PerformanceTiming.h" @@ -61,7 +60,6 @@ public: virtual const AtomicString& interfaceName() const; virtual ScriptExecutionContext* scriptExecutionContext() const; - PassRefPtr<MemoryInfo> memory() const; PerformanceNavigation* navigation() const; PerformanceTiming* timing() const; double now() const; @@ -105,7 +103,7 @@ private: mutable RefPtr<PerformanceNavigation> m_navigation; mutable RefPtr<PerformanceTiming> m_timing; - + #if ENABLE(RESOURCE_TIMING) Vector<RefPtr<PerformanceEntry> > m_resourceTimingBuffer; unsigned m_resourceTimingBufferSize; diff --git a/Source/WebCore/page/Performance.idl b/Source/WebCore/page/Performance.idl index 776203b79..53e8390db 100644 --- a/Source/WebCore/page/Performance.idl +++ b/Source/WebCore/page/Performance.idl @@ -33,34 +33,30 @@ [ Conditional=WEB_TIMING, EventTarget, - OmitConstructor ] interface Performance { readonly attribute PerformanceNavigation navigation; readonly attribute PerformanceTiming timing; - readonly attribute MemoryInfo memory; #if defined(ENABLE_PERFORMANCE_TIMELINE) && ENABLE_PERFORMANCE_TIMELINE PerformanceEntryList webkitGetEntries(); - PerformanceEntryList webkitGetEntriesByType(in DOMString entryType); - PerformanceEntryList webkitGetEntriesByName(in DOMString name, in [Optional=DefaultIsNullString] DOMString entryType); + PerformanceEntryList webkitGetEntriesByType(DOMString entryType); + PerformanceEntryList webkitGetEntriesByName(DOMString name, [Default=NullString] optional DOMString entryType); #endif #if defined(ENABLE_RESOURCE_TIMING) && ENABLE_RESOURCE_TIMING void webkitClearResourceTimings(); - void webkitSetResourceTimingBufferSize(in unsigned long maxSize); + void webkitSetResourceTimingBufferSize(unsigned long maxSize); attribute EventListener onwebkitresourcetimingbufferfull; #endif // See http://www.w3.org/TR/2012/CR-user-timing-20120726/ #if defined(ENABLE_USER_TIMING) && ENABLE_USER_TIMING - void webkitMark(in DOMString markName) - raises(DOMException); - void webkitClearMarks(in [Optional=DefaultIsNullString] DOMString markName); + [RaisesException] void webkitMark(DOMString markName); + void webkitClearMarks([Default=NullString] optional DOMString markName); - void webkitMeasure(in DOMString measureName, in [Optional=DefaultIsNullString] DOMString startMark, in [Optional=DefaultIsNullString] DOMString endMark) - raises(DOMException); - void webkitClearMeasures(in [Optional=DefaultIsNullString] DOMString measureName); + [RaisesException] void webkitMeasure(DOMString measureName, [Default=NullString] optional DOMString startMark, [Default=NullString] optional DOMString endMark); + void webkitClearMeasures([Default=NullString] optional DOMString measureName); #endif // See http://www.w3.org/TR/hr-time/ for details. diff --git a/Source/WebCore/page/PerformanceEntry.h b/Source/WebCore/page/PerformanceEntry.h index 4db101db0..129a24640 100644 --- a/Source/WebCore/page/PerformanceEntry.h +++ b/Source/WebCore/page/PerformanceEntry.h @@ -51,6 +51,8 @@ public: double duration() const; virtual bool isResource() { return false; } + virtual bool isMark() { return false; } + virtual bool isMeasure() { return false; } static bool startTimeCompareLessThan(PassRefPtr<PerformanceEntry> a, PassRefPtr<PerformanceEntry> b) { diff --git a/Source/WebCore/page/PerformanceEntry.idl b/Source/WebCore/page/PerformanceEntry.idl index ff38ded7c..23f79479b 100644 --- a/Source/WebCore/page/PerformanceEntry.idl +++ b/Source/WebCore/page/PerformanceEntry.idl @@ -33,7 +33,6 @@ Conditional=WEB_TIMING, Conditional=PERFORMANCE_TIMELINE, CustomToJSObject, - OmitConstructor ] interface PerformanceEntry { readonly attribute DOMString name; readonly attribute DOMString entryType; diff --git a/Source/WebCore/page/PerformanceEntryList.cpp b/Source/WebCore/page/PerformanceEntryList.cpp index 0a8cc6ab9..f399e0764 100644 --- a/Source/WebCore/page/PerformanceEntryList.cpp +++ b/Source/WebCore/page/PerformanceEntryList.cpp @@ -65,7 +65,7 @@ void PerformanceEntryList::append(PassRefPtr<PerformanceEntry> entry) void PerformanceEntryList::appendAll(const Vector<RefPtr<PerformanceEntry> >& entries) { - m_entries.append(entries); + m_entries.appendVector(entries); } void PerformanceEntryList::sort() diff --git a/Source/WebCore/page/PerformanceEntryList.idl b/Source/WebCore/page/PerformanceEntryList.idl index 9226541c8..4dc9ebf05 100644 --- a/Source/WebCore/page/PerformanceEntryList.idl +++ b/Source/WebCore/page/PerformanceEntryList.idl @@ -30,12 +30,12 @@ // See: https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/PerformanceTimeline/Overview.html [ + NoInterfaceObject, Conditional=WEB_TIMING, Conditional=PERFORMANCE_TIMELINE, - OmitConstructor, - IndexedGetter + ImplementationLacksVTable ] interface PerformanceEntryList { readonly attribute unsigned long length; - PerformanceEntry item(in unsigned long index); + getter PerformanceEntry item(unsigned long index); }; diff --git a/Source/WebCore/page/PerformanceMark.h b/Source/WebCore/page/PerformanceMark.h index d131860aa..64b39abfd 100644 --- a/Source/WebCore/page/PerformanceMark.h +++ b/Source/WebCore/page/PerformanceMark.h @@ -38,8 +38,10 @@ class PerformanceMark : public PerformanceEntry { public: static PassRefPtr<PerformanceMark> create(const String& name, double startTime) { return adoptRef(new PerformanceMark(name, startTime)); } + virtual bool isMark() { return true; } + private: - PerformanceMark(const String& name, double startTime) : PerformanceEntry(name, "mark", startTime, 0.0) { } + PerformanceMark(const String& name, double startTime) : PerformanceEntry(name, "mark", startTime, startTime) { } ~PerformanceMark() { } }; diff --git a/Source/WebCore/page/PerformanceMark.idl b/Source/WebCore/page/PerformanceMark.idl index 85c12e043..45ba6b1b3 100644 --- a/Source/WebCore/page/PerformanceMark.idl +++ b/Source/WebCore/page/PerformanceMark.idl @@ -25,6 +25,5 @@ [ Conditional=USER_TIMING, - OmitConstructor ] interface PerformanceMark : PerformanceEntry { }; diff --git a/Source/WebCore/page/PerformanceMeasure.h b/Source/WebCore/page/PerformanceMeasure.h index b0243d1f4..65564959b 100644 --- a/Source/WebCore/page/PerformanceMeasure.h +++ b/Source/WebCore/page/PerformanceMeasure.h @@ -38,6 +38,8 @@ class PerformanceMeasure : public PerformanceEntry { public: static PassRefPtr<PerformanceMeasure> create(const String& name, double startTime, double duration) { return adoptRef(new PerformanceMeasure(name, startTime, duration)); } + virtual bool isMeasure() { return true; } + private: PerformanceMeasure(const String& name, double startTime, double duration) : PerformanceEntry(name, "measure", startTime, duration) { } ~PerformanceMeasure() { } diff --git a/Source/WebCore/page/PerformanceMeasure.idl b/Source/WebCore/page/PerformanceMeasure.idl index 3900eb59b..5dfcbb7c7 100644 --- a/Source/WebCore/page/PerformanceMeasure.idl +++ b/Source/WebCore/page/PerformanceMeasure.idl @@ -25,6 +25,5 @@ [ Conditional=USER_TIMING, - OmitConstructor ] interface PerformanceMeasure : PerformanceEntry { }; diff --git a/Source/WebCore/page/PerformanceNavigation.idl b/Source/WebCore/page/PerformanceNavigation.idl index e9add4cb5..22bac4081 100644 --- a/Source/WebCore/page/PerformanceNavigation.idl +++ b/Source/WebCore/page/PerformanceNavigation.idl @@ -31,7 +31,6 @@ // See: http://www.w3.org/TR/navigation-timing/ [ Conditional=WEB_TIMING, - OmitConstructor ] interface PerformanceNavigation { const unsigned short TYPE_NAVIGATE = 0; const unsigned short TYPE_RELOAD = 1; diff --git a/Source/WebCore/page/PerformanceResourceTiming.cpp b/Source/WebCore/page/PerformanceResourceTiming.cpp index df1dc76ec..539878f6f 100644 --- a/Source/WebCore/page/PerformanceResourceTiming.cpp +++ b/Source/WebCore/page/PerformanceResourceTiming.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2012 Google Inc. All rights reserved. + * Copyright (C) 2012 Intel Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -44,17 +45,44 @@ namespace WebCore { -double monotonicTimeToDocumentMilliseconds(Document* document, double seconds) +static double monotonicTimeToDocumentMilliseconds(Document* document, double seconds) { ASSERT(seconds >= 0.0); return document->loader()->timing()->monotonicTimeToZeroBasedDocumentTime(seconds) * 1000.0; } +static bool passesTimingAllowCheck(const ResourceResponse& response, Document* requestingDocument) +{ + AtomicallyInitializedStatic(AtomicString&, timingAllowOrigin = *new AtomicString("timing-allow-origin")); + + RefPtr<SecurityOrigin> resourceOrigin = SecurityOrigin::create(response.url()); + if (resourceOrigin->isSameSchemeHostPort(requestingDocument->securityOrigin())) + return true; + + const String& timingAllowOriginString = response.httpHeaderField(timingAllowOrigin); + if (timingAllowOriginString.isEmpty() || equalIgnoringCase(timingAllowOriginString, "null")) + return false; + + if (timingAllowOriginString == "*") + return true; + + const String& securityOrigin = requestingDocument->securityOrigin()->toString(); + Vector<String> timingAllowOrigins; + timingAllowOriginString.split(" ", timingAllowOrigins); + for (size_t i = 0; i < timingAllowOrigins.size(); ++i) + if (timingAllowOrigins[i] == securityOrigin) + return true; + + return false; +} + PerformanceResourceTiming::PerformanceResourceTiming(const AtomicString& initiatorType, const ResourceRequest& request, const ResourceResponse& response, double initiationTime, double finishTime, Document* requestingDocument) : PerformanceEntry(request.url().string(), "resource", monotonicTimeToDocumentMilliseconds(requestingDocument, initiationTime), monotonicTimeToDocumentMilliseconds(requestingDocument, finishTime)) , m_initiatorType(initiatorType) , m_timing(response.resourceLoadTiming()) , m_finishTime(finishTime) + , m_didReuseConnection(response.connectionReused()) + , m_shouldReportDetails(passesTimingAllowCheck(response, requestingDocument)) , m_requestingDocument(requestingDocument) { } @@ -68,16 +96,18 @@ AtomicString PerformanceResourceTiming::initiatorType() const return m_initiatorType; } -// FIXME: Need to enforce same-origin policy on these. - double PerformanceResourceTiming::redirectStart() const { // FIXME: Need to track and report redirects for resources. + if (!m_shouldReportDetails) + return 0.0; return 0; } double PerformanceResourceTiming::redirectEnd() const { + if (!m_shouldReportDetails) + return 0.0; return 0; } @@ -89,6 +119,9 @@ double PerformanceResourceTiming::fetchStart() const double PerformanceResourceTiming::domainLookupStart() const { + if (!m_shouldReportDetails) + return 0.0; + if (!m_timing || m_timing->dnsStart < 0) return fetchStart(); @@ -97,6 +130,9 @@ double PerformanceResourceTiming::domainLookupStart() const double PerformanceResourceTiming::domainLookupEnd() const { + if (!m_shouldReportDetails) + return 0.0; + if (!m_timing || m_timing->dnsEnd < 0) return domainLookupStart(); @@ -105,7 +141,11 @@ double PerformanceResourceTiming::domainLookupEnd() const double PerformanceResourceTiming::connectStart() const { - if (!m_timing || m_timing->connectStart < 0) // Connection was reused. + if (!m_shouldReportDetails) + return 0.0; + + // connectStart will be -1 when a network request is not made. + if (!m_timing || m_timing->connectStart < 0 || m_didReuseConnection) return domainLookupEnd(); // connectStart includes any DNS time, so we may need to trim that off. @@ -118,7 +158,11 @@ double PerformanceResourceTiming::connectStart() const double PerformanceResourceTiming::connectEnd() const { - if (!m_timing || m_timing->connectEnd < 0) // Connection was reused. + if (!m_shouldReportDetails) + return 0.0; + + // connectStart will be -1 when a network request is not made. + if (!m_timing || m_timing->connectEnd < 0 || m_didReuseConnection) return connectStart(); return resourceTimeToDocumentMilliseconds(m_timing->connectEnd); @@ -126,6 +170,9 @@ double PerformanceResourceTiming::connectEnd() const double PerformanceResourceTiming::secureConnectionStart() const { + if (!m_shouldReportDetails) + return 0.0; + if (!m_timing || m_timing->sslStart < 0) // Secure connection not negotiated. return 0.0; @@ -134,13 +181,20 @@ double PerformanceResourceTiming::secureConnectionStart() const double PerformanceResourceTiming::requestStart() const { + if (!m_shouldReportDetails) + return 0.0; + if (!m_timing) return connectEnd(); + return resourceTimeToDocumentMilliseconds(m_timing->sendStart); } double PerformanceResourceTiming::responseStart() const { + if (!m_shouldReportDetails) + return 0.0; + if (!m_timing) return requestStart(); // FIXME: This number isn't exactly correct. See the notes in PerformanceTiming::responseStart(). @@ -149,8 +203,9 @@ double PerformanceResourceTiming::responseStart() const double PerformanceResourceTiming::responseEnd() const { - if (!m_timing) + if (!m_finishTime) return responseStart(); + return monotonicTimeToDocumentMilliseconds(m_requestingDocument.get(), m_finishTime); } diff --git a/Source/WebCore/page/PerformanceResourceTiming.h b/Source/WebCore/page/PerformanceResourceTiming.h index 66428d70c..ed24492c3 100644 --- a/Source/WebCore/page/PerformanceResourceTiming.h +++ b/Source/WebCore/page/PerformanceResourceTiming.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2012 Google Inc. All rights reserved. + * Copyright (C) 2012 Intel Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -78,6 +79,8 @@ private: AtomicString m_initiatorType; RefPtr<ResourceLoadTiming> m_timing; double m_finishTime; + bool m_didReuseConnection; + bool m_shouldReportDetails; RefPtr<Document> m_requestingDocument; }; diff --git a/Source/WebCore/page/PerformanceResourceTiming.idl b/Source/WebCore/page/PerformanceResourceTiming.idl index b5d6053b2..a0e48633b 100644 --- a/Source/WebCore/page/PerformanceResourceTiming.idl +++ b/Source/WebCore/page/PerformanceResourceTiming.idl @@ -31,7 +31,6 @@ // See: https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/ResourceTiming/Overview.html [ Conditional=RESOURCE_TIMING, - OmitConstructor ] interface PerformanceResourceTiming : PerformanceEntry { readonly attribute DOMString initiatorType; diff --git a/Source/WebCore/page/PerformanceTiming.cpp b/Source/WebCore/page/PerformanceTiming.cpp index 4a0c0bd74..4f992a854 100644 --- a/Source/WebCore/page/PerformanceTiming.cpp +++ b/Source/WebCore/page/PerformanceTiming.cpp @@ -38,6 +38,7 @@ #include "DocumentLoader.h" #include "DocumentTiming.h" #include "Frame.h" +#include "FrameLoader.h" #include "ResourceLoadTiming.h" #include "ResourceResponse.h" #include <wtf/CurrentTime.h> diff --git a/Source/WebCore/page/PerformanceTiming.idl b/Source/WebCore/page/PerformanceTiming.idl index ea823aa82..9f4f60c40 100644 --- a/Source/WebCore/page/PerformanceTiming.idl +++ b/Source/WebCore/page/PerformanceTiming.idl @@ -31,7 +31,6 @@ // See: http://dev.w3.org/2006/webapi/WebTiming/ [ Conditional=WEB_TIMING, - OmitConstructor ] interface PerformanceTiming { readonly attribute unsigned long long navigationStart; readonly attribute unsigned long long unloadEventStart; diff --git a/Source/WebCore/page/PerformanceUserTiming.cpp b/Source/WebCore/page/PerformanceUserTiming.cpp index 8ac04d4f4..f5516faec 100644 --- a/Source/WebCore/page/PerformanceUserTiming.cpp +++ b/Source/WebCore/page/PerformanceUserTiming.cpp @@ -36,46 +36,43 @@ namespace WebCore { -HashMap<String, NavigationTimingFunction> UserTiming::m_restrictedKeyMap; +namespace { + +typedef HashMap<String, NavigationTimingFunction> RestrictedKeyMap; +static RestrictedKeyMap restrictedKeyMap() +{ + DEFINE_STATIC_LOCAL(RestrictedKeyMap, map, ()); + if (map.isEmpty()) { + map.add("navigationStart", &PerformanceTiming::navigationStart); + map.add("unloadEventStart", &PerformanceTiming::unloadEventStart); + map.add("unloadEventEnd", &PerformanceTiming::unloadEventEnd); + map.add("redirectStart", &PerformanceTiming::redirectStart); + map.add("redirectEnd", &PerformanceTiming::redirectEnd); + map.add("fetchStart", &PerformanceTiming::fetchStart); + map.add("domainLookupStart", &PerformanceTiming::domainLookupStart); + map.add("domainLookupEnd", &PerformanceTiming::domainLookupEnd); + map.add("connectStart", &PerformanceTiming::connectStart); + map.add("connectEnd", &PerformanceTiming::connectEnd); + map.add("secureConnectionStart", &PerformanceTiming::secureConnectionStart); + map.add("requestStart", &PerformanceTiming::requestStart); + map.add("responseStart", &PerformanceTiming::responseStart); + map.add("responseEnd", &PerformanceTiming::responseEnd); + map.add("domLoading", &PerformanceTiming::domLoading); + map.add("domInteractive", &PerformanceTiming::domInteractive); + map.add("domContentLoadedEventStart", &PerformanceTiming::domContentLoadedEventStart); + map.add("domContentLoadedEventEnd", &PerformanceTiming::domContentLoadedEventEnd); + map.add("domComplete", &PerformanceTiming::domComplete); + map.add("loadEventStart", &PerformanceTiming::loadEventStart); + map.add("loadEventEnd", &PerformanceTiming::loadEventEnd); + } + return map; +} + +} // namespace anonymous UserTiming::UserTiming(Performance* performance) : m_performance(performance) { - static const struct RestrictedField { - String key; - NavigationTimingFunction navigationTimingFunction; - } defaultRestrictions[] = { - {"navigationStart", &PerformanceTiming::navigationStart}, - {"unloadEventStart", &PerformanceTiming::unloadEventStart}, - {"unloadEventEnd", &PerformanceTiming::unloadEventEnd}, - {"redirectStart", &PerformanceTiming::redirectStart}, - {"redirectEnd", &PerformanceTiming::redirectEnd}, - {"fetchStart", &PerformanceTiming::fetchStart}, - {"domainLookupStart", &PerformanceTiming::domainLookupStart}, - {"domainLookupEnd", &PerformanceTiming::domainLookupEnd}, - {"connectStart", &PerformanceTiming::connectStart}, - {"connectEnd", &PerformanceTiming::connectEnd}, - {"secureConnectionStart", &PerformanceTiming::secureConnectionStart}, - {"requestStart", &PerformanceTiming::requestStart}, - {"responseStart", &PerformanceTiming::responseStart}, - {"responseEnd", &PerformanceTiming::responseEnd}, - {"domLoading", &PerformanceTiming::domLoading}, - {"domInteractive", &PerformanceTiming::domInteractive}, - {"domContentLoadedEventStart", &PerformanceTiming::domContentLoadedEventStart}, - {"domContentLoadedEventEnd", &PerformanceTiming::domContentLoadedEventEnd}, - {"domComplete", &PerformanceTiming::domComplete}, - {"loadEventStart", &PerformanceTiming::loadEventStart}, - {"loadEventEnd", &PerformanceTiming::loadEventEnd} - }; - - if (!m_restrictedKeyMap.isEmpty()) - return; - - for (const struct RestrictedField* restriction = defaultRestrictions; - static_cast<unsigned>(restriction - defaultRestrictions) < ARRAY_SIZE(defaultRestrictions); - ++restriction) { - m_restrictedKeyMap.add(restriction->key, restriction->navigationTimingFunction); - } } static void insertPerformanceEntry(PerformanceEntryMap& performanceEntryMap, PassRefPtr<PerformanceEntry> performanceEntry) @@ -105,7 +102,7 @@ static void clearPeformanceEntries(PerformanceEntryMap& performanceEntryMap, con void UserTiming::mark(const String& markName, ExceptionCode& ec) { ec = 0; - if (m_restrictedKeyMap.contains(markName)) { + if (restrictedKeyMap().contains(markName)) { ec = SYNTAX_ERR; return; } @@ -126,8 +123,14 @@ double UserTiming::findExistingMarkStartTime(const String& markName, ExceptionCo if (m_marksMap.contains(markName)) return m_marksMap.get(markName).last()->startTime(); - if (m_restrictedKeyMap.contains(markName)) - return static_cast<double>((m_performance->timing()->*(m_restrictedKeyMap.get(markName)))()) - m_performance->timing()->navigationStart(); + if (restrictedKeyMap().contains(markName)) { + double value = static_cast<double>((m_performance->timing()->*(restrictedKeyMap().get(markName)))()); + if (!value) { + ec = INVALID_ACCESS_ERR; + return 0.0; + } + return value - m_performance->timing()->navigationStart(); + } ec = SYNTAX_ERR; return 0.0; @@ -154,7 +157,7 @@ void UserTiming::measure(const String& measureName, const String& startMark, con return; } - insertPerformanceEntry(m_measuresMap, PerformanceMeasure::create(measureName, startTime, endTime - startTime)); + insertPerformanceEntry(m_measuresMap, PerformanceMeasure::create(measureName, startTime, endTime)); } void UserTiming::clearMeasures(const String& measureName) @@ -167,7 +170,7 @@ static Vector<RefPtr<PerformanceEntry> > convertToEntrySequence(const Performanc Vector<RefPtr<PerformanceEntry> > entries; for (PerformanceEntryMap::const_iterator it = performanceEntryMap.begin(); it != performanceEntryMap.end(); ++it) - entries.append(it->value); + entries.appendVector(it->value); return entries; } @@ -178,7 +181,7 @@ static Vector<RefPtr<PerformanceEntry> > getEntrySequenceByName(const Performanc PerformanceEntryMap::const_iterator it = performanceEntryMap.find(name); if (it != performanceEntryMap.end()) - entries.append(it->value); + entries.appendVector(it->value); return entries; } diff --git a/Source/WebCore/page/PerformanceUserTiming.h b/Source/WebCore/page/PerformanceUserTiming.h index c6e69d4e9..14c8c3f9b 100644 --- a/Source/WebCore/page/PerformanceUserTiming.h +++ b/Source/WebCore/page/PerformanceUserTiming.h @@ -49,6 +49,7 @@ typedef HashMap<String, Vector<RefPtr<PerformanceEntry> > > PerformanceEntryMap; class UserTiming : public RefCounted<UserTiming> { public: static PassRefPtr<UserTiming> create(Performance* performance) { return adoptRef(new UserTiming(performance)); } + void mark(const String& markName, ExceptionCode&); void clearMarks(const String& markName); @@ -63,8 +64,7 @@ public: private: explicit UserTiming(Performance*); - static HashMap<String, NavigationTimingFunction> m_restrictedKeyMap; - + double findExistingMarkStartTime(const String& markName, ExceptionCode&); Performance* m_performance; PerformanceEntryMap m_marksMap; diff --git a/Source/WebCore/page/PlugInClient.h b/Source/WebCore/page/PlugInClient.h new file mode 100644 index 000000000..6582c4efe --- /dev/null +++ b/Source/WebCore/page/PlugInClient.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PlugInClient_h +#define PlugInClient_h + +#include <wtf/Forward.h> + +namespace WebCore { + +class PlugInClient { +public: + virtual void pageDestroyed() = 0; + virtual bool shouldAutoStartFromOrigin(const String& pageOrigin, const String& pluginOrigin, const String& mimeType) = 0; + virtual void didStartFromOrigin(const String& pageOrigin, const String& pluginOrigin, const String& mimeType) = 0; + +protected: + virtual ~PlugInClient() { } +}; + +} +#endif // PlugInClient_h diff --git a/Source/WebCore/page/PointerLockController.cpp b/Source/WebCore/page/PointerLockController.cpp index ddbb84fd0..974b98da5 100644 --- a/Source/WebCore/page/PointerLockController.cpp +++ b/Source/WebCore/page/PointerLockController.cpp @@ -28,6 +28,7 @@ #include "Chrome.h" #include "ChromeClient.h" #include "Element.h" +#include "Event.h" #include "Page.h" #include "PlatformMouseEvent.h" #include "VoidCallback.h" @@ -48,8 +49,14 @@ PassOwnPtr<PointerLockController> PointerLockController::create(Page* page) void PointerLockController::requestPointerLock(Element* target) { - if (!target || !target->inDocument() || m_documentOfRemovedElementWhileWaitingForUnlock - || target->document()->isSandboxed(SandboxPointerLock)) { + if (!target || !target->inDocument() || m_documentOfRemovedElementWhileWaitingForUnlock) { + enqueueEvent(eventNames().webkitpointerlockerrorEvent, target); + return; + } + + if (target->document()->isSandboxed(SandboxPointerLock)) { + // FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists. + target->document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, "Blocked pointer lock on an element because the element's frame is sandboxed and the 'allow-pointer-lock' permission is not set."); enqueueEvent(eventNames().webkitpointerlockerrorEvent, target); return; } @@ -61,7 +68,7 @@ void PointerLockController::requestPointerLock(Element* target) } enqueueEvent(eventNames().webkitpointerlockchangeEvent, target); m_element = target; - } else if (m_page->chrome()->client()->requestPointerLock()) { + } else if (m_page->chrome().client()->requestPointerLock()) { m_lockPending = true; m_element = target; } else { @@ -71,7 +78,7 @@ void PointerLockController::requestPointerLock(Element* target) void PointerLockController::requestPointerUnlock() { - return m_page->chrome()->client()->requestPointerUnlock(); + return m_page->chrome().client()->requestPointerUnlock(); } void PointerLockController::elementRemoved(Element* element) diff --git a/Source/WebCore/page/PrintContext.cpp b/Source/WebCore/page/PrintContext.cpp index ed60b48eb..482b46250 100644 --- a/Source/WebCore/page/PrintContext.cpp +++ b/Source/WebCore/page/PrintContext.cpp @@ -279,7 +279,7 @@ String PrintContext::pageProperty(Frame* frame, const char* propertyName, int pa if (!strcmp(propertyName, "font-size")) return String::number(style->fontDescription().computedPixelSize()); if (!strcmp(propertyName, "font-family")) - return style->fontDescription().family().family().string(); + return style->fontDescription().firstFamily(); if (!strcmp(propertyName, "size")) return String::number(style->pageSize().width().value()) + ' ' + String::number(style->pageSize().height().value()); diff --git a/Source/WebCore/page/Screen.cpp b/Source/WebCore/page/Screen.cpp index e639a9c13..7615ba001 100644 --- a/Source/WebCore/page/Screen.cpp +++ b/Source/WebCore/page/Screen.cpp @@ -45,35 +45,6 @@ Screen::Screen(Frame* frame) { } -unsigned Screen::horizontalDPI() const -{ - if (!m_frame) - return 0; - - // Used by the testing system, can be set from internals. - IntSize override = m_frame->page()->settings()->resolutionOverride(); - if (!override.isEmpty()) - return override.width(); - - // The DPI is defined as dots per CSS inch and thus not device inch. - return m_frame->page()->deviceScaleFactor() * 96; -} - -unsigned Screen::verticalDPI() const -{ - // The DPI is defined as dots per CSS inch and thus not device inch. - if (!m_frame) - return 0; - - // Used by the testing system, can be set from internals. - IntSize override = m_frame->page()->settings()->resolutionOverride(); - if (!override.isEmpty()) - return override.height(); - - // The DPI is defined as dots per CSS inch and thus not device inch. - return m_frame->page()->deviceScaleFactor() * 96; -} - unsigned Screen::height() const { if (!m_frame) diff --git a/Source/WebCore/page/Screen.h b/Source/WebCore/page/Screen.h index 5abcc1d69..c78850c1e 100644 --- a/Source/WebCore/page/Screen.h +++ b/Source/WebCore/page/Screen.h @@ -43,8 +43,6 @@ namespace WebCore { public: static PassRefPtr<Screen> create(Frame *frame) { return adoptRef(new Screen(frame)); } - unsigned horizontalDPI() const; - unsigned verticalDPI() const; unsigned height() const; unsigned width() const; unsigned colorDepth() const; diff --git a/Source/WebCore/page/Screen.idl b/Source/WebCore/page/Screen.idl index ee3cc30ae..8ff1748b8 100644 --- a/Source/WebCore/page/Screen.idl +++ b/Source/WebCore/page/Screen.idl @@ -28,8 +28,7 @@ [ - JSGenerateIsReachable=ImplFrame, - OmitConstructor + GenerateIsReachable=ImplFrame, ] interface Screen { readonly attribute unsigned long height; readonly attribute unsigned long width; diff --git a/Source/WebCore/page/SecurityOrigin.cpp b/Source/WebCore/page/SecurityOrigin.cpp index d53750a17..cebc89684 100644 --- a/Source/WebCore/page/SecurityOrigin.cpp +++ b/Source/WebCore/page/SecurityOrigin.cpp @@ -30,7 +30,6 @@ #include "SecurityOrigin.h" #include "BlobURL.h" -#include "Document.h" #include "FileSystem.h" #include "KURL.h" #include "SchemeRegistry.h" @@ -45,7 +44,7 @@ namespace WebCore { const int InvalidPort = 0; const int MaxAllowedPort = 65535; -static bool schemeRequiresAuthority(const KURL& url) +static bool schemeRequiresHost(const KURL& url) { // We expect URLs with these schemes to have authority components. If the // URL lacks an authority component, we get concerned and mark the origin @@ -56,6 +55,7 @@ static bool schemeRequiresAuthority(const KURL& url) bool SecurityOrigin::shouldUseInnerURL(const KURL& url) { #if ENABLE(BLOB) + // FIXME: Blob URLs don't have inner URLs. Their form is "blob:<inner-origin>/<UUID>", so treating the part after "blob:" as a URL is incorrect. if (url.protocolIs("blob")) return true; #endif @@ -84,6 +84,8 @@ static PassRefPtr<SecurityOrigin> getCachedOrigin(const KURL& url) #if ENABLE(BLOB) if (url.protocolIs("blob")) return ThreadableBlobRegistry::getCachedOrigin(url); +#else + UNUSED_PARAM(url); #endif return 0; } @@ -99,9 +101,9 @@ static bool shouldTreatAsUniqueOrigin(const KURL& url) // FIXME: Check whether innerURL is valid. // For edge case URLs that were probably misparsed, make sure that the origin is unique. - // FIXME: Do we really need to do this? This looks to be a hack around a - // security bug in CFNetwork that might have been fixed. - if (schemeRequiresAuthority(innerURL) && innerURL.host().isEmpty()) + // This is an additional safety net against bugs in KURL parsing, and for network back-ends that parse URLs differently, + // and could misinterpret another component for hostname. + if (schemeRequiresHost(innerURL) && innerURL.host().isEmpty()) return true; // SchemeRegistry needs a lower case protocol because it uses HashMaps @@ -157,7 +159,6 @@ SecurityOrigin::SecurityOrigin() SecurityOrigin::SecurityOrigin(const SecurityOrigin* other) : m_protocol(other->m_protocol.isolatedCopy()) , m_host(other->m_host.isolatedCopy()) - , m_encodedHost(other->m_encodedHost.isolatedCopy()) , m_domain(other->m_domain.isolatedCopy()) , m_filePath(other->m_filePath.isolatedCopy()) , m_port(other->m_port) @@ -380,18 +381,24 @@ bool SecurityOrigin::canDisplay(const KURL& url) const return true; } -bool SecurityOrigin::canAccessStorage(const SecurityOrigin* topOrigin) const +bool SecurityOrigin::canAccessStorage(const SecurityOrigin* topOrigin, ShouldAllowFromThirdParty shouldAllowFromThirdParty) const { if (isUnique()) return false; + if (m_storageBlockingPolicy == BlockAllStorage) + return false; + // FIXME: This check should be replaced with an ASSERT once we can guarantee that topOrigin is not null. if (!topOrigin) return true; - if (m_storageBlockingPolicy == BlockAllStorage || topOrigin->m_storageBlockingPolicy == BlockAllStorage) + if (topOrigin->m_storageBlockingPolicy == BlockAllStorage) return false; + if (shouldAllowFromThirdParty == AlwaysAllowFromThirdParty) + return true; + if ((m_storageBlockingPolicy == BlockThirdPartyStorage || topOrigin->m_storageBlockingPolicy == BlockThirdPartyStorage) && topOrigin->isThirdParty(this)) return false; @@ -435,6 +442,19 @@ void SecurityOrigin::grantUniversalAccess() m_universalAccess = true; } +#if ENABLE(CACHE_PARTITIONING) +String SecurityOrigin::cachePartition() const +{ + if (m_storageBlockingPolicy != BlockThirdPartyStorage) + return String(); + + if (m_protocol != "http" && m_protocol != "https") + return String(); + + return host(); +} +#endif + void SecurityOrigin::enforceFilePathSeparation() { ASSERT(isLocal()); @@ -479,17 +499,17 @@ PassRefPtr<SecurityOrigin> SecurityOrigin::createFromString(const String& origin return SecurityOrigin::create(KURL(KURL(), originString)); } -static const char SeparatorCharacter = '_'; +static const char separatorCharacter = '_'; PassRefPtr<SecurityOrigin> SecurityOrigin::createFromDatabaseIdentifier(const String& databaseIdentifier) { // Make sure there's a first separator - size_t separator1 = databaseIdentifier.find(SeparatorCharacter); + size_t separator1 = databaseIdentifier.find(separatorCharacter); if (separator1 == notFound) return create(KURL()); // Make sure there's a second separator - size_t separator2 = databaseIdentifier.reverseFind(SeparatorCharacter); + size_t separator2 = databaseIdentifier.reverseFind(separatorCharacter); if (separator2 == notFound) return create(KURL()); @@ -513,15 +533,15 @@ PassRefPtr<SecurityOrigin> SecurityOrigin::createFromDatabaseIdentifier(const St String host = databaseIdentifier.substring(separator1 + 1, separator2 - separator1 - 1); host = decodeURLEscapeSequences(host); - return create(KURL(KURL(), protocol + "://" + host + ":" + String::number(port))); + return create(KURL(KURL(), protocol + "://" + host + ":" + String::number(port) + "/")); } PassRefPtr<SecurityOrigin> SecurityOrigin::create(const String& protocol, const String& host, int port) { if (port < 0 || port > MaxAllowedPort) - createUnique(); + return createUnique(); String decodedHost = decodeURLEscapeSequences(host); - return create(KURL(KURL(), protocol + "://" + host + ":" + String::number(port))); + return create(KURL(KURL(), protocol + "://" + host + ":" + String::number(port) + "/")); } String SecurityOrigin::databaseIdentifier() const @@ -534,12 +554,14 @@ String SecurityOrigin::databaseIdentifier() const if (m_needsDatabaseIdentifierQuirkForFiles) return "file__0"; - String separatorString(&SeparatorCharacter, 1); - - if (m_encodedHost.isEmpty()) - m_encodedHost = encodeForFileName(m_host); + StringBuilder stringBuilder; + stringBuilder.append(m_protocol); + stringBuilder.append(separatorCharacter); + stringBuilder.append(encodeForFileName(m_host)); + stringBuilder.append(separatorCharacter); + stringBuilder.appendNumber(m_port); - return m_protocol + separatorString + m_encodedHost + separatorString + String::number(m_port); + return stringBuilder.toString(); } bool SecurityOrigin::equal(const SecurityOrigin* other) const @@ -576,4 +598,11 @@ bool SecurityOrigin::isSameSchemeHostPort(const SecurityOrigin* other) const return true; } +String SecurityOrigin::urlWithUniqueSecurityOrigin() +{ + ASSERT(isMainThread()); + DEFINE_STATIC_LOCAL(const String, uniqueSecurityOriginURL, (ASCIILiteral("data:,"))); + return uniqueSecurityOriginURL; +} + } // namespace WebCore diff --git a/Source/WebCore/page/SecurityOrigin.h b/Source/WebCore/page/SecurityOrigin.h index e8120eda0..8572f4ce4 100644 --- a/Source/WebCore/page/SecurityOrigin.h +++ b/Source/WebCore/page/SecurityOrigin.h @@ -34,7 +34,6 @@ namespace WebCore { -class Document; class KURL; class SecurityOrigin : public ThreadSafeRefCounted<SecurityOrigin> { @@ -142,20 +141,21 @@ public: void setStorageBlockingPolicy(StorageBlockingPolicy policy) { m_storageBlockingPolicy = policy; } +#if ENABLE(CACHE_PARTITIONING) + String cachePartition() const; +#endif + bool canAccessDatabase(const SecurityOrigin* topOrigin = 0) const { return canAccessStorage(topOrigin); }; + bool canAccessSessionStorage(const SecurityOrigin* topOrigin) const { return canAccessStorage(topOrigin, AlwaysAllowFromThirdParty); } bool canAccessLocalStorage(const SecurityOrigin* topOrigin) const { return canAccessStorage(topOrigin); }; bool canAccessSharedWorkers(const SecurityOrigin* topOrigin) const { return canAccessStorage(topOrigin); } bool canAccessPluginStorage(const SecurityOrigin* topOrigin) const { return canAccessStorage(topOrigin); } + bool canAccessApplicationCache(const SecurityOrigin* topOrigin) const { return canAccessStorage(topOrigin); } bool canAccessCookies() const { return !isUnique(); } bool canAccessPasswordManager() const { return !isUnique(); } bool canAccessFileSystem() const { return !isUnique(); } Policy canShowNotifications() const; - // Technically, we should always allow access to sessionStorage, but we - // currently don't handle creating a sessionStorage area for unique - // origins. - bool canAccessSessionStorage() const { return !isUnique(); } - // The local SecurityOrigin is the most privileged SecurityOrigin. // The local SecurityOrigin can script any document, navigate to local // resources, and can set arbitrary headers on XMLHttpRequests. @@ -205,6 +205,8 @@ public: // (and whether it was set) but considering the host. It is used for postMessage. bool isSameSchemeHostPort(const SecurityOrigin*) const; + static String urlWithUniqueSecurityOrigin(); + private: SecurityOrigin(); explicit SecurityOrigin(const KURL&); @@ -213,11 +215,12 @@ private: // FIXME: Rename this function to something more semantic. bool passesFileCheck(const SecurityOrigin*) const; bool isThirdParty(const SecurityOrigin*) const; - bool canAccessStorage(const SecurityOrigin*) const; + + enum ShouldAllowFromThirdParty { AlwaysAllowFromThirdParty, MaybeAllowFromThirdParty }; + bool canAccessStorage(const SecurityOrigin*, ShouldAllowFromThirdParty = MaybeAllowFromThirdParty) const; String m_protocol; String m_host; - mutable String m_encodedHost; String m_domain; String m_filePath; unsigned short m_port; diff --git a/Source/WebCore/page/SecurityOriginHash.h b/Source/WebCore/page/SecurityOriginHash.h index db3845cb6..454cf83ed 100644 --- a/Source/WebCore/page/SecurityOriginHash.h +++ b/Source/WebCore/page/SecurityOriginHash.h @@ -52,13 +52,9 @@ struct SecurityOriginHash { static bool equal(SecurityOrigin* a, SecurityOrigin* b) { - // FIXME: The hash function above compares three specific fields. - // This code to compare those three specific fields should be moved here from - // SecurityOrigin as mentioned in SecurityOrigin.h so we don't accidentally change - // equal without changing hash to match it. if (!a || !b) return a == b; - return a->equal(b); + return a->isSameSchemeHostPort(b); } static bool equal(SecurityOrigin* a, const RefPtr<SecurityOrigin>& b) { @@ -78,4 +74,13 @@ struct SecurityOriginHash { } // namespace WebCore -#endif +namespace WTF { + template<typename> struct DefaultHash; + + template<> struct DefaultHash<RefPtr<WebCore::SecurityOrigin> > { + typedef WebCore::SecurityOriginHash Hash; + }; + +} // namespace WTF + +#endif // SecurityOriginHash_h diff --git a/Source/WebCore/page/Settings.cpp b/Source/WebCore/page/Settings.cpp index b274e758f..9bc607fdd 100644 --- a/Source/WebCore/page/Settings.cpp +++ b/Source/WebCore/page/Settings.cpp @@ -32,14 +32,18 @@ #include "DOMTimer.h" #include "Database.h" #include "Document.h" +#include "Font.h" +#include "FontGenericFamilies.h" #include "Frame.h" #include "FrameTree.h" #include "FrameView.h" +#include "HTMLMediaElement.h" #include "HistoryItem.h" +#include "InspectorInstrumentation.h" #include "Page.h" #include "PageCache.h" -#include "ResourceHandle.h" #include "StorageMap.h" +#include "TextAutosizer.h" #include <limits> using namespace std; @@ -54,35 +58,16 @@ static void setImageLoadingSettings(Page* page) } } -// Sets the entry in the font map for the given script. If family is the empty string, removes the entry instead. -static inline void setGenericFontFamilyMap(ScriptFontFamilyMap& fontMap, const AtomicString& family, UScriptCode script, Page* page) +static void invalidateAfterGenericFamilyChange(Page* page) { - ScriptFontFamilyMap::iterator it = fontMap.find(static_cast<int>(script)); - if (family.isEmpty()) { - if (it == fontMap.end()) - return; - fontMap.remove(it); - } else if (it != fontMap.end() && it->value == family) - return; - else - fontMap.set(static_cast<int>(script), family); - + invalidateFontGlyphsCache(); if (page) page->setNeedsRecalcStyleInAllFrames(); } -static inline const AtomicString& getGenericFontFamilyForScript(const ScriptFontFamilyMap& fontMap, UScriptCode script) -{ - ScriptFontFamilyMap::const_iterator it = fontMap.find(static_cast<int>(script)); - if (it != fontMap.end()) - return it->value; - if (script != USCRIPT_COMMON) - return getGenericFontFamilyForScript(fontMap, USCRIPT_COMMON); - return emptyAtom; -} - double Settings::gDefaultMinDOMTimerInterval = 0.010; // 10 milliseconds double Settings::gDefaultDOMTimerAlignmentInterval = 0; +double Settings::gHiddenPageDOMTimerAlignmentInterval = 1.0; #if USE(SAFARI_THEME) bool Settings::gShouldPaintNativeControls = true; @@ -92,22 +77,25 @@ bool Settings::gShouldPaintNativeControls = true; bool Settings::gAVFoundationEnabled = false; #endif +#if PLATFORM(MAC) +bool Settings::gQTKitEnabled = true; +#endif + bool Settings::gMockScrollbarsEnabled = false; bool Settings::gUsesOverlayScrollbars = false; -#if PLATFORM(WIN) || (OS(WINDOWS) && PLATFORM(WX)) +#if PLATFORM(WIN) bool Settings::gShouldUseHighResolutionTimers = true; #endif -#if USE(JSC) bool Settings::gShouldRespectPriorityInCSSAttributeSetters = false; -#endif +bool Settings::gLowPowerVideoAudioBufferSizeEnabled = false; // NOTEs -// 1) EditingMacBehavior comprises Tiger, Leopard, SnowLeopard and iOS builds, as well QtWebKit and Chromium when built on Mac; +// 1) EditingMacBehavior comprises Tiger, Leopard, SnowLeopard and iOS builds, as well as QtWebKit when built on Mac; // 2) EditingWindowsBehavior comprises Win32 and WinCE builds, as well as QtWebKit and Chromium when built on Windows; // 3) EditingUnixBehavior comprises all unix-based systems, but Darwin/MacOS (and then abusing the terminology); -// 99) MacEditingBehavior is used a fallback. +// 99) MacEditingBehavior is used as a fallback. static EditingBehaviorType editingBehaviorTypeForPlatform() { return @@ -125,15 +113,18 @@ static EditingBehaviorType editingBehaviorTypeForPlatform() } static const double defaultIncrementalRenderingSuppressionTimeoutInSeconds = 5; +#if USE(UNIFIED_TEXT_CHECKING) +static const bool defaultUnifiedTextCheckerEnabled = true; +#else +static const bool defaultUnifiedTextCheckerEnabled = false; +#endif +static const bool defaultSmartInsertDeleteEnabled = true; +static const bool defaultSelectTrailingWhitespaceEnabled = false; Settings::Settings(Page* page) : m_page(0) , m_mediaTypeOverride("screen") - , m_minimumFontSize(0) - , m_minimumLogicalFontSize(0) - , m_defaultFontSize(0) - , m_defaultFixedFontSize(0) - , m_screenFontSubstitutionEnabled(true) + , m_fontGenericFamilies(FontGenericFamilies::create()) , m_storageBlockingPolicy(SecurityOrigin::AllowAllStorage) #if ENABLE(TEXT_AUTOSIZING) , m_textAutosizingFontScaleFactor(1) @@ -150,16 +141,11 @@ Settings::Settings(Page* page) , m_loadsImagesAutomatically(false) , m_privateBrowsingEnabled(false) , m_areImagesEnabled(true) - , m_isMediaEnabled(true) , m_arePluginsEnabled(false) , m_isScriptEnabled(false) - , m_textAreasAreResizable(false) , m_needsAdobeFrameReloadingQuirk(false) - , m_isDOMPasteAllowed(false) , m_usesPageCache(false) - , m_authorAndUserStylesEnabled(true) , m_fontRenderingMode(0) - , m_inApplicationChromeMode(false) , m_isCSSCustomFilterEnabled(false) #if ENABLE(CSS_STICKY_POSITION) , m_cssStickyPositionEnabled(true) @@ -167,24 +153,22 @@ Settings::Settings(Page* page) #if ENABLE(CSS_VARIABLES) , m_cssVariablesEnabled(false) #endif - , m_acceleratedCompositingEnabled(true) - , m_showDebugBorders(false) - , m_showRepaintCounter(false) + , m_showTiledScrollingIndicator(false) , m_tiledBackingStoreEnabled(false) , m_dnsPrefetchingEnabled(false) -#if USE(UNIFIED_TEXT_CHECKING) - , m_unifiedTextCheckerEnabled(true) -#else - , m_unifiedTextCheckerEnabled(false) -#endif -#if ENABLE(SMOOTH_SCROLLING) - , m_scrollAnimatorEnabled(true) -#endif #if ENABLE(TOUCH_EVENTS) , m_touchEventEmulationEnabled(false) #endif , m_scrollingPerformanceLoggingEnabled(false) + , m_aggressiveTileRetentionEnabled(false) + , m_timeWithoutMouseMovementBeforeHidingControls(3) , m_setImageLoadingSettingsTimer(this, &Settings::imageLoadingSettingsTimerFired) +#if ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING) + , m_hiddenPageDOMTimerThrottlingEnabled(false) +#endif +#if ENABLE(PAGE_VISIBILITY_API) + , m_hiddenPageCSSAnimationSuspensionEnabled(false) +#endif { // A Frame may not have been created yet, so we initialize the AtomicString // hash before trying to use it. @@ -193,10 +177,26 @@ Settings::Settings(Page* page) m_page = page; // Page is not yet fully initialized wen constructing Settings, so keeping m_page null over initializeDefaultFontFamilies() call. } +Settings::~Settings() +{ +} + PassOwnPtr<Settings> Settings::create(Page* page) { return adoptPtr(new Settings(page)); -} +} + +SETTINGS_SETTER_BODIES + +void Settings::setHiddenPageDOMTimerAlignmentInterval(double hiddenPageDOMTimerAlignmentinterval) +{ + gHiddenPageDOMTimerAlignmentInterval = hiddenPageDOMTimerAlignmentinterval; +} + +double Settings::hiddenPageDOMTimerAlignmentInterval() +{ + return gHiddenPageDOMTimerAlignmentInterval; +} #if !PLATFORM(MAC) && !PLATFORM(BLACKBERRY) void Settings::initializeDefaultFontFamilies() @@ -207,117 +207,86 @@ void Settings::initializeDefaultFontFamilies() const AtomicString& Settings::standardFontFamily(UScriptCode script) const { - return getGenericFontFamilyForScript(m_standardFontFamilyMap, script); + return m_fontGenericFamilies->standardFontFamily(script); } void Settings::setStandardFontFamily(const AtomicString& family, UScriptCode script) { - setGenericFontFamilyMap(m_standardFontFamilyMap, family, script, m_page); + bool changes = m_fontGenericFamilies->setStandardFontFamily(family, script); + if (changes) + invalidateAfterGenericFamilyChange(m_page); } const AtomicString& Settings::fixedFontFamily(UScriptCode script) const { - return getGenericFontFamilyForScript(m_fixedFontFamilyMap, script); + return m_fontGenericFamilies->fixedFontFamily(script); } void Settings::setFixedFontFamily(const AtomicString& family, UScriptCode script) { - setGenericFontFamilyMap(m_fixedFontFamilyMap, family, script, m_page); + bool changes = m_fontGenericFamilies->setFixedFontFamily(family, script); + if (changes) + invalidateAfterGenericFamilyChange(m_page); } const AtomicString& Settings::serifFontFamily(UScriptCode script) const { - return getGenericFontFamilyForScript(m_serifFontFamilyMap, script); + return m_fontGenericFamilies->serifFontFamily(script); } void Settings::setSerifFontFamily(const AtomicString& family, UScriptCode script) { - setGenericFontFamilyMap(m_serifFontFamilyMap, family, script, m_page); + bool changes = m_fontGenericFamilies->setSerifFontFamily(family, script); + if (changes) + invalidateAfterGenericFamilyChange(m_page); } const AtomicString& Settings::sansSerifFontFamily(UScriptCode script) const { - return getGenericFontFamilyForScript(m_sansSerifFontFamilyMap, script); + return m_fontGenericFamilies->sansSerifFontFamily(script); } void Settings::setSansSerifFontFamily(const AtomicString& family, UScriptCode script) { - setGenericFontFamilyMap(m_sansSerifFontFamilyMap, family, script, m_page); + bool changes = m_fontGenericFamilies->setSansSerifFontFamily(family, script); + if (changes) + invalidateAfterGenericFamilyChange(m_page); } const AtomicString& Settings::cursiveFontFamily(UScriptCode script) const { - return getGenericFontFamilyForScript(m_cursiveFontFamilyMap, script); + return m_fontGenericFamilies->cursiveFontFamily(script); } void Settings::setCursiveFontFamily(const AtomicString& family, UScriptCode script) { - setGenericFontFamilyMap(m_cursiveFontFamilyMap, family, script, m_page); + bool changes = m_fontGenericFamilies->setCursiveFontFamily(family, script); + if (changes) + invalidateAfterGenericFamilyChange(m_page); } const AtomicString& Settings::fantasyFontFamily(UScriptCode script) const { - return getGenericFontFamilyForScript(m_fantasyFontFamilyMap, script); + return m_fontGenericFamilies->fantasyFontFamily(script); } void Settings::setFantasyFontFamily(const AtomicString& family, UScriptCode script) { - setGenericFontFamilyMap(m_fantasyFontFamilyMap, family, script, m_page); + bool changes = m_fontGenericFamilies->setFantasyFontFamily(family, script); + if (changes) + invalidateAfterGenericFamilyChange(m_page); } const AtomicString& Settings::pictographFontFamily(UScriptCode script) const { - return getGenericFontFamilyForScript(m_pictographFontFamilyMap, script); + return m_fontGenericFamilies->pictographFontFamily(script); } void Settings::setPictographFontFamily(const AtomicString& family, UScriptCode script) { - setGenericFontFamilyMap(m_pictographFontFamilyMap, family, script, m_page); -} - -void Settings::setMinimumFontSize(int minimumFontSize) -{ - if (m_minimumFontSize == minimumFontSize) - return; - - m_minimumFontSize = minimumFontSize; - m_page->setNeedsRecalcStyleInAllFrames(); -} - -void Settings::setMinimumLogicalFontSize(int minimumLogicalFontSize) -{ - if (m_minimumLogicalFontSize == minimumLogicalFontSize) - return; - - m_minimumLogicalFontSize = minimumLogicalFontSize; - m_page->setNeedsRecalcStyleInAllFrames(); -} - -void Settings::setDefaultFontSize(int defaultFontSize) -{ - if (m_defaultFontSize == defaultFontSize) - return; - - m_defaultFontSize = defaultFontSize; - m_page->setNeedsRecalcStyleInAllFrames(); -} - -void Settings::setDefaultFixedFontSize(int defaultFontSize) -{ - if (m_defaultFixedFontSize == defaultFontSize) - return; - - m_defaultFixedFontSize = defaultFontSize; - m_page->setNeedsRecalcStyleInAllFrames(); -} - -void Settings::setScreenFontSubstitutionEnabled(bool screenFontSubstitutionEnabled) -{ - if (m_screenFontSubstitutionEnabled == screenFontSubstitutionEnabled) - return; - - m_screenFontSubstitutionEnabled = screenFontSubstitutionEnabled; - m_page->setNeedsRecalcStyleInAllFrames(); + bool changes = m_fontGenericFamilies->setPictographFontFamily(family, script); + if (changes) + invalidateAfterGenericFamilyChange(m_page); } #if ENABLE(TEXT_AUTOSIZING) @@ -342,20 +311,16 @@ void Settings::setTextAutosizingWindowSizeOverride(const IntSize& textAutosizing void Settings::setTextAutosizingFontScaleFactor(float fontScaleFactor) { m_textAutosizingFontScaleFactor = fontScaleFactor; - m_page->setNeedsRecalcStyleInAllFrames(); -} -#endif - -void Settings::setResolutionOverride(const IntSize& densityPerInchOverride) -{ - if (m_resolutionDensityPerInchOverride == densityPerInchOverride) - return; + // FIXME: I wonder if this needs to traverse frames like in WebViewImpl::resize, or whether there is only one document per Settings instance? + for (Frame* frame = m_page->mainFrame(); frame; frame = frame->tree()->traverseNext()) + frame->document()->textAutosizer()->recalculateMultipliers(); - m_resolutionDensityPerInchOverride = densityPerInchOverride; m_page->setNeedsRecalcStyleInAllFrames(); } +#endif + void Settings::setMediaTypeOverride(const String& mediaTypeOverride) { if (m_mediaTypeOverride == mediaTypeOverride) @@ -394,6 +359,7 @@ void Settings::imageLoadingSettingsTimerFired(Timer<Settings>*) void Settings::setScriptEnabled(bool isScriptEnabled) { m_isScriptEnabled = isScriptEnabled; + InspectorInstrumentation::scriptsEnabled(m_page, m_isScriptEnabled); } void Settings::setJavaEnabled(bool isJavaEnabled) @@ -414,11 +380,6 @@ void Settings::setImagesEnabled(bool areImagesEnabled) m_setImageLoadingSettingsTimer.startOneShot(0); } -void Settings::setMediaEnabled(bool isMediaEnabled) -{ - m_isMediaEnabled = isMediaEnabled; -} - void Settings::setPluginsEnabled(bool arePluginsEnabled) { m_arePluginsEnabled = arePluginsEnabled; @@ -443,15 +404,6 @@ void Settings::setUserStyleSheetLocation(const KURL& userStyleSheetLocation) m_page->userStyleSheetLocationChanged(); } -void Settings::setTextAreasAreResizable(bool textAreasAreResizable) -{ - if (m_textAreasAreResizable == textAreasAreResizable) - return; - - m_textAreasAreResizable = textAreasAreResizable; - m_page->setNeedsRecalcStyleInAllFrames(); -} - // FIXME: This quirk is needed because of Radar 4674537 and 5211271. We need to phase it out once Adobe // can fix the bug from their end. void Settings::setNeedsAdobeFrameReloadingQuirk(bool shouldNotReloadIFramesForUnchangedSRC) @@ -459,11 +411,6 @@ void Settings::setNeedsAdobeFrameReloadingQuirk(bool shouldNotReloadIFramesForUn m_needsAdobeFrameReloadingQuirk = shouldNotReloadIFramesForUnchangedSRC; } -void Settings::setDOMPasteAllowed(bool DOMPasteAllowed) -{ - m_isDOMPasteAllowed = DOMPasteAllowed; -} - void Settings::setDefaultMinDOMTimerInterval(double interval) { gDefaultMinDOMTimerInterval = interval; @@ -515,19 +462,9 @@ void Settings::setUsesPageCache(bool usesPageCache) int last = m_page->backForward()->forwardCount(); for (int i = first; i <= last; i++) pageCache()->remove(m_page->backForward()->itemAtIndex(i)); - pageCache()->releaseAutoreleasedPagesNow(); } } -void Settings::setAuthorAndUserStylesEnabled(bool authorAndUserStylesEnabled) -{ - if (m_authorAndUserStylesEnabled == authorAndUserStylesEnabled) - return; - - m_authorAndUserStylesEnabled = authorAndUserStylesEnabled; - m_page->setNeedsRecalcStyleInAllFrames(); -} - void Settings::setFontRenderingMode(FontRenderingMode mode) { if (fontRenderingMode() == mode) @@ -541,11 +478,6 @@ FontRenderingMode Settings::fontRenderingMode() const return static_cast<FontRenderingMode>(m_fontRenderingMode); } -void Settings::setApplicationChromeMode(bool mode) -{ - m_inApplicationChromeMode = mode; -} - #if USE(SAFARI_THEME) void Settings::setShouldPaintNativeControls(bool shouldPaintNativeControls) { @@ -562,34 +494,15 @@ void Settings::setDNSPrefetchingEnabled(bool dnsPrefetchingEnabled) m_page->dnsPrefetchingStateChanged(); } -void Settings::setAcceleratedCompositingEnabled(bool enabled) -{ - if (m_acceleratedCompositingEnabled == enabled) - return; - - m_acceleratedCompositingEnabled = enabled; - m_page->setNeedsRecalcStyleInAllFrames(); -} - -void Settings::setShowDebugBorders(bool enabled) -{ - if (m_showDebugBorders == enabled) - return; - - m_showDebugBorders = enabled; - m_page->setNeedsRecalcStyleInAllFrames(); -} - -void Settings::setShowRepaintCounter(bool enabled) +void Settings::setShowTiledScrollingIndicator(bool enabled) { - if (m_showRepaintCounter == enabled) + if (m_showTiledScrollingIndicator == enabled) return; - m_showRepaintCounter = enabled; - m_page->setNeedsRecalcStyleInAllFrames(); + m_showTiledScrollingIndicator = enabled; } -#if PLATFORM(WIN) || (OS(WINDOWS) && PLATFORM(WX)) +#if PLATFORM(WIN) void Settings::setShouldUseHighResolutionTimers(bool shouldUseHighResolutionTimers) { gShouldUseHighResolutionTimers = shouldUseHighResolutionTimers; @@ -614,6 +527,28 @@ void Settings::setTiledBackingStoreEnabled(bool enabled) #endif } +#if USE(AVFOUNDATION) +void Settings::setAVFoundationEnabled(bool enabled) +{ + if (gAVFoundationEnabled == enabled) + return; + + gAVFoundationEnabled = enabled; + HTMLMediaElement::resetMediaEngines(); +} +#endif + +#if PLATFORM(MAC) +void Settings::setQTKitEnabled(bool enabled) +{ + if (gQTKitEnabled == enabled) + return; + + gQTKitEnabled = enabled; + HTMLMediaElement::resetMediaEngines(); +} +#endif + void Settings::setScrollingPerformanceLoggingEnabled(bool enabled) { m_scrollingPerformanceLoggingEnabled = enabled; @@ -621,6 +556,11 @@ void Settings::setScrollingPerformanceLoggingEnabled(bool enabled) if (m_page->mainFrame() && m_page->mainFrame()->view()) m_page->mainFrame()->view()->setScrollingPerformanceLoggingEnabled(enabled); } + +void Settings::setAggressiveTileRetentionEnabled(bool enabled) +{ + m_aggressiveTileRetentionEnabled = enabled; +} void Settings::setMockScrollbarsEnabled(bool flag) { @@ -642,7 +582,6 @@ bool Settings::usesOverlayScrollbars() return gUsesOverlayScrollbars; } -#if USE(JSC) void Settings::setShouldRespectPriorityInCSSAttributeSetters(bool flag) { gShouldRespectPriorityInCSSAttributeSetters = flag; @@ -652,6 +591,30 @@ bool Settings::shouldRespectPriorityInCSSAttributeSetters() { return gShouldRespectPriorityInCSSAttributeSetters; } + +#if ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING) +void Settings::setHiddenPageDOMTimerThrottlingEnabled(bool flag) +{ + if (m_hiddenPageDOMTimerThrottlingEnabled == flag) + return; + m_hiddenPageDOMTimerThrottlingEnabled = flag; + m_page->hiddenPageDOMTimerThrottlingStateChanged(); +} #endif +#if ENABLE(PAGE_VISIBILITY_API) +void Settings::setHiddenPageCSSAnimationSuspensionEnabled(bool flag) +{ + if (m_hiddenPageCSSAnimationSuspensionEnabled == flag) + return; + m_hiddenPageCSSAnimationSuspensionEnabled = flag; + m_page->hiddenPageCSSAnimationSuspensionStateChanged(); +} +#endif + +void Settings::setLowPowerVideoAudioBufferSizeEnabled(bool flag) +{ + gLowPowerVideoAudioBufferSizeEnabled = flag; +} + } // namespace WebCore diff --git a/Source/WebCore/page/Settings.h b/Source/WebCore/page/Settings.h index 7513ba35a..f8ba09e0c 100644 --- a/Source/WebCore/page/Settings.h +++ b/Source/WebCore/page/Settings.h @@ -41,6 +41,7 @@ namespace WebCore { + class FontGenericFamilies; class Page; enum EditableLinkBehavior { @@ -57,22 +58,13 @@ namespace WebCore { TextDirectionSubmenuAlwaysIncluded }; - // UScriptCode uses -1 and 0 for UScriptInvalidCode and UScriptCommon. - // We need to use -2 and -3 for empty value and deleted value. - struct UScriptCodeHashTraits : WTF::GenericHashTraits<int> { - static const bool emptyValueIsZero = false; - static int emptyValue() { return -2; } - static void constructDeletedValue(int& slot) { slot = -3; } - static bool isDeletedValue(int value) { return value == -3; } - }; - - typedef HashMap<int, AtomicString, DefaultHash<int>::Hash, UScriptCodeHashTraits> ScriptFontFamilyMap; - class Settings { WTF_MAKE_NONCOPYABLE(Settings); WTF_MAKE_FAST_ALLOCATED; public: static PassOwnPtr<Settings> create(Page*); + ~Settings(); + void setStandardFontFamily(const AtomicString&, UScriptCode = USCRIPT_COMMON); const AtomicString& standardFontFamily(UScriptCode = USCRIPT_COMMON) const; @@ -94,21 +86,6 @@ namespace WebCore { void setPictographFontFamily(const AtomicString&, UScriptCode = USCRIPT_COMMON); const AtomicString& pictographFontFamily(UScriptCode = USCRIPT_COMMON) const; - void setMinimumFontSize(int); - int minimumFontSize() const { return m_minimumFontSize; } - - void setMinimumLogicalFontSize(int); - int minimumLogicalFontSize() const { return m_minimumLogicalFontSize; } - - void setDefaultFontSize(int); - int defaultFontSize() const { return m_defaultFontSize; } - - void setDefaultFixedFontSize(int); - int defaultFixedFontSize() const { return m_defaultFixedFontSize; } - - void setScreenFontSubstitutionEnabled(bool); - bool screenFontSubstitutionEnabled() const { return m_screenFontSubstitutionEnabled; } - #if ENABLE(TEXT_AUTOSIZING) void setTextAutosizingEnabled(bool); bool textAutosizingEnabled() const { return m_textAutosizingEnabled; } @@ -122,10 +99,6 @@ namespace WebCore { #endif // Only set by Layout Tests. - void setResolutionOverride(const IntSize&); - const IntSize& resolutionOverride() const { return m_resolutionDensityPerInchOverride; } - - // Only set by Layout Tests. void setMediaTypeOverride(const String&); const String& mediaTypeOverride() const { return m_mediaTypeOverride; } @@ -134,11 +107,11 @@ namespace WebCore { void setLoadsImagesAutomatically(bool); bool loadsImagesAutomatically() const { return m_loadsImagesAutomatically; } - void setScriptEnabled(bool); - // Instead of calling isScriptEnabled directly, please consider calling - // ScriptController::canExecuteScripts, which takes things like the - // HTML sandbox attribute into account. + // Clients that execute script should call ScriptController::canExecuteScripts() + // instead of this function. ScriptController::canExecuteScripts() checks the + // HTML sandbox, plug-in sandboxing, and other important details. bool isScriptEnabled() const { return m_isScriptEnabled; } + void setScriptEnabled(bool); SETTINGS_GETTERS_AND_SETTERS @@ -152,9 +125,6 @@ namespace WebCore { void setImagesEnabled(bool); bool areImagesEnabled() const { return m_areImagesEnabled; } - void setMediaEnabled(bool); - bool isMediaEnabled() const { return m_isMediaEnabled; } - void setPluginsEnabled(bool); bool arePluginsEnabled() const { return m_arePluginsEnabled; } @@ -180,18 +150,15 @@ namespace WebCore { void setUserStyleSheetLocation(const KURL&); const KURL& userStyleSheetLocation() const { return m_userStyleSheetLocation; } - void setTextAreasAreResizable(bool); - bool textAreasAreResizable() const { return m_textAreasAreResizable; } - void setNeedsAdobeFrameReloadingQuirk(bool); bool needsAcrobatFrameReloadingQuirk() const { return m_needsAdobeFrameReloadingQuirk; } - void setDOMPasteAllowed(bool); - bool isDOMPasteAllowed() const { return m_isDOMPasteAllowed; } - static void setDefaultMinDOMTimerInterval(double); // Interval specified in seconds. static double defaultMinDOMTimerInterval(); + static void setHiddenPageDOMTimerAlignmentInterval(double); // Interval specified in seconds. + static double hiddenPageDOMTimerAlignmentInterval(); + void setMinDOMTimerInterval(double); // Per-page; initialized to default value. double minDOMTimerInterval(); @@ -201,18 +168,17 @@ namespace WebCore { void setDOMTimerAlignmentInterval(double); double domTimerAlignmentInterval() const; +#if ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING) + bool hiddenPageDOMTimerThrottlingEnabled() const { return m_hiddenPageDOMTimerThrottlingEnabled; } + void setHiddenPageDOMTimerThrottlingEnabled(bool); +#endif + void setUsesPageCache(bool); bool usesPageCache() const { return m_usesPageCache; } - void setAuthorAndUserStylesEnabled(bool); - bool authorAndUserStylesEnabled() const { return m_authorAndUserStylesEnabled; } - void setFontRenderingMode(FontRenderingMode mode); FontRenderingMode fontRenderingMode() const; - void setApplicationChromeMode(bool); - bool inApplicationChromeMode() const { return m_inApplicationChromeMode; } - void setCSSCustomFilterEnabled(bool enabled) { m_isCSSCustomFilterEnabled = enabled; } bool isCSSCustomFilterEnabled() const { return m_isCSSCustomFilterEnabled; } @@ -232,16 +198,10 @@ namespace WebCore { bool cssVariablesEnabled() const { return false; } #endif - void setAcceleratedCompositingEnabled(bool); - bool acceleratedCompositingEnabled() const { return m_acceleratedCompositingEnabled; } - - void setShowDebugBorders(bool); - bool showDebugBorders() const { return m_showDebugBorders; } - - void setShowRepaintCounter(bool); - bool showRepaintCounter() const { return m_showRepaintCounter; } + void setShowTiledScrollingIndicator(bool); + bool showTiledScrollingIndicator() const { return m_showTiledScrollingIndicator; } -#if PLATFORM(WIN) || (OS(WINDOWS) && PLATFORM(WX)) +#if PLATFORM(WIN) static void setShouldUseHighResolutionTimers(bool); static bool shouldUseHighResolutionTimers() { return gShouldUseHighResolutionTimers; } #endif @@ -250,20 +210,17 @@ namespace WebCore { bool tiledBackingStoreEnabled() const { return m_tiledBackingStoreEnabled; } #if USE(AVFOUNDATION) - static void setAVFoundationEnabled(bool flag) { gAVFoundationEnabled = flag; } + static void setAVFoundationEnabled(bool flag); static bool isAVFoundationEnabled() { return gAVFoundationEnabled; } #endif - void setUnifiedTextCheckerEnabled(bool flag) { m_unifiedTextCheckerEnabled = flag; } - bool unifiedTextCheckerEnabled() const { return m_unifiedTextCheckerEnabled; } +#if PLATFORM(MAC) + static void setQTKitEnabled(bool flag); + static bool isQTKitEnabled() { return gQTKitEnabled; } +#endif static const unsigned defaultMaximumHTMLParserDOMTreeDepth = 512; -#if ENABLE(SMOOTH_SCROLLING) - void setEnableScrollAnimator(bool flag) { m_scrollAnimatorEnabled = flag; } - bool scrollAnimatorEnabled() const { return m_scrollAnimatorEnabled; } -#endif - #if USE(SAFARI_THEME) // Windows debugging pref (global) for switching between the Aqua look and a native windows look. static void setShouldPaintNativeControls(bool); @@ -286,12 +243,24 @@ namespace WebCore { void setScrollingPerformanceLoggingEnabled(bool); bool scrollingPerformanceLoggingEnabled() { return m_scrollingPerformanceLoggingEnabled; } + + void setAggressiveTileRetentionEnabled(bool); + bool aggressiveTileRetentionEnabled() { return m_aggressiveTileRetentionEnabled; } -#if USE(JSC) static void setShouldRespectPriorityInCSSAttributeSetters(bool); static bool shouldRespectPriorityInCSSAttributeSetters(); + + void setTimeWithoutMouseMovementBeforeHidingControls(double time) { m_timeWithoutMouseMovementBeforeHidingControls = time; } + double timeWithoutMouseMovementBeforeHidingControls() const { return m_timeWithoutMouseMovementBeforeHidingControls; } + +#if ENABLE(PAGE_VISIBILITY_API) + bool hiddenPageCSSAnimationSuspensionEnabled() const { return m_hiddenPageCSSAnimationSuspensionEnabled; } + void setHiddenPageCSSAnimationSuspensionEnabled(bool); #endif + static bool lowPowerVideoAudioBufferSizeEnabled() { return gLowPowerVideoAudioBufferSizeEnabled; } + static void setLowPowerVideoAudioBufferSizeEnabled(bool); + private: explicit Settings(Page*); @@ -301,25 +270,13 @@ namespace WebCore { String m_mediaTypeOverride; KURL m_userStyleSheetLocation; - ScriptFontFamilyMap m_standardFontFamilyMap; - ScriptFontFamilyMap m_serifFontFamilyMap; - ScriptFontFamilyMap m_fixedFontFamilyMap; - ScriptFontFamilyMap m_sansSerifFontFamilyMap; - ScriptFontFamilyMap m_cursiveFontFamilyMap; - ScriptFontFamilyMap m_fantasyFontFamilyMap; - ScriptFontFamilyMap m_pictographFontFamilyMap; - int m_minimumFontSize; - int m_minimumLogicalFontSize; - int m_defaultFontSize; - int m_defaultFixedFontSize; - bool m_screenFontSubstitutionEnabled; + RefPtr<FontGenericFamilies> m_fontGenericFamilies; SecurityOrigin::StorageBlockingPolicy m_storageBlockingPolicy; #if ENABLE(TEXT_AUTOSIZING) float m_textAutosizingFontScaleFactor; IntSize m_textAutosizingWindowSizeOverride; bool m_textAutosizingEnabled : 1; #endif - IntSize m_resolutionDensityPerInchOverride; SETTINGS_MEMBER_VARIABLES @@ -328,16 +285,11 @@ namespace WebCore { bool m_loadsImagesAutomatically : 1; bool m_privateBrowsingEnabled : 1; bool m_areImagesEnabled : 1; - bool m_isMediaEnabled : 1; bool m_arePluginsEnabled : 1; bool m_isScriptEnabled : 1; - bool m_textAreasAreResizable : 1; bool m_needsAdobeFrameReloadingQuirk : 1; - bool m_isDOMPasteAllowed : 1; bool m_usesPageCache : 1; - bool m_authorAndUserStylesEnabled : 1; unsigned m_fontRenderingMode : 1; - bool m_inApplicationChromeMode : 1; bool m_isCSSCustomFilterEnabled : 1; #if ENABLE(CSS_STICKY_POSITION) bool m_cssStickyPositionEnabled : 1; @@ -345,42 +297,52 @@ namespace WebCore { #if ENABLE(CSS_VARIABLES) bool m_cssVariablesEnabled : 1; #endif - bool m_acceleratedCompositingEnabled : 1; - bool m_showDebugBorders : 1; - bool m_showRepaintCounter : 1; + bool m_showTiledScrollingIndicator : 1; bool m_tiledBackingStoreEnabled : 1; bool m_dnsPrefetchingEnabled : 1; - bool m_unifiedTextCheckerEnabled : 1; -#if ENABLE(SMOOTH_SCROLLING) - bool m_scrollAnimatorEnabled : 1; -#endif #if ENABLE(TOUCH_EVENTS) bool m_touchEventEmulationEnabled : 1; #endif bool m_scrollingPerformanceLoggingEnabled : 1; + bool m_aggressiveTileRetentionEnabled : 1; + + double m_timeWithoutMouseMovementBeforeHidingControls; Timer<Settings> m_setImageLoadingSettingsTimer; void imageLoadingSettingsTimerFired(Timer<Settings>*); +#if ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING) + bool m_hiddenPageDOMTimerThrottlingEnabled : 1; +#endif +#if ENABLE(PAGE_VISIBILITY_API) + bool m_hiddenPageCSSAnimationSuspensionEnabled : 1; +#endif static double gDefaultMinDOMTimerInterval; static double gDefaultDOMTimerAlignmentInterval; #if USE(AVFOUNDATION) static bool gAVFoundationEnabled; #endif + +#if PLATFORM(MAC) + static bool gQTKitEnabled; +#endif + static bool gMockScrollbarsEnabled; static bool gUsesOverlayScrollbars; #if USE(SAFARI_THEME) static bool gShouldPaintNativeControls; #endif -#if PLATFORM(WIN) || (OS(WINDOWS) && PLATFORM(WX)) +#if PLATFORM(WIN) static bool gShouldUseHighResolutionTimers; #endif -#if USE(JSC) static bool gShouldRespectPriorityInCSSAttributeSetters; -#endif + + static double gHiddenPageDOMTimerAlignmentInterval; + + static bool gLowPowerVideoAudioBufferSizeEnabled; }; } // namespace WebCore diff --git a/Source/WebCore/page/Settings.in b/Source/WebCore/page/Settings.in index 126630c33..dd51d6850 100644 --- a/Source/WebCore/page/Settings.in +++ b/Source/WebCore/page/Settings.in @@ -33,6 +33,11 @@ deviceHeight type=int, initial=0 # since the memory used won't be released until the Page is destroyed. sessionStorageQuota type=unsigned, initial=StorageMap::noQuota +minimumFontSize type=int, initial=0, setNeedsStyleRecalcInAllFrames=1 +minimumLogicalFontSize type=int, initial=0, setNeedsStyleRecalcInAllFrames=1 +defaultFontSize type=int, initial=0, setNeedsStyleRecalcInAllFrames=1 +defaultFixedFontSize type=int, initial=0, setNeedsStyleRecalcInAllFrames=1 + editingBehaviorType type=EditingBehaviorType, initial=editingBehaviorTypeForPlatform() maximumHTMLParserDOMTreeDepth type=unsigned, initial=defaultMaximumHTMLParserDOMTreeDepth @@ -50,13 +55,19 @@ javaScriptCanAccessClipboard initial=false shouldPrintBackgrounds initial=false usesDashboardBackwardCompatibilityMode initial=false, conditional=DASHBOARD_SUPPORT +screenFontSubstitutionEnabled initial=true, setNeedsStyleRecalcInAllFrames=1 +textAreasAreResizable initial=false, setNeedsStyleRecalcInAllFrames=1 +authorAndUserStylesEnabled initial=true, setNeedsStyleRecalcInAllFrames=1 +acceleratedCompositingEnabled initial=true, setNeedsStyleRecalcInAllFrames=1 +showDebugBorders initial=false, setNeedsStyleRecalcInAllFrames=1 +showRepaintCounter initial=false, setNeedsStyleRecalcInAllFrames=1 + # This is a quirk we are pro-actively applying to old applications. It changes keyboard event dispatching, # making keyIdentifier available on keypress events, making charCode available on keydown/keyup events, # and getting keypress dispatched in more cases. needsKeyboardEventDisambiguationQuirks initial=false treatsAnyTextCSSLinkAsStylesheet initial=false -needsLeopardMailQuirks initial=false shrinksStandaloneImagesToFit initial=true pageCacheSupportsPlugins initial=false showsURLsInToolTips initial=false @@ -64,6 +75,7 @@ showsToolTipOverTruncatedText initial=false forceFTPDirectoryListings initial=false developerExtrasEnabled initial=false javaScriptExperimentsEnabled initial=false +scriptMarkupEnabled initial=true needsSiteSpecificQuirks initial=false webArchiveDebugModeEnabled initial=false, conditional=WEB_ARCHIVE localFileContentSniffingEnabled initial=false @@ -82,31 +94,26 @@ cssGridLayoutEnabled initial=false downloadableBinaryFontsEnabled initial=true xssAuditorEnabled initial=false -acceleratedCompositingFor3DTransformsEnabled initial=true -acceleratedCompositingForVideoEnabled initial=true -acceleratedCompositingForPluginsEnabled initial=true -acceleratedCompositingForCanvasEnabled initial=true -acceleratedCompositingForAnimationEnabled initial=true +unsafePluginPastingEnabled initial=true acceleratedCompositingForFixedPositionEnabled initial=false acceleratedCompositingForOverflowScrollEnabled initial=false # Works only in conjunction with forceCompositingMode. acceleratedCompositingForScrollableFramesEnabled initial=false +compositedScrollingForFramesEnabled initial=false experimentalNotificationsEnabled initial=false webGLEnabled initial=false -webGLErrorsToConsoleEnabled initial=false +webGLErrorsToConsoleEnabled initial=true openGLMultisamplingEnabled initial=true privilegedWebGLExtensionsEnabled initial=false accelerated2dCanvasEnabled initial=false -deferred2dCanvasEnabled initial=false +antialiased2dCanvasEnabled initial=true loadDeferringEnabled initial=true webAudioEnabled initial=false paginateDuringLayoutEnabled initial=false fullScreenEnabled initial=false, conditional=FULLSCREEN_API asynchronousSpellCheckingEnabled initial=false -memoryInfoEnabled initial=false -quantizedMemoryInfoEnabled initial=false # This feature requires an implementation of ValidationMessageClient. interactiveFormValidationEnabled initial=false @@ -130,6 +137,7 @@ shouldDisplaySubtitles initial=false, conditional=VIDEO_TRACK shouldDisplayCaptions initial=false, conditional=VIDEO_TRACK shouldDisplayTextDescriptions initial=false, conditional=VIDEO_TRACK scrollingCoordinatorEnabled initial=false +scrollAnimatorEnabled initial=true, conditional=SMOOTH_SCROLLING notificationsEnabled initial=true # Some apps needs isLoadingInAPISense to account for active subresource loaders. @@ -150,6 +158,12 @@ needsDidFinishLoadOrderQuirk initial=false fixedPositionCreatesStackingContext initial=false syncXHRInDocumentsEnabled initial=true cookieEnabled initial=true +mediaEnabled initial=true +applicationChromeMode initial=false +DOMPasteAllowed initial=false + +threadedHTMLParser initial=false, conditional=THREADED_HTML_PARSER +useThreadedHTMLParserForDataURLs initial=false, conditional=THREADED_HTML_PARSER # When enabled, window.blur() does not change focus, and # window.focus() only changes focus when invoked from the context that @@ -157,8 +171,13 @@ cookieEnabled initial=true windowFocusRestricted initial=true diagnosticLoggingEnabled initial=false +applyDeviceScaleFactorInCompositor initial=true applyPageScaleFactorInCompositor initial=false plugInSnapshottingEnabled initial=false +snapshotAllPlugIns initial=false +autostartOriginPlugInSnapshottingEnabled initial=true +primaryPlugInSnapshotDetectionEnabled initial=true +maximumPlugInSnapshotAttempts type=unsigned, initial=20 frameFlatteningEnabled initial=false allowCustomScrollbarInMainFrame initial=true @@ -168,3 +187,18 @@ spatialNavigationEnabled initial=false # This setting adds a means to enable/disable touch initiated drag & drop. If # enabled, the user can initiate drag using long press. touchDragDropEnabled initial=false + +unifiedTextCheckerEnabled initial=defaultUnifiedTextCheckerEnabled + +logsPageMessagesToSystemConsoleEnabled initial=false + +backForwardCacheExpirationInterval type=double, initial=1800 + +# Some apps could have a default video poster if it is not set. +defaultVideoPosterURL type=String + +smartInsertDeleteEnabled initial=defaultSmartInsertDeleteEnabled +selectTrailingWhitespaceEnabled initial=defaultSelectTrailingWhitespaceEnabled + +selectionIncludesAltImageText initial=true +useLegacyBackgroundSizeShorthandBehavior initial=false diff --git a/Source/WebCore/page/SpatialNavigation.cpp b/Source/WebCore/page/SpatialNavigation.cpp index 62a39866e..240ca914e 100644 --- a/Source/WebCore/page/SpatialNavigation.cpp +++ b/Source/WebCore/page/SpatialNavigation.cpp @@ -60,17 +60,15 @@ FocusCandidate::FocusCandidate(Node* node, FocusDirection direction) , focusableNode(0) , enclosingScrollableBox(0) , distance(maxDistance()) - , parentDistance(maxDistance()) , alignment(None) - , parentAlignment(None) , isOffscreen(true) , isOffscreenAfterScrolling(true) { ASSERT(node); ASSERT(node->isElementNode()); - if (node->hasTagName(HTMLNames::areaTag)) { - HTMLAreaElement* area = static_cast<HTMLAreaElement*>(node); + if (isHTMLAreaElement(node)) { + HTMLAreaElement* area = toHTMLAreaElement(node); HTMLImageElement* image = area->imageElement(); if (!image || !image->renderer()) return; @@ -234,7 +232,6 @@ static bool areRectsPartiallyAligned(FocusDirection direction, const LayoutRect& // // ... and variants of the above cases. return ((bStart >= aStart && bStart <= aEnd) - || (bEnd >= aStart && bEnd <= aEnd) || (bMiddle >= aStart && bMiddle <= aEnd) || (bEnd >= aStart && bEnd <= aEnd)); } @@ -371,7 +368,7 @@ bool scrollInDirection(Node* container, FocusDirection direction) { ASSERT(container); if (container->isDocumentNode()) - return scrollInDirection(static_cast<Document*>(container)->frame(), direction); + return scrollInDirection(toDocument(container)->frame(), direction); if (!container->renderBox()) return false; @@ -440,7 +437,7 @@ Node* scrollableEnclosingBoxOrParentFrameForNodeInDirection(FocusDirection direc Node* parent = node; do { if (parent->isDocumentNode()) - parent = static_cast<Document*>(parent)->document()->frame()->ownerElement(); + parent = toDocument(parent)->document()->frame()->ownerElement(); else parent = parent->parentNode(); } while (parent && !canScrollInDirection(parent, direction) && !parent->isDocumentNode()); @@ -451,8 +448,12 @@ Node* scrollableEnclosingBoxOrParentFrameForNodeInDirection(FocusDirection direc bool canScrollInDirection(const Node* container, FocusDirection direction) { ASSERT(container); + + if (container->hasTagName(HTMLNames::selectTag)) + return false; + if (container->isDocumentNode()) - return canScrollInDirection(static_cast<const Document*>(container)->frame(), direction); + return canScrollInDirection(toDocument(container)->frame(), direction); if (!isScrollableNode(container)) return false; @@ -483,9 +484,9 @@ bool canScrollInDirection(const Frame* frame, FocusDirection direction) return false; if ((direction == FocusDirectionUp || direction == FocusDirectionDown) && ScrollbarAlwaysOff == verticalMode) return false; - LayoutSize size = frame->view()->contentsSize(); + LayoutSize size = frame->view()->totalContentsSize(); LayoutSize offset = frame->view()->scrollOffset(); - LayoutRect rect = frame->view()->visibleContentRect(true); + LayoutRect rect = frame->view()->visibleContentRect(ScrollableArea::IncludeScrollbars); switch (direction) { case FocusDirectionLeft: @@ -506,7 +507,7 @@ static LayoutRect rectToAbsoluteCoordinates(Frame* initialFrame, const LayoutRec { LayoutRect rect = initialRect; for (Frame* frame = initialFrame; frame; frame = frame->tree()->parent()) { - if (Element* element = static_cast<Element*>(frame->ownerElement())) { + if (Element* element = frame->ownerElement()) { do { rect.move(element->offsetLeft(), element->offsetTop()); } while ((element = element->offsetParent())); @@ -521,7 +522,7 @@ LayoutRect nodeRectInAbsoluteCoordinates(Node* node, bool ignoreBorder) ASSERT(node && node->renderer() && !node->document()->view()->needsLayout()); if (node->isDocumentNode()) - return frameRectInAbsoluteCoordinates(static_cast<Document*>(node)->frame()); + return frameRectInAbsoluteCoordinates(toDocument(node)->frame()); LayoutRect rect = rectToAbsoluteCoordinates(node->document()->frame(), node->boundingBox()); // For authors that use border instead of outline in their CSS, we compensate by ignoring the border when calculating @@ -607,7 +608,7 @@ bool areElementsOnSameLine(const FocusCandidate& firstCandidate, const FocusCand if (!firstCandidate.rect.intersects(secondCandidate.rect)) return false; - if (firstCandidate.focusableNode->hasTagName(HTMLNames::areaTag) || secondCandidate.focusableNode->hasTagName(HTMLNames::areaTag)) + if (isHTMLAreaElement(firstCandidate.focusableNode) || isHTMLAreaElement(secondCandidate.focusableNode)) return false; if (!firstCandidate.visibleNode->renderer()->isRenderInline() || !secondCandidate.visibleNode->renderer()->isRenderInline()) diff --git a/Source/WebCore/page/SpatialNavigation.h b/Source/WebCore/page/SpatialNavigation.h index 37e346e16..d58b0df19 100644 --- a/Source/WebCore/page/SpatialNavigation.h +++ b/Source/WebCore/page/SpatialNavigation.h @@ -105,9 +105,7 @@ struct FocusCandidate { , focusableNode(0) , enclosingScrollableBox(0) , distance(maxDistance()) - , parentDistance(maxDistance()) , alignment(None) - , parentAlignment(None) , isOffscreen(true) , isOffscreenAfterScrolling(true) { @@ -127,9 +125,7 @@ struct FocusCandidate { Node* focusableNode; Node* enclosingScrollableBox; long long distance; - long long parentDistance; RectsAlignment alignment; - RectsAlignment parentAlignment; LayoutRect rect; bool isOffscreen; bool isOffscreenAfterScrolling; diff --git a/Source/WebCore/page/SpeechInput.cpp b/Source/WebCore/page/SpeechInput.cpp index cb4a21f2d..228d3fcd8 100644 --- a/Source/WebCore/page/SpeechInput.cpp +++ b/Source/WebCore/page/SpeechInput.cpp @@ -117,10 +117,9 @@ void SpeechInput::cancelRecognition(int listenerId) m_client->cancelRecognition(listenerId); } -const AtomicString& SpeechInput::supplementName() +const char* SpeechInput::supplementName() { - DEFINE_STATIC_LOCAL(AtomicString, name, ("SpeechInput", AtomicString::ConstructFromLiteral)); - return name; + return "SpeechInput"; } void provideSpeechInputTo(Page* page, SpeechInputClient* client) diff --git a/Source/WebCore/page/SpeechInput.h b/Source/WebCore/page/SpeechInput.h index 38113a06d..447f632e6 100644 --- a/Source/WebCore/page/SpeechInput.h +++ b/Source/WebCore/page/SpeechInput.h @@ -55,7 +55,7 @@ public: virtual ~SpeechInput(); static PassOwnPtr<SpeechInput> create(SpeechInputClient*); - static const AtomicString& supplementName(); + static const char* supplementName(); static SpeechInput* from(Page* page) { return static_cast<SpeechInput*>(Supplement<Page>::from(page, supplementName())); } // Generates a unique ID for the given listener to be used for speech requests. diff --git a/Source/WebCore/page/SpeechInputResult.idl b/Source/WebCore/page/SpeechInputResult.idl index ee1727089..41a530ad3 100644 --- a/Source/WebCore/page/SpeechInputResult.idl +++ b/Source/WebCore/page/SpeechInputResult.idl @@ -24,7 +24,9 @@ */ [ + NoInterfaceObject, Conditional=INPUT_SPEECH, + ImplementationLacksVTable ] interface SpeechInputResult { readonly attribute DOMString utterance; readonly attribute float confidence; diff --git a/Source/WebCore/page/SpeechInputResultList.idl b/Source/WebCore/page/SpeechInputResultList.idl index 79357cdad..4cf29ea2d 100644 --- a/Source/WebCore/page/SpeechInputResultList.idl +++ b/Source/WebCore/page/SpeechInputResultList.idl @@ -24,10 +24,11 @@ */ [ - IndexedGetter, - Conditional=INPUT_SPEECH + NoInterfaceObject, + Conditional=INPUT_SPEECH, + ImplementationLacksVTable ] interface SpeechInputResultList { readonly attribute unsigned long length; - SpeechInputResult item(in [IsIndex] unsigned long index); + getter SpeechInputResult item([IsIndex] unsigned long index); }; diff --git a/Source/WebCore/page/SuspendableTimer.cpp b/Source/WebCore/page/SuspendableTimer.cpp index 15e56280f..57afcc512 100644 --- a/Source/WebCore/page/SuspendableTimer.cpp +++ b/Source/WebCore/page/SuspendableTimer.cpp @@ -32,7 +32,7 @@ namespace WebCore { SuspendableTimer::SuspendableTimer(ScriptExecutionContext* context) - : ActiveDOMObject(context, this) + : ActiveDOMObject(context) , m_nextFireInterval(0) , m_repeatInterval(0) , m_active(false) diff --git a/Source/WebCore/page/TouchAdjustment.cpp b/Source/WebCore/page/TouchAdjustment.cpp index 1de02203c..8b01c4501 100644 --- a/Source/WebCore/page/TouchAdjustment.cpp +++ b/Source/WebCore/page/TouchAdjustment.cpp @@ -22,9 +22,11 @@ #include "TouchAdjustment.h" #include "ContainerNode.h" +#include "Editor.h" #include "FloatPoint.h" #include "FloatQuad.h" #include "FrameView.h" +#include "HTMLFrameOwnerElement.h" #include "HTMLInputElement.h" #include "HTMLLabelElement.h" #include "HTMLNames.h" @@ -71,13 +73,13 @@ typedef float (*DistanceFunction)(const IntPoint&, const IntRect&, const Subtarg // Takes non-const Node* because isContentEditable is a non-const function. bool nodeRespondsToTapGesture(Node* node) { - if (node->isMouseFocusable()) - return true; if (node->willRespondToMouseClickEvents() || node->willRespondToMouseMoveEvents()) return true; // Accept nodes that has a CSS effect when touched. if (node->isElementNode()) { Element* element = toElement(node); + if (element->isMouseFocusable()) + return true; if (element->childrenAffectedByActive() || element->childrenAffectedByHover()) return true; } @@ -114,7 +116,7 @@ bool providesContextMenuItems(Node* node) return true; if (node->renderer()->canBeSelectionLeaf()) { // If the context menu gesture will trigger a selection all selectable nodes are valid targets. - if (node->renderer()->frame()->editor()->behavior().shouldSelectOnContextualMenuClick()) + if (node->renderer()->frame()->editor().behavior().shouldSelectOnContextualMenuClick()) return true; // Only the selected part of the renderer is a valid target, but this will be corrected in // appendContextSubtargetsForNode. @@ -155,7 +157,7 @@ static inline void appendContextSubtargetsForNode(Node* node, SubtargetGeometryL Text* textNode = static_cast<WebCore::Text*>(node); RenderText* textRenderer = static_cast<RenderText*>(textNode->renderer()); - if (textRenderer->frame()->editor()->behavior().shouldSelectOnContextualMenuClick()) { + if (textRenderer->frame()->editor().behavior().shouldSelectOnContextualMenuClick()) { // Make subtargets out of every word. String textValue = textNode->data(); TextBreakIterator* wordIterator = wordBreakIterator(textValue.characters(), textValue.length()); @@ -221,8 +223,17 @@ static inline void appendZoomableSubtargets(Node* node, SubtargetGeometryList& s subtargets.append(SubtargetGeometry(node, *it)); } +static inline Node* parentShadowHostOrOwner(const Node* node) +{ + if (Node* ancestor = node->parentOrShadowHostNode()) + return ancestor; + if (node->isDocumentNode()) + return toDocument(node)->ownerElement(); + return 0; +} + // Compiles a list of subtargets of all the relevant target nodes. -void compileSubtargetList(const NodeList& intersectedNodes, SubtargetGeometryList& subtargets, NodeFilter nodeFilter, AppendSubtargetsForNode appendSubtargetsForNode) +void compileSubtargetList(const NodeListHashSet& intersectedNodes, SubtargetGeometryList& subtargets, NodeFilter nodeFilter, AppendSubtargetsForNode appendSubtargetsForNode) { // Find candidates responding to tap gesture events in O(n) time. HashMap<Node*, Node*> responderMap; @@ -233,12 +244,12 @@ void compileSubtargetList(const NodeList& intersectedNodes, SubtargetGeometryLis // A node matching the NodeFilter is called a responder. Candidate nodes must either be a // responder or have an ancestor that is a responder. // This iteration tests all ancestors at most once by caching earlier results. - unsigned length = intersectedNodes.length(); - for (unsigned i = 0; i < length; ++i) { - Node* const node = intersectedNodes.item(i); + NodeListHashSet::const_iterator end = intersectedNodes.end(); + for (NodeListHashSet::const_iterator it = intersectedNodes.begin(); it != end; ++it) { + Node* const node = it->get(); Vector<Node*> visitedNodes; Node* respondingNode = 0; - for (Node* visitedNode = node; visitedNode; visitedNode = visitedNode->parentOrHostNode()) { + for (Node* visitedNode = node; visitedNode; visitedNode = visitedNode->parentOrShadowHostNode()) { // Check if we already have a result for a common ancestor from another candidate. respondingNode = responderMap.get(visitedNode); if (respondingNode) @@ -248,7 +259,7 @@ void compileSubtargetList(const NodeList& intersectedNodes, SubtargetGeometryLis if (nodeFilter(visitedNode)) { respondingNode = visitedNode; // Continue the iteration to collect the ancestors of the responder, which we will need later. - for (visitedNode = visitedNode->parentOrHostNode(); visitedNode; visitedNode = visitedNode->parentOrHostNode()) { + for (visitedNode = parentShadowHostOrOwner(visitedNode); visitedNode; visitedNode = parentShadowHostOrOwner(visitedNode)) { HashSet<Node*>::AddResult addResult = ancestorsToRespondersSet.add(visitedNode); if (!addResult.isNewEntry) break; @@ -266,7 +277,7 @@ void compileSubtargetList(const NodeList& intersectedNodes, SubtargetGeometryLis // We compile the list of component absolute quads instead of using the bounding rect // to be able to perform better hit-testing on inline links on line-breaks. - length = candidates.size(); + unsigned length = candidates.size(); for (unsigned i = 0; i < length; i++) { Node* candidate = candidates[i]; // Skip nodes who's responders are ancestors of other responders. This gives preference to @@ -281,7 +292,7 @@ void compileSubtargetList(const NodeList& intersectedNodes, SubtargetGeometryLis continue; if (candidate->isContentEditable()) { Node* replacement = candidate; - Node* parent = candidate->parentOrHostNode(); + Node* parent = candidate->parentOrShadowHostNode(); while (parent && parent->isContentEditable()) { replacement = parent; if (editableAncestors.contains(replacement)) { @@ -289,7 +300,7 @@ void compileSubtargetList(const NodeList& intersectedNodes, SubtargetGeometryLis break; } editableAncestors.add(replacement); - parent = parent->parentOrHostNode(); + parent = parent->parentOrShadowHostNode(); } candidate = replacement; } @@ -299,11 +310,11 @@ void compileSubtargetList(const NodeList& intersectedNodes, SubtargetGeometryLis } // Compiles a list of zoomable subtargets. -void compileZoomableSubtargets(const NodeList& intersectedNodes, SubtargetGeometryList& subtargets) +void compileZoomableSubtargets(const NodeListHashSet& intersectedNodes, SubtargetGeometryList& subtargets) { - unsigned length = intersectedNodes.length(); - for (unsigned i = 0; i < length; ++i) { - Node* const candidate = intersectedNodes.item(i); + NodeListHashSet::const_iterator end = intersectedNodes.end(); + for (NodeListHashSet::const_iterator it = intersectedNodes.begin(); it != end; ++it) { + Node* const candidate = it->get(); if (nodeIsZoomTarget(candidate)) appendZoomableSubtargets(candidate, subtargets); } @@ -465,7 +476,7 @@ bool findNodeWithLowestDistanceMetric(Node*& targetNode, IntPoint& targetPoint, } // namespace TouchAdjustment -bool findBestClickableCandidate(Node*& targetNode, IntPoint &targetPoint, const IntPoint &touchHotspot, const IntRect &touchArea, const NodeList& nodeList) +bool findBestClickableCandidate(Node*& targetNode, IntPoint &targetPoint, const IntPoint &touchHotspot, const IntRect &touchArea, const NodeListHashSet& nodeList) { IntRect targetArea; TouchAdjustment::SubtargetGeometryList subtargets; @@ -473,7 +484,7 @@ bool findBestClickableCandidate(Node*& targetNode, IntPoint &targetPoint, const return TouchAdjustment::findNodeWithLowestDistanceMetric(targetNode, targetPoint, targetArea, touchHotspot, touchArea, subtargets, TouchAdjustment::hybridDistanceFunction); } -bool findBestContextMenuCandidate(Node*& targetNode, IntPoint &targetPoint, const IntPoint &touchHotspot, const IntRect &touchArea, const NodeList& nodeList) +bool findBestContextMenuCandidate(Node*& targetNode, IntPoint &targetPoint, const IntPoint &touchHotspot, const IntRect &touchArea, const NodeListHashSet& nodeList) { IntRect targetArea; TouchAdjustment::SubtargetGeometryList subtargets; @@ -481,7 +492,7 @@ bool findBestContextMenuCandidate(Node*& targetNode, IntPoint &targetPoint, cons return TouchAdjustment::findNodeWithLowestDistanceMetric(targetNode, targetPoint, targetArea, touchHotspot, touchArea, subtargets, TouchAdjustment::hybridDistanceFunction); } -bool findBestZoomableArea(Node*& targetNode, IntRect& targetArea, const IntPoint& touchHotspot, const IntRect& touchArea, const NodeList& nodeList) +bool findBestZoomableArea(Node*& targetNode, IntRect& targetArea, const IntPoint& touchHotspot, const IntRect& touchArea, const NodeListHashSet& nodeList) { IntPoint targetPoint; TouchAdjustment::SubtargetGeometryList subtargets; diff --git a/Source/WebCore/page/TouchAdjustment.h b/Source/WebCore/page/TouchAdjustment.h index 498bbd864..06ac00813 100644 --- a/Source/WebCore/page/TouchAdjustment.h +++ b/Source/WebCore/page/TouchAdjustment.h @@ -28,9 +28,11 @@ namespace WebCore { -bool findBestClickableCandidate(Node*& targetNode, IntPoint& targetPoint, const IntPoint& touchHotspot, const IntRect& touchArea, const NodeList&); -bool findBestContextMenuCandidate(Node*& targetNode, IntPoint& targetPoint, const IntPoint& touchHotspot, const IntRect& touchArea, const NodeList&); -bool findBestZoomableArea(Node*& targetNode, IntRect& targetArea, const IntPoint& touchHotspot, const IntRect& touchArea, const NodeList&); +typedef ListHashSet<RefPtr<Node> > NodeListHashSet; + +bool findBestClickableCandidate(Node*& targetNode, IntPoint& targetPoint, const IntPoint& touchHotspot, const IntRect& touchArea, const NodeListHashSet&); +bool findBestContextMenuCandidate(Node*& targetNode, IntPoint& targetPoint, const IntPoint& touchHotspot, const IntRect& touchArea, const NodeListHashSet&); +bool findBestZoomableArea(Node*& targetNode, IntRect& targetArea, const IntPoint& touchHotspot, const IntRect& touchArea, const NodeListHashSet&); // FIXME: Implement the similar functions for other gestures here as well. } // namespace WebCore diff --git a/Source/WebCore/page/TouchDisambiguation.cpp b/Source/WebCore/page/TouchDisambiguation.cpp deleted file mode 100644 index b582338c2..000000000 --- a/Source/WebCore/page/TouchDisambiguation.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (C) 2012 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" - -#include "TouchDisambiguation.h" - -#include "Document.h" -#include "Element.h" -#include "Frame.h" -#include "FrameView.h" -#include "HTMLNames.h" -#include "HitTestResult.h" -#include <algorithm> -#include <cmath> - -using namespace std; - -namespace WebCore { - -static IntRect boundingBoxForEventNodes(Node* eventNode) -{ - if (!eventNode->document()->view()) - return IntRect(); - - IntRect result; - Node* node = eventNode; - while (node) { - // Skip the whole sub-tree if the node doesn't propagate events. - if (node != eventNode && node->willRespondToMouseClickEvents()) { - node = node->traverseNextSibling(eventNode); - continue; - } - result.unite(node->pixelSnappedBoundingBox()); - node = node->traverseNextNode(eventNode); - } - return eventNode->document()->view()->contentsToWindow(result); -} - -static float scoreTouchTarget(IntPoint touchPoint, int padding, IntRect boundingBox) -{ - if (boundingBox.isEmpty()) - return 0; - - float reciprocalPadding = 1.f / padding; - float score = 1; - - IntSize distance = boundingBox.differenceToPoint(touchPoint); - score *= max((padding - abs(distance.width())) * reciprocalPadding, 0.f); - score *= max((padding - abs(distance.height())) * reciprocalPadding, 0.f); - - return score; -} - -struct TouchTargetData { - IntRect windowBoundingBox; - float score; -}; - -void findGoodTouchTargets(const IntRect& touchBox, Frame* mainFrame, float pageScaleFactor, Vector<IntRect>& goodTargets) -{ - goodTargets.clear(); - - int touchPointPadding = ceil(max(touchBox.width(), touchBox.height()) * 0.5); - // FIXME: Rect-based hit test doesn't transform the touch point size. - // We have to pre-apply page scale factor here. - int padding = ceil(touchPointPadding / pageScaleFactor); - - IntPoint touchPoint = touchBox.center(); - IntPoint contentsPoint = mainFrame->view()->windowToContents(touchPoint); - - HitTestResult result = mainFrame->eventHandler()->hitTestResultAtPoint(contentsPoint, false, false, DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly, IntSize(padding, padding)); - const ListHashSet<RefPtr<Node> >& hitResults = result.rectBasedTestResult(); - - HashMap<Node*, TouchTargetData> touchTargets; - float bestScore = 0; - for (ListHashSet<RefPtr<Node> >::const_iterator it = hitResults.begin(); it != hitResults.end(); ++it) { - for (Node* node = it->get(); node; node = node->parentNode()) { - if (node->isDocumentNode() || node->hasTagName(HTMLNames::htmlTag) || node->hasTagName(HTMLNames::bodyTag)) - break; - if (node->willRespondToMouseClickEvents()) { - TouchTargetData& targetData = touchTargets.add(node, TouchTargetData()).iterator->value; - targetData.windowBoundingBox = boundingBoxForEventNodes(node); - targetData.score = scoreTouchTarget(touchPoint, touchPointPadding, targetData.windowBoundingBox); - bestScore = max(bestScore, targetData.score); - break; - } - } - } - - for (HashMap<Node*, TouchTargetData>::iterator it = touchTargets.begin(); it != touchTargets.end(); ++it) { - // Currently the scoring function uses the overlap area with the fat point as the score. - // We ignore the candidates that has less than 1/2 overlap (we consider not really ambiguous enough) than the best candidate to avoid excessive popups. - if (it->value.score < bestScore * 0.5) - continue; - goodTargets.append(it->value.windowBoundingBox); - } -} - -} // namespace WebCore diff --git a/Source/WebCore/page/TouchDisambiguation.h b/Source/WebCore/page/TouchDisambiguation.h deleted file mode 100644 index 5afeb6b5b..000000000 --- a/Source/WebCore/page/TouchDisambiguation.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2012 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TouchDisambiguation_h -#define TouchDisambiguation_h - -#include <wtf/Vector.h> - -namespace WebCore { - -class Frame; -class IntRect; - -void findGoodTouchTargets(const IntRect& touchBox, Frame* mainFrame, float pageScaleFactor, Vector<IntRect>& goodTargets); - -} // namespace WebCore - -#endif diff --git a/Source/WebCore/page/WebKitAnimation.cpp b/Source/WebCore/page/WebKitAnimation.cpp deleted file mode 100644 index 98e77367c..000000000 --- a/Source/WebCore/page/WebKitAnimation.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (C) 2011 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "WebKitAnimation.h" - -#include "Animation.h" -#include "AnimationBase.h" -#include "RenderStyle.h" - -using namespace std; - -namespace WebCore { - -WebKitAnimation::WebKitAnimation(PassRefPtr<KeyframeAnimation> keyframeAnimation) - : m_keyframeAnimation(keyframeAnimation) -{ -} - -String WebKitAnimation::name() const -{ - return m_keyframeAnimation->animation()->name(); -} - -double WebKitAnimation::duration() const -{ - return m_keyframeAnimation->duration(); -} - -double WebKitAnimation::elapsedTime() const -{ - return m_keyframeAnimation->getElapsedTime(); -} - -void WebKitAnimation::setElapsedTime(double time) -{ - m_keyframeAnimation->setElapsedTime(time); -} - -double WebKitAnimation::delay() const -{ - return m_keyframeAnimation->animation()->delay(); -} - -int WebKitAnimation::iterationCount() const -{ - return m_keyframeAnimation->animation()->iterationCount(); -} - -bool WebKitAnimation::paused() const -{ - return m_keyframeAnimation->paused(); -} - -bool WebKitAnimation::ended() const -{ - int iterations = iterationCount(); - if (iterations == Animation::IterationCountInfinite) - return false; - return m_keyframeAnimation->getElapsedTime() > (m_keyframeAnimation->duration() * iterations); -} - -WebKitAnimation::Direction WebKitAnimation::direction() const -{ - switch (m_keyframeAnimation->animation()->direction()) { - case Animation::AnimationDirectionNormal: - return DIRECTION_NORMAL; - case Animation::AnimationDirectionAlternate: - return DIRECTION_ALTERNATE; - case Animation::AnimationDirectionReverse: - return DIRECTION_REVERSE; - case Animation::AnimationDirectionAlternateReverse: - return DIRECTION_ALTERNATE_REVERSE; - } - ASSERT_NOT_REACHED(); - return DIRECTION_NORMAL; -} - -WebKitAnimation::FillMode WebKitAnimation::fillMode() const -{ - switch (m_keyframeAnimation->animation()->fillMode()) { - case AnimationFillModeNone: - return FILL_NONE; - case AnimationFillModeForwards: - return FILL_FORWARDS; - case AnimationFillModeBackwards: - return FILL_BACKWARDS; - case AnimationFillModeBoth: - return FILL_BOTH; - } - ASSERT_NOT_REACHED(); - return FILL_BOTH; -} - -void WebKitAnimation::pause() -{ - m_keyframeAnimation->pause(); -} - -void WebKitAnimation::play() -{ - m_keyframeAnimation->play(); -} - -} diff --git a/Source/WebCore/page/WebKitAnimation.h b/Source/WebCore/page/WebKitAnimation.h deleted file mode 100644 index 65e05efb3..000000000 --- a/Source/WebCore/page/WebKitAnimation.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2011 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WebKitAnimation_h -#define WebKitAnimation_h - -#include "Animation.h" -#include "AnimationBase.h" -#include "KeyframeAnimation.h" -#include "RenderStyle.h" - -namespace WebCore { - -class WebKitAnimation : public RefCounted<WebKitAnimation> { -public: - - static PassRefPtr<WebKitAnimation> create(PassRefPtr<KeyframeAnimation> keyframeAnimation) - { - return adoptRef(new WebKitAnimation(keyframeAnimation)); - } - - virtual ~WebKitAnimation() { } - - // DOM API - - String name() const; - - double duration() const; - - double elapsedTime() const; - void setElapsedTime(double); - - double delay() const; - int iterationCount() const; - - bool paused() const; - bool ended() const; - - // direction - enum Direction { DIRECTION_NORMAL, DIRECTION_ALTERNATE, DIRECTION_REVERSE, DIRECTION_ALTERNATE_REVERSE }; - Direction direction() const; - - // fill mode - enum FillMode { FILL_NONE, FILL_BACKWARDS, FILL_FORWARDS, FILL_BOTH }; - FillMode fillMode() const; - - void play(); - void pause(); - -protected: - explicit WebKitAnimation(PassRefPtr<KeyframeAnimation>); - -private: - RefPtr<KeyframeAnimation> m_keyframeAnimation; -}; - -} // namespace - -#endif diff --git a/Source/WebCore/page/WebKitAnimationList.cpp b/Source/WebCore/page/WebKitAnimationList.cpp deleted file mode 100644 index 3acfa4c40..000000000 --- a/Source/WebCore/page/WebKitAnimationList.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2011 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "WebKitAnimationList.h" - -#include "WebKitAnimation.h" - -namespace WebCore { - -WebKitAnimationList::WebKitAnimationList() -{ -} - -WebKitAnimationList::~WebKitAnimationList() -{ -} - -unsigned WebKitAnimationList::length() const -{ - return m_animations.size(); -} - -WebKitAnimation* WebKitAnimationList::item(unsigned index) -{ - if (index < m_animations.size()) - return m_animations[index].get(); - return 0; -} - -void WebKitAnimationList::deleteAnimation(unsigned index) -{ - if (index >= m_animations.size()) - return; - - m_animations.remove(index); -} - -void WebKitAnimationList::append(PassRefPtr<WebKitAnimation> animation) -{ - m_animations.append(animation); -} - -unsigned WebKitAnimationList::insertAnimation(PassRefPtr<WebKitAnimation> animation, unsigned index) -{ - if (!animation) - return 0; - - if (index > m_animations.size()) - return 0; - - m_animations.insert(index, animation); - return index; -} - -} // namespace WebCore diff --git a/Source/WebCore/page/WebKitPoint.idl b/Source/WebCore/page/WebKitPoint.idl index 7034eb46e..44e3b10fc 100644 --- a/Source/WebCore/page/WebKitPoint.idl +++ b/Source/WebCore/page/WebKitPoint.idl @@ -25,7 +25,8 @@ [ CustomConstructor, - ConstructorParameters=2 + CustomConstructor(float x, float y), + ImplementationLacksVTable ] interface WebKitPoint { attribute float x; attribute float y; diff --git a/Source/WebCore/page/WebKitAnimationList.idl b/Source/WebCore/page/WindowBase64.idl index cf2da14f1..e2b53cbc0 100644 --- a/Source/WebCore/page/WebKitAnimationList.idl +++ b/Source/WebCore/page/WindowBase64.idl @@ -1,5 +1,7 @@ /* - * Copyright (C) 2011 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008, 2009, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2011 Google Inc. All rights reserved. + * Copyright (C) 2013 Samsung Electronics. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -20,13 +22,12 @@ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ [ - IndexedGetter -] interface WebKitAnimationList { - readonly attribute unsigned long length; - WebKitAnimation item(in unsigned long index); + NoInterfaceObject +] interface WindowBase64 { + [RaisesException] DOMString atob(DOMString string); + [RaisesException] DOMString btoa(DOMString string); }; - diff --git a/Source/WebCore/page/WindowFeatures.cpp b/Source/WebCore/page/WindowFeatures.cpp index 7768a09cd..d93420161 100644 --- a/Source/WebCore/page/WindowFeatures.cpp +++ b/Source/WebCore/page/WindowFeatures.cpp @@ -111,7 +111,7 @@ WindowFeatures::WindowFeatures(const String& features) i++; valueEnd = i; - ASSERT(i <= length); + ASSERT_WITH_SECURITY_IMPLICATION(i <= length); String keyString(buffer.substring(keyBegin, keyEnd - keyBegin)); String valueString(buffer.substring(valueBegin, valueEnd - valueBegin)); @@ -224,7 +224,7 @@ float WindowFeatures::floatFeature(const DialogFeaturesMap& features, const char // return the number 0 and false for ok. But "0q" should yield the minimum rather than the default. bool ok; double parsedNumber = it->value.toDouble(&ok); - if ((parsedNumber == 0 && !ok) || isnan(parsedNumber)) + if ((!parsedNumber && !ok) || std::isnan(parsedNumber)) return defaultValue; if (parsedNumber < min || max <= min) return min; diff --git a/Source/WebCore/page/WindowFeatures.h b/Source/WebCore/page/WindowFeatures.h index 204b7f8f4..43a0b1ba2 100644 --- a/Source/WebCore/page/WindowFeatures.h +++ b/Source/WebCore/page/WindowFeatures.h @@ -34,59 +34,55 @@ namespace WebCore { - class FloatRect; +class FloatRect; - struct WindowFeatures { - // FIXME: We can delete this constructor once V8 showModalDialog is changed to use DOMWindow. - WindowFeatures() - : xSet(false) - , ySet(false) - , widthSet(false) - , heightSet(false) - , menuBarVisible(true) - , statusBarVisible(true) - , toolBarVisible(true) - , locationBarVisible(true) - , scrollbarsVisible(true) - , resizable(true) - , fullscreen(false) - , dialog(false) - { - } +struct WindowFeatures { + WindowFeatures() + : xSet(false) + , ySet(false) + , widthSet(false) + , heightSet(false) + , menuBarVisible(true) + , statusBarVisible(true) + , toolBarVisible(true) + , locationBarVisible(true) + , scrollbarsVisible(true) + , resizable(true) + , fullscreen(false) + , dialog(false) + { + } + explicit WindowFeatures(const String& windowFeaturesString); + WindowFeatures(const String& dialogFeaturesString, const FloatRect& screenAvailableRect); - explicit WindowFeatures(const String& windowFeaturesString); - WindowFeatures(const String& dialogFeaturesString, const FloatRect& screenAvailableRect); + float x; + bool xSet; + float y; + bool ySet; + float width; + bool widthSet; + float height; + bool heightSet; - float x; - bool xSet; - float y; - bool ySet; - float width; - bool widthSet; - float height; - bool heightSet; + bool menuBarVisible; + bool statusBarVisible; + bool toolBarVisible; + bool locationBarVisible; + bool scrollbarsVisible; + bool resizable; - bool menuBarVisible; - bool statusBarVisible; - bool toolBarVisible; - bool locationBarVisible; - bool scrollbarsVisible; - bool resizable; + bool fullscreen; + bool dialog; - bool fullscreen; - bool dialog; + Vector<String> additionalFeatures; - Vector<String> additionalFeatures; - - // FIXME: We can make these functions private non-member functions once V8 showModalDialog is changed to use DOMWindow. - typedef HashMap<String, String> DialogFeaturesMap; - static void parseDialogFeatures(const String&, HashMap<String, String>&); - static bool boolFeature(const DialogFeaturesMap&, const char* key, bool defaultValue = false); - static float floatFeature(const DialogFeaturesMap&, const char* key, float min, float max, float defaultValue); - - private: - void setWindowFeature(const String& keyString, const String& valueString); - }; +private: + typedef HashMap<String, String> DialogFeaturesMap; + static void parseDialogFeatures(const String&, HashMap<String, String>&); + static bool boolFeature(const DialogFeaturesMap&, const char* key, bool defaultValue = false); + static float floatFeature(const DialogFeaturesMap&, const char* key, float min, float max, float defaultValue); + void setWindowFeature(const String& keyString, const String& valueString); +}; } // namespace WebCore diff --git a/Source/WebCore/page/WebKitAnimationList.h b/Source/WebCore/page/WindowTimers.idl index 58df2c08f..bfea6a69f 100644 --- a/Source/WebCore/page/WebKitAnimationList.h +++ b/Source/WebCore/page/WindowTimers.idl @@ -1,5 +1,7 @@ /* - * Copyright (C) 2011 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008, 2009, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2011 Google Inc. All rights reserved. + * Copyright (C) 2013 Samsung Electronics. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -20,42 +22,15 @@ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef WebKitAnimationList_h -#define WebKitAnimationList_h - -#include <wtf/PassRefPtr.h> -#include <wtf/RefCounted.h> -#include <wtf/RefPtr.h> -#include <wtf/Vector.h> - -namespace WebCore { - -class WebKitAnimation; - -class WebKitAnimationList : public RefCounted<WebKitAnimationList> { -public: - static PassRefPtr<WebKitAnimationList> create() - { - return adoptRef(new WebKitAnimationList); - } - ~WebKitAnimationList(); - - unsigned length() const; - WebKitAnimation* item(unsigned index); - - unsigned insertAnimation(PassRefPtr<WebKitAnimation>, unsigned index); - void deleteAnimation(unsigned index); - void append(PassRefPtr<WebKitAnimation>); - -private: - WebKitAnimationList(); - - Vector<RefPtr<WebKitAnimation> > m_animations; +[ + NoInterfaceObject +] interface WindowTimers { + [Custom] long setTimeout(any handler, [Default=Undefined] optional long timeout); + void clearTimeout([Default=Undefined] optional long handle); + [Custom] long setInterval(any handler, [Default=Undefined] optional long timeout); + void clearInterval([Default=Undefined] optional long handle); }; -} // namespace WebCore - -#endif // WebKitAnimationList_h diff --git a/Source/WebCore/page/WorkerNavigator.h b/Source/WebCore/page/WorkerNavigator.h index a01c44ccb..965907924 100644 --- a/Source/WebCore/page/WorkerNavigator.h +++ b/Source/WebCore/page/WorkerNavigator.h @@ -20,7 +20,7 @@ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef WorkerNavigator_h @@ -29,6 +29,7 @@ #if ENABLE(WORKERS) #include "NavigatorBase.h" +#include "Supplementable.h" #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> #include <wtf/RefPtr.h> @@ -36,18 +37,18 @@ namespace WebCore { - class WorkerNavigator : public NavigatorBase, public RefCounted<WorkerNavigator> { - public: - static PassRefPtr<WorkerNavigator> create(const String& userAgent) { return adoptRef(new WorkerNavigator(userAgent)); } - virtual ~WorkerNavigator(); +class WorkerNavigator : public NavigatorBase, public RefCounted<WorkerNavigator>, public Supplementable<WorkerNavigator> { +public: + static PassRefPtr<WorkerNavigator> create(const String& userAgent) { return adoptRef(new WorkerNavigator(userAgent)); } + virtual ~WorkerNavigator(); - virtual String userAgent() const; + virtual String userAgent() const; - private: - explicit WorkerNavigator(const String&); +private: + explicit WorkerNavigator(const String&); - String m_userAgent; - }; + String m_userAgent; +}; } // namespace WebCore diff --git a/Source/WebCore/page/WorkerNavigator.idl b/Source/WebCore/page/WorkerNavigator.idl index c37e200af..265442cc2 100644 --- a/Source/WebCore/page/WorkerNavigator.idl +++ b/Source/WebCore/page/WorkerNavigator.idl @@ -27,10 +27,10 @@ */ [ + NoInterfaceObject, Conditional=WORKERS, - JSGenerateIsReachable=Impl, + GenerateIsReachable=Impl, JSNoStaticTables, - OmitConstructor ] interface WorkerNavigator { readonly attribute DOMString appName; readonly attribute DOMString appVersion; diff --git a/Source/WebCore/page/animation/AnimationBase.cpp b/Source/WebCore/page/animation/AnimationBase.cpp index 33d6326c8..8da678b49 100644 --- a/Source/WebCore/page/animation/AnimationBase.cpp +++ b/Source/WebCore/page/animation/AnimationBase.cpp @@ -36,6 +36,7 @@ #include "Document.h" #include "EventNames.h" #include "FloatConversion.h" +#include "Logging.h" #include "RenderBox.h" #include "RenderStyle.h" #include "UnitBezier.h" @@ -70,7 +71,6 @@ static inline double solveStepsFunction(int numSteps, bool stepAtStart, double t AnimationBase::AnimationBase(const Animation* transition, RenderObject* renderer, CompositeAnimation* compAnim) : m_animState(AnimationStateNew) - , m_isAnimating(false) , m_isAccelerated(false) , m_transformFunctionListValid(false) #if ENABLE(CSS_FILTERS) @@ -112,6 +112,28 @@ bool AnimationBase::animationsMatch(const Animation* anim) const return m_animation->animationsMatch(anim); } +#if !LOG_DISABLED +static const char* nameForState(AnimationBase::AnimState state) +{ + switch (state) { + case AnimationBase::AnimationStateNew: return "New"; + case AnimationBase::AnimationStateStartWaitTimer: return "StartWaitTimer"; + case AnimationBase::AnimationStateStartWaitStyleAvailable: return "StartWaitStyleAvailable"; + case AnimationBase::AnimationStateStartWaitResponse: return "StartWaitResponse"; + case AnimationBase::AnimationStateLooping: return "Looping"; + case AnimationBase::AnimationStateEnding: return "Ending"; + case AnimationBase::AnimationStatePausedNew: return "PausedNew"; + case AnimationBase::AnimationStatePausedWaitTimer: return "PausedWaitTimer"; + case AnimationBase::AnimationStatePausedWaitStyleAvailable: return "PausedWaitStyleAvailable"; + case AnimationBase::AnimationStatePausedWaitResponse: return "PausedWaitResponse"; + case AnimationBase::AnimationStatePausedRun: return "PausedRun"; + case AnimationBase::AnimationStateDone: return "Done"; + case AnimationBase::AnimationStateFillingForwards: return "FillingForwards"; + } + return ""; +} +#endif + void AnimationBase::updateStateMachine(AnimStateInput input, double param) { if (!m_compAnim) @@ -121,6 +143,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) if (input == AnimationStateInputMakeNew) { if (m_animState == AnimationStateStartWaitStyleAvailable) m_compAnim->animationController()->removeFromAnimationsWaitingForStyle(this); + LOG(Animations, "%p AnimationState %s -> New", this, nameForState(m_animState)); m_animState = AnimationStateNew; m_startTime = 0; m_pauseTime = -1; @@ -133,6 +156,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) if (input == AnimationStateInputRestartAnimation) { if (m_animState == AnimationStateStartWaitStyleAvailable) m_compAnim->animationController()->removeFromAnimationsWaitingForStyle(this); + LOG(Animations, "%p AnimationState %s -> New", this, nameForState(m_animState)); m_animState = AnimationStateNew; m_startTime = 0; m_pauseTime = -1; @@ -148,6 +172,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) if (input == AnimationStateInputEndAnimation) { if (m_animState == AnimationStateStartWaitStyleAvailable) m_compAnim->animationController()->removeFromAnimationsWaitingForStyle(this); + LOG(Animations, "%p AnimationState %s -> Done", this, nameForState(m_animState)); m_animState = AnimationStateDone; endAnimation(); return; @@ -177,7 +202,12 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) ASSERT(input == AnimationStateInputStartAnimation || input == AnimationStateInputPlayStateRunning || input == AnimationStateInputPlayStatePaused); if (input == AnimationStateInputStartAnimation || input == AnimationStateInputPlayStateRunning) { m_requestedStartTime = beginAnimationUpdateTime(); + LOG(Animations, "%p AnimationState %s -> StartWaitTimer", this, nameForState(m_animState)); m_animState = AnimationStateStartWaitTimer; + } else { + // We are pausing before we even started. + LOG(Animations, "%p AnimationState %s -> AnimationStatePausedNew", this, nameForState(m_animState)); + m_animState = AnimationStatePausedNew; } break; case AnimationStateStartWaitTimer: @@ -186,6 +216,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) if (input == AnimationStateInputStartTimerFired) { ASSERT(param >= 0); // Start timer has fired, tell the animation to start and wait for it to respond with start time + LOG(Animations, "%p AnimationState %s -> StartWaitStyleAvailable", this, nameForState(m_animState)); m_animState = AnimationStateStartWaitStyleAvailable; m_compAnim->animationController()->addToAnimationsWaitingForStyle(this); @@ -196,6 +227,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) ASSERT(!paused()); // We're waiting for the start timer to fire and we got a pause. Cancel the timer, pause and wait m_pauseTime = beginAnimationUpdateTime(); + LOG(Animations, "%p AnimationState %s -> PausedWaitTimer", this, nameForState(m_animState)); m_animState = AnimationStatePausedWaitTimer; } break; @@ -204,6 +236,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) if (input == AnimationStateInputStyleAvailable) { // Start timer has fired, tell the animation to start and wait for it to respond with start time + LOG(Animations, "%p AnimationState %s -> StartWaitResponse", this, nameForState(m_animState)); m_animState = AnimationStateStartWaitResponse; overrideAnimations(); @@ -212,6 +245,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) if (overridden()) { // We won't try to start accelerated animations if we are overridden and // just move on to the next state. + LOG(Animations, "%p AnimationState %s -> StartWaitResponse", this, nameForState(m_animState)); m_animState = AnimationStateStartWaitResponse; m_isAccelerated = false; updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUpdateTime()); @@ -228,6 +262,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) } else { // We're waiting for the style to be available and we got a pause. Pause and wait m_pauseTime = beginAnimationUpdateTime(); + LOG(Animations, "%p AnimationState %s -> PausedWaitStyleAvailable", this, nameForState(m_animState)); m_animState = AnimationStatePausedWaitStyleAvailable; } break; @@ -258,6 +293,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) // we unpause, we will act as though the start timer just fired m_pauseTime = beginAnimationUpdateTime(); pauseAnimation(beginAnimationUpdateTime() - m_startTime); + LOG(Animations, "%p AnimationState %s -> PausedWaitResponse", this, nameForState(m_animState)); m_animState = AnimationStatePausedWaitResponse; } break; @@ -275,6 +311,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) // We are pausing while running. Cancel the animation and wait m_pauseTime = beginAnimationUpdateTime(); pauseAnimation(beginAnimationUpdateTime() - m_startTime); + LOG(Animations, "%p AnimationState %s -> PausedRun", this, nameForState(m_animState)); m_animState = AnimationStatePausedRun; } break; @@ -289,12 +326,14 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) // End timer fired, finish up onAnimationEnd(param); + LOG(Animations, "%p AnimationState %s -> Done", this, nameForState(m_animState)); m_animState = AnimationStateDone; if (m_object) { - if (m_animation->fillsForwards()) + if (m_animation->fillsForwards()) { + LOG(Animations, "%p AnimationState %s -> FillingForwards", this, nameForState(m_animState)); m_animState = AnimationStateFillingForwards; - else + } else resumeOverriddenAnimations(); // Fire off another style change so we can set the final value @@ -304,6 +343,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) // We are pausing while running. Cancel the animation and wait m_pauseTime = beginAnimationUpdateTime(); pauseAnimation(beginAnimationUpdateTime() - m_startTime); + LOG(Animations, "%p AnimationState %s -> PausedRun", this, nameForState(m_animState)); m_animState = AnimationStatePausedRun; } // |this| may be deleted here @@ -316,9 +356,11 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) m_pauseTime = -1; // we were waiting for the start timer to fire, go back and wait again + LOG(Animations, "%p AnimationState %s -> New", this, nameForState(m_animState)); m_animState = AnimationStateNew; updateStateMachine(AnimationStateInputStartAnimation, 0); break; + case AnimationStatePausedNew: case AnimationStatePausedWaitResponse: case AnimationStatePausedWaitStyleAvailable: case AnimationStatePausedRun: @@ -326,10 +368,19 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) // AnimationStatePausedWaitResponse, we don't yet have a valid startTime, so we send 0 to startAnimation. // When the AnimationStateInputStartTimeSet comes in and we were in AnimationStatePausedRun, we will notice // that we have already set the startTime and will ignore it. - ASSERT(input == AnimationStateInputPlayStateRunning || input == AnimationStateInputStartTimeSet || input == AnimationStateInputStyleAvailable); + ASSERT(input == AnimationStateInputPlayStateRunning || input == AnimationStateInputStartTimeSet || input == AnimationStateInputStyleAvailable || input == AnimationStateInputStartAnimation); ASSERT(paused()); - + if (input == AnimationStateInputPlayStateRunning) { + if (m_animState == AnimationStatePausedNew) { + // We were paused before we even started, and now we're supposed + // to start, so jump back to the New state and reset. + LOG(Animations, "%p AnimationState %s -> AnimationStateNew", this, nameForState(m_animState)); + m_animState = AnimationStateNew; + updateStateMachine(input, param); + break; + } + // Update the times if (m_animState == AnimationStatePausedRun) m_startTime += beginAnimationUpdateTime() - m_pauseTime; @@ -337,12 +388,14 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) m_startTime = 0; m_pauseTime = -1; - if (m_animState == AnimationStatePausedWaitStyleAvailable) + if (m_animState == AnimationStatePausedWaitStyleAvailable) { + LOG(Animations, "%p AnimationState %s -> StartWaitStyleAvailable", this, nameForState(m_animState)); m_animState = AnimationStateStartWaitStyleAvailable; - else { + } else { // We were either running or waiting for a begin time response from the animation. // Either way we need to restart the animation (possibly with an offset if we // had already been running) and wait for it to start. + LOG(Animations, "%p AnimationState %s -> StartWaitResponse", this, nameForState(m_animState)); m_animState = AnimationStateStartWaitResponse; // Start the animation @@ -365,16 +418,18 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) // We are paused but we got the callback that notifies us that an accelerated animation started. // We ignore the start time and just move into the paused-run state. + LOG(Animations, "%p AnimationState %s -> PausedRun", this, nameForState(m_animState)); m_animState = AnimationStatePausedRun; ASSERT(m_startTime == 0); m_startTime = param; m_pauseTime += m_startTime; break; } - + ASSERT(m_animState == AnimationStatePausedWaitStyleAvailable); // We are paused but we got the callback that notifies us that style has been updated. // We move to the AnimationStatePausedWaitResponse state + LOG(Animations, "%p AnimationState %s -> PausedWaitResponse", this, nameForState(m_animState)); m_animState = AnimationStatePausedWaitResponse; overrideAnimations(); break; @@ -418,6 +473,7 @@ void AnimationBase::fireAnimationEventsIfNeeded() if (m_totalDuration >= 0 && elapsedDuration >= m_totalDuration) { // We may still be in AnimationStateLooping if we've managed to skip a // whole iteration, in which case we should jump to the end state. + LOG(Animations, "%p AnimationState %s -> Ending", this, nameForState(m_animState)); m_animState = AnimationStateEnding; // Fire an end event @@ -450,11 +506,11 @@ void AnimationBase::updatePlayState(EAnimPlayState playState) // When we get here, we can have one of 4 desired states: running, paused, suspended, paused & suspended. // The state machine can be in one of two states: running, paused. // Set the state machine to the desired state. - bool pause = playState == AnimPlayStatePaused || m_compAnim->suspended(); - + bool pause = playState == AnimPlayStatePaused || m_compAnim->isSuspended(); + if (pause == paused() && !isNew()) return; - + updateStateMachine(pause ? AnimationStateInputPlayStatePaused : AnimationStateInputPlayStateRunning, -1); } @@ -523,6 +579,7 @@ double AnimationBase::progress(double scale, double offset, const TimingFunction if (postActive() || !m_animation->duration()) return 1.0; + if (m_animation->iterationCount() > 0 && elapsedTime >= dur) { const int integralIterationCount = static_cast<int>(m_animation->iterationCount()); const bool iterationCountHasFractional = m_animation->iterationCount() - integralIterationCount; @@ -541,11 +598,14 @@ double AnimationBase::progress(double scale, double offset, const TimingFunction ctf->x2(), ctf->y2(), fractionalTime, m_animation->duration()); - } else if (tf->isStepsTimingFunction()) { + } + + if (tf->isStepsTimingFunction()) { const StepsTimingFunction* stf = static_cast<const StepsTimingFunction*>(tf); return solveStepsFunction(stf->numberOfSteps(), stf->stepAtStart(), fractionalTime); - } else - return fractionalTime; + } + + return fractionalTime; } void AnimationBase::getTimeToNextEvent(double& time, bool& isLooping) const @@ -577,6 +637,7 @@ void AnimationBase::goIntoEndingOrLoopingState() double t; bool isLooping; getTimeToNextEvent(t, isLooping); + LOG(Animations, "%p AnimationState %s -> %s", this, nameForState(m_animState), isLooping ? "Looping" : "Ending"); m_animState = isLooping ? AnimationStateLooping : AnimationStateEnding; } @@ -587,6 +648,7 @@ void AnimationBase::freezeAtTime(double t) if (!m_startTime) { // If we haven't started yet, make it as if we started. + LOG(Animations, "%p AnimationState %s -> StartWaitResponse", this, nameForState(m_animState)); m_animState = AnimationStateStartWaitResponse; onAnimationStartResponse(currentTime()); } diff --git a/Source/WebCore/page/animation/AnimationBase.h b/Source/WebCore/page/animation/AnimationBase.h index e340eed1e..dee083603 100644 --- a/Source/WebCore/page/animation/AnimationBase.h +++ b/Source/WebCore/page/animation/AnimationBase.h @@ -78,6 +78,7 @@ public: AnimationStateStartWaitResponse, // animation started, waiting for response AnimationStateLooping, // response received, animation running, loop timer running, waiting for fire AnimationStateEnding, // received, animation running, end timer running, waiting for fire + AnimationStatePausedNew, // in pause mode when animation was created AnimationStatePausedWaitTimer, // in pause mode when animation started AnimationStatePausedWaitStyleAvailable, // in pause mode when waiting for style setup AnimationStatePausedWaitResponse, // animation paused when in STARTING state @@ -115,7 +116,7 @@ public: void updatePlayState(EAnimPlayState); bool playStatePlaying() const; - bool waitingToStart() const { return m_animState == AnimationStateNew || m_animState == AnimationStateStartWaitTimer; } + bool waitingToStart() const { return m_animState == AnimationStateNew || m_animState == AnimationStateStartWaitTimer || m_animState == AnimationStatePausedNew; } bool preActive() const { return m_animState == AnimationStateNew || m_animState == AnimationStateStartWaitTimer || m_animState == AnimationStateStartWaitStyleAvailable || m_animState == AnimationStateStartWaitResponse; @@ -124,14 +125,11 @@ public: bool postActive() const { return m_animState == AnimationStateDone; } bool active() const { return !postActive() && !preActive(); } bool running() const { return !isNew() && !postActive(); } - bool paused() const { return m_pauseTime >= 0; } - bool isNew() const { return m_animState == AnimationStateNew; } + bool paused() const { return m_pauseTime >= 0 || m_animState == AnimationStatePausedNew; } + bool isNew() const { return m_animState == AnimationStateNew || m_animState == AnimationStatePausedNew; } bool waitingForStartTime() const { return m_animState == AnimationStateStartWaitResponse; } bool waitingForStyleAvailable() const { return m_animState == AnimationStateStartWaitStyleAvailable; } - // "animating" means that something is running that requires a timer to keep firing - // (e.g. a software animation) - void setAnimating(bool inAnimating = true) { m_isAnimating = inAnimating; } virtual double timeToNextService(); double progress(double scale, double offset, const TimingFunction*) const; @@ -224,7 +222,6 @@ protected: AnimState m_animState; - bool m_isAnimating; // transition/animation requires continual timer firing bool m_isAccelerated; bool m_transformFunctionListValid; #if ENABLE(CSS_FILTERS) diff --git a/Source/WebCore/page/animation/AnimationController.cpp b/Source/WebCore/page/animation/AnimationController.cpp index 5e0717e0a..4cca653e7 100644 --- a/Source/WebCore/page/animation/AnimationController.cpp +++ b/Source/WebCore/page/animation/AnimationController.cpp @@ -37,12 +37,13 @@ #include "EventNames.h" #include "Frame.h" #include "FrameView.h" +#include "Logging.h" +#include "PseudoElement.h" #include "RenderView.h" +#include "TransitionEvent.h" #include "WebKitAnimationEvent.h" -#include "WebKitAnimationList.h" #include "WebKitTransitionEvent.h" #include <wtf/CurrentTime.h> -#include <wtf/UnusedParam.h> namespace WebCore { @@ -57,7 +58,7 @@ AnimationControllerPrivate::AnimationControllerPrivate(Frame* frame) , m_animationsWaitingForStyle() , m_animationsWaitingForStartTimeResponse() , m_waitingForAsyncStartNotification(false) - , m_previousTimeToNextService(0) + , m_isSuspended(false) { } @@ -65,25 +66,23 @@ AnimationControllerPrivate::~AnimationControllerPrivate() { } -PassRefPtr<CompositeAnimation> AnimationControllerPrivate::accessCompositeAnimation(RenderObject* renderer) +CompositeAnimation* AnimationControllerPrivate::ensureCompositeAnimation(RenderObject* renderer) { - RefPtr<CompositeAnimation> animation = m_compositeAnimations.get(renderer); - if (!animation) { - animation = CompositeAnimation::create(this); - m_compositeAnimations.set(renderer, animation); - } - return animation; + RenderObjectAnimationMap::AddResult result = m_compositeAnimations.add(renderer, 0); + if (result.isNewEntry) + result.iterator->value = CompositeAnimation::create(this); + return result.iterator->value.get(); } bool AnimationControllerPrivate::clear(RenderObject* renderer) { // Return false if we didn't do anything OR we are suspended (so we don't try to // do a setNeedsStyleRecalc() when suspended). - PassRefPtr<CompositeAnimation> animation = m_compositeAnimations.take(renderer); + RefPtr<CompositeAnimation> animation = m_compositeAnimations.take(renderer); if (!animation) return false; animation->clearRenderer(); - return animation->suspended(); + return animation->isSuspended(); } double AnimationControllerPrivate::updateAnimations(SetChanged callSetChanged/* = DoNotCallSetChanged*/) @@ -94,7 +93,7 @@ double AnimationControllerPrivate::updateAnimations(SetChanged callSetChanged/* RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end(); for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) { CompositeAnimation* compAnim = it->value.get(); - if (!compAnim->suspended() && compAnim->hasAnimations()) { + if (!compAnim->isSuspended() && compAnim->hasAnimations()) { double t = compAnim->timeToNextService(); if (t != -1 && (t < timeToNextService || timeToNextService == -1)) timeToNextService = t; @@ -121,18 +120,13 @@ void AnimationControllerPrivate::updateAnimationTimerForRenderer(RenderObject* r { double timeToNextService = 0; - RefPtr<CompositeAnimation> compAnim = m_compositeAnimations.get(renderer); - if (!compAnim->suspended() && compAnim->hasAnimations()) - timeToNextService = compAnim->timeToNextService(); - - if (m_animationTimer.isActive()) { - if (m_previousTimeToNextService < timeToNextService) - return; + const CompositeAnimation* compositeAnimation = m_compositeAnimations.get(renderer); + if (!compositeAnimation->isSuspended() && compositeAnimation->hasAnimations()) + timeToNextService = compositeAnimation->timeToNextService(); - m_animationTimer.stop(); - } + if (m_animationTimer.isActive() && (m_animationTimer.repeatInterval() || m_animationTimer.nextFireInterval() <= timeToNextService)) + return; - m_previousTimeToNextService = timeToNextService; m_animationTimer.startOneShot(timeToNextService); } @@ -140,12 +134,12 @@ void AnimationControllerPrivate::updateAnimationTimer(SetChanged callSetChanged/ { double timeToNextService = updateAnimations(callSetChanged); + LOG(Animations, "updateAnimationTimer: timeToNextService is %.2f", timeToNextService); + // If we want service immediately, we start a repeating timer to reduce the overhead of starting if (!timeToNextService) { if (!m_animationTimer.isActive() || m_animationTimer.repeatInterval() == 0) m_animationTimer.startRepeating(cAnimationTimerDelay); - - m_previousTimeToNextService = timeToNextService; return; } @@ -157,9 +151,6 @@ void AnimationControllerPrivate::updateAnimationTimer(SetChanged callSetChanged/ } // Otherwise, we want to start a one-shot timer so we get here again - if (m_animationTimer.isActive()) - m_animationTimer.stop(); - m_previousTimeToNextService = timeToNextService; m_animationTimer.startOneShot(timeToNextService); } @@ -180,10 +171,11 @@ void AnimationControllerPrivate::fireEventsAndUpdateStyle() m_eventsToDispatch.clear(); Vector<EventToDispatch>::const_iterator eventsToDispatchEnd = eventsToDispatch.end(); for (Vector<EventToDispatch>::const_iterator it = eventsToDispatch.begin(); it != eventsToDispatchEnd; ++it) { - if (it->eventType == eventNames().webkitTransitionEndEvent) - it->element->dispatchEvent(WebKitTransitionEvent::create(it->eventType, it->name, it->elapsedTime)); + Element* element = it->element.get(); + if (it->eventType == eventNames().transitionendEvent) + element->dispatchEvent(TransitionEvent::create(it->eventType, it->name, it->elapsedTime, PseudoElement::pseudoElementNameForEvents(element->pseudoId()))); else - it->element->dispatchEvent(WebKitAnimationEvent::create(it->eventType, it->name, it->elapsedTime)); + element->dispatchEvent(WebKitAnimationEvent::create(it->eventType, it->name, it->elapsedTime)); } // call setChanged on all the elements @@ -252,7 +244,7 @@ void AnimationControllerPrivate::animationTimerFired(Timer<AnimationControllerPr bool AnimationControllerPrivate::isRunningAnimationOnRenderer(RenderObject* renderer, CSSPropertyID property, bool isRunningNow) const { - RefPtr<CompositeAnimation> animation = m_compositeAnimations.get(renderer); + const CompositeAnimation* animation = m_compositeAnimations.get(renderer); if (!animation) return false; @@ -261,7 +253,7 @@ bool AnimationControllerPrivate::isRunningAnimationOnRenderer(RenderObject* rend bool AnimationControllerPrivate::isRunningAcceleratedAnimationOnRenderer(RenderObject* renderer, CSSPropertyID property, bool isRunningNow) const { - RefPtr<CompositeAnimation> animation = m_compositeAnimations.get(renderer); + const CompositeAnimation* animation = m_compositeAnimations.get(renderer); if (!animation) return false; @@ -270,26 +262,36 @@ bool AnimationControllerPrivate::isRunningAcceleratedAnimationOnRenderer(RenderO void AnimationControllerPrivate::suspendAnimations() { + if (isSuspended()) + return; + suspendAnimationsForDocument(m_frame->document()); - + // Traverse subframes for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) child->animation()->suspendAnimations(); + + m_isSuspended = true; } void AnimationControllerPrivate::resumeAnimations() { + if (!isSuspended()) + return; + resumeAnimationsForDocument(m_frame->document()); - + // Traverse subframes for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) child->animation()->resumeAnimations(); + + m_isSuspended = false; } void AnimationControllerPrivate::suspendAnimationsForDocument(Document* document) { setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet); - + RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end(); for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) { RenderObject* renderer = it->key; @@ -298,14 +300,14 @@ void AnimationControllerPrivate::suspendAnimationsForDocument(Document* document compAnim->suspendAnimations(); } } - + updateAnimationTimer(); } void AnimationControllerPrivate::resumeAnimationsForDocument(Document* document) { setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet); - + RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end(); for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) { RenderObject* renderer = it->key; @@ -314,20 +316,23 @@ void AnimationControllerPrivate::resumeAnimationsForDocument(Document* document) compAnim->resumeAnimations(); } } - + updateAnimationTimer(); } -bool AnimationControllerPrivate::pauseAnimationAtTime(RenderObject* renderer, const String& name, double t) +void AnimationControllerPrivate::startAnimationsIfNotSuspended(Document* document) { - if (!renderer) - return false; + if (!isSuspended()) + resumeAnimationsForDocument(document); +} - RefPtr<CompositeAnimation> compAnim = accessCompositeAnimation(renderer); - if (!compAnim) +bool AnimationControllerPrivate::pauseAnimationAtTime(RenderObject* renderer, const AtomicString& name, double t) +{ + if (!renderer) return false; - if (compAnim->pauseAnimationAtTime(name, t)) { + CompositeAnimation* compositeAnimation = ensureCompositeAnimation(renderer); + if (compositeAnimation->pauseAnimationAtTime(name, t)) { renderer->node()->setNeedsStyleRecalc(SyntheticStyleChange); startUpdateStyleIfNeededDispatcher(); return true; @@ -341,11 +346,8 @@ bool AnimationControllerPrivate::pauseTransitionAtTime(RenderObject* renderer, c if (!renderer) return false; - RefPtr<CompositeAnimation> compAnim = accessCompositeAnimation(renderer); - if (!compAnim) - return false; - - if (compAnim->pauseTransitionAtTime(cssPropertyID(property), t)) { + CompositeAnimation* compositeAnimation = ensureCompositeAnimation(renderer); + if (compositeAnimation->pauseTransitionAtTime(cssPropertyID(property), t)) { renderer->node()->setNeedsStyleRecalc(SyntheticStyleChange); startUpdateStyleIfNeededDispatcher(); return true; @@ -379,7 +381,7 @@ PassRefPtr<RenderStyle> AnimationControllerPrivate::getAnimatedStyleForRenderer( if (!renderer) return 0; - RefPtr<CompositeAnimation> rendererAnimations = m_compositeAnimations.get(renderer); + const CompositeAnimation* rendererAnimations = m_compositeAnimations.get(renderer); if (!rendererAnimations) return renderer->style(); @@ -482,16 +484,6 @@ void AnimationControllerPrivate::animationWillBeRemoved(AnimationBase* animation removeFromAnimationsWaitingForStartTimeResponse(animation); } -PassRefPtr<WebKitAnimationList> AnimationControllerPrivate::animationsForRenderer(RenderObject* renderer) const -{ - RefPtr<CompositeAnimation> animation = m_compositeAnimations.get(renderer); - - if (!animation) - return 0; - - return animation->animations(); -} - AnimationController::AnimationController(Frame* frame) : m_data(adoptPtr(new AnimationControllerPrivate(frame))) , m_beginAnimationUpdateCount(0) @@ -510,7 +502,8 @@ void AnimationController::cancelAnimations(RenderObject* renderer) if (m_data->clear(renderer)) { Node* node = renderer->node(); ASSERT(!node || (node->document() && !node->document()->inPageCache())); - node->setNeedsStyleRecalc(SyntheticStyleChange); + if (node) + node->setNeedsStyleRecalc(SyntheticStyleChange); } } @@ -533,9 +526,11 @@ PassRefPtr<RenderStyle> AnimationController::updateAnimations(RenderObject* rend // against the animations in the style and make sure we're in sync. If destination values // have changed, we reset the animation. We then do a blend to get new values and we return // a new style. - ASSERT(renderer->node()); // FIXME: We do not animate generated content yet. - RefPtr<CompositeAnimation> rendererAnimations = m_data->accessCompositeAnimation(renderer); + // We don't support anonymous pseudo elements like :first-line or :first-letter. + ASSERT(renderer->node()); + + CompositeAnimation* rendererAnimations = m_data->ensureCompositeAnimation(renderer); RefPtr<RenderStyle> blendedStyle = rendererAnimations->animate(renderer, oldStyle, newStyle); if (renderer->parent() || newStyle->animations() || (oldStyle && oldStyle->animations())) { @@ -566,7 +561,7 @@ void AnimationController::notifyAnimationStarted(RenderObject*, double startTime m_data->receivedStartTimeResponse(startTime); } -bool AnimationController::pauseAnimationAtTime(RenderObject* renderer, const String& name, double t) +bool AnimationController::pauseAnimationAtTime(RenderObject* renderer, const AtomicString& name, double t) { return m_data->pauseAnimationAtTime(renderer, name, t); } @@ -591,13 +586,20 @@ bool AnimationController::isRunningAcceleratedAnimationOnRenderer(RenderObject* return m_data->isRunningAcceleratedAnimationOnRenderer(renderer, property, isRunningNow); } +bool AnimationController::isSuspended() const +{ + return m_data->isSuspended(); +} + void AnimationController::suspendAnimations() { + LOG(Animations, "controller is suspending animations"); m_data->suspendAnimations(); } void AnimationController::resumeAnimations() { + LOG(Animations, "controller is resuming animations"); m_data->resumeAnimations(); } @@ -610,14 +612,22 @@ void AnimationController::serviceAnimations() void AnimationController::suspendAnimationsForDocument(Document* document) { + LOG(Animations, "suspending animations for document %p", document); m_data->suspendAnimationsForDocument(document); } void AnimationController::resumeAnimationsForDocument(Document* document) { + LOG(Animations, "resuming animations for document %p", document); m_data->resumeAnimationsForDocument(document); } +void AnimationController::startAnimationsIfNotSuspended(Document* document) +{ + LOG(Animations, "animations may start for document %p", document); + m_data->startAnimationsIfNotSuspended(document); +} + void AnimationController::beginAnimationUpdate() { if (!m_beginAnimationUpdateCount) @@ -643,9 +653,4 @@ bool AnimationController::supportsAcceleratedAnimationOfProperty(CSSPropertyID p #endif } -PassRefPtr<WebKitAnimationList> AnimationController::animationsForRenderer(RenderObject* renderer) const -{ - return m_data->animationsForRenderer(renderer); -} - } // namespace WebCore diff --git a/Source/WebCore/page/animation/AnimationController.h b/Source/WebCore/page/animation/AnimationController.h index ea3c41cf7..9a267d45b 100644 --- a/Source/WebCore/page/animation/AnimationController.h +++ b/Source/WebCore/page/animation/AnimationController.h @@ -43,7 +43,6 @@ class Frame; class Node; class RenderObject; class RenderStyle; -class WebKitAnimationList; class AnimationController { public: @@ -57,13 +56,14 @@ public: // This is called when an accelerated animation or transition has actually started to animate. void notifyAnimationStarted(RenderObject*, double startTime); - bool pauseAnimationAtTime(RenderObject*, const String& name, double t); // To be used only for testing + bool pauseAnimationAtTime(RenderObject*, const AtomicString& name, double t); // To be used only for testing bool pauseTransitionAtTime(RenderObject*, const String& property, double t); // To be used only for testing unsigned numberOfActiveAnimations(Document*) const; // To be used only for testing bool isRunningAnimationOnRenderer(RenderObject*, CSSPropertyID, bool isRunningNow = true) const; bool isRunningAcceleratedAnimationOnRenderer(RenderObject*, CSSPropertyID, bool isRunningNow = true) const; + bool isSuspended() const; void suspendAnimations(); void resumeAnimations(); #if ENABLE(REQUEST_ANIMATION_FRAME) @@ -72,14 +72,13 @@ public: void suspendAnimationsForDocument(Document*); void resumeAnimationsForDocument(Document*); + void startAnimationsIfNotSuspended(Document*); void beginAnimationUpdate(); void endAnimationUpdate(); static bool supportsAcceleratedAnimationOfProperty(CSSPropertyID); - PassRefPtr<WebKitAnimationList> animationsForRenderer(RenderObject*) const; - private: OwnPtr<AnimationControllerPrivate> m_data; int m_beginAnimationUpdateCount; diff --git a/Source/WebCore/page/animation/AnimationControllerPrivate.h b/Source/WebCore/page/animation/AnimationControllerPrivate.h index ec76f1c98..3f4632896 100644 --- a/Source/WebCore/page/animation/AnimationControllerPrivate.h +++ b/Source/WebCore/page/animation/AnimationControllerPrivate.h @@ -49,7 +49,6 @@ class Frame; class Node; class RenderObject; class RenderStyle; -class WebKitAnimationList; enum SetChanged { DoNotCallSetChanged = 0, @@ -66,7 +65,7 @@ public: double updateAnimations(SetChanged callSetChanged = DoNotCallSetChanged); void updateAnimationTimer(SetChanged callSetChanged = DoNotCallSetChanged); - PassRefPtr<CompositeAnimation> accessCompositeAnimation(RenderObject*); + CompositeAnimation* ensureCompositeAnimation(RenderObject*); bool clear(RenderObject*); void updateStyleIfNeededDispatcherFired(Timer<AnimationControllerPrivate>*); @@ -76,6 +75,7 @@ public: bool hasAnimations() const { return !m_compositeAnimations.isEmpty(); } + bool isSuspended() const { return m_isSuspended; } void suspendAnimations(); void resumeAnimations(); #if ENABLE(REQUEST_ANIMATION_FRAME) @@ -84,11 +84,12 @@ public: void suspendAnimationsForDocument(Document*); void resumeAnimationsForDocument(Document*); + void startAnimationsIfNotSuspended(Document*); bool isRunningAnimationOnRenderer(RenderObject*, CSSPropertyID, bool isRunningNow) const; bool isRunningAcceleratedAnimationOnRenderer(RenderObject*, CSSPropertyID, bool isRunningNow) const; - bool pauseAnimationAtTime(RenderObject*, const String& name, double t); + bool pauseAnimationAtTime(RenderObject*, const AtomicString& name, double t); bool pauseTransitionAtTime(RenderObject*, const String& property, double t); unsigned numberOfActiveAnimations(Document*) const; @@ -107,8 +108,6 @@ public: void animationWillBeRemoved(AnimationBase*); - PassRefPtr<WebKitAnimationList> animationsForRenderer(RenderObject*) const; - void updateAnimationTimerForRenderer(RenderObject*); private: @@ -142,7 +141,7 @@ private: WaitingAnimationsSet m_animationsWaitingForStyle; WaitingAnimationsSet m_animationsWaitingForStartTimeResponse; bool m_waitingForAsyncStartNotification; - double m_previousTimeToNextService; + bool m_isSuspended; }; } // namespace WebCore diff --git a/Source/WebCore/page/animation/CSSPropertyAnimation.cpp b/Source/WebCore/page/animation/CSSPropertyAnimation.cpp index 2504da404..fca626f80 100644 --- a/Source/WebCore/page/animation/CSSPropertyAnimation.cpp +++ b/Source/WebCore/page/animation/CSSPropertyAnimation.cpp @@ -36,6 +36,7 @@ #include "CSSImageValue.h" #include "CSSPrimitiveValue.h" #include "CSSPropertyNames.h" +#include "CachedImage.h" #include "ClipPathOperation.h" #include "FloatConversion.h" #include "IdentityTransformOperation.h" @@ -113,7 +114,7 @@ static inline PassOwnPtr<ShadowData> blendFunc(const AnimationBase* anim, const return adoptPtr(new ShadowData(*to)); return adoptPtr(new ShadowData(blend(from->location(), to->location(), progress), - blend(from->blur(), to->blur(), progress), + blend(from->radius(), to->radius(), progress), blend(from->spread(), to->spread(), progress), blendFunc(anim, from->style(), to->style(), progress), from->isWebkitBoxShadow(), @@ -142,11 +143,11 @@ static inline PassRefPtr<ClipPathOperation> blendFunc(const AnimationBase*, Clip return ShapeClipPathOperation::create(toShape->blend(fromShape, progress)); } -#if ENABLE(CSS_EXCLUSIONS) -static inline PassRefPtr<ExclusionShapeValue> blendFunc(const AnimationBase*, ExclusionShapeValue* from, ExclusionShapeValue* to, double progress) +#if ENABLE(CSS_SHAPES) +static inline PassRefPtr<ShapeValue> blendFunc(const AnimationBase*, ShapeValue* from, ShapeValue* to, double progress) { // FIXME Bug 102723: Shape-inside should be able to animate a value of 'outside-shape' when shape-outside is set to a BasicShape - if (from->type() != ExclusionShapeValue::SHAPE || to->type() != ExclusionShapeValue::SHAPE) + if (from->type() != ShapeValue::Shape || to->type() != ShapeValue::Shape) return to; const BasicShape* fromShape = from->shape(); @@ -155,7 +156,7 @@ static inline PassRefPtr<ExclusionShapeValue> blendFunc(const AnimationBase*, Ex if (!fromShape->canBlend(toShape)) return to; - return ExclusionShapeValue::createShapeValue(toShape->blend(fromShape, progress)); + return ShapeValue::createShapeValue(toShape->blend(fromShape, progress)); } #endif @@ -217,13 +218,6 @@ static inline EVisibility blendFunc(const AnimationBase* anim, EVisibility from, static inline LengthBox blendFunc(const AnimationBase* anim, const LengthBox& from, const LengthBox& to, double progress) { - // Length types have to match to animate - if (from.top().type() != to.top().type() - || from.right().type() != to.right().type() - || from.bottom().type() != to.bottom().type() - || from.left().type() != to.left().type()) - return to; - LengthBox result(blendFunc(anim, from.top(), to.top(), progress), blendFunc(anim, from.right(), to.right(), progress), blendFunc(anim, from.bottom(), to.bottom(), progress), @@ -410,11 +404,11 @@ public: } }; -#if ENABLE(CSS_EXCLUSIONS) -class PropertyWrapperExclusionShape : public RefCountedPropertyWrapper<ExclusionShapeValue> { +#if ENABLE(CSS_SHAPES) +class PropertyWrapperShape : public RefCountedPropertyWrapper<ShapeValue> { public: - PropertyWrapperExclusionShape(CSSPropertyID prop, ExclusionShapeValue* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(PassRefPtr<ExclusionShapeValue>)) - : RefCountedPropertyWrapper<ExclusionShapeValue>(prop, getter, setter) + PropertyWrapperShape(CSSPropertyID prop, ShapeValue* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(PassRefPtr<ShapeValue>)) + : RefCountedPropertyWrapper<ShapeValue>(prop, getter, setter) { } }; @@ -1130,6 +1124,8 @@ void CSSPropertyAnimation::ensurePropertyMap() gPropertyWrappers->append(new PropertyWrapper<short>(CSSPropertyWebkitBorderHorizontalSpacing, &RenderStyle::horizontalBorderSpacing, &RenderStyle::setHorizontalBorderSpacing)); gPropertyWrappers->append(new PropertyWrapper<short>(CSSPropertyWebkitBorderVerticalSpacing, &RenderStyle::verticalBorderSpacing, &RenderStyle::setVerticalBorderSpacing)); gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyZIndex, &RenderStyle::zIndex, &RenderStyle::setZIndex)); + gPropertyWrappers->append(new PropertyWrapper<short>(CSSPropertyOrphans, &RenderStyle::orphans, &RenderStyle::setOrphans)); + gPropertyWrappers->append(new PropertyWrapper<short>(CSSPropertyWidows, &RenderStyle::widows, &RenderStyle::setWidows)); gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyLineHeight, &RenderStyle::specifiedLineHeight, &RenderStyle::setLineHeight)); gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyOutlineOffset, &RenderStyle::outlineOffset, &RenderStyle::setOutlineOffset)); gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyOutlineWidth, &RenderStyle::outlineWidth, &RenderStyle::setOutlineWidth)); @@ -1168,8 +1164,8 @@ void CSSPropertyAnimation::ensurePropertyMap() gPropertyWrappers->append(new PropertyWrapperClipPath(CSSPropertyWebkitClipPath, &RenderStyle::clipPath, &RenderStyle::setClipPath)); -#if ENABLE(CSS_EXCLUSIONS) - gPropertyWrappers->append(new PropertyWrapperExclusionShape(CSSPropertyWebkitShapeInside, &RenderStyle::shapeInside, &RenderStyle::setShapeInside)); +#if ENABLE(CSS_SHAPES) + gPropertyWrappers->append(new PropertyWrapperShape(CSSPropertyWebkitShapeInside, &RenderStyle::shapeInside, &RenderStyle::setShapeInside)); #endif gPropertyWrappers->append(new PropertyWrapperVisitedAffectedColor(CSSPropertyWebkitColumnRuleColor, MaybeInvalidColor, &RenderStyle::columnRuleColor, &RenderStyle::setColumnRuleColor, &RenderStyle::visitedLinkColumnRuleColor, &RenderStyle::setVisitedLinkColumnRuleColor)); diff --git a/Source/WebCore/page/animation/CompositeAnimation.cpp b/Source/WebCore/page/animation/CompositeAnimation.cpp index 1bb5059e6..e7d1837e8 100644 --- a/Source/WebCore/page/animation/CompositeAnimation.cpp +++ b/Source/WebCore/page/animation/CompositeAnimation.cpp @@ -34,13 +34,19 @@ #include "CSSPropertyNames.h" #include "ImplicitAnimation.h" #include "KeyframeAnimation.h" +#include "Logging.h" #include "RenderObject.h" #include "RenderStyle.h" -#include "WebKitAnimation.h" -#include "WebKitAnimationList.h" +#include <wtf/text/CString.h> namespace WebCore { +CompositeAnimation::CompositeAnimation(AnimationControllerPrivate* animationController) + : m_animationController(animationController) +{ + m_suspended = animationController->isSuspended(); +} + CompositeAnimation::~CompositeAnimation() { // Toss the refs to all animations, but make sure we remove them from @@ -92,7 +98,7 @@ void CompositeAnimation::updateTransitions(RenderObject* renderer, RenderStyle* if (targetStyle->transitions()) { for (size_t i = 0; i < targetStyle->transitions()->size(); ++i) { const Animation* anim = targetStyle->transitions()->animation(i); - bool isActiveTransition = anim->duration() || anim->delay() > 0; + bool isActiveTransition = !m_suspended && (anim->duration() || anim->delay() > 0); Animation::AnimationMode mode = anim->animationMode(); if (mode == Animation::AnimateNone) @@ -123,7 +129,7 @@ void CompositeAnimation::updateTransitions(RenderObject* renderer, RenderStyle* RenderStyle* fromStyle = keyframeAnim ? keyframeAnim->unanimatedStyle() : currentStyle; // See if there is a current transition for this prop - ImplicitAnimation* implAnim = m_transitions.get(prop).get(); + ImplicitAnimation* implAnim = m_transitions.get(prop); bool equal = true; if (implAnim) { @@ -142,7 +148,7 @@ void CompositeAnimation::updateTransitions(RenderObject* renderer, RenderStyle* // list. In this case, the latter one overrides the earlier one, so we // behave as though this is a running animation being replaced. if (!implAnim->isTargetPropertyEqual(prop, targetStyle)) { - #if USE(ACCELERATED_COMPOSITING) +#if USE(ACCELERATED_COMPOSITING) // For accelerated animations we need to return a new RenderStyle with the _current_ value // of the property, so that restarted transitions use the correct starting point. if (CSSPropertyAnimation::animationOfPropertyIsAccelerated(prop) && implAnim->isAccelerated()) { @@ -151,7 +157,8 @@ void CompositeAnimation::updateTransitions(RenderObject* renderer, RenderStyle* implAnim->blendPropertyValueInStyle(prop, modifiedCurrentStyle.get()); } - #endif +#endif + LOG(Animations, "Removing existing ImplicitAnimation %p for property %s", implAnim, getPropertyName(prop)); animationController()->animationWillBeRemoved(implAnim); m_transitions.remove(prop); equal = false; @@ -167,7 +174,9 @@ void CompositeAnimation::updateTransitions(RenderObject* renderer, RenderStyle* // <https://bugs.webkit.org/show_bug.cgi?id=24787> if (!equal && isActiveTransition) { // Add the new transition - m_transitions.set(prop, ImplicitAnimation::create(const_cast<Animation*>(anim), prop, renderer, this, modifiedCurrentStyle ? modifiedCurrentStyle.get() : fromStyle)); + RefPtr<ImplicitAnimation> animation = ImplicitAnimation::create(const_cast<Animation*>(anim), prop, renderer, this, modifiedCurrentStyle ? modifiedCurrentStyle.get() : fromStyle); + LOG(Animations, "Created ImplicitAnimation %p for property %s duration %.2f delay %.2f", animation.get(), getPropertyName(prop), anim->duration(), anim->delay()); + m_transitions.set(prop, animation.release()); } // We only need one pass for the single prop case @@ -185,6 +194,7 @@ void CompositeAnimation::updateTransitions(RenderObject* renderer, RenderStyle* if (!anim->active()) { animationController()->animationWillBeRemoved(anim); toBeRemoved.append(anim->animatingProperty()); + LOG(Animations, "Removing ImplicitAnimation %p for property %s", anim, getPropertyName(anim->animatingProperty())); } } @@ -248,6 +258,16 @@ void CompositeAnimation::updateKeyframeAnimations(RenderObject* renderer, Render keyframeAnim->setIndex(i); } else if ((anim->duration() || anim->delay()) && anim->iterationCount() && animationName != none) { keyframeAnim = KeyframeAnimation::create(const_cast<Animation*>(anim), renderer, i, this, targetStyle); + LOG(Animations, "Creating KeyframeAnimation %p with keyframes %s, duration %.2f, delay %.2f, iterations %.2f", keyframeAnim.get(), anim->name().utf8().data(), anim->duration(), anim->delay(), anim->iterationCount()); + if (m_suspended) { + keyframeAnim->updatePlayState(AnimPlayStatePaused); + LOG(Animations, " (created in suspended/paused state)"); + } +#if !LOG_DISABLED + HashSet<CSSPropertyID>::const_iterator endProperties = keyframeAnim->keyframes().endProperties(); + for (HashSet<CSSPropertyID>::const_iterator it = keyframeAnim->keyframes().beginProperties(); it != endProperties; ++it) + LOG(Animations, " property %s", getPropertyName(*it)); +#endif m_keyframeAnimations.set(keyframeAnim->name().impl(), keyframeAnim); } @@ -267,6 +287,7 @@ void CompositeAnimation::updateKeyframeAnimations(RenderObject* renderer, Render animsToBeRemoved.append(keyframeAnim->name().impl()); animationController()->animationWillBeRemoved(keyframeAnim); keyframeAnim->clear(); + LOG(Animations, "Removing KeyframeAnimation %p", keyframeAnim); } } @@ -327,26 +348,6 @@ PassRefPtr<RenderStyle> CompositeAnimation::getAnimatedStyle() const return resultStyle; } -// "animating" means that something is running that requires the timer to keep firing -void CompositeAnimation::setAnimating(bool animating) -{ - if (!m_transitions.isEmpty()) { - CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end(); - for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) { - ImplicitAnimation* transition = it->value.get(); - transition->setAnimating(animating); - } - } - if (!m_keyframeAnimations.isEmpty()) { - m_keyframeAnimations.checkConsistency(); - AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end(); - for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) { - KeyframeAnimation* anim = it->value.get(); - anim->setAnimating(animating); - } - } -} - double CompositeAnimation::timeToNextService() const { // Returns the time at which next service is required. -1 means no service is required. 0 means @@ -500,9 +501,6 @@ bool CompositeAnimation::isAnimatingProperty(CSSPropertyID property, bool accele bool CompositeAnimation::pauseAnimationAtTime(const AtomicString& name, double t) { - if (!name) - return false; - m_keyframeAnimations.checkConsistency(); RefPtr<KeyframeAnimation> keyframeAnim = m_keyframeAnimations.get(name.impl()); @@ -523,7 +521,7 @@ bool CompositeAnimation::pauseTransitionAtTime(CSSPropertyID property, double t) if ((property < firstCSSProperty) || (property >= firstCSSProperty + numCSSProperties)) return false; - ImplicitAnimation* implAnim = m_transitions.get(property).get(); + ImplicitAnimation* implAnim = m_transitions.get(property); if (!implAnim) { // Check to see if this property is being animated via a shorthand. // This code is only used for testing, so performance is not critical here. @@ -574,20 +572,4 @@ unsigned CompositeAnimation::numberOfActiveAnimations() const return count; } -PassRefPtr<WebKitAnimationList> CompositeAnimation::animations() const -{ - RefPtr<WebKitAnimationList> animations = WebKitAnimationList::create(); - if (!m_keyframeAnimations.isEmpty()) { - m_keyframeAnimations.checkConsistency(); - for (Vector<AtomicStringImpl*>::const_iterator it = m_keyframeAnimationOrderMap.begin(); it != m_keyframeAnimationOrderMap.end(); ++it) { - RefPtr<KeyframeAnimation> keyframeAnimation = m_keyframeAnimations.get(*it); - if (keyframeAnimation) { - RefPtr<WebKitAnimation> anim = WebKitAnimation::create(keyframeAnimation); - animations->append(anim); - } - } - } - return animations; -} - } // namespace WebCore diff --git a/Source/WebCore/page/animation/CompositeAnimation.h b/Source/WebCore/page/animation/CompositeAnimation.h index 91a35f02c..4f4919070 100644 --- a/Source/WebCore/page/animation/CompositeAnimation.h +++ b/Source/WebCore/page/animation/CompositeAnimation.h @@ -41,7 +41,6 @@ class AnimationControllerPrivate; class AnimationController; class RenderObject; class RenderStyle; -class WebKitAnimationList; // A CompositeAnimation represents a collection of animations that are running // on a single RenderObject, such as a number of properties transitioning at once. @@ -65,11 +64,10 @@ public: void suspendAnimations(); void resumeAnimations(); - bool suspended() const { return m_suspended; } + bool isSuspended() const { return m_suspended; } bool hasAnimations() const { return !m_transitions.isEmpty() || !m_keyframeAnimations.isEmpty(); } - void setAnimating(bool); bool isAnimatingProperty(CSSPropertyID, bool acceleratedOnly, bool isRunningNow) const; PassRefPtr<KeyframeAnimation> getAnimationForProperty(CSSPropertyID) const; @@ -81,14 +79,8 @@ public: bool pauseTransitionAtTime(CSSPropertyID, double); unsigned numberOfActiveAnimations() const; - PassRefPtr<WebKitAnimationList> animations() const; - private: - CompositeAnimation(AnimationControllerPrivate* animationController) - : m_animationController(animationController) - , m_suspended(false) - { - } + CompositeAnimation(AnimationControllerPrivate*); void updateTransitions(RenderObject*, RenderStyle* currentStyle, RenderStyle* targetStyle); void updateKeyframeAnimations(RenderObject*, RenderStyle* currentStyle, RenderStyle* targetStyle); diff --git a/Source/WebCore/page/animation/ImplicitAnimation.cpp b/Source/WebCore/page/animation/ImplicitAnimation.cpp index 497ca3f54..920666288 100644 --- a/Source/WebCore/page/animation/ImplicitAnimation.cpp +++ b/Source/WebCore/page/animation/ImplicitAnimation.cpp @@ -35,7 +35,6 @@ #include "ImplicitAnimation.h" #include "KeyframeAnimation.h" #include "RenderBoxModelObject.h" -#include <wtf/UnusedParam.h> namespace WebCore { @@ -78,20 +77,17 @@ void ImplicitAnimation::animate(CompositeAnimation*, RenderObject*, const Render if (!animatedStyle) animatedStyle = RenderStyle::clone(targetStyle); +#if USE(ACCELERATED_COMPOSITING) bool needsAnim = CSSPropertyAnimation::blendProperties(this, m_animatingProperty, animatedStyle.get(), m_fromStyle.get(), m_toStyle.get(), progress(1, 0, 0)); // FIXME: we also need to detect cases where we have to software animate for other reasons, // such as a child using inheriting the transform. https://bugs.webkit.org/show_bug.cgi?id=23902 - if (needsAnim) - setAnimating(); - else { -#if USE(ACCELERATED_COMPOSITING) + if (!needsAnim) // If we are running an accelerated animation, set a flag in the style which causes the style // to compare as different to any other style. This ensures that changes to the property // that is animating are correctly detected during the animation (e.g. when a transition // gets interrupted). animatedStyle->setIsRunningAcceleratedAnimation(); #endif - } // Fire the start timeout if needed fireAnimationEventsIfNeeded(); @@ -151,13 +147,13 @@ void ImplicitAnimation::onAnimationEnd(double elapsedTime) if (keyframeAnim) keyframeAnim->setUnanimatedStyle(m_toStyle); - sendTransitionEvent(eventNames().webkitTransitionEndEvent, elapsedTime); + sendTransitionEvent(eventNames().transitionendEvent, elapsedTime); endAnimation(); } bool ImplicitAnimation::sendTransitionEvent(const AtomicString& eventType, double elapsedTime) { - if (eventType == eventNames().webkitTransitionEndEvent) { + if (eventType == eventNames().transitionendEvent) { Document::ListenerType listenerType = Document::TRANSITIONEND_LISTENER; if (shouldSendEventForListener(listenerType)) { @@ -166,7 +162,7 @@ bool ImplicitAnimation::sendTransitionEvent(const AtomicString& eventType, doubl // Dispatch the event RefPtr<Element> element = 0; if (m_object->node() && m_object->node()->isElementNode()) - element = static_cast<Element*>(m_object->node()); + element = toElement(m_object->node()); ASSERT(!element || (element->document() && !element->document()->inPageCache())); if (!element) @@ -176,7 +172,7 @@ bool ImplicitAnimation::sendTransitionEvent(const AtomicString& eventType, doubl m_compAnim->animationController()->addEventToDispatch(element, eventType, propertyName, elapsedTime); // Restore the original (unanimated) style - if (eventType == eventNames().webkitTransitionEndEvent && element->renderer()) + if (eventType == eventNames().transitionendEvent && element->renderer()) setNeedsStyleRecalc(element.get()); return true; // Did dispatch an event diff --git a/Source/WebCore/page/animation/KeyframeAnimation.cpp b/Source/WebCore/page/animation/KeyframeAnimation.cpp index da2915d52..454dd8769 100644 --- a/Source/WebCore/page/animation/KeyframeAnimation.cpp +++ b/Source/WebCore/page/animation/KeyframeAnimation.cpp @@ -37,7 +37,6 @@ #include "RenderBoxModelObject.h" #include "RenderStyle.h" #include "StyleResolver.h" -#include <wtf/UnusedParam.h> using namespace std; @@ -52,7 +51,7 @@ KeyframeAnimation::KeyframeAnimation(const Animation* animation, RenderObject* r { // Get the keyframe RenderStyles if (m_object && m_object->node() && m_object->node()->isElementNode()) - m_object->document()->styleResolver()->keyframeStylesForAnimation(static_cast<Element*>(m_object->node()), unanimatedStyle, m_keyframes); + m_object->document()->ensureStyleResolver()->keyframeStylesForAnimation(toElement(m_object->node()), unanimatedStyle, m_keyframes); // Update the m_transformFunctionListValid flag based on whether the function lists in the keyframes match. validateTransformFunctionList(); @@ -140,13 +139,13 @@ void KeyframeAnimation::fetchIntervalEndpointsForProperty(CSSPropertyID property prog = progress(scale, offset, timingFunction); } -void KeyframeAnimation::animate(CompositeAnimation*, RenderObject*, const RenderStyle*, RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle) +void KeyframeAnimation::animate(CompositeAnimation* compositeAnimation, RenderObject*, const RenderStyle*, RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle) { // Fire the start timeout if needed fireAnimationEventsIfNeeded(); // If we have not yet started, we will not have a valid start time, so just start the animation if needed. - if (isNew() && m_animation->playState() == AnimPlayStatePlaying) + if (isNew() && m_animation->playState() == AnimPlayStatePlaying && !compositeAnimation->isSuspended()) updateStateMachine(AnimationStateInputStartAnimation, -1); // If we get this far and the animation is done, it means we are cleaning up a just finished animation. @@ -185,18 +184,14 @@ void KeyframeAnimation::animate(CompositeAnimation*, RenderObject*, const Render const RenderStyle* toStyle = 0; double progress = 0.0; fetchIntervalEndpointsForProperty(*it, fromStyle, toStyle, progress); - - bool needsAnim = CSSPropertyAnimation::blendProperties(this, *it, animatedStyle.get(), fromStyle, toStyle, progress); - if (needsAnim) - setAnimating(); - else { #if USE(ACCELERATED_COMPOSITING) + bool needsAnim = CSSPropertyAnimation::blendProperties(this, *it, animatedStyle.get(), fromStyle, toStyle, progress); + if (!needsAnim) // If we are running an accelerated animation, set a flag in the style // to indicate it. This can be used to make sure we get an updated // style for hit testing, etc. animatedStyle->setIsRunningAcceleratedAnimation(); #endif - } } } @@ -315,7 +310,7 @@ bool KeyframeAnimation::sendAnimationEvent(const AtomicString& eventType, double // Dispatch the event RefPtr<Element> element; if (m_object->node() && m_object->node()->isElementNode()) - element = static_cast<Element*>(m_object->node()); + element = toElement(m_object->node()); ASSERT(!element || (element->document() && !element->document()->inPageCache())); if (!element) diff --git a/Source/WebCore/page/animation/KeyframeAnimation.h b/Source/WebCore/page/animation/KeyframeAnimation.h index 8b710219f..72bfd203b 100644 --- a/Source/WebCore/page/animation/KeyframeAnimation.h +++ b/Source/WebCore/page/animation/KeyframeAnimation.h @@ -49,6 +49,8 @@ public: virtual void animate(CompositeAnimation*, RenderObject*, const RenderStyle* currentStyle, RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle); virtual void getAnimatedStyle(RefPtr<RenderStyle>& animatedStyle); + const KeyframeList& keyframes() const { return m_keyframes; } + const AtomicString& name() const { return m_keyframes.animationName(); } int index() const { return m_index; } void setIndex(int i) { m_index = i; } diff --git a/Source/WebCore/page/blackberry/EventHandlerBlackBerry.cpp b/Source/WebCore/page/blackberry/EventHandlerBlackBerry.cpp index 8fb72b800..4cf99f4d9 100644 --- a/Source/WebCore/page/blackberry/EventHandlerBlackBerry.cpp +++ b/Source/WebCore/page/blackberry/EventHandlerBlackBerry.cpp @@ -20,7 +20,6 @@ #include "config.h" #include "EventHandler.h" -#include "ClipboardBlackBerry.h" #include "FocusController.h" #include "Frame.h" #include "KeyboardEvent.h" @@ -87,11 +86,4 @@ void EventHandler::focusDocumentView() page->focusController()->setFocusedFrame(m_frame); } -#if ENABLE(DRAG_SUPPORT) -WTF::PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const -{ - return ClipboardBlackBerry::create(ClipboardWritable); -} -#endif - } // namespace WebCore diff --git a/Source/WebCore/page/blackberry/SettingsBlackBerry.cpp b/Source/WebCore/page/blackberry/SettingsBlackBerry.cpp index ec02cc6b7..a1d6e54e3 100644 --- a/Source/WebCore/page/blackberry/SettingsBlackBerry.cpp +++ b/Source/WebCore/page/blackberry/SettingsBlackBerry.cpp @@ -27,29 +27,10 @@ namespace WebCore { void Settings::initializeDefaultFontFamilies() { - static const char* kLanguages[] = { - "ar", - "bn", - "gu", - "he", - "hi", - "ja", - "kn", - "ko", - "ml", - "pa", - "ta", - "te", - "th", - "zh-CN", - "zh-TW", - }; - - static BlackBerry::Platform::String* languages[WTF_ARRAY_LENGTH(kLanguages)]; + static std::vector<BlackBerry::Platform::String> languages; static bool init = false; if (!init) { - for (size_t i = 0; i < WTF_ARRAY_LENGTH(kLanguages); ++i) - languages[i] = new BlackBerry::Platform::String(kLanguages[i]); + languages = BlackBerry::Platform::FontInfo::instance()->languagesWithFonts(); init = true; } @@ -70,12 +51,12 @@ void Settings::initializeDefaultFontFamilies() STATIC_LOCAL_STRING(s_monospace, "monospace"); STATIC_LOCAL_STRING(s_serif, "serif"); STATIC_LOCAL_STRING(s_sansSerif, "sans-serif"); - for (size_t i = 0; i < WTF_ARRAY_LENGTH(languages); ++i) { - UScriptCode script = localeToScriptCodeForFontSelection(*languages[i]); - setFixedFontFamily(BlackBerry::Platform::FontInfo::instance()->fontFamily(s_monospace, *languages[i]), script); - setSansSerifFontFamily(BlackBerry::Platform::FontInfo::instance()->fontFamily(s_sansSerif, *languages[i]), script); - setSerifFontFamily(BlackBerry::Platform::FontInfo::instance()->fontFamily(s_serif, *languages[i]), script); - setStandardFontFamily(BlackBerry::Platform::FontInfo::instance()->fontFamily(BlackBerry::Platform::String::emptyString(), *languages[i]), script); + for (size_t i = 0; i < languages.size(); ++i) { + UScriptCode script = localeToScriptCodeForFontSelection(languages[i]); + setFixedFontFamily(BlackBerry::Platform::FontInfo::instance()->fontFamily(s_monospace, languages[i]), script); + setSansSerifFontFamily(BlackBerry::Platform::FontInfo::instance()->fontFamily(s_sansSerif, languages[i]), script); + setSerifFontFamily(BlackBerry::Platform::FontInfo::instance()->fontFamily(s_serif, languages[i]), script); + setStandardFontFamily(BlackBerry::Platform::FontInfo::instance()->fontFamily(BlackBerry::Platform::String::emptyString(), languages[i]), script); } } diff --git a/Source/WebCore/page/chromium/ChromeClientChromium.h b/Source/WebCore/page/chromium/ChromeClientChromium.h deleted file mode 100644 index 02e2a945d..000000000 --- a/Source/WebCore/page/chromium/ChromeClientChromium.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2008, Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef ChromeClientChromium_h -#define ChromeClientChromium_h - -#include "ChromeClient.h" -#include <wtf/Forward.h> - -namespace WebCore { -class IntRect; -class PopupContainer; - -// Contains Chromium-specific extensions to the ChromeClient. Only put -// things here that don't make sense for other ports. -class ChromeClientChromium : public ChromeClient { -public: - // Notifies the client of a new popup widget. The client should place - // and size the widget with the given bounds, relative to the screen. - // If handleExternal is true, then drawing and input handling for the - // popup will be handled by the external embedder. - virtual void popupOpened(PopupContainer* popupContainer, const IntRect& bounds, - bool handleExternal) = 0; - - // Notifies the client a popup was closed. - virtual void popupClosed(PopupContainer* popupContainer) = 0; -}; - -} // namespace WebCore - -#endif diff --git a/Source/WebCore/page/chromium/DragControllerChromium.cpp b/Source/WebCore/page/chromium/DragControllerChromium.cpp deleted file mode 100644 index 704480ce1..000000000 --- a/Source/WebCore/page/chromium/DragControllerChromium.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2007 Apple Inc. All rights reserved. - * Copyright (C) 2008 Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "DragController.h" - -#include "DragData.h" -#include "FrameSelection.h" -#include <wtf/RefPtr.h> - -#if OS(WINDOWS) -#include <windows.h> -#endif - -namespace WebCore { - -const int DragController::LinkDragBorderInset = 2; -const int DragController::MaxOriginalImageArea = 1500 * 1500; -const int DragController::DragIconRightInset = 7; -const int DragController::DragIconBottomInset = 3; - -const float DragController::DragImageAlpha = 0.75f; - -DragOperation DragController::dragOperation(DragData* dragData) -{ - // FIXME: To match the MacOS behaviour we should return DragOperationNone - // if we are a modal window, we are the drag source, or the window is an - // attached sheet If this can be determined from within WebCore - // operationForDrag can be pulled into WebCore itself - ASSERT(dragData); - return dragData->containsURL(0) && !m_didInitiateDrag ? DragOperationCopy : DragOperationNone; -} - -bool DragController::isCopyKeyDown(DragData*) -{ - // FIXME: This should not be OS specific. Delegate to the embedder instead. -#if OS(WINDOWS) - return ::GetAsyncKeyState(VK_CONTROL); -#else - return false; -#endif -} - -const IntSize& DragController::maxDragImageSize() -{ -#if OS(DARWIN) - // Match Safari's drag image size. - static const IntSize maxDragImageSize(400, 400); -#else - static const IntSize maxDragImageSize(200, 200); -#endif - return maxDragImageSize; -} - -void DragController::cleanupAfterSystemDrag() -{ -} - -} // namespace WebCore diff --git a/Source/WebCore/page/chromium/EventHandlerChromium.cpp b/Source/WebCore/page/chromium/EventHandlerChromium.cpp deleted file mode 100644 index 112b0e5bd..000000000 --- a/Source/WebCore/page/chromium/EventHandlerChromium.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2008 Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "EventHandler.h" - -#include "ChromiumDataObject.h" -#include "ClipboardChromium.h" -#include "Cursor.h" -#include "FloatPoint.h" -#include "FocusController.h" -#include "Frame.h" -#include "FrameSelection.h" -#include "FrameView.h" -#include "HitTestRequest.h" -#include "HitTestResult.h" -#include "MouseEventWithHitTestResults.h" -#include "NotImplemented.h" -#include "Page.h" -#include "PlatformKeyboardEvent.h" -#include "PlatformWheelEvent.h" -#include "RenderWidget.h" - -namespace WebCore { - -#if OS(DARWIN) -const double EventHandler::TextDragDelay = 0.15; -#else -const double EventHandler::TextDragDelay = 0.0; -#endif - -bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe) -{ - // If we're clicking into a frame that is selected, the frame will appear - // greyed out even though we're clicking on the selection. This looks - // really strange (having the whole frame be greyed out), so we deselect the - // selection. - IntPoint p = m_frame->view()->windowToContents(mev.event().position()); - if (m_frame->selection()->contains(p)) { - VisiblePosition visiblePos( - mev.targetNode()->renderer()->positionForPoint(mev.localPoint())); - VisibleSelection newSelection(visiblePos); - if (m_frame->selection()->shouldChangeSelection(newSelection)) - m_frame->selection()->setSelection(newSelection); - } - - subframe->eventHandler()->handleMousePressEvent(mev.event()); - return true; -} - -bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe, HitTestResult* hoveredNode) -{ - if (m_mouseDownMayStartDrag && !m_mouseDownWasInSubframe) - return false; - subframe->eventHandler()->handleMouseMoveEvent(mev.event(), hoveredNode); - return true; -} - -bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe) -{ - subframe->eventHandler()->handleMouseReleaseEvent(mev.event()); - return true; -} - -bool EventHandler::passWheelEventToWidget(const PlatformWheelEvent& wheelEvent, Widget* widget) -{ - // We can sometimes get a null widget! EventHandlerMac handles a null - // widget by returning false, so we do the same. - if (!widget) - return false; - - // If not a FrameView, then probably a plugin widget. Those will receive - // the event via an EventTargetNode dispatch when this returns false. - if (!widget->isFrameView()) - return false; - - return static_cast<FrameView*>(widget)->frame()->eventHandler()->handleWheelEvent(wheelEvent); -} - -bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults& event) -{ - // Figure out which view to send the event to. - if (!event.targetNode() || !event.targetNode()->renderer() || !event.targetNode()->renderer()->isWidget()) - return false; - return passMouseDownEventToWidget(toRenderWidget(event.targetNode()->renderer())->widget()); -} - -bool EventHandler::passMouseDownEventToWidget(Widget* widget) -{ - notImplemented(); - return false; -} - -bool EventHandler::tabsToAllFormControls(KeyboardEvent*) const -{ - return true; -} - -bool EventHandler::eventActivatedView(const PlatformMouseEvent& event) const -{ - // FIXME: EventHandlerWin.cpp does the following: - // return event.activatedWebView(); - return false; -} - -PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const -{ - RefPtr<ChromiumDataObject> dataObject = ChromiumDataObject::create(); - return ClipboardChromium::create(Clipboard::DragAndDrop, dataObject.get(), ClipboardWritable, m_frame); -} - -void EventHandler::focusDocumentView() -{ - Page* page = m_frame->page(); - if (!page) - return; - page->focusController()->setFocusedFrame(m_frame); -} - -bool EventHandler::passWidgetMouseDownEventToWidget(RenderWidget* renderWidget) -{ - return passMouseDownEventToWidget(renderWidget->widget()); -} - -unsigned EventHandler::accessKeyModifiers() -{ -#if OS(DARWIN) - return PlatformEvent::CtrlKey | PlatformEvent::AltKey; -#else - return PlatformEvent::AltKey; -#endif -} - -#if OS(UNIX) && !OS(DARWIN) -// GTK+ must scroll horizontally if the mouse pointer is on top of the -// horizontal scrollbar while scrolling with the wheel. -// This code comes from gtk/EventHandlerGtk.cpp. -bool EventHandler::shouldTurnVerticalTicksIntoHorizontal(const HitTestResult& result, const PlatformWheelEvent& event) const -{ - return !event.hasPreciseScrollingDeltas() && result.scrollbar() && result.scrollbar()->orientation() == HorizontalScrollbar; -} -#endif - -} // namespace WebCore diff --git a/Source/WebCore/page/efl/EventHandlerEfl.cpp b/Source/WebCore/page/efl/EventHandlerEfl.cpp index db69589dd..5017ef5fe 100644 --- a/Source/WebCore/page/efl/EventHandlerEfl.cpp +++ b/Source/WebCore/page/efl/EventHandlerEfl.cpp @@ -29,7 +29,7 @@ #include "config.h" #include "EventHandler.h" -#include "ClipboardEfl.h" +#include "Clipboard.h" #include "EventNames.h" #include "FloatPoint.h" #include "FocusController.h" @@ -42,7 +42,6 @@ #include "PlatformKeyboardEvent.h" #include "PlatformWheelEvent.h" #include "RenderWidget.h" -#include "Scrollbar.h" namespace WebCore { @@ -94,13 +93,13 @@ bool EventHandler::passWheelEventToWidget(const PlatformWheelEvent& event, Widge if (!widget->isFrameView()) return false; - return static_cast<FrameView*>(widget)->frame()->eventHandler()->handleWheelEvent(event); + return toFrameView(widget)->frame()->eventHandler()->handleWheelEvent(event); } #if ENABLE(DRAG_SUPPORT) PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const { - return ClipboardEfl::create(ClipboardWritable, Clipboard::DragAndDrop); + return Clipboard::createForDragAndDrop(); } #endif diff --git a/Source/WebCore/page/gtk/EventHandlerGtk.cpp b/Source/WebCore/page/gtk/EventHandlerGtk.cpp index 368cfe019..10176f704 100644 --- a/Source/WebCore/page/gtk/EventHandlerGtk.cpp +++ b/Source/WebCore/page/gtk/EventHandlerGtk.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "EventHandler.h" -#include "ClipboardGtk.h" +#include "Clipboard.h" #include "FloatPoint.h" #include "FocusController.h" #include "Frame.h" @@ -91,12 +91,12 @@ bool EventHandler::passWheelEventToWidget(const PlatformWheelEvent& event, Widge if (!widget->isFrameView()) return false; - return static_cast<FrameView*>(widget)->frame()->eventHandler()->handleWheelEvent(event); + return toFrameView(widget)->frame()->eventHandler()->handleWheelEvent(event); } PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const { - return ClipboardGtk::create(ClipboardWritable, DataObjectGtk::create(), Clipboard::DragAndDrop, m_frame); + return Clipboard::createForDragAndDrop(); } bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe) diff --git a/Source/WebCore/page/mac/EventHandlerMac.mm b/Source/WebCore/page/mac/EventHandlerMac.mm index 45150e4f5..0ddb37ab9 100644 --- a/Source/WebCore/page/mac/EventHandlerMac.mm +++ b/Source/WebCore/page/mac/EventHandlerMac.mm @@ -30,7 +30,7 @@ #include "BlockExceptions.h" #include "Chrome.h" #include "ChromeClient.h" -#include "ClipboardMac.h" +#include "Clipboard.h" #include "DragController.h" #include "EventNames.h" #include "FocusController.h" @@ -104,7 +104,7 @@ bool EventHandler::wheelEvent(NSEvent *event) return false; CurrentEventScope scope(event); - return handleWheelEvent(PlatformEventFactory::createPlatformWheelEvent(event, page->chrome()->platformPageClient())); + return handleWheelEvent(PlatformEventFactory::createPlatformWheelEvent(event, page->chrome().platformPageClient())); } bool EventHandler::keyEvent(NSEvent *event) @@ -129,7 +129,7 @@ void EventHandler::focusDocumentView() if (FrameView* frameView = m_frame->view()) { if (NSView *documentView = frameView->documentView()) - page->chrome()->focusNSView(documentView); + page->chrome().focusNSView(documentView); } page->focusController()->setFocusedFrame(m_frame); @@ -203,11 +203,11 @@ bool EventHandler::passMouseDownEventToWidget(Widget* pWidget) if (!page) return true; - if (page->chrome()->client()->firstResponder() != view) { + if (page->chrome().client()->firstResponder() != view) { // Normally [NSWindow sendEvent:] handles setting the first responder. // But in our case, the event was sent to the view representing the entire web page. if ([currentNSEvent() clickCount] <= 1 && [view acceptsFirstResponder] && [view needsPanelToBecomeKey]) - page->chrome()->client()->makeFirstResponder(view); + page->chrome().client()->makeFirstResponder(view); } // We need to "defer loading" while tracking the mouse, because tearing down the @@ -431,7 +431,7 @@ bool EventHandler::passWheelEventToWidget(const PlatformWheelEvent& wheelEvent, if (!widget->isFrameView()) return false; - return static_cast<FrameView*>(widget)->frame()->eventHandler()->handleWheelEvent(wheelEvent); + return toFrameView(widget)->frame()->eventHandler()->handleWheelEvent(wheelEvent); } if ([currentNSEvent() type] != NSScrollWheel || m_sendingEventToSubview) @@ -660,7 +660,7 @@ PlatformMouseEvent EventHandler::currentPlatformMouseEvent() const { NSView *windowView = nil; if (Page* page = m_frame->page()) - windowView = page->chrome()->platformPageClient(); + windowView = page->chrome().platformPageClient(); return PlatformEventFactory::createPlatformMouseEvent(currentNSEvent(), windowView); } @@ -674,10 +674,10 @@ bool EventHandler::eventActivatedView(const PlatformMouseEvent& event) const PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const { // Must be done before ondragstart adds types and data to the pboard, - // also done for security, as it erases data from the last drag - Pasteboard pasteboard(NSDragPboard); - pasteboard.clear(); - return ClipboardMac::create(Clipboard::DragAndDrop, String(NSDragPboard), ClipboardWritable, ClipboardMac::DragAndDropData, m_frame); + // also done for security, as it erases data from the last drag. + OwnPtr<Pasteboard> pasteboard = Pasteboard::create(NSDragPboard); + pasteboard->clear(); + return Clipboard::createForDragAndDrop(); } #endif @@ -688,7 +688,7 @@ bool EventHandler::tabsToAllFormControls(KeyboardEvent* event) const if (!page) return false; - KeyboardUIMode keyboardUIMode = page->chrome()->client()->keyboardUIMode(); + KeyboardUIMode keyboardUIMode = page->chrome().client()->keyboardUIMode(); bool handlingOptionTab = isKeyboardOptionTab(event); // If tab-to-links is off, option-tab always highlights all controls diff --git a/Source/WebCore/page/mac/FrameMac.mm b/Source/WebCore/page/mac/FrameMac.mm index 31d6649af..ebd586fb5 100644 --- a/Source/WebCore/page/mac/FrameMac.mm +++ b/Source/WebCore/page/mac/FrameMac.mm @@ -28,158 +28,15 @@ #import "config.h" #import "Frame.h" -#import "BlockExceptions.h" -#import "ColorMac.h" -#import "Cursor.h" -#import "DOMInternal.h" -#import "Event.h" +#import "Document.h" #import "FrameLoaderClient.h" +#import "FrameSelection.h" +#import "FrameSnapshottingMac.h" #import "FrameView.h" -#import "GraphicsContext.h" -#import "HTMLNames.h" -#import "HTMLTableCellElement.h" -#import "HitTestRequest.h" -#import "HitTestResult.h" -#import "KeyboardEvent.h" -#import "Logging.h" -#import "MouseEventWithHitTestResults.h" -#import "Page.h" -#import "PlatformKeyboardEvent.h" -#import "PlatformWheelEvent.h" -#import "RegularExpression.h" -#import "RenderTableCell.h" -#import "RenderView.h" -#import "Scrollbar.h" -#import "SimpleFontData.h" -#import "visible_units.h" -#import <wtf/StdLibExtras.h> - -@interface NSView (WebCoreHTMLDocumentView) -- (void)drawSingleRect:(NSRect)rect; -@end - -using namespace std; +#import "RenderObject.h" namespace WebCore { -using namespace HTMLNames; - -NSImage* Frame::imageFromRect(NSRect rect) const -{ - PaintBehavior oldBehavior = m_view->paintBehavior(); - m_view->setPaintBehavior(oldBehavior | PaintBehaviorFlattenCompositingLayers); - - BEGIN_BLOCK_OBJC_EXCEPTIONS; - - NSImage* resultImage = [[[NSImage alloc] initWithSize:rect.size] autorelease]; - - if (rect.size.width != 0 && rect.size.height != 0) { - [resultImage setFlipped:YES]; - [resultImage lockFocus]; - - GraphicsContext graphicsContext((CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]); - graphicsContext.save(); - graphicsContext.translate(-rect.origin.x, -rect.origin.y); - m_view->paintContents(&graphicsContext, IntRect(rect)); - graphicsContext.restore(); - - [resultImage unlockFocus]; - [resultImage setFlipped:NO]; - } - - m_view->setPaintBehavior(oldBehavior); - return resultImage; - - END_BLOCK_OBJC_EXCEPTIONS; - - m_view->setPaintBehavior(oldBehavior); - return nil; -} - -NSImage* Frame::selectionImage(bool forceBlackText) const -{ - m_view->setPaintBehavior(PaintBehaviorSelectionOnly | (forceBlackText ? PaintBehaviorForceBlackText : 0)); - m_doc->updateLayout(); - NSImage* result = imageFromRect(selection()->bounds()); - m_view->setPaintBehavior(PaintBehaviorNormal); - return result; -} - -NSImage *Frame::rangeImage(Range* range, bool forceBlackText) const -{ - m_view->setPaintBehavior(PaintBehaviorSelectionOnly | (forceBlackText ? PaintBehaviorForceBlackText : 0)); - m_doc->updateLayout(); - RenderView* view = contentRenderer(); - if (!view) - return nil; - - Position start = range->startPosition(); - Position candidate = start.downstream(); - if (candidate.deprecatedNode() && candidate.deprecatedNode()->renderer()) - start = candidate; - - Position end = range->endPosition(); - candidate = end.upstream(); - if (candidate.deprecatedNode() && candidate.deprecatedNode()->renderer()) - end = candidate; - - if (start.isNull() || end.isNull() || start == end) - return nil; - - RenderObject* savedStartRenderer; - int savedStartOffset; - RenderObject* savedEndRenderer; - int savedEndOffset; - view->getSelection(savedStartRenderer, savedStartOffset, savedEndRenderer, savedEndOffset); - - RenderObject* startRenderer = start.deprecatedNode()->renderer(); - if (!startRenderer) - return nil; - - RenderObject* endRenderer = end.deprecatedNode()->renderer(); - if (!endRenderer) - return nil; - - view->setSelection(startRenderer, start.deprecatedEditingOffset(), endRenderer, end.deprecatedEditingOffset(), RenderView::RepaintNothing); - NSImage* result = imageFromRect(view->selectionBounds()); - view->setSelection(savedStartRenderer, savedStartOffset, savedEndRenderer, savedEndOffset, RenderView::RepaintNothing); - - m_view->setPaintBehavior(PaintBehaviorNormal); - return result; -} - -NSImage* Frame::snapshotDragImage(Node* node, NSRect* imageRect, NSRect* elementRect) const -{ - RenderObject* renderer = node->renderer(); - if (!renderer) - return nil; - - renderer->updateDragState(true); // mark dragged nodes (so they pick up the right CSS) - m_doc->updateLayout(); // forces style recalc - needed since changing the drag state might - // imply new styles, plus JS could have changed other things - - - // Document::updateLayout may have blown away the original RenderObject. - renderer = node->renderer(); - if (!renderer) - return nil; - - LayoutRect topLevelRect; - NSRect paintingRect = pixelSnappedIntRect(renderer->paintingRootRect(topLevelRect)); - - m_view->setNodeToDraw(node); // invoke special sub-tree drawing mode - NSImage* result = imageFromRect(paintingRect); - renderer->updateDragState(false); - m_doc->updateLayout(); - m_view->setNodeToDraw(0); - - if (elementRect) - *elementRect = pixelSnappedIntRect(topLevelRect); - if (imageRect) - *imageRect = paintingRect; - return result; -} - DragImageRef Frame::nodeImage(Node* node) { m_doc->updateLayout(); // forces style recalc @@ -191,7 +48,7 @@ DragImageRef Frame::nodeImage(Node* node) NSRect paintingRect = pixelSnappedIntRect(renderer->paintingRootRect(topLevelRect)); m_view->setNodeToDraw(node); // invoke special sub-tree drawing mode - NSImage* result = imageFromRect(paintingRect); + NSImage* result = imageFromRect(this, paintingRect); m_view->setNodeToDraw(0); return result; @@ -201,7 +58,7 @@ DragImageRef Frame::dragImageForSelection() { if (!selection()->isRange()) return nil; - return selectionImage(); + return selectionImage(this); } } // namespace WebCore diff --git a/Source/WebCore/page/Coordinates.idl b/Source/WebCore/page/mac/FrameSnapshottingMac.h index cccba2272..bfab67e76 100644 --- a/Source/WebCore/page/Coordinates.idl +++ b/Source/WebCore/page/mac/FrameSnapshottingMac.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Apple Inc. All Rights Reserved. + * Copyright (C) 2013 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,27 +10,35 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -[ - OmitConstructor -] interface Coordinates { - readonly attribute double latitude; - readonly attribute double longitude; - [Custom] readonly attribute double altitude; - readonly attribute double accuracy; - [Custom] readonly attribute double altitudeAccuracy; - [Custom] readonly attribute double heading; - [Custom] readonly attribute double speed; -}; +#ifndef FrameSnapshottingMac_h +#define FrameSnapshottingMac_h + +OBJC_CLASS NSImage; + +namespace WebCore { + +class Frame; +class Range; +class Node; + +NSImage* selectionImage(Frame*, bool forceBlackText = false); +NSImage* rangeImage(Frame*, Range*, bool forceBlackText = false); +NSImage* snapshotDragImage(Frame*, Node*, NSRect* imageRect, NSRect* elementRect); +NSImage* imageFromRect(Frame*, NSRect); + +} + +#endif // FrameSnapshottingMac_h diff --git a/Source/WebCore/page/mac/FrameSnapshottingMac.mm b/Source/WebCore/page/mac/FrameSnapshottingMac.mm new file mode 100644 index 000000000..ab3149e0d --- /dev/null +++ b/Source/WebCore/page/mac/FrameSnapshottingMac.mm @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com) + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "FrameSnapshottingMac.h" + +#import "BlockExceptions.h" +#import "Document.h" +#import "Frame.h" +#import "FrameSelection.h" +#import "FrameView.h" +#import "GraphicsContext.h" +#import "Range.h" +#import "RenderView.h" + +namespace WebCore { + +NSImage* imageFromRect(Frame* frame, NSRect rect) +{ + PaintBehavior oldBehavior = frame->view()->paintBehavior(); + frame->view()->setPaintBehavior(oldBehavior | PaintBehaviorFlattenCompositingLayers); + + BEGIN_BLOCK_OBJC_EXCEPTIONS; + + NSImage* resultImage = [[[NSImage alloc] initWithSize:rect.size] autorelease]; + + if (rect.size.width != 0 && rect.size.height != 0) { + [resultImage setFlipped:YES]; + [resultImage lockFocus]; + + GraphicsContext graphicsContext((CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]); + graphicsContext.save(); + graphicsContext.translate(-rect.origin.x, -rect.origin.y); + frame->view()->paintContents(&graphicsContext, IntRect(rect)); + graphicsContext.restore(); + + [resultImage unlockFocus]; + [resultImage setFlipped:NO]; + } + + frame->view()->setPaintBehavior(oldBehavior); + return resultImage; + + END_BLOCK_OBJC_EXCEPTIONS; + + frame->view()->setPaintBehavior(oldBehavior); + return nil; +} + +NSImage* selectionImage(Frame* frame, bool forceBlackText) +{ + frame->view()->setPaintBehavior(PaintBehaviorSelectionOnly | (forceBlackText ? PaintBehaviorForceBlackText : 0)); + frame->document()->updateLayout(); + NSImage* result = imageFromRect(frame, frame->selection()->bounds()); + frame->view()->setPaintBehavior(PaintBehaviorNormal); + return result; +} + +NSImage *rangeImage(Frame* frame, Range* range, bool forceBlackText) +{ + frame->view()->setPaintBehavior(PaintBehaviorSelectionOnly | (forceBlackText ? PaintBehaviorForceBlackText : 0)); + frame->document()->updateLayout(); + RenderView* view = frame->contentRenderer(); + if (!view) + return nil; + + Position start = range->startPosition(); + Position candidate = start.downstream(); + if (candidate.deprecatedNode() && candidate.deprecatedNode()->renderer()) + start = candidate; + + Position end = range->endPosition(); + candidate = end.upstream(); + if (candidate.deprecatedNode() && candidate.deprecatedNode()->renderer()) + end = candidate; + + if (start.isNull() || end.isNull() || start == end) + return nil; + + RenderObject* savedStartRenderer; + int savedStartOffset; + RenderObject* savedEndRenderer; + int savedEndOffset; + view->getSelection(savedStartRenderer, savedStartOffset, savedEndRenderer, savedEndOffset); + + RenderObject* startRenderer = start.deprecatedNode()->renderer(); + if (!startRenderer) + return nil; + + RenderObject* endRenderer = end.deprecatedNode()->renderer(); + if (!endRenderer) + return nil; + + view->setSelection(startRenderer, start.deprecatedEditingOffset(), endRenderer, end.deprecatedEditingOffset(), RenderView::RepaintNothing); + NSImage* result = imageFromRect(frame, view->selectionBounds()); + view->setSelection(savedStartRenderer, savedStartOffset, savedEndRenderer, savedEndOffset, RenderView::RepaintNothing); + + frame->view()->setPaintBehavior(PaintBehaviorNormal); + return result; +} + + +NSImage* snapshotDragImage(Frame* frame, Node* node, NSRect* imageRect, NSRect* elementRect) +{ + RenderObject* renderer = node->renderer(); + if (!renderer) + return nil; + + renderer->updateDragState(true); // mark dragged nodes (so they pick up the right CSS) + frame->document()->updateLayout(); // forces style recalc - needed since changing the drag state might + // imply new styles, plus JS could have changed other things + + + // Document::updateLayout may have blown away the original RenderObject. + renderer = node->renderer(); + if (!renderer) + return nil; + + LayoutRect topLevelRect; + NSRect paintingRect = pixelSnappedIntRect(renderer->paintingRootRect(topLevelRect)); + + frame->view()->setNodeToDraw(node); // invoke special sub-tree drawing mode + NSImage* result = imageFromRect(frame, paintingRect); + renderer->updateDragState(false); + frame->document()->updateLayout(); + frame->view()->setNodeToDraw(0); + + if (elementRect) + *elementRect = pixelSnappedIntRect(topLevelRect); + if (imageRect) + *imageRect = paintingRect; + return result; +} + +} // namespace WebCore diff --git a/Source/WebCore/page/mac/SettingsMac.mm b/Source/WebCore/page/mac/SettingsMac.mm index 04bf49984..039f9a7fa 100644 --- a/Source/WebCore/page/mac/SettingsMac.mm +++ b/Source/WebCore/page/mac/SettingsMac.mm @@ -31,8 +31,13 @@ namespace WebCore { void Settings::initializeDefaultFontFamilies() { #if !PLATFORM(IOS) +#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 + setStandardFontFamily("Songti TC", USCRIPT_TRADITIONAL_HAN); + setSerifFontFamily("Songti TC", USCRIPT_TRADITIONAL_HAN); +#else setStandardFontFamily("Apple LiSung", USCRIPT_TRADITIONAL_HAN); setSerifFontFamily("Apple LiSung", USCRIPT_TRADITIONAL_HAN); +#endif #else // There is no serif Chinese font in default iOS installation. setStandardFontFamily("Heiti TC", USCRIPT_TRADITIONAL_HAN); @@ -42,8 +47,13 @@ void Settings::initializeDefaultFontFamilies() setSansSerifFontFamily("Heiti TC", USCRIPT_TRADITIONAL_HAN); #if !PLATFORM(IOS) +#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 + setStandardFontFamily("Songti SC", USCRIPT_SIMPLIFIED_HAN); + setSerifFontFamily("Songti SC", USCRIPT_SIMPLIFIED_HAN); +#else setStandardFontFamily("STSong", USCRIPT_SIMPLIFIED_HAN); setSerifFontFamily("STSong", USCRIPT_SIMPLIFIED_HAN); +#endif #else // There is no serif Chinese font in default iOS installation. setStandardFontFamily("Heiti SC", USCRIPT_SIMPLIFIED_HAN); diff --git a/Source/WebCore/page/make_settings.pl b/Source/WebCore/page/make_settings.pl index d99cc0fce..9ea45edfb 100755 --- a/Source/WebCore/page/make_settings.pl +++ b/Source/WebCore/page/make_settings.pl @@ -30,12 +30,23 @@ use InFilesCompiler; my %defaultParameters = ( ); +my %webcoreTypeToIdlType = ( + 'int' => 'long', + 'unsigned' => 'unsigned long', + 'size_t' => 'unsigned long', + 'double' => 'double', + 'float' => 'float', + 'String' => 'DOMString', + 'bool' => 'boolean' +); + sub defaultItemFactory { return ( 'conditional' => 0, 'initial' => '', - 'type' => 'bool' + 'type' => 'bool', + 'setNeedsStyleRecalcInAllFrames' => 0, ); } @@ -49,10 +60,13 @@ sub generateCode() my $parsedParametersRef = shift; my $parsedItemsRef = shift; - generateHeader($parsedItemsRef); + generateSettingsMacrosHeader($parsedItemsRef); + generateInternalSettingsIdlFile($parsedItemsRef); + generateInternalSettingsHeaderFile($parsedItemsRef); + generateInternalSettingsCppFile($parsedItemsRef); } -sub generateHeader($) +sub generateSettingsMacrosHeader($) { my $parsedItemsRef = shift; @@ -89,6 +103,7 @@ sub generateHeader($) printGettersAndSetters($file, \%unconditionalSettings, \%settingsByConditional, $parsedItemsRef); printMemberVariables($file, \%unconditionalSettings, \%settingsByConditional, $parsedItemsRef); printInitializerList($file, \%unconditionalSettings, \%settingsByConditional, $parsedItemsRef); + printSetterBodies($file, \%unconditionalSettings, \%settingsByConditional, $parsedItemsRef); print $file "#endif // SettingsMacros_h\n"; @@ -107,7 +122,7 @@ sub printConditionalMacros($$$) print $file "#define ${preferredConditional}_SETTINGS_GETTER_AND_SETTERS \\\n"; for my $settingName (sort keys %{ $settingsByConditional{$conditional} }) { - printGetterAndSetter($file, $settingName, $parsedItems{$settingName}{"type"}); + printGetterAndSetter($file, $settingName, $parsedItems{$settingName}{"type"}, $parsedItems{$settingName}{"setNeedsStyleRecalcInAllFrames"}); } print $file "// End of ${preferredConditional}_SETTINGS_GETTER_AND_SETTERS\n"; @@ -140,12 +155,19 @@ sub printConditionalMacros($$$) } print $file "// End of ${preferredConditional}_SETTINGS_BOOL_INITIALIZERS\n"; + print $file "#define ${preferredConditional}_SETTINGS_SETTER_BODIES \\\n"; + for my $settingName (sort keys %{ $settingsByConditional{$conditional} }) { + printSetterBody($file, $settingName, $parsedItems{$settingName}{"type"}, $parsedItems{$settingName}{"setNeedsStyleRecalcInAllFrames"}); + } + print $file "// End of ${preferredConditional}_SETTINGS_SETTER_BODIES\n"; + print $file "#else\n"; print $file "#define ${preferredConditional}_SETTINGS_GETTER_AND_SETTERS\n"; print $file "#define ${preferredConditional}_SETTINGS_NON_BOOL_MEMBER_VARIABLES\n"; print $file "#define ${preferredConditional}_SETTINGS_BOOL_MEMBER_VARIABLES\n"; print $file "#define ${preferredConditional}_SETTINGS_NON_BOOL_INITIALIZERS\n"; print $file "#define ${preferredConditional}_SETTINGS_BOOL_INITIALIZERS\n"; + print $file "#define ${preferredConditional}_SETTINGS_SETTER_BODIES\n"; print $file "#endif\n"; print $file "\n"; } @@ -160,7 +182,7 @@ sub printGettersAndSetters($$$$) print $file "#define SETTINGS_GETTERS_AND_SETTERS \\\n"; for my $settingName (sort keys %unconditionalSettings) { - printGetterAndSetter($file, $settingName, $parsedItems{$settingName}{"type"}); + printGetterAndSetter($file, $settingName, $parsedItems{$settingName}{"type"}, $parsedItems{$settingName}{"setNeedsStyleRecalcInAllFrames"}); } for my $conditional (sort keys %settingsByConditional) { my $preferredConditional = $InCompiler->preferredConditional($conditional); @@ -198,20 +220,36 @@ sub printMemberVariables($$$$) print $file "// End of SETTINGS_MEMBER_VARIABLES.\n\n"; } -sub printGetterAndSetter($$$) +sub setterFunctionName($) { - my ($file, $settingName, $type) = @_; + my $settingName = shift; my $setterFunctionName = "set" . $settingName; substr($setterFunctionName, 3, 1) = uc(substr($setterFunctionName, 3, 1)); - if (substr($settingName, 0, 3) eq "css" || substr($settingName, 0, 3) eq "xss" || substr($settingName, 0, 3) eq "ftp") { - substr($setterFunctionName, 3, 3) = uc(substr($setterFunctionName, 3, 3)); + my @prefixesToUpperCase = ("css", "xss", "ftp", "dom"); + foreach my $prefix (@prefixesToUpperCase) { + my $prefixLength = length($prefix); + if (substr($settingName, 0, $prefixLength) eq $prefix) { + substr($setterFunctionName, $prefixLength, $prefixLength) = uc(substr($setterFunctionName, 3, 3)); + } } + return $setterFunctionName; +} + +sub printGetterAndSetter($$$$) +{ + my ($file, $settingName, $type, $setNeedsStyleRecalcInAllFrames) = @_; + my $setterFunctionName = setterFunctionName($settingName); if (lc(substr($type, 0, 1)) eq substr($type, 0, 1)) { print $file " $type $settingName() const { return m_$settingName; } \\\n"; - print $file " void $setterFunctionName($type $settingName) { m_$settingName = $settingName; } \\\n"; + print $file " void $setterFunctionName($type $settingName)"; } else { print $file " const $type& $settingName() { return m_$settingName; } \\\n"; - print $file " void $setterFunctionName(const $type& $settingName) { m_$settingName = $settingName; } \\\n"; + print $file " void $setterFunctionName(const $type& $settingName)"; + } + if ($setNeedsStyleRecalcInAllFrames) { + print $file "; \\\n"; + } else { + print $file " { m_$settingName = $settingName; } \\\n"; } } @@ -253,3 +291,243 @@ sub printInitializer($$$) return if ($initialValue eq ''); print $file " , m_$settingName($initialValue) \\\n" } + +sub printSetterBodies($$$$) +{ + my ($file, $unconditionalSettingsRef, $settingsByConditionalRef, $parsedItemsRef) = @_; + my %parsedItems = %{ $parsedItemsRef }; + my %unconditionalSettings = %{ $unconditionalSettingsRef }; + my %settingsByConditional = %{ $settingsByConditionalRef }; + + print $file "#define SETTINGS_SETTER_BODIES \\\n"; + for my $settingName (sort keys %unconditionalSettings) { + printSetterBody($file, $settingName, $parsedItems{$settingName}{"type"}, $parsedItems{$settingName}{"setNeedsStyleRecalcInAllFrames"}); + } + for my $conditional (sort keys %settingsByConditional) { + my $preferredConditional = $InCompiler->preferredConditional($conditional); + print $file " ${preferredConditional}_SETTINGS_SETTER_BODIES \\\n"; + } + print $file "// End of SETTINGS_SETTER_BODIES.\n\n"; +} + +sub printSetterBody($$$$) +{ + my ($file, $settingName, $type, $setNeedsStyleRecalcInAllFrames) = @_; + return if (!$setNeedsStyleRecalcInAllFrames); + + my $setterFunctionName = setterFunctionName($settingName); + if (lc(substr($type, 0, 1)) eq substr($type, 0, 1)) { + print $file "void Settings::$setterFunctionName($type $settingName) \\\n"; + } else { + print $file "void Settings::$setterFunctionName(const $type& $settingName) \\\n"; + } + print $file "{ \\\n"; + print $file " if (m_$settingName == $settingName) \\\n"; + print $file " return; \\\n"; + print $file " m_$settingName = $settingName; \\\n"; + print $file " m_page->setNeedsRecalcStyleInAllFrames(); \\\n"; + print $file "} \\\n"; +} + +sub enumerateParsedItems($$$) +{ + my ($file, $parsedItemsRef, $visitorFunction) = @_; + my %parsedItems = %{ $parsedItemsRef }; + + for my $settingName (sort keys %parsedItems) { + my $type = $parsedItems{$settingName}{"type"}; + # FIXME: Learn how to auto-generate code for enumerate types. + next if (!defined($webcoreTypeToIdlType{$type})); + + &$visitorFunction($file, $parsedItemsRef, $settingName) + } +} + +sub generateInternalSettingsIdlFile($) +{ + my $parsedItemsRef = shift; + + my $filename = "$outputDir/InternalSettingsGenerated.idl"; + open my $file, ">$filename" or die "Failed to open file: $!"; + print $file $InCompiler->license(); + + print $file "[\n"; + print $file " NoInterfaceObject,\n"; + print $file "] interface InternalSettingsGenerated {\n"; + + sub writeIdlSetter($$$) { + my ($file, $parsedItemsRef, $settingName) = @_; + my %parsedItems = %{ $parsedItemsRef }; + my $type = $parsedItems{$settingName}{"type"}; + my $idlType = $webcoreTypeToIdlType{$type}; + my $setterFunctionName = setterFunctionName($settingName); + print $file " void $setterFunctionName(in $idlType $settingName);\n"; + }; + + enumerateParsedItems($file, $parsedItemsRef, \&writeIdlSetter); + + print $file "};\n"; + close $file; +} + +sub generateInternalSettingsHeaderFile($) +{ + my $parsedItemsRef = shift; + my %parsedItems = %{ $parsedItemsRef }; + + my $filename = "$outputDir/InternalSettingsGenerated.h"; + open my $file, ">$filename" or die "Failed to open file: $!"; + print $file $InCompiler->license(); + + print $file <<EOF; +#ifndef InternalSettingsGenerated_h +#define InternalSettingsGenerated_h + +#include "RefCountedSupplement.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/text/WTFString.h> + +namespace WebCore { + +class Page; + +class InternalSettingsGenerated : public RefCounted<InternalSettingsGenerated> { +public: + explicit InternalSettingsGenerated(Page*); + virtual ~InternalSettingsGenerated(); + void resetToConsistentState(); +EOF + sub writeHeaderPrototypes($$$) { + my ($file, $parsedItemsRef, $settingName) = @_; + my %parsedItems = %{ $parsedItemsRef }; + my $type = $parsedItems{$settingName}{"type"}; + my $setterFunctionName = setterFunctionName($settingName); + $type = "const String&" if $type eq "String"; + print $file " void $setterFunctionName($type $settingName);\n"; + }; + enumerateParsedItems($file, $parsedItemsRef, \&writeHeaderPrototypes); + + print $file <<EOF; + +private: + Page* m_page; + +EOF + + sub writeBackupMembers($$$) { + my ($file, $parsedItemsRef, $settingName) = @_; + my %parsedItems = %{ $parsedItemsRef }; + my $type = $parsedItems{$settingName}{"type"}; + my $conditional = $parsedItems{$settingName}{"conditional"}; + if ($conditional) { + print $file "#if " . $InCompiler->conditionalStringFromAttributeValue($conditional) . "\n"; + } + print $file " $type m_$settingName;\n"; + if ($conditional) { + print $file "#endif\n"; + } + }; + enumerateParsedItems($file, $parsedItemsRef, \&writeBackupMembers); + + print $file "};\n\n"; + print $file "} // namespace WebCore\n"; + print $file "#endif // InternalSettingsGenerated_h\n"; + + close $file; +} + +sub generateInternalSettingsCppFile($) +{ + my $parsedItemsRef = shift; + my %parsedItems = %{ $parsedItemsRef }; + + my $filename = "$outputDir/InternalSettingsGenerated.cpp"; + open my $file, ">$filename" or die "Failed to open file: $!"; + print $file $InCompiler->license(); + + print $file <<EOF; +#include "config.h" +#include "InternalSettingsGenerated.h" + +#include "Page.h" +#include "Settings.h" + +namespace WebCore { + +InternalSettingsGenerated::InternalSettingsGenerated(Page* page) + : m_page(page) +EOF + + sub writeBackupInitializers($$$) { + my ($file, $parsedItemsRef, $settingName) = @_; + my %parsedItems = %{ $parsedItemsRef }; + my $type = $parsedItems{$settingName}{"type"}; + my $conditional = $parsedItems{$settingName}{"conditional"}; + if ($conditional) { + print $file "#if " . $InCompiler->conditionalStringFromAttributeValue($conditional) . "\n"; + } + print $file " , m_$settingName(page->settings()->$settingName())\n"; + if ($conditional) { + print $file "#endif\n"; + } + }; + enumerateParsedItems($file, $parsedItemsRef, \&writeBackupInitializers); + + print $file <<EOF; +{ +} + +InternalSettingsGenerated::~InternalSettingsGenerated() +{ +} + +void InternalSettingsGenerated::resetToConsistentState() +{ +EOF + sub writeResetToConsistentState($$$) { + my ($file, $parsedItemsRef, $settingName) = @_; + my %parsedItems = %{ $parsedItemsRef }; + my $type = $parsedItems{$settingName}{"type"}; + my $setterFunctionName = setterFunctionName($settingName); + my $conditional = $parsedItems{$settingName}{"conditional"}; + if ($conditional) { + print $file "#if " . $InCompiler->conditionalStringFromAttributeValue($conditional) . "\n"; + } + print $file " m_page->settings()->$setterFunctionName(m_$settingName);\n"; + if ($conditional) { + print $file "#endif\n"; + } + }; + enumerateParsedItems($file, $parsedItemsRef, \&writeResetToConsistentState); + + print $file "}\n"; + + sub writeSetterFunctions($$$) { + my ($file, $parsedItemsRef, $settingName) = @_; + my %parsedItems = %{ $parsedItemsRef }; + my $type = $parsedItems{$settingName}{"type"}; + my $conditional = $parsedItems{$settingName}{"conditional"}; + my $setterFunctionName = setterFunctionName($settingName); + $type = "const String&" if $type eq "String"; + + print $file "void InternalSettingsGenerated::$setterFunctionName($type $settingName)\n"; + print $file "{\n"; + + if ($conditional) { + print $file "#if " . $InCompiler->conditionalStringFromAttributeValue($conditional) . "\n"; + } + print $file " m_page->settings()->$setterFunctionName($settingName);\n"; + if ($conditional) { + print $file "#else\n"; + print $file " UNUSED_PARAM($settingName);\n"; + print $file "#endif\n"; + } + print $file "}\n\n"; + }; + enumerateParsedItems($file, $parsedItemsRef, \&writeSetterFunctions); + + print $file "} // namespace WebCore\n"; + + close $file; +} diff --git a/Source/WebCore/page/qt/EventHandlerQt.cpp b/Source/WebCore/page/qt/EventHandlerQt.cpp index ab759496f..f45f81dc7 100644 --- a/Source/WebCore/page/qt/EventHandlerQt.cpp +++ b/Source/WebCore/page/qt/EventHandlerQt.cpp @@ -28,7 +28,7 @@ #include "config.h" #include "EventHandler.h" -#include "ClipboardQt.h" +#include "Clipboard.h" #include "Cursor.h" #include "Document.h" #include "EventNames.h" @@ -91,12 +91,12 @@ bool EventHandler::passWheelEventToWidget(const PlatformWheelEvent& event, Widge if (!widget->isFrameView()) return false; - return static_cast<FrameView*>(widget)->frame()->eventHandler()->handleWheelEvent(event); + return toFrameView(widget)->frame()->eventHandler()->handleWheelEvent(event); } PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const { - return ClipboardQt::create(ClipboardWritable, m_frame, Clipboard::DragAndDrop); + return Clipboard::createForDragAndDrop(); } bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe) diff --git a/Source/WebCore/page/scrolling/ScrollingConstraints.cpp b/Source/WebCore/page/scrolling/ScrollingConstraints.cpp index 0bbc6577f..4b3f4d68c 100644 --- a/Source/WebCore/page/scrolling/ScrollingConstraints.cpp +++ b/Source/WebCore/page/scrolling/ScrollingConstraints.cpp @@ -45,14 +45,14 @@ FloatPoint FixedPositionViewportConstraints::layerPositionForViewportRect(const return m_layerPositionAtLastLayout + offset; } -FloatSize StickyPositionViewportConstraints::computeStickyOffset(const FloatRect& viewportRect) const +FloatSize StickyPositionViewportConstraints::computeStickyOffset(const FloatRect& constrainingRect) const { - FloatRect boxRect = m_absoluteStickyBoxRect; + FloatRect boxRect = m_stickyBoxRect; if (hasAnchorEdge(AnchorEdgeRight)) { - float rightLimit = viewportRect.maxX() - m_rightOffset; - float rightDelta = std::min<float>(0, rightLimit - m_absoluteStickyBoxRect.maxX()); - float availableSpace = std::min<float>(0, m_absoluteContainingBlockRect.x() - m_absoluteStickyBoxRect.x()); + float rightLimit = constrainingRect.maxX() - m_rightOffset; + float rightDelta = std::min<float>(0, rightLimit - m_stickyBoxRect.maxX()); + float availableSpace = std::min<float>(0, m_containingBlockRect.x() - m_stickyBoxRect.x()); if (rightDelta < availableSpace) rightDelta = availableSpace; @@ -60,9 +60,9 @@ FloatSize StickyPositionViewportConstraints::computeStickyOffset(const FloatRect } if (hasAnchorEdge(AnchorEdgeLeft)) { - float leftLimit = viewportRect.x() + m_leftOffset; - float leftDelta = std::max<float>(0, leftLimit - m_absoluteStickyBoxRect.x()); - float availableSpace = std::max<float>(0, m_absoluteContainingBlockRect.maxX() - m_absoluteStickyBoxRect.maxX()); + float leftLimit = constrainingRect.x() + m_leftOffset; + float leftDelta = std::max<float>(0, leftLimit - m_stickyBoxRect.x()); + float availableSpace = std::max<float>(0, m_containingBlockRect.maxX() - m_stickyBoxRect.maxX()); if (leftDelta > availableSpace) leftDelta = availableSpace; @@ -70,9 +70,9 @@ FloatSize StickyPositionViewportConstraints::computeStickyOffset(const FloatRect } if (hasAnchorEdge(AnchorEdgeBottom)) { - float bottomLimit = viewportRect.maxY() - m_bottomOffset; - float bottomDelta = std::min<float>(0, bottomLimit - m_absoluteStickyBoxRect.maxY()); - float availableSpace = std::min<float>(0, m_absoluteContainingBlockRect.y() - m_absoluteStickyBoxRect.y()); + float bottomLimit = constrainingRect.maxY() - m_bottomOffset; + float bottomDelta = std::min<float>(0, bottomLimit - m_stickyBoxRect.maxY()); + float availableSpace = std::min<float>(0, m_containingBlockRect.y() - m_stickyBoxRect.y()); if (bottomDelta < availableSpace) bottomDelta = availableSpace; @@ -80,21 +80,21 @@ FloatSize StickyPositionViewportConstraints::computeStickyOffset(const FloatRect } if (hasAnchorEdge(AnchorEdgeTop)) { - float topLimit = viewportRect.y() + m_topOffset; - float topDelta = std::max<float>(0, topLimit - m_absoluteStickyBoxRect.y()); - float availableSpace = std::max<float>(0, m_absoluteContainingBlockRect.maxY() - m_absoluteStickyBoxRect.maxY()); + float topLimit = constrainingRect.y() + m_topOffset; + float topDelta = std::max<float>(0, topLimit - m_stickyBoxRect.y()); + float availableSpace = std::max<float>(0, m_containingBlockRect.maxY() - m_stickyBoxRect.maxY()); if (topDelta > availableSpace) topDelta = availableSpace; boxRect.move(0, topDelta); } - return boxRect.location() - m_absoluteStickyBoxRect.location(); + return boxRect.location() - m_stickyBoxRect.location(); } -FloatPoint StickyPositionViewportConstraints::layerPositionForViewportRect(const FloatRect& viewportRect) const +FloatPoint StickyPositionViewportConstraints::layerPositionForConstrainingRect(const FloatRect& constrainingRect) const { - FloatSize offset = computeStickyOffset(viewportRect); + FloatSize offset = computeStickyOffset(constrainingRect); return m_layerPositionAtLastLayout + offset - m_stickyOffsetAtLastLayout; } diff --git a/Source/WebCore/page/scrolling/ScrollingConstraints.h b/Source/WebCore/page/scrolling/ScrollingConstraints.h index eaaaef508..507812626 100644 --- a/Source/WebCore/page/scrolling/ScrollingConstraints.h +++ b/Source/WebCore/page/scrolling/ScrollingConstraints.h @@ -47,6 +47,11 @@ public: }; typedef unsigned AnchorEdges; + ViewportConstraints(const ViewportConstraints& other) + : m_alignmentOffset(other.m_alignmentOffset) + , m_anchorEdges(other.m_anchorEdges) + { } + virtual ~ViewportConstraints() { } virtual ConstraintType constraintType() const = 0; @@ -70,6 +75,16 @@ protected: class FixedPositionViewportConstraints : public ViewportConstraints { public: + FixedPositionViewportConstraints() + : ViewportConstraints() + { } + + FixedPositionViewportConstraints(const FixedPositionViewportConstraints& other) + : ViewportConstraints(other) + , m_viewportRectAtLastLayout(other.m_viewportRectAtLastLayout) + , m_layerPositionAtLastLayout(other.m_layerPositionAtLastLayout) + { } + FloatPoint layerPositionForViewportRect(const FloatRect& viewportRect) const; const FloatRect& viewportRectAtLastLayout() const { return m_viewportRectAtLastLayout; } @@ -104,12 +119,25 @@ public: , m_bottomOffset(0) { } - FloatSize computeStickyOffset(const FloatRect& viewportRect) const; + StickyPositionViewportConstraints(const StickyPositionViewportConstraints& other) + : ViewportConstraints(other) + , m_leftOffset(other.m_leftOffset) + , m_rightOffset(other.m_rightOffset) + , m_topOffset(other.m_topOffset) + , m_bottomOffset(other.m_bottomOffset) + , m_constrainingRectAtLastLayout(other.m_constrainingRectAtLastLayout) + , m_containingBlockRect(other.m_containingBlockRect) + , m_stickyBoxRect(other.m_stickyBoxRect) + , m_stickyOffsetAtLastLayout(other.m_stickyOffsetAtLastLayout) + , m_layerPositionAtLastLayout(other.m_layerPositionAtLastLayout) + { } + + FloatSize computeStickyOffset(const FloatRect& constrainingRect) const; const FloatSize stickyOffsetAtLastLayout() const { return m_stickyOffsetAtLastLayout; } void setStickyOffsetAtLastLayout(const FloatSize& offset) { m_stickyOffsetAtLastLayout = offset; } - FloatPoint layerPositionForViewportRect(const FloatRect& viewportRect) const; + FloatPoint layerPositionForConstrainingRect(const FloatRect& constrainingRect) const; const FloatPoint& layerPositionAtLastLayout() const { return m_layerPositionAtLastLayout; } void setLayerPositionAtLastLayout(const FloatPoint& point) { m_layerPositionAtLastLayout = point; } @@ -124,8 +152,32 @@ public: void setTopOffset(float offset) { m_topOffset = offset; } void setBottomOffset(float offset) { m_bottomOffset = offset; } - void setAbsoluteContainingBlockRect(const FloatRect& rect) { m_absoluteContainingBlockRect = rect; } - void setAbsoluteStickyBoxRect(const FloatRect& rect) { m_absoluteStickyBoxRect = rect; } + // constrainingRectAtLastLayout() is the viewport rect if this sticky object sticks to the viewport, and + // it is the overflow area's scrolled clip rect if this sticky object sticks inside an overflow area. + FloatRect constrainingRectAtLastLayout() const { return m_constrainingRectAtLastLayout; } + void setConstrainingRectAtLastLayout(const FloatRect& rect) { m_constrainingRectAtLastLayout = rect; } + + // containingBlockRect() is in the scrolling ancestor's coordinate space. + FloatRect containingBlockRect() const { return m_containingBlockRect; } + void setContainingBlockRect(const FloatRect& rect) { m_containingBlockRect = rect; } + + // stickyBoxRect() is in the scrolling ancestor's coordinate space. + FloatRect stickyBoxRect() const { return m_stickyBoxRect; } + void setStickyBoxRect(const FloatRect& rect) { m_stickyBoxRect = rect; } + + bool operator==(const StickyPositionViewportConstraints& other) const + { + return m_leftOffset == other.m_leftOffset + && m_rightOffset == other.m_rightOffset + && m_topOffset == other.m_topOffset + && m_bottomOffset == other.m_bottomOffset + && m_containingBlockRect == other.m_containingBlockRect + && m_stickyBoxRect == other.m_stickyBoxRect + && m_stickyOffsetAtLastLayout == other.m_stickyOffsetAtLastLayout + && m_layerPositionAtLastLayout == other.m_layerPositionAtLastLayout; + } + + bool operator!=(const StickyPositionViewportConstraints& other) const { return !(*this == other); } private: virtual ConstraintType constraintType() const OVERRIDE { return StickyPositionConstraint; }; @@ -134,8 +186,9 @@ private: float m_rightOffset; float m_topOffset; float m_bottomOffset; - FloatRect m_absoluteContainingBlockRect; - FloatRect m_absoluteStickyBoxRect; + FloatRect m_constrainingRectAtLastLayout; + FloatRect m_containingBlockRect; + FloatRect m_stickyBoxRect; FloatSize m_stickyOffsetAtLastLayout; FloatPoint m_layerPositionAtLastLayout; }; diff --git a/Source/WebCore/page/scrolling/ScrollingCoordinator.cpp b/Source/WebCore/page/scrolling/ScrollingCoordinator.cpp index cd9432c2a..4d4723a6c 100644 --- a/Source/WebCore/page/scrolling/ScrollingCoordinator.cpp +++ b/Source/WebCore/page/scrolling/ScrollingCoordinator.cpp @@ -27,8 +27,10 @@ #include "ScrollingCoordinator.h" +#include "Document.h" #include "Frame.h" #include "FrameView.h" +#include "GraphicsLayer.h" #include "IntRect.h" #include "Page.h" #include "PlatformWheelEvent.h" @@ -37,6 +39,7 @@ #include "RenderView.h" #include "ScrollAnimator.h" #include <wtf/MainThread.h> +#include <wtf/text/StringBuilder.h> #if USE(ACCELERATED_COMPOSITING) #include "RenderLayerCompositor.h" @@ -46,8 +49,12 @@ #include "ScrollingCoordinatorMac.h" #endif -#if PLATFORM(CHROMIUM) -#include "ScrollingCoordinatorChromium.h" +#if USE(COORDINATED_GRAPHICS) +#include "ScrollingCoordinatorCoordinatedGraphics.h" +#endif + +#if PLATFORM(BLACKBERRY) +#include "ScrollingCoordinatorBlackBerry.h" #endif namespace WebCore { @@ -58,45 +65,15 @@ PassRefPtr<ScrollingCoordinator> ScrollingCoordinator::create(Page* page) return adoptRef(new ScrollingCoordinatorMac(page)); #endif -#if PLATFORM(CHROMIUM) - return adoptRef(new ScrollingCoordinatorChromium(page)); +#if USE(COORDINATED_GRAPHICS) + return adoptRef(new ScrollingCoordinatorCoordinatedGraphics(page)); #endif - return adoptRef(new ScrollingCoordinator(page)); -} - -static int fixedPositionScrollOffset(int scrollPosition, int maxValue, int scrollOrigin, float dragFactor) -{ - if (!maxValue) - return 0; - - if (!scrollOrigin) { - if (scrollPosition < 0) - scrollPosition = 0; - else if (scrollPosition > maxValue) - scrollPosition = maxValue; - } else { - if (scrollPosition > 0) - scrollPosition = 0; - else if (scrollPosition < -maxValue) - scrollPosition = -maxValue; - } - - return scrollPosition * dragFactor; -} - -IntSize scrollOffsetForFixedPosition(const IntRect& visibleContentRect, const IntSize& contentsSize, const IntPoint& scrollPosition, const IntPoint& scrollOrigin, float frameScaleFactor, bool fixedElementsLayoutRelativeToFrame) -{ - IntSize maxOffset(contentsSize.width() - visibleContentRect.width(), contentsSize.height() - visibleContentRect.height()); - - FloatSize dragFactor = fixedElementsLayoutRelativeToFrame ? FloatSize(1, 1) : FloatSize( - (contentsSize.width() - visibleContentRect.width() * frameScaleFactor) / maxOffset.width(), - (contentsSize.height() - visibleContentRect.height() * frameScaleFactor) / maxOffset.height()); - - int x = fixedPositionScrollOffset(scrollPosition.x(), maxOffset.width(), scrollOrigin.x(), dragFactor.width() / frameScaleFactor); - int y = fixedPositionScrollOffset(scrollPosition.y(), maxOffset.height(), scrollOrigin.y(), dragFactor.height() / frameScaleFactor); +#if PLATFORM(BLACKBERRY) + return adoptRef(new ScrollingCoordinatorBlackBerry(page)); +#endif - return IntSize(x, y); + return adoptRef(new ScrollingCoordinator(page)); } ScrollingCoordinator::ScrollingCoordinator(Page* page) @@ -139,7 +116,7 @@ bool ScrollingCoordinator::coordinatesScrollingForFrameView(FrameView* frameView #endif } -Region ScrollingCoordinator::computeNonFastScrollableRegion(Frame* frame, const IntPoint& frameLocation) +Region ScrollingCoordinator::computeNonFastScrollableRegion(const Frame* frame, const IntPoint& frameLocation) const { Region nonFastScrollableRegion; FrameView* frameView = frame->view(); @@ -168,7 +145,7 @@ Region ScrollingCoordinator::computeNonFastScrollableRegion(Frame* frame, const if (!(*it)->isPluginViewBase()) continue; - PluginViewBase* pluginViewBase = static_cast<PluginViewBase*>((*it).get()); + PluginViewBase* pluginViewBase = toPluginViewBase((*it).get()); if (pluginViewBase->wantsWheelEvents()) nonFastScrollableRegion.unite(pluginViewBase->frameRect()); } @@ -181,6 +158,79 @@ Region ScrollingCoordinator::computeNonFastScrollableRegion(Frame* frame, const return nonFastScrollableRegion; } +#if ENABLE(TOUCH_EVENT_TRACKING) +static void accumulateRendererTouchEventTargetRects(Vector<IntRect>& rects, const RenderObject* renderer, const IntRect& parentRect = IntRect()) +{ + IntRect adjustedParentRect = parentRect; + if (parentRect.isEmpty() || renderer->isFloating() || renderer->isPositioned() || renderer->hasTransform()) { + // FIXME: This method is O(N^2) as it walks the tree to the root for every renderer. RenderGeometryMap would fix this. + IntRect r = enclosingIntRect(renderer->clippedOverflowRectForRepaint(0)); + if (!r.isEmpty()) { + // Convert to the top-level view's coordinates. + ASSERT(renderer->document()->view()); + r = renderer->document()->view()->convertToRootView(r); + + if (!parentRect.contains(r)) { + rects.append(r); + adjustedParentRect = r; + } + } + } + + for (RenderObject* child = renderer->firstChild(); child; child = child->nextSibling()) + accumulateRendererTouchEventTargetRects(rects, child, adjustedParentRect); +} + +static void accumulateDocumentEventTargetRects(Vector<IntRect>& rects, const Document* document) +{ + ASSERT(document); + if (!document->touchEventTargets()) + return; + + const TouchEventTargetSet* targets = document->touchEventTargets(); + for (TouchEventTargetSet::const_iterator iter = targets->begin(); iter != targets->end(); ++iter) { + const Node* touchTarget = iter->key; + if (!touchTarget->inDocument()) + continue; + + if (touchTarget == document) { + if (RenderView* view = document->renderView()) { + IntRect r; + if (touchTarget == document->topDocument()) + r = view->documentRect(); + else + r = enclosingIntRect(view->clippedOverflowRectForRepaint(0)); + + if (!r.isEmpty()) { + ASSERT(view->document()->view()); + r = view->document()->view()->convertToRootView(r); + rects.append(r); + } + } + return; + } + + if (touchTarget->isDocumentNode() && touchTarget != document) { + accumulateDocumentEventTargetRects(rects, toDocument(touchTarget)); + continue; + } + + if (RenderObject* renderer = touchTarget->renderer()) + accumulateRendererTouchEventTargetRects(rects, renderer); + } +} + +void ScrollingCoordinator::computeAbsoluteTouchEventTargetRects(const Document* document, Vector<IntRect>& rects) +{ + ASSERT(document); + if (!document->view()) + return; + + // FIXME: These rects won't be properly updated if the renderers are in a sub-tree that scrolls. + accumulateDocumentEventTargetRects(rects, document); +} +#endif + unsigned ScrollingCoordinator::computeCurrentWheelEventHandlerCount() { unsigned wheelEventHandlerCount = 0; @@ -223,6 +273,23 @@ void ScrollingCoordinator::frameViewFixedObjectsDidChange(FrameView* frameView) updateShouldUpdateScrollLayerPositionOnMainThread(); } +#if USE(ACCELERATED_COMPOSITING) +GraphicsLayer* ScrollingCoordinator::scrollLayerForScrollableArea(ScrollableArea* scrollableArea) +{ + return scrollableArea->layerForScrolling(); +} + +GraphicsLayer* ScrollingCoordinator::horizontalScrollbarLayerForScrollableArea(ScrollableArea* scrollableArea) +{ + return scrollableArea->layerForHorizontalScrollbar(); +} + +GraphicsLayer* ScrollingCoordinator::verticalScrollbarLayerForScrollableArea(ScrollableArea* scrollableArea) +{ + return scrollableArea->layerForVerticalScrollbar(); +} +#endif + GraphicsLayer* ScrollingCoordinator::scrollLayerForFrameView(FrameView* frameView) { #if USE(ACCELERATED_COMPOSITING) @@ -240,6 +307,58 @@ GraphicsLayer* ScrollingCoordinator::scrollLayerForFrameView(FrameView* frameVie #endif } +GraphicsLayer* ScrollingCoordinator::headerLayerForFrameView(FrameView* frameView) +{ +#if USE(ACCELERATED_COMPOSITING) && ENABLE(RUBBER_BANDING) + Frame* frame = frameView->frame(); + if (!frame) + return 0; + + RenderView* renderView = frame->contentRenderer(); + if (!renderView) + return 0; + + return renderView->compositor()->headerLayer(); +#else + UNUSED_PARAM(frameView); + return 0; +#endif +} + +GraphicsLayer* ScrollingCoordinator::footerLayerForFrameView(FrameView* frameView) +{ +#if USE(ACCELERATED_COMPOSITING) && ENABLE(RUBBER_BANDING) + Frame* frame = frameView->frame(); + if (!frame) + return 0; + + RenderView* renderView = frame->contentRenderer(); + if (!renderView) + return 0; + return renderView->compositor()->footerLayer(); +#else + UNUSED_PARAM(frameView); + return 0; +#endif +} + +GraphicsLayer* ScrollingCoordinator::counterScrollingLayerForFrameView(FrameView* frameView) +{ +#if USE(ACCELERATED_COMPOSITING) + Frame* frame = frameView->frame(); + if (!frame) + return 0; + + RenderView* renderView = frame->contentRenderer(); + if (!renderView) + return 0; + return renderView->compositor()->fixedRootBackgroundLayer(); +#else + UNUSED_PARAM(frameView); + return 0; +#endif +} + void ScrollingCoordinator::frameViewRootLayerDidChange(FrameView* frameView) { ASSERT(isMainThread()); @@ -302,12 +421,29 @@ void ScrollingCoordinator::updateMainFrameScrollPosition(const IntPoint& scrollP #if USE(ACCELERATED_COMPOSITING) if (GraphicsLayer* scrollLayer = scrollLayerForFrameView(frameView)) { - if (programmaticScroll || scrollingLayerPositionAction == SetScrollingLayerPosition) + GraphicsLayer* counterScrollingLayer = counterScrollingLayerForFrameView(frameView); + GraphicsLayer* headerLayer = headerLayerForFrameView(frameView); + GraphicsLayer* footerLayer = footerLayerForFrameView(frameView); + IntSize scrollOffsetForFixed = frameView->scrollOffsetForFixedPosition(); + + if (programmaticScroll || scrollingLayerPositionAction == SetScrollingLayerPosition) { scrollLayer->setPosition(-frameView->scrollPosition()); - else { + if (counterScrollingLayer) + counterScrollingLayer->setPosition(IntPoint(scrollOffsetForFixed)); + if (headerLayer) + headerLayer->setPosition(FloatPoint(scrollOffsetForFixed.width(), 0)); + if (footerLayer) + footerLayer->setPosition(FloatPoint(scrollOffsetForFixed.width(), frameView->totalContentsSize().height() - frameView->footerHeight())); + } else { scrollLayer->syncPosition(-frameView->scrollPosition()); - LayoutRect viewportRect = frameView->visibleContentRect(); - viewportRect.setLocation(toPoint(frameView->scrollOffsetForFixedPosition())); + if (counterScrollingLayer) + counterScrollingLayer->syncPosition(IntPoint(scrollOffsetForFixed)); + if (headerLayer) + headerLayer->syncPosition(FloatPoint(scrollOffsetForFixed.width(), 0)); + if (footerLayer) + footerLayer->syncPosition(FloatPoint(scrollOffsetForFixed.width(), frameView->totalContentsSize().height() - frameView->footerHeight())); + + LayoutRect viewportRect = frameView->viewportConstrainedVisibleContentRect(); syncChildPositions(viewportRect); } } @@ -316,7 +452,7 @@ void ScrollingCoordinator::updateMainFrameScrollPosition(const IntPoint& scrollP #endif } -#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(DARWIN)) +#if PLATFORM(MAC) void ScrollingCoordinator::handleWheelEventPhase(PlatformWheelEventPhase phase) { ASSERT(isMainThread()); @@ -332,7 +468,7 @@ void ScrollingCoordinator::handleWheelEventPhase(PlatformWheelEventPhase phase) } #endif -bool ScrollingCoordinator::hasVisibleSlowRepaintFixedObjects(FrameView* frameView) const +bool ScrollingCoordinator::hasVisibleSlowRepaintViewportConstrainedObjects(FrameView* frameView) const { const FrameView::ViewportConstrainedObjectSet* viewportConstrainedObjects = frameView->viewportConstrainedObjects(); if (!viewportConstrainedObjects) @@ -343,8 +479,9 @@ bool ScrollingCoordinator::hasVisibleSlowRepaintFixedObjects(FrameView* frameVie RenderObject* viewportConstrainedObject = *it; if (!viewportConstrainedObject->isBoxModelObject() || !viewportConstrainedObject->hasLayer()) return true; - RenderBoxModelObject* viewportConstrainedBoxModelObject = toRenderBoxModelObject(viewportConstrainedObject); - if (!viewportConstrainedBoxModelObject->layer()->backing()) + RenderLayer* layer = toRenderBoxModelObject(viewportConstrainedObject)->layer(); + // Any explicit reason that a fixed position element is not composited shouldn't cause slow scrolling. + if (!layer->isComposited() && layer->viewportConstrainedNotCompositedReason() == RenderLayer::NoNotCompositedReason) return true; } return false; @@ -356,6 +493,8 @@ bool ScrollingCoordinator::hasVisibleSlowRepaintFixedObjects(FrameView* frameVie MainThreadScrollingReasons ScrollingCoordinator::mainThreadScrollingReasons() const { FrameView* frameView = m_page->mainFrame()->view(); + if (!frameView) + return static_cast<MainThreadScrollingReasons>(0); MainThreadScrollingReasons mainThreadScrollingReasons = (MainThreadScrollingReasons)0; @@ -365,9 +504,9 @@ MainThreadScrollingReasons ScrollingCoordinator::mainThreadScrollingReasons() co mainThreadScrollingReasons |= HasSlowRepaintObjects; if (!supportsFixedPositionLayers() && frameView->hasViewportConstrainedObjects()) mainThreadScrollingReasons |= HasViewportConstrainedObjectsWithoutSupportingFixedLayers; - if (supportsFixedPositionLayers() && hasVisibleSlowRepaintFixedObjects(frameView)) - mainThreadScrollingReasons |= HasNonLayerFixedObjects; - if (m_page->mainFrame()->document()->isImageDocument()) + if (supportsFixedPositionLayers() && hasVisibleSlowRepaintViewportConstrainedObjects(frameView)) + mainThreadScrollingReasons |= HasNonLayerViewportConstrainedObjects; + if (m_page->mainFrame()->document() && m_page->mainFrame()->document()->isImageDocument()) mainThreadScrollingReasons |= IsImageDocument; return mainThreadScrollingReasons; @@ -398,4 +537,29 @@ String ScrollingCoordinator::scrollingStateTreeAsText() const return String(); } +String ScrollingCoordinator::mainThreadScrollingReasonsAsText(MainThreadScrollingReasons reasons) +{ + StringBuilder stringBuilder; + + if (reasons & ScrollingCoordinator::ForcedOnMainThread) + stringBuilder.append("Forced on main thread, "); + if (reasons & ScrollingCoordinator::HasSlowRepaintObjects) + stringBuilder.append("Has slow repaint objects, "); + if (reasons & ScrollingCoordinator::HasViewportConstrainedObjectsWithoutSupportingFixedLayers) + stringBuilder.append("Has viewport constrained objects without supporting fixed layers, "); + if (reasons & ScrollingCoordinator::HasNonLayerViewportConstrainedObjects) + stringBuilder.append("Has non-layer viewport-constrained objects, "); + if (reasons & ScrollingCoordinator::IsImageDocument) + stringBuilder.append("Is image document, "); + + if (stringBuilder.length()) + stringBuilder.resize(stringBuilder.length() - 2); + return stringBuilder.toString(); +} + +String ScrollingCoordinator::mainThreadScrollingReasonsAsText() const +{ + return mainThreadScrollingReasonsAsText(mainThreadScrollingReasons()); +} + } // namespace WebCore diff --git a/Source/WebCore/page/scrolling/ScrollingCoordinator.h b/Source/WebCore/page/scrolling/ScrollingCoordinator.h index c2f1fa865..bcb20618e 100644 --- a/Source/WebCore/page/scrolling/ScrollingCoordinator.h +++ b/Source/WebCore/page/scrolling/ScrollingCoordinator.h @@ -29,6 +29,7 @@ #include "IntRect.h" #include "LayoutRect.h" #include "PlatformWheelEvent.h" +#include "RenderObject.h" #include "ScrollTypes.h" #include "Timer.h" #include <wtf/Forward.h> @@ -48,8 +49,9 @@ namespace WebCore { typedef unsigned MainThreadScrollingReasons; typedef uint64_t ScrollingNodeID; -enum ScrollingNodeType { ScrollingNode, FixedNode }; +enum ScrollingNodeType { ScrollingNode, FixedNode, StickyNode }; +class Document; class Frame; class FrameView; class GraphicsLayer; @@ -62,9 +64,6 @@ class ViewportConstraints; class ScrollingTree; #endif -IntSize scrollOffsetForFixedPosition(const IntRect& visibleContentRect, const IntSize& contentsSize, const IntPoint& scrollPosition, - const IntPoint& scrollOrigin, float frameScaleFactor, bool fixedElementsLayoutRelativeToFrame); - enum SetOrSyncScrollingLayerPosition { SetScrollingLayerPosition, SyncScrollingLayerPosition @@ -104,7 +103,7 @@ public: // containers while scrolling. virtual bool supportsFixedPositionLayers() const { return false; } -#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(DARWIN)) +#if PLATFORM(MAC) // Dispatched by the scrolling tree during handleWheelEvent. This is required as long as scrollbars are painted on the main thread. void handleWheelEventPhase(PlatformWheelEventPhase); #endif @@ -121,8 +120,15 @@ public: virtual void detachFromStateTree(ScrollingNodeID) { } virtual void clearStateTree() { } virtual void updateViewportConstrainedNode(ScrollingNodeID, const ViewportConstraints&, GraphicsLayer*) { } + virtual void updateScrollingNode(ScrollingNodeID, GraphicsLayer* /*scrollLayer*/, GraphicsLayer* /*counterScrollingLayer*/) { } virtual void syncChildPositions(const LayoutRect&) { } virtual String scrollingStateTreeAsText() const; + virtual bool isRubberBandInProgress() const { return false; } + virtual bool rubberBandsAtBottom() const { return false; } + virtual void setRubberBandsAtBottom(bool) { } + virtual bool rubberBandsAtTop() const { return false; } + virtual void setRubberBandsAtTop(bool) { } + virtual void setScrollPinningBehavior(ScrollPinningBehavior) { } // Generated a unique id for scroll layers. ScrollingNodeID uniqueScrollLayerID(); @@ -135,7 +141,7 @@ public: ForcedOnMainThread = 1 << 0, HasSlowRepaintObjects = 1 << 1, HasViewportConstrainedObjectsWithoutSupportingFixedLayers = 1 << 2, - HasNonLayerFixedObjects = 1 << 3, + HasNonLayerViewportConstrainedObjects = 1 << 3, IsImageDocument = 1 << 4 }; @@ -144,18 +150,36 @@ public: // These virtual functions are currently unique to Chromium's WebLayer approach. Their meaningful // implementations are in ScrollingCoordinatorChromium. - virtual void frameViewHorizontalScrollbarLayerDidChange(FrameView*, GraphicsLayer*) { } - virtual void frameViewVerticalScrollbarLayerDidChange(FrameView*, GraphicsLayer*) { } - virtual void scrollableAreaScrollLayerDidChange(ScrollableArea*, GraphicsLayer*) { } + virtual void willDestroyScrollableArea(ScrollableArea*) { } + virtual void scrollableAreaScrollLayerDidChange(ScrollableArea*) { } + virtual void scrollableAreaScrollbarLayerDidChange(ScrollableArea*, ScrollbarOrientation) { } virtual void setLayerIsContainerForFixedPositionLayers(GraphicsLayer*, bool) { } - virtual void setLayerIsFixedToContainerLayer(GraphicsLayer*, bool) { } + virtual void updateLayerPositionConstraint(RenderLayer*) { } + virtual void touchEventTargetRectsDidChange(const Document*) { } + +#if ENABLE(TOUCH_EVENT_TRACKING) + void computeAbsoluteTouchEventTargetRects(const Document*, Vector<IntRect>&); +#endif + + static String mainThreadScrollingReasonsAsText(MainThreadScrollingReasons); + String mainThreadScrollingReasonsAsText() const; + + Region computeNonFastScrollableRegion(const Frame*, const IntPoint& frameLocation) const; protected: explicit ScrollingCoordinator(Page*); - Region computeNonFastScrollableRegion(Frame*, const IntPoint& frameLocation); +#if USE(ACCELERATED_COMPOSITING) + static GraphicsLayer* scrollLayerForScrollableArea(ScrollableArea*); + static GraphicsLayer* horizontalScrollbarLayerForScrollableArea(ScrollableArea*); + static GraphicsLayer* verticalScrollbarLayerForScrollableArea(ScrollableArea*); +#endif + unsigned computeCurrentWheelEventHandlerCount(); GraphicsLayer* scrollLayerForFrameView(FrameView*); + GraphicsLayer* counterScrollingLayerForFrameView(FrameView*); + GraphicsLayer* headerLayerForFrameView(FrameView*); + GraphicsLayer* footerLayerForFrameView(FrameView*); Page* m_page; @@ -163,7 +187,7 @@ private: virtual void recomputeWheelEventHandlerCountForFrameView(FrameView*) { } virtual void setShouldUpdateScrollLayerPositionOnMainThread(MainThreadScrollingReasons) { } - virtual bool hasVisibleSlowRepaintFixedObjects(FrameView*) const; + virtual bool hasVisibleSlowRepaintViewportConstrainedObjects(FrameView*) const; void updateShouldUpdateScrollLayerPositionOnMainThread(); void updateMainFrameScrollPositionTimerFired(Timer<ScrollingCoordinator>*); diff --git a/Source/WebCore/page/scrolling/ScrollingStateFixedNode.cpp b/Source/WebCore/page/scrolling/ScrollingStateFixedNode.cpp index bc60aa884..98b1d710c 100644 --- a/Source/WebCore/page/scrolling/ScrollingStateFixedNode.cpp +++ b/Source/WebCore/page/scrolling/ScrollingStateFixedNode.cpp @@ -26,11 +26,12 @@ #include "config.h" #include "ScrollingStateFixedNode.h" +#include "GraphicsLayer.h" #include "ScrollingStateTree.h" #include "TextStream.h" #include <wtf/OwnPtr.h> -#if ENABLE(THREADED_SCROLLING) +#if ENABLE(THREADED_SCROLLING) || USE(COORDINATED_GRAPHICS) namespace WebCore { @@ -41,14 +42,12 @@ PassOwnPtr<ScrollingStateFixedNode> ScrollingStateFixedNode::create(ScrollingSta ScrollingStateFixedNode::ScrollingStateFixedNode(ScrollingStateTree* tree, ScrollingNodeID nodeID) : ScrollingStateNode(tree, nodeID) - , m_changedProperties(0) { } ScrollingStateFixedNode::ScrollingStateFixedNode(const ScrollingStateFixedNode& node) : ScrollingStateNode(node) , m_constraints(FixedPositionViewportConstraints(node.viewportConstraints())) - , m_changedProperties(node.changedProperties()) { } @@ -67,10 +66,16 @@ void ScrollingStateFixedNode::updateConstraints(const FixedPositionViewportConst return; m_constraints = constraints; - m_changedProperties = ViewportConstraints; + setPropertyChanged(ViewportConstraints); m_scrollingStateTree->setHasChangedProperties(true); } +void ScrollingStateFixedNode::syncLayerPositionForViewportRect(const LayoutRect& viewportRect) +{ + FloatPoint position = m_constraints.layerPositionForViewportRect(viewportRect); + graphicsLayer()->syncPosition(position); +} + void ScrollingStateFixedNode::dumpProperties(TextStream& ts, int indent) const { ts << "(" << "Fixed node" << "\n"; @@ -108,4 +113,4 @@ void ScrollingStateFixedNode::dumpProperties(TextStream& ts, int indent) const } // namespace WebCore -#endif // ENABLE(THREADED_SCROLLING) +#endif // ENABLE(THREADED_SCROLLING) || USE(COORDINATED_GRAPHICS) diff --git a/Source/WebCore/page/scrolling/ScrollingStateFixedNode.h b/Source/WebCore/page/scrolling/ScrollingStateFixedNode.h index 7c86397cb..84ae4225b 100644 --- a/Source/WebCore/page/scrolling/ScrollingStateFixedNode.h +++ b/Source/WebCore/page/scrolling/ScrollingStateFixedNode.h @@ -26,7 +26,7 @@ #ifndef ScrollingStateFixedNode_h #define ScrollingStateFixedNode_h -#if ENABLE(THREADED_SCROLLING) +#if ENABLE(THREADED_SCROLLING) || USE(COORDINATED_GRAPHICS) #include "ScrollingConstraints.h" #include "ScrollingStateNode.h" @@ -45,12 +45,10 @@ public: virtual ~ScrollingStateFixedNode(); - enum ChangedPropertyForFixed { - ViewportConstraints = 1 << 0 + enum { + ViewportConstraints = NumStateNodeBits }; - virtual unsigned changedProperties() const OVERRIDE { return m_changedProperties; } - void updateConstraints(const FixedPositionViewportConstraints&); const FixedPositionViewportConstraints& viewportConstraints() const { return m_constraints; } @@ -60,18 +58,16 @@ private: virtual bool isFixedNode() OVERRIDE { return true; } - virtual bool hasChangedProperties() const OVERRIDE { return m_changedProperties; } - virtual void resetChangedProperties() OVERRIDE { m_changedProperties = 0; } + virtual void syncLayerPositionForViewportRect(const LayoutRect& viewportRect) OVERRIDE; virtual void dumpProperties(TextStream&, int indent) const OVERRIDE; FixedPositionViewportConstraints m_constraints; - unsigned m_changedProperties; }; inline ScrollingStateFixedNode* toScrollingStateFixedNode(ScrollingStateNode* node) { - ASSERT(!node || node->isFixedNode()); + ASSERT_WITH_SECURITY_IMPLICATION(!node || node->isFixedNode()); return static_cast<ScrollingStateFixedNode*>(node); } @@ -80,6 +76,6 @@ void toScrollingStateFixedNode(const ScrollingStateFixedNode*); } // namespace WebCore -#endif // ENABLE(THREADED_SCROLLING) +#endif // ENABLE(THREADED_SCROLLING) || USE(COORDINATED_GRAPHICS) #endif // ScrollingStateFixedNode_h diff --git a/Source/WebCore/page/scrolling/ScrollingStateNode.cpp b/Source/WebCore/page/scrolling/ScrollingStateNode.cpp index b2aa8366e..6afe5b0c6 100644 --- a/Source/WebCore/page/scrolling/ScrollingStateNode.cpp +++ b/Source/WebCore/page/scrolling/ScrollingStateNode.cpp @@ -26,21 +26,21 @@ #include "config.h" #include "ScrollingStateNode.h" +#if ENABLE(THREADED_SCROLLING) || USE(COORDINATED_GRAPHICS) + #include "ScrollingStateFixedNode.h" #include "ScrollingStateTree.h" #include "TextStream.h" #include <wtf/text/WTFString.h> -#if ENABLE(THREADED_SCROLLING) - namespace WebCore { ScrollingStateNode::ScrollingStateNode(ScrollingStateTree* scrollingStateTree, ScrollingNodeID nodeID) : m_scrollingStateTree(scrollingStateTree) , m_nodeID(nodeID) + , m_changedProperties(0) , m_parent(0) - , m_scrollLayerDidChange(false) { } @@ -50,10 +50,11 @@ ScrollingStateNode::ScrollingStateNode(ScrollingStateTree* scrollingStateTree, S ScrollingStateNode::ScrollingStateNode(const ScrollingStateNode& stateNode) : m_scrollingStateTree(0) , m_nodeID(stateNode.scrollingNodeID()) + , m_changedProperties(stateNode.changedProperties()) , m_parent(0) - , m_scrollLayerDidChange(stateNode.scrollLayerDidChange()) { - setScrollLayer(stateNode.platformScrollLayer()); + // FIXME: why doesn't this set the GraphicsLayer? + setScrollPlatformLayer(stateNode.platformScrollLayer()); } ScrollingStateNode::~ScrollingStateNode() @@ -65,7 +66,6 @@ PassOwnPtr<ScrollingStateNode> ScrollingStateNode::cloneAndReset() OwnPtr<ScrollingStateNode> clone = this->clone(); // Now that this node is cloned, reset our change properties. - setScrollLayerDidChange(false); resetChangedProperties(); cloneAndResetChildren(clone.get()); @@ -148,4 +148,4 @@ String ScrollingStateNode::scrollingStateTreeAsText() const } // namespace WebCore -#endif // ENABLE(THREADED_SCROLLING) +#endif // ENABLE(THREADED_SCROLLING) || USE(COORDINATED_GRAPHICS) diff --git a/Source/WebCore/page/scrolling/ScrollingStateNode.h b/Source/WebCore/page/scrolling/ScrollingStateNode.h index 60b9ef901..9800f30f8 100644 --- a/Source/WebCore/page/scrolling/ScrollingStateNode.h +++ b/Source/WebCore/page/scrolling/ScrollingStateNode.h @@ -26,7 +26,7 @@ #ifndef ScrollingStateNode_h #define ScrollingStateNode_h -#if ENABLE(THREADED_SCROLLING) +#if ENABLE(THREADED_SCROLLING) || USE(COORDINATED_GRAPHICS) #include "PlatformLayer.h" #include "ScrollingCoordinator.h" @@ -51,29 +51,34 @@ public: virtual bool isScrollingNode() { return false; } virtual bool isFixedNode() { return false; } + virtual bool isStickyNode() { return false; } virtual PassOwnPtr<ScrollingStateNode> clone() = 0; PassOwnPtr<ScrollingStateNode> cloneAndReset(); void cloneAndResetChildren(ScrollingStateNode*); - virtual bool hasChangedProperties() const = 0; - virtual unsigned changedProperties() const = 0; - virtual void resetChangedProperties() = 0; - virtual void setHasChangedProperties() { setScrollLayerDidChange(true); } + enum { + ScrollLayer = 0, + NumStateNodeBits = 1 + }; + typedef unsigned ChangedProperties; + + bool hasChangedProperties() const { return m_changedProperties; } + bool hasChangedProperty(unsigned propertyBit) { return m_changedProperties & (1 << propertyBit); } + void resetChangedProperties() { m_changedProperties = 0; } + void setPropertyChanged(unsigned propertyBit) { m_changedProperties |= (1 << propertyBit); } + + virtual void syncLayerPositionForViewportRect(const LayoutRect& /*viewportRect*/) { } GraphicsLayer* graphicsLayer() { return m_graphicsLayer; } PlatformLayer* platformScrollLayer() const; void setScrollLayer(GraphicsLayer*); - void setScrollLayer(PlatformLayer*); - - bool scrollLayerDidChange() const { return m_scrollLayerDidChange; } - void setScrollLayerDidChange(bool scrollLayerDidChange) { m_scrollLayerDidChange = scrollLayerDidChange; } + void setScrollPlatformLayer(PlatformLayer*); ScrollingStateTree* scrollingStateTree() const { return m_scrollingStateTree; } void setScrollingStateTree(ScrollingStateTree* tree) { m_scrollingStateTree = tree; } ScrollingNodeID scrollingNodeID() const { return m_nodeID; } - void setScrollingNodeID(ScrollingNodeID nodeID) { m_nodeID = nodeID; } ScrollingStateNode* parent() const { return m_parent; } void setParent(ScrollingStateNode* parent) { m_parent = parent; } @@ -95,14 +100,14 @@ private: void dump(TextStream&, int indent) const; virtual void dumpProperties(TextStream&, int indent) const = 0; + ChangedProperties changedProperties() const { return m_changedProperties; } ScrollingNodeID m_nodeID; + ChangedProperties m_changedProperties; ScrollingStateNode* m_parent; OwnPtr<Vector<OwnPtr<ScrollingStateNode> > > m_children; - bool m_scrollLayerDidChange; - #if PLATFORM(MAC) RetainPtr<PlatformLayer> m_platformScrollLayer; #endif @@ -112,6 +117,6 @@ private: } // namespace WebCore -#endif // ENABLE(THREADED_SCROLLING) +#endif // ENABLE(THREADED_SCROLLING) || USE(COORDINATED_GRAPHICS) #endif // ScrollingStateNode_h diff --git a/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.cpp b/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.cpp index 5d37be2f5..01893dc75 100644 --- a/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.cpp +++ b/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.cpp @@ -26,12 +26,12 @@ #include "config.h" #include "ScrollingStateScrollingNode.h" +#if ENABLE(THREADED_SCROLLING) || USE(COORDINATED_GRAPHICS) + #include "ScrollingStateTree.h" #include "TextStream.h" #include <wtf/OwnPtr.h> -#if ENABLE(THREADED_SCROLLING) - namespace WebCore { PassOwnPtr<ScrollingStateScrollingNode> ScrollingStateScrollingNode::create(ScrollingStateTree* stateTree, ScrollingNodeID nodeID) @@ -41,7 +41,10 @@ PassOwnPtr<ScrollingStateScrollingNode> ScrollingStateScrollingNode::create(Scro ScrollingStateScrollingNode::ScrollingStateScrollingNode(ScrollingStateTree* stateTree, ScrollingNodeID nodeID) : ScrollingStateNode(stateTree, nodeID) - , m_changedProperties(0) + , m_counterScrollingLayer(0) + , m_headerLayer(0) + , m_footerLayer(0) + , m_frameScaleFactor(1) , m_wheelEventHandlerCount(0) , m_shouldUpdateScrollLayerPositionOnMainThread(0) , m_horizontalScrollElasticity(ScrollElasticityNone) @@ -51,14 +54,16 @@ ScrollingStateScrollingNode::ScrollingStateScrollingNode(ScrollingStateTree* sta , m_requestedScrollPositionRepresentsProgrammaticScroll(false) , m_horizontalScrollbarMode(ScrollbarAuto) , m_verticalScrollbarMode(ScrollbarAuto) + , m_headerHeight(0) + , m_footerHeight(0) { } ScrollingStateScrollingNode::ScrollingStateScrollingNode(const ScrollingStateScrollingNode& stateNode) : ScrollingStateNode(stateNode) - , m_changedProperties(stateNode.changedProperties()) , m_viewportRect(stateNode.viewportRect()) - , m_contentsSize(stateNode.contentsSize()) + , m_totalContentsSize(stateNode.totalContentsSize()) + , m_frameScaleFactor(stateNode.frameScaleFactor()) , m_nonFastScrollableRegion(stateNode.nonFastScrollableRegion()) , m_wheelEventHandlerCount(stateNode.wheelEventHandlerCount()) , m_shouldUpdateScrollLayerPositionOnMainThread(stateNode.shouldUpdateScrollLayerPositionOnMainThread()) @@ -71,7 +76,12 @@ ScrollingStateScrollingNode::ScrollingStateScrollingNode(const ScrollingStateScr , m_verticalScrollbarMode(stateNode.verticalScrollbarMode()) , m_requestedScrollPosition(stateNode.requestedScrollPosition()) , m_scrollOrigin(stateNode.scrollOrigin()) + , m_headerHeight(stateNode.headerHeight()) + , m_footerHeight(stateNode.footerHeight()) { + setCounterScrollingLayer(stateNode.counterScrollingLayer()); + setHeaderLayer(stateNode.headerLayer()); + setFooterLayer(stateNode.footerLayer()); } ScrollingStateScrollingNode::~ScrollingStateScrollingNode() @@ -89,17 +99,28 @@ void ScrollingStateScrollingNode::setViewportRect(const IntRect& viewportRect) return; m_viewportRect = viewportRect; - m_changedProperties |= ViewportRect; + setPropertyChanged(ViewportRect); m_scrollingStateTree->setHasChangedProperties(true); } -void ScrollingStateScrollingNode::setContentsSize(const IntSize& contentsSize) +void ScrollingStateScrollingNode::setTotalContentsSize(const IntSize& totalContentsSize) { - if (m_contentsSize == contentsSize) + if (m_totalContentsSize == totalContentsSize) return; - m_contentsSize = contentsSize; - m_changedProperties |= ContentsSize; + m_totalContentsSize = totalContentsSize; + setPropertyChanged(TotalContentsSize); + m_scrollingStateTree->setHasChangedProperties(true); +} + +void ScrollingStateScrollingNode::setFrameScaleFactor(float scaleFactor) +{ + if (m_frameScaleFactor == scaleFactor) + return; + + m_frameScaleFactor = scaleFactor; + + setPropertyChanged(FrameScaleFactor); m_scrollingStateTree->setHasChangedProperties(true); } @@ -109,7 +130,7 @@ void ScrollingStateScrollingNode::setNonFastScrollableRegion(const Region& nonFa return; m_nonFastScrollableRegion = nonFastScrollableRegion; - m_changedProperties |= NonFastScrollableRegion; + setPropertyChanged(NonFastScrollableRegion); m_scrollingStateTree->setHasChangedProperties(true); } @@ -119,7 +140,7 @@ void ScrollingStateScrollingNode::setWheelEventHandlerCount(unsigned wheelEventH return; m_wheelEventHandlerCount = wheelEventHandlerCount; - m_changedProperties |= WheelEventHandlerCount; + setPropertyChanged(WheelEventHandlerCount); m_scrollingStateTree->setHasChangedProperties(true); } @@ -129,7 +150,7 @@ void ScrollingStateScrollingNode::setShouldUpdateScrollLayerPositionOnMainThread return; m_shouldUpdateScrollLayerPositionOnMainThread = reasons; - m_changedProperties |= ShouldUpdateScrollLayerPositionOnMainThread; + setPropertyChanged(ShouldUpdateScrollLayerPositionOnMainThread); m_scrollingStateTree->setHasChangedProperties(true); } @@ -139,7 +160,7 @@ void ScrollingStateScrollingNode::setHorizontalScrollElasticity(ScrollElasticity return; m_horizontalScrollElasticity = horizontalScrollElasticity; - m_changedProperties |= HorizontalScrollElasticity; + setPropertyChanged(HorizontalScrollElasticity); m_scrollingStateTree->setHasChangedProperties(true); } @@ -149,7 +170,7 @@ void ScrollingStateScrollingNode::setVerticalScrollElasticity(ScrollElasticity v return; m_verticalScrollElasticity = verticalScrollElasticity; - m_changedProperties |= VerticalScrollElasticity; + setPropertyChanged(VerticalScrollElasticity); m_scrollingStateTree->setHasChangedProperties(true); } @@ -159,7 +180,7 @@ void ScrollingStateScrollingNode::setHasEnabledHorizontalScrollbar(bool hasEnabl return; m_hasEnabledHorizontalScrollbar = hasEnabledHorizontalScrollbar; - m_changedProperties |= HasEnabledHorizontalScrollbar; + setPropertyChanged(HasEnabledHorizontalScrollbar); m_scrollingStateTree->setHasChangedProperties(true); } @@ -169,7 +190,7 @@ void ScrollingStateScrollingNode::setHasEnabledVerticalScrollbar(bool hasEnabled return; m_hasEnabledVerticalScrollbar = hasEnabledVerticalScrollbar; - m_changedProperties |= HasEnabledVerticalScrollbar; + setPropertyChanged(HasEnabledVerticalScrollbar); m_scrollingStateTree->setHasChangedProperties(true); } @@ -179,7 +200,7 @@ void ScrollingStateScrollingNode::setHorizontalScrollbarMode(ScrollbarMode horiz return; m_horizontalScrollbarMode = horizontalScrollbarMode; - m_changedProperties |= HorizontalScrollbarMode; + setPropertyChanged(HorizontalScrollbarMode); m_scrollingStateTree->setHasChangedProperties(true); } @@ -189,7 +210,7 @@ void ScrollingStateScrollingNode::setVerticalScrollbarMode(ScrollbarMode vertica return; m_verticalScrollbarMode = verticalScrollbarMode; - m_changedProperties |= VerticalScrollbarMode; + setPropertyChanged(VerticalScrollbarMode); m_scrollingStateTree->setHasChangedProperties(true); } @@ -197,7 +218,7 @@ void ScrollingStateScrollingNode::setRequestedScrollPosition(const IntPoint& req { m_requestedScrollPosition = requestedScrollPosition; m_requestedScrollPositionRepresentsProgrammaticScroll = representsProgrammaticScroll; - m_changedProperties |= RequestedScrollPosition; + setPropertyChanged(RequestedScrollPosition); m_scrollingStateTree->setHasChangedProperties(true); } @@ -207,7 +228,27 @@ void ScrollingStateScrollingNode::setScrollOrigin(const IntPoint& scrollOrigin) return; m_scrollOrigin = scrollOrigin; - m_changedProperties |= ScrollOrigin; + setPropertyChanged(ScrollOrigin); + m_scrollingStateTree->setHasChangedProperties(true); +} + +void ScrollingStateScrollingNode::setHeaderHeight(int headerHeight) +{ + if (m_headerHeight == headerHeight) + return; + + m_headerHeight = headerHeight; + setPropertyChanged(HeaderHeight); + m_scrollingStateTree->setHasChangedProperties(true); +} + +void ScrollingStateScrollingNode::setFooterHeight(int footerHeight) +{ + if (m_footerHeight == footerHeight) + return; + + m_footerHeight = footerHeight; + setPropertyChanged(FooterHeight); m_scrollingStateTree->setHasChangedProperties(true); } @@ -220,25 +261,19 @@ void ScrollingStateScrollingNode::dumpProperties(TextStream& ts, int indent) con ts << "(viewport rect " << m_viewportRect.x() << " " << m_viewportRect.y() << " " << m_viewportRect.width() << " " << m_viewportRect.height() << ")\n"; } - if (!m_contentsSize.isEmpty()) { + if (!m_totalContentsSize.isEmpty()) { + writeIndent(ts, indent + 1); + ts << "(contents size " << m_totalContentsSize.width() << " " << m_totalContentsSize.height() << ")\n"; + } + + if (m_frameScaleFactor != 1) { writeIndent(ts, indent + 1); - ts << "(contents size " << m_contentsSize.width() << " " << m_contentsSize.height() << ")\n"; + ts << "(frame scale factor " << m_frameScaleFactor << ")\n"; } if (m_shouldUpdateScrollLayerPositionOnMainThread) { writeIndent(ts, indent + 1); - ts << "(Scrolling on main thread because: "; - if (m_shouldUpdateScrollLayerPositionOnMainThread & ScrollingCoordinator::ForcedOnMainThread) - ts << "Forced on main thread, "; - if (m_shouldUpdateScrollLayerPositionOnMainThread & ScrollingCoordinator::HasSlowRepaintObjects) - ts << "Has slow repaint objects, "; - if (m_shouldUpdateScrollLayerPositionOnMainThread & ScrollingCoordinator::HasViewportConstrainedObjectsWithoutSupportingFixedLayers) - ts << "Has viewport constrained objects without supporting fixed layers, "; - if (m_shouldUpdateScrollLayerPositionOnMainThread & ScrollingCoordinator::HasNonLayerFixedObjects) - ts << "Has non-layer fixed objects, "; - if (m_shouldUpdateScrollLayerPositionOnMainThread & ScrollingCoordinator::IsImageDocument) - ts << "Is image document"; - ts << ")\n"; + ts << "(Scrolling on main thread because: " << ScrollingCoordinator::mainThreadScrollingReasonsAsText(m_shouldUpdateScrollLayerPositionOnMainThread) << ")\n"; } if (m_requestedScrollPosition != IntPoint()) { @@ -250,9 +285,8 @@ void ScrollingStateScrollingNode::dumpProperties(TextStream& ts, int indent) con writeIndent(ts, indent + 1); ts << "(scroll origin " << m_scrollOrigin.x() << " " << m_scrollOrigin.y() << ")\n"; } - } } // namespace WebCore -#endif // ENABLE(THREADED_SCROLLING) +#endif // ENABLE(THREADED_SCROLLING) || USE(COORDINATED_GRAPHICS) diff --git a/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.h b/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.h index 5902e27bd..91ac56aa9 100644 --- a/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.h +++ b/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.h @@ -26,7 +26,7 @@ #ifndef ScrollingStateScrollingNode_h #define ScrollingStateScrollingNode_h -#if ENABLE(THREADED_SCROLLING) +#if ENABLE(THREADED_SCROLLING) || USE(COORDINATED_GRAPHICS) #include "IntRect.h" #include "Region.h" @@ -46,32 +46,37 @@ public: virtual ~ScrollingStateScrollingNode(); enum ChangedProperty { - ViewportRect = 1 << 0, - ContentsSize = 1 << 1, - NonFastScrollableRegion = 1 << 2, - WheelEventHandlerCount = 1 << 3, - ShouldUpdateScrollLayerPositionOnMainThread = 1 << 4, - HorizontalScrollElasticity = 1 << 5, - VerticalScrollElasticity = 1 << 6, - HasEnabledHorizontalScrollbar = 1 << 7, - HasEnabledVerticalScrollbar = 1 << 8, - HorizontalScrollbarMode = 1 << 9, - VerticalScrollbarMode = 1 << 10, - ScrollOrigin = 1 << 11, - RequestedScrollPosition = 1 << 12, + ViewportRect = NumStateNodeBits, + TotalContentsSize, + FrameScaleFactor, + NonFastScrollableRegion, + WheelEventHandlerCount, + ShouldUpdateScrollLayerPositionOnMainThread, + HorizontalScrollElasticity, + VerticalScrollElasticity, + HasEnabledHorizontalScrollbar, + HasEnabledVerticalScrollbar, + HorizontalScrollbarMode, + VerticalScrollbarMode, + ScrollOrigin, + RequestedScrollPosition, + CounterScrollingLayer, + HeaderHeight, + FooterHeight, + HeaderLayer, + FooterLayer }; virtual bool isScrollingNode() OVERRIDE { return true; } - virtual bool hasChangedProperties() const OVERRIDE { return m_changedProperties; } - virtual unsigned changedProperties() const OVERRIDE { return m_changedProperties; } - virtual void resetChangedProperties() OVERRIDE { m_changedProperties = 0; } - const IntRect& viewportRect() const { return m_viewportRect; } void setViewportRect(const IntRect&); - const IntSize& contentsSize() const { return m_contentsSize; } - void setContentsSize(const IntSize&); + const IntSize& totalContentsSize() const { return m_totalContentsSize; } + void setTotalContentsSize(const IntSize&); + + float frameScaleFactor() const { return m_frameScaleFactor; } + void setFrameScaleFactor(float); const Region& nonFastScrollableRegion() const { return m_nonFastScrollableRegion; } void setNonFastScrollableRegion(const Region&); @@ -106,6 +111,27 @@ public: const IntPoint& scrollOrigin() const { return m_scrollOrigin; } void setScrollOrigin(const IntPoint&); + int headerHeight() const { return m_headerHeight; } + void setHeaderHeight(int); + + int footerHeight() const { return m_footerHeight; } + void setFooterHeight(int); + + // This is a layer moved in the opposite direction to scrolling, for example for background-attachment:fixed + GraphicsLayer* counterScrollingLayer() const { return m_counterScrollingLayer; } + void setCounterScrollingLayer(GraphicsLayer*); + PlatformLayer* counterScrollingPlatformLayer() const; + + // The header and footer layers scroll vertically with the page, they should remain fixed when scrolling horizontally. + GraphicsLayer* headerLayer() const { return m_headerLayer; } + void setHeaderLayer(GraphicsLayer*); + PlatformLayer* headerPlatformLayer() const; + + // The header and footer layers scroll vertically with the page, they should remain fixed when scrolling horizontally. + GraphicsLayer* footerLayer() const { return m_footerLayer; } + void setFooterLayer(GraphicsLayer*); + PlatformLayer* footerPlatformLayer() const; + bool requestedScrollPositionRepresentsProgrammaticScroll() const { return m_requestedScrollPositionRepresentsProgrammaticScroll; } virtual void dumpProperties(TextStream&, int indent) const OVERRIDE; @@ -114,10 +140,19 @@ private: ScrollingStateScrollingNode(ScrollingStateTree*, ScrollingNodeID); ScrollingStateScrollingNode(const ScrollingStateScrollingNode&); - unsigned m_changedProperties; - + GraphicsLayer* m_counterScrollingLayer; + GraphicsLayer* m_headerLayer; + GraphicsLayer* m_footerLayer; +#if PLATFORM(MAC) + RetainPtr<PlatformLayer> m_counterScrollingPlatformLayer; + RetainPtr<PlatformLayer> m_headerPlatformLayer; + RetainPtr<PlatformLayer> m_footerPlatformLayer; +#endif + IntRect m_viewportRect; - IntSize m_contentsSize; + IntSize m_totalContentsSize; + + float m_frameScaleFactor; Region m_nonFastScrollableRegion; @@ -137,11 +172,14 @@ private: IntPoint m_requestedScrollPosition; IntPoint m_scrollOrigin; + + int m_headerHeight; + int m_footerHeight; }; inline ScrollingStateScrollingNode* toScrollingStateScrollingNode(ScrollingStateNode* node) { - ASSERT(!node || node->isScrollingNode()); + ASSERT_WITH_SECURITY_IMPLICATION(!node || node->isScrollingNode()); return static_cast<ScrollingStateScrollingNode*>(node); } @@ -150,6 +188,6 @@ void toScrollingStateScrollingNode(const ScrollingStateScrollingNode*); } // namespace WebCore -#endif // ENABLE(THREADED_SCROLLING) +#endif // ENABLE(THREADED_SCROLLING) || USE(COORDINATED_GRAPHICS) #endif // ScrollingStateScrollingNode_h diff --git a/Source/WebCore/page/scrolling/ScrollingStateStickyNode.cpp b/Source/WebCore/page/scrolling/ScrollingStateStickyNode.cpp new file mode 100644 index 000000000..73b5ade52 --- /dev/null +++ b/Source/WebCore/page/scrolling/ScrollingStateStickyNode.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ScrollingStateStickyNode.h" + +#if ENABLE(THREADED_SCROLLING) || USE(COORDINATED_GRAPHICS) + +#include "GraphicsLayer.h" +#include "ScrollingStateTree.h" +#include "TextStream.h" +#include <wtf/OwnPtr.h> + +namespace WebCore { + +PassOwnPtr<ScrollingStateStickyNode> ScrollingStateStickyNode::create(ScrollingStateTree* stateTree, ScrollingNodeID nodeID) +{ + return adoptPtr(new ScrollingStateStickyNode(stateTree, nodeID)); +} + +ScrollingStateStickyNode::ScrollingStateStickyNode(ScrollingStateTree* tree, ScrollingNodeID nodeID) + : ScrollingStateNode(tree, nodeID) +{ +} + +ScrollingStateStickyNode::ScrollingStateStickyNode(const ScrollingStateStickyNode& node) + : ScrollingStateNode(node) + , m_constraints(StickyPositionViewportConstraints(node.viewportConstraints())) +{ +} + +ScrollingStateStickyNode::~ScrollingStateStickyNode() +{ +} + +PassOwnPtr<ScrollingStateNode> ScrollingStateStickyNode::clone() +{ + return adoptPtr(new ScrollingStateStickyNode(*this)); +} + +void ScrollingStateStickyNode::updateConstraints(const StickyPositionViewportConstraints& constraints) +{ + if (m_constraints == constraints) + return; + + m_constraints = constraints; + setPropertyChanged(ViewportConstraints); + m_scrollingStateTree->setHasChangedProperties(true); +} + +void ScrollingStateStickyNode::syncLayerPositionForViewportRect(const LayoutRect& viewportRect) +{ + FloatPoint position = m_constraints.layerPositionForConstrainingRect(viewportRect); + graphicsLayer()->syncPosition(position); +} + +void ScrollingStateStickyNode::dumpProperties(TextStream& ts, int indent) const +{ + ts << "(" << "Sticky node" << "\n"; + + if (m_constraints.anchorEdges()) { + writeIndent(ts, indent + 1); + ts << "(anchor edges: "; + if (m_constraints.hasAnchorEdge(ViewportConstraints::AnchorEdgeLeft)) + ts << "AnchorEdgeLeft "; + if (m_constraints.hasAnchorEdge(ViewportConstraints::AnchorEdgeRight)) + ts << "AnchorEdgeRight "; + if (m_constraints.hasAnchorEdge(ViewportConstraints::AnchorEdgeTop)) + ts << "AnchorEdgeTop "; + if (m_constraints.hasAnchorEdge(ViewportConstraints::AnchorEdgeBottom)) + ts << "AnchorEdgeBottom"; + ts << ")\n"; + } + + if (m_constraints.hasAnchorEdge(ViewportConstraints::AnchorEdgeLeft)) { + writeIndent(ts, indent + 1); + ts << "(left offset " << m_constraints.leftOffset() << ")\n"; + } + if (m_constraints.hasAnchorEdge(ViewportConstraints::AnchorEdgeRight)) { + writeIndent(ts, indent + 1); + ts << "(right offset " << m_constraints.rightOffset() << ")\n"; + } + if (m_constraints.hasAnchorEdge(ViewportConstraints::AnchorEdgeTop)) { + writeIndent(ts, indent + 1); + ts << "(top offset " << m_constraints.topOffset() << ")\n"; + } + if (m_constraints.hasAnchorEdge(ViewportConstraints::AnchorEdgeBottom)) { + writeIndent(ts, indent + 1); + ts << "(bottom offset " << m_constraints.bottomOffset() << ")\n"; + } + + writeIndent(ts, indent + 1); + FloatRect r = m_constraints.containingBlockRect(); + ts << "(containing block rect " << r.x() << ", " << r.y() << " " << r.width() << " x " << r.height() << ")\n"; + + writeIndent(ts, indent + 1); + r = m_constraints.stickyBoxRect(); + ts << "(sticky box rect " << r.x() << " " << r.y() << " " << r.width() << " " << r.height() << ")\n"; + + writeIndent(ts, indent + 1); + r = m_constraints.stickyBoxRect(); + ts << "(sticky box rect " << r.x() << " " << r.y() << " " << r.width() << " " << r.height() << ")\n"; + + writeIndent(ts, indent + 1); + ts << "(sticky offset at last layout " << m_constraints.stickyOffsetAtLastLayout().width() << " " << m_constraints.stickyOffsetAtLastLayout().height() << ")\n"; + + writeIndent(ts, indent + 1); + ts << "(layer position at last layout " << m_constraints.layerPositionAtLastLayout().x() << " " << m_constraints.layerPositionAtLastLayout().y() << ")\n"; +} + +} // namespace WebCore + +#endif // ENABLE(THREADED_SCROLLING) || USE(COORDINATED_GRAPHICS) diff --git a/Source/WebCore/page/scrolling/ScrollingStateStickyNode.h b/Source/WebCore/page/scrolling/ScrollingStateStickyNode.h new file mode 100644 index 000000000..54a7daa8b --- /dev/null +++ b/Source/WebCore/page/scrolling/ScrollingStateStickyNode.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ScrollingStateStickyNode_h +#define ScrollingStateStickyNode_h + +#if ENABLE(THREADED_SCROLLING) || USE(COORDINATED_GRAPHICS) + +#include "ScrollingConstraints.h" +#include "ScrollingStateNode.h" + +#include <wtf/Forward.h> + +namespace WebCore { + +class StickyPositionViewportConstraints; + +class ScrollingStateStickyNode : public ScrollingStateNode { +public: + static PassOwnPtr<ScrollingStateStickyNode> create(ScrollingStateTree*, ScrollingNodeID); + + virtual PassOwnPtr<ScrollingStateNode> clone(); + + virtual ~ScrollingStateStickyNode(); + + enum { + ViewportConstraints = NumStateNodeBits + }; + + void updateConstraints(const StickyPositionViewportConstraints&); + const StickyPositionViewportConstraints& viewportConstraints() const { return m_constraints; } + +private: + ScrollingStateStickyNode(ScrollingStateTree*, ScrollingNodeID); + ScrollingStateStickyNode(const ScrollingStateStickyNode&); + + virtual bool isStickyNode() OVERRIDE { return true; } + + virtual void syncLayerPositionForViewportRect(const LayoutRect& viewportRect) OVERRIDE; + + virtual void dumpProperties(TextStream&, int indent) const OVERRIDE; + + StickyPositionViewportConstraints m_constraints; +}; + +inline ScrollingStateStickyNode* toScrollingStateStickyNode(ScrollingStateNode* node) +{ + ASSERT_WITH_SECURITY_IMPLICATION(!node || node->isStickyNode()); + return static_cast<ScrollingStateStickyNode*>(node); +} + +// This will catch anyone doing an unnecessary cast. +void toScrollingStateStickyNode(const ScrollingStateStickyNode*); + +} // namespace WebCore + +#endif // ENABLE(THREADED_SCROLLING) || USE(COORDINATED_GRAPHICS) + +#endif // ScrollingStateStickyNode_h diff --git a/Source/WebCore/page/scrolling/ScrollingStateTree.cpp b/Source/WebCore/page/scrolling/ScrollingStateTree.cpp index 4e3b5385d..75d3fa7b1 100644 --- a/Source/WebCore/page/scrolling/ScrollingStateTree.cpp +++ b/Source/WebCore/page/scrolling/ScrollingStateTree.cpp @@ -26,7 +26,11 @@ #include "config.h" #include "ScrollingStateTree.h" -#if ENABLE(THREADED_SCROLLING) +#if ENABLE(THREADED_SCROLLING) || USE(COORDINATED_GRAPHICS) + +#include "ScrollingStateFixedNode.h" +#include "ScrollingStateScrollingNode.h" +#include "ScrollingStateStickyNode.h" namespace WebCore { @@ -36,8 +40,8 @@ PassOwnPtr<ScrollingStateTree> ScrollingStateTree::create() } ScrollingStateTree::ScrollingStateTree() - : m_rootStateNode(ScrollingStateScrollingNode::create(this, 0)) - , m_hasChangedProperties(false) + : m_hasChangedProperties(false) + , m_hasNewRootStateNode(false) { } @@ -45,11 +49,87 @@ ScrollingStateTree::~ScrollingStateTree() { } +ScrollingNodeID ScrollingStateTree::attachNode(ScrollingNodeType nodeType, ScrollingNodeID newNodeID, ScrollingNodeID parentID) +{ + ASSERT(newNodeID); + + if (ScrollingStateNode* node = stateNodeForID(newNodeID)) { + ScrollingStateNode* parent = stateNodeForID(parentID); + if (!parent) + return newNodeID; + if (node->parent() == parent) + return newNodeID; + + // The node is being re-parented. To do that, we'll remove it, and then re-create a new node. + removeNode(node); + } + + ScrollingStateNode* newNode = 0; + if (!parentID) { + // If we're resetting the root node, we should clear the HashMap and destroy the current children. + clear(); + + setRootStateNode(ScrollingStateScrollingNode::create(this, newNodeID)); + newNode = rootStateNode(); + m_hasNewRootStateNode = true; + } else { + ScrollingStateNode* parent = stateNodeForID(parentID); + if (!parent) + return 0; + + switch (nodeType) { + case FixedNode: { + OwnPtr<ScrollingStateFixedNode> fixedNode = ScrollingStateFixedNode::create(this, newNodeID); + newNode = fixedNode.get(); + parent->appendChild(fixedNode.release()); + break; + } + case StickyNode: { + OwnPtr<ScrollingStateStickyNode> stickyNode = ScrollingStateStickyNode::create(this, newNodeID); + newNode = stickyNode.get(); + parent->appendChild(stickyNode.release()); + break; + } + case ScrollingNode: { + // FIXME: We currently only support child nodes that are fixed. + ASSERT_NOT_REACHED(); + OwnPtr<ScrollingStateScrollingNode> scrollingNode = ScrollingStateScrollingNode::create(this, newNodeID); + newNode = scrollingNode.get(); + parent->appendChild(scrollingNode.release()); + break; + } + } + } + + m_stateNodeMap.set(newNodeID, newNode); + return newNodeID; +} + +void ScrollingStateTree::detachNode(ScrollingNodeID nodeID) +{ + if (!nodeID) + return; + + // The node may not be found if clearStateTree() was recently called. + ScrollingStateNode* node = m_stateNodeMap.take(nodeID); + if (!node) + return; + + removeNode(node); +} + +void ScrollingStateTree::clear() +{ + removeNode(rootStateNode()); + m_stateNodeMap.clear(); +} + PassOwnPtr<ScrollingStateTree> ScrollingStateTree::commit() { - // This function clones and resets the current state tree, but leaves the tree structure intact. + // This function clones and resets the current state tree, but leaves the tree structure intact. OwnPtr<ScrollingStateTree> treeStateClone = ScrollingStateTree::create(); - treeStateClone->setRootStateNode(static_pointer_cast<ScrollingStateScrollingNode>(m_rootStateNode->cloneAndReset())); + if (m_rootStateNode) + treeStateClone->setRootStateNode(static_pointer_cast<ScrollingStateScrollingNode>(m_rootStateNode->cloneAndReset())); // Copy the IDs of the nodes that have been removed since the last commit into the clone. treeStateClone->m_nodesRemovedSinceLastCommit.swap(m_nodesRemovedSinceLastCommit); @@ -58,20 +138,52 @@ PassOwnPtr<ScrollingStateTree> ScrollingStateTree::commit() treeStateClone->m_hasChangedProperties = true; m_hasChangedProperties = false; + treeStateClone->m_hasNewRootStateNode = m_hasNewRootStateNode; + m_hasNewRootStateNode = false; + return treeStateClone.release(); } void ScrollingStateTree::removeNode(ScrollingStateNode* node) { + if (!node) + return; + + if (node == m_rootStateNode) { + didRemoveNode(node->scrollingNodeID()); + m_rootStateNode = nullptr; + return; + } + ASSERT(m_rootStateNode); m_rootStateNode->removeChild(node); + + // ScrollingStateTree::removeNode() will destroy children, so we have to make sure we remove those children + // from the HashMap. + size_t size = m_nodesRemovedSinceLastCommit.size(); + for (size_t i = 0; i < size; ++i) + m_stateNodeMap.remove(m_nodesRemovedSinceLastCommit[i]); } void ScrollingStateTree::didRemoveNode(ScrollingNodeID nodeID) { m_nodesRemovedSinceLastCommit.append(nodeID); + m_hasChangedProperties = true; +} + +ScrollingStateNode* ScrollingStateTree::stateNodeForID(ScrollingNodeID scrollLayerID) +{ + if (!scrollLayerID) + return 0; + + HashMap<ScrollingNodeID, ScrollingStateNode*>::const_iterator it = m_stateNodeMap.find(scrollLayerID); + if (it == m_stateNodeMap.end()) + return 0; + + ASSERT(it->value->scrollingNodeID() == scrollLayerID); + return it->value; } } // namespace WebCore -#endif // ENABLE(THREADED_SCROLLING) +#endif // ENABLE(THREADED_SCROLLING) || USE(COORDINATED_GRAPHICS) diff --git a/Source/WebCore/page/scrolling/ScrollingStateTree.h b/Source/WebCore/page/scrolling/ScrollingStateTree.h index 98659fcae..eb091977d 100644 --- a/Source/WebCore/page/scrolling/ScrollingStateTree.h +++ b/Source/WebCore/page/scrolling/ScrollingStateTree.h @@ -26,7 +26,7 @@ #ifndef ScrollingStateTree_h #define ScrollingStateTree_h -#if ENABLE(THREADED_SCROLLING) +#if ENABLE(THREADED_SCROLLING) || USE(COORDINATED_GRAPHICS) #include "ScrollingStateScrollingNode.h" #include <wtf/OwnPtr.h> @@ -40,46 +40,48 @@ namespace WebCore { // will be informed and will schedule a timer that will clone the new state tree and send it over to // the scrolling thread, avoiding locking. -// FIXME: Right now the scrolling thread only ever looks at the root node. In the future, it should -// look at the whole tree and build a ScrollingTree that mimics the ScrollingStateTree. - -// FIXME: Right now there is only one type of ScrollingStateNode, which is the ScrollingStateScrollingNode. -// It is currently used for the main frame, but in the future it should be able to be used for subframes -// and overflow areas. In the future, more classes will inherit from ScrollingStateNode, such as -// ScrollingStateFixedNode and ScrollingStateStickyNode for fixed position objects and sticky positoned -// objects, respectively. - class ScrollingStateTree { + friend class ScrollingStateNode; public: + static PassOwnPtr<ScrollingStateTree> create(); ~ScrollingStateTree(); ScrollingStateScrollingNode* rootStateNode() const { return m_rootStateNode.get(); } + ScrollingStateNode* stateNodeForID(ScrollingNodeID); + + ScrollingNodeID attachNode(ScrollingNodeType, ScrollingNodeID, ScrollingNodeID parentID); + void detachNode(ScrollingNodeID); + void clear(); + + const Vector<ScrollingNodeID>& removedNodes() const { return m_nodesRemovedSinceLastCommit; } // Copies the current tree state and clears the changed properties mask in the original. PassOwnPtr<ScrollingStateTree> commit(); - void removeNode(ScrollingStateNode*); - void didRemoveNode(ScrollingNodeID); - const Vector<ScrollingNodeID>& removedNodes() const { return m_nodesRemovedSinceLastCommit; } - void setHasChangedProperties(bool changedProperties) { m_hasChangedProperties = changedProperties; } bool hasChangedProperties() const { return m_hasChangedProperties; } + bool hasNewRootStateNode() const { return m_hasNewRootStateNode; } + private: ScrollingStateTree(); void setRootStateNode(PassOwnPtr<ScrollingStateScrollingNode> rootStateNode) { m_rootStateNode = rootStateNode; } + void removeNode(ScrollingStateNode*); + void didRemoveNode(ScrollingNodeID); PassOwnPtr<ScrollingStateTree> clone(); + HashMap<ScrollingNodeID, ScrollingStateNode*> m_stateNodeMap; OwnPtr<ScrollingStateScrollingNode> m_rootStateNode; Vector<ScrollingNodeID> m_nodesRemovedSinceLastCommit; bool m_hasChangedProperties; + bool m_hasNewRootStateNode; }; } // namespace WebCore -#endif // ENABLE(THREADED_SCROLLING) +#endif // ENABLE(THREADED_SCROLLING) || USE(COORDINATED_GRAPHICS) #endif // ScrollingStateTree_h diff --git a/Source/WebCore/page/scrolling/ScrollingTree.cpp b/Source/WebCore/page/scrolling/ScrollingTree.cpp index 547ea9626..e0f1bdee6 100644 --- a/Source/WebCore/page/scrolling/ScrollingTree.cpp +++ b/Source/WebCore/page/scrolling/ScrollingTree.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2013 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,6 +35,7 @@ #include "ScrollingTreeFixedNode.h" #include "ScrollingTreeNode.h" #include "ScrollingTreeScrollingNode.h" +#include "ScrollingTreeStickyNode.h" #include <wtf/MainThread.h> #include <wtf/TemporaryChange.h> @@ -47,12 +48,17 @@ PassRefPtr<ScrollingTree> ScrollingTree::create(ScrollingCoordinator* scrollingC ScrollingTree::ScrollingTree(ScrollingCoordinator* scrollingCoordinator) : m_scrollingCoordinator(scrollingCoordinator) - , m_rootNode(ScrollingTreeScrollingNode::create(this)) , m_hasWheelEventHandlers(false) , m_canGoBack(false) , m_canGoForward(false) , m_mainFramePinnedToTheLeft(false) , m_mainFramePinnedToTheRight(false) + , m_rubberBandsAtBottom(true) + , m_rubberBandsAtTop(true) + , m_mainFramePinnedToTheTop(false) + , m_mainFramePinnedToTheBottom(false) + , m_mainFrameIsRubberBanding(false) + , m_scrollPinningBehavior(DoNotPin) , m_scrollingPerformanceLoggingEnabled(false) , m_isHandlingProgrammaticScroll(false) { @@ -98,8 +104,9 @@ void ScrollingTree::updateBackForwardState(bool canGoBack, bool canGoForward) void ScrollingTree::handleWheelEvent(const PlatformWheelEvent& wheelEvent) { ASSERT(ScrollingThread::isCurrentThread()); - - m_rootNode->handleWheelEvent(wheelEvent); + + if (m_rootNode) + m_rootNode->handleWheelEvent(wheelEvent); } static void derefScrollingCoordinator(ScrollingCoordinator* scrollingCoordinator) @@ -126,52 +133,72 @@ void ScrollingTree::commitNewTreeState(PassOwnPtr<ScrollingStateTree> scrollingS { ASSERT(ScrollingThread::isCurrentThread()); - if (scrollingStateTree->rootStateNode()->changedProperties() & (ScrollingStateScrollingNode::WheelEventHandlerCount | ScrollingStateScrollingNode::NonFastScrollableRegion) || scrollingStateTree->rootStateNode()->scrollLayerDidChange()) { + bool rootStateNodeChanged = scrollingStateTree->hasNewRootStateNode(); + + ScrollingStateScrollingNode* rootNode = scrollingStateTree->rootStateNode(); + if (rootNode + && (rootStateNodeChanged + || rootNode->hasChangedProperty(ScrollingStateScrollingNode::WheelEventHandlerCount) + || rootNode->hasChangedProperty(ScrollingStateScrollingNode::NonFastScrollableRegion) + || rootNode->hasChangedProperty(ScrollingStateNode::ScrollLayer))) { MutexLocker lock(m_mutex); - if (scrollingStateTree->rootStateNode()->scrollLayerDidChange()) + if (rootStateNodeChanged || rootNode->hasChangedProperty(ScrollingStateNode::ScrollLayer)) m_mainFrameScrollPosition = IntPoint(); - if (scrollingStateTree->rootStateNode()->changedProperties() & ScrollingStateScrollingNode::WheelEventHandlerCount) + if (rootStateNodeChanged || rootNode->hasChangedProperty(ScrollingStateScrollingNode::WheelEventHandlerCount)) m_hasWheelEventHandlers = scrollingStateTree->rootStateNode()->wheelEventHandlerCount(); - if (scrollingStateTree->rootStateNode()->changedProperties() & ScrollingStateScrollingNode::NonFastScrollableRegion) + if (rootStateNodeChanged || rootNode->hasChangedProperty(ScrollingStateScrollingNode::NonFastScrollableRegion)) m_nonFastScrollableRegion = scrollingStateTree->rootStateNode()->nonFastScrollableRegion(); } - TemporaryChange<bool> changeHandlingProgrammaticScroll(m_isHandlingProgrammaticScroll, scrollingStateTree->rootStateNode()->requestedScrollPositionRepresentsProgrammaticScroll()); + bool scrollRequestIsProgammatic = rootNode ? rootNode->requestedScrollPositionRepresentsProgrammaticScroll() : false; + TemporaryChange<bool> changeHandlingProgrammaticScroll(m_isHandlingProgrammaticScroll, scrollRequestIsProgammatic); removeDestroyedNodes(scrollingStateTree.get()); - updateTreeFromStateNode(scrollingStateTree->rootStateNode()); - - updateDebugRootLayer(); + updateTreeFromStateNode(rootNode); } void ScrollingTree::updateTreeFromStateNode(ScrollingStateNode* stateNode) { + if (!stateNode) { + m_nodeMap.clear(); + m_rootNode = nullptr; + return; + } + // This fuction recurses through the ScrollingStateTree and updates the corresponding ScrollingTreeNodes. // Find the ScrollingTreeNode associated with the current stateNode using the shared ID and our HashMap. ScrollingTreeNodeMap::const_iterator it = m_nodeMap.find(stateNode->scrollingNodeID()); + ScrollingTreeNode* node; if (it != m_nodeMap.end()) { - ScrollingTreeNode* node = it->value; - node->update(stateNode); + node = it->value; + node->updateBeforeChildren(stateNode); } else { // If the node isn't found, it's either new and needs to be added to the tree, or there is a new ID for our // root node. + ScrollingNodeID nodeID = stateNode->scrollingNodeID(); if (!stateNode->parent()) { - // This is the root node. - m_rootNode->setScrollingNodeID(stateNode->scrollingNodeID()); - m_nodeMap.set(stateNode->scrollingNodeID(), m_rootNode.get()); - m_rootNode->update(stateNode); + // This is the root node. Nuke the node map. + m_nodeMap.clear(); + + m_rootNode = ScrollingTreeScrollingNode::create(this, nodeID); + m_nodeMap.set(nodeID, m_rootNode.get()); + m_rootNode->updateBeforeChildren(stateNode); + node = m_rootNode.get(); } else { OwnPtr<ScrollingTreeNode> newNode; if (stateNode->isScrollingNode()) - newNode = ScrollingTreeScrollingNode::create(this); + newNode = ScrollingTreeScrollingNode::create(this, nodeID); else if (stateNode->isFixedNode()) - newNode = ScrollingTreeFixedNode::create(this); + newNode = ScrollingTreeFixedNode::create(this, nodeID); + else if (stateNode->isStickyNode()) + newNode = ScrollingTreeStickyNode::create(this, nodeID); else ASSERT_NOT_REACHED(); - ScrollingTreeNode* newNodeRawPtr = newNode.get(); - m_nodeMap.set(stateNode->scrollingNodeID(), newNodeRawPtr); + + node = newNode.get(); + m_nodeMap.set(nodeID, node); ScrollingTreeNodeMap::const_iterator it = m_nodeMap.find(stateNode->parent()->scrollingNodeID()); ASSERT(it != m_nodeMap.end()); if (it != m_nodeMap.end()) { @@ -179,18 +206,18 @@ void ScrollingTree::updateTreeFromStateNode(ScrollingStateNode* stateNode) newNode->setParent(parent); parent->appendChild(newNode.release()); } - newNodeRawPtr->update(stateNode); + node->updateBeforeChildren(stateNode); } } // Now update the children if we have any. Vector<OwnPtr<ScrollingStateNode> >* stateNodeChildren = stateNode->children(); - if (!stateNodeChildren) - return; - - size_t size = stateNodeChildren->size(); - for (size_t i = 0; i < size; ++i) - updateTreeFromStateNode(stateNodeChildren->at(i).get()); + if (stateNodeChildren) { + size_t size = stateNodeChildren->size(); + for (size_t i = 0; i < size; ++i) + updateTreeFromStateNode(stateNodeChildren->at(i).get()); + } + node->updateAfterChildren(stateNode); } void ScrollingTree::removeDestroyedNodes(ScrollingStateTree* stateTree) @@ -206,12 +233,14 @@ void ScrollingTree::removeDestroyedNodes(ScrollingStateTree* stateTree) } } -void ScrollingTree::setMainFramePinState(bool pinnedToTheLeft, bool pinnedToTheRight) +void ScrollingTree::setMainFramePinState(bool pinnedToTheLeft, bool pinnedToTheRight, bool pinnedToTheTop, bool pinnedToTheBottom) { MutexLocker locker(m_swipeStateMutex); m_mainFramePinnedToTheLeft = pinnedToTheLeft; m_mainFramePinnedToTheRight = pinnedToTheRight; + m_mainFramePinnedToTheTop = pinnedToTheTop; + m_mainFramePinnedToTheBottom = pinnedToTheBottom; } void ScrollingTree::updateMainFrameScrollPosition(const IntPoint& scrollPosition, SetOrSyncScrollingLayerPosition scrollingLayerPositionAction) @@ -233,7 +262,7 @@ IntPoint ScrollingTree::mainFrameScrollPosition() return m_mainFrameScrollPosition; } -#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(DARWIN)) +#if PLATFORM(MAC) void ScrollingTree::handleWheelEventPhase(PlatformWheelEventPhase phase) { if (!m_scrollingCoordinator) @@ -257,12 +286,66 @@ bool ScrollingTree::canGoForward() return m_canGoForward; } +bool ScrollingTree::isRubberBandInProgress() +{ + MutexLocker lock(m_mutex); + + return m_mainFrameIsRubberBanding; +} + +void ScrollingTree::setMainFrameIsRubberBanding(bool isRubberBanding) +{ + MutexLocker locker(m_mutex); + + m_mainFrameIsRubberBanding = isRubberBanding; +} + +bool ScrollingTree::rubberBandsAtBottom() +{ + MutexLocker lock(m_swipeStateMutex); + + return m_rubberBandsAtBottom; +} + +void ScrollingTree::setRubberBandsAtBottom(bool rubberBandsAtBottom) +{ + MutexLocker locker(m_swipeStateMutex); + + m_rubberBandsAtBottom = rubberBandsAtBottom; +} + +bool ScrollingTree::rubberBandsAtTop() +{ + MutexLocker lock(m_swipeStateMutex); + + return m_rubberBandsAtTop; +} + +void ScrollingTree::setRubberBandsAtTop(bool rubberBandsAtTop) +{ + MutexLocker locker(m_swipeStateMutex); + + m_rubberBandsAtTop = rubberBandsAtTop; +} + +void ScrollingTree::setScrollPinningBehavior(ScrollPinningBehavior pinning) +{ + MutexLocker locker(m_swipeStateMutex); + + m_scrollPinningBehavior = pinning; +} + +ScrollPinningBehavior ScrollingTree::scrollPinningBehavior() +{ + MutexLocker lock(m_swipeStateMutex); + + return m_scrollPinningBehavior; +} + bool ScrollingTree::willWheelEventStartSwipeGesture(const PlatformWheelEvent& wheelEvent) { if (wheelEvent.phase() != PlatformWheelEventPhaseBegan) return false; - if (!wheelEvent.deltaX()) - return false; MutexLocker lock(m_swipeStateMutex); @@ -270,6 +353,10 @@ bool ScrollingTree::willWheelEventStartSwipeGesture(const PlatformWheelEvent& wh return true; if (wheelEvent.deltaX() < 0 && m_mainFramePinnedToTheRight && m_canGoForward) return true; + if (wheelEvent.deltaY() > 0 && m_mainFramePinnedToTheTop && !m_rubberBandsAtTop) + return true; + if (wheelEvent.deltaY() < 0 && m_mainFramePinnedToTheBottom && !m_rubberBandsAtBottom) + return true; return false; } diff --git a/Source/WebCore/page/scrolling/ScrollingTree.h b/Source/WebCore/page/scrolling/ScrollingTree.h index 5b679dc61..423eefd35 100644 --- a/Source/WebCore/page/scrolling/ScrollingTree.h +++ b/Source/WebCore/page/scrolling/ScrollingTree.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2013 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -71,6 +71,7 @@ public: // Returns true if the wheel event can be handled on the scrolling thread and false if the // event must be sent again to the WebCore event handler. EventResult tryToHandleWheelEvent(const PlatformWheelEvent&); + bool hasWheelEventHandlers() const { return m_hasWheelEventHandlers; } // Can be called from any thread. Will update the back forward state of the page, used for rubber-banding. void updateBackForwardState(bool canGoBack, bool canGoForward); @@ -78,35 +79,42 @@ public: // Must be called from the scrolling thread. Handles the wheel event. void handleWheelEvent(const PlatformWheelEvent&); + void setMainFrameIsRubberBanding(bool); + bool isRubberBandInProgress(); + void invalidate(); void commitNewTreeState(PassOwnPtr<ScrollingStateTree>); - void setMainFramePinState(bool pinnedToTheLeft, bool pinnedToTheRight); + void setMainFramePinState(bool pinnedToTheLeft, bool pinnedToTheRight, bool pinnedToTheTop, bool pinnedToTheBottom); void updateMainFrameScrollPosition(const IntPoint& scrollPosition, SetOrSyncScrollingLayerPosition = SyncScrollingLayerPosition); IntPoint mainFrameScrollPosition(); -#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(DARWIN)) +#if PLATFORM(MAC) void handleWheelEventPhase(PlatformWheelEventPhase); #endif bool canGoBack(); bool canGoForward(); - bool willWheelEventStartSwipeGesture(const PlatformWheelEvent&); + bool rubberBandsAtBottom(); + void setRubberBandsAtBottom(bool); + bool rubberBandsAtTop(); + void setRubberBandsAtTop(bool); + + void setScrollPinningBehavior(ScrollPinningBehavior); + ScrollPinningBehavior scrollPinningBehavior(); -#if PLATFORM(MAC) - void setDebugRootLayer(CALayer *); -#endif + bool willWheelEventStartSwipeGesture(const PlatformWheelEvent&); void setScrollingPerformanceLoggingEnabled(bool flag); bool scrollingPerformanceLoggingEnabled(); + ScrollingTreeScrollingNode* rootNode() const { return m_rootNode.get(); } + private: explicit ScrollingTree(ScrollingCoordinator*); - void updateDebugRootLayer(); - void removeDestroyedNodes(ScrollingStateTree*); void updateTreeFromStateNode(ScrollingStateNode*); @@ -126,14 +134,16 @@ private: bool m_canGoForward; bool m_mainFramePinnedToTheLeft; bool m_mainFramePinnedToTheRight; + bool m_rubberBandsAtBottom; + bool m_rubberBandsAtTop; + bool m_mainFramePinnedToTheTop; + bool m_mainFramePinnedToTheBottom; + bool m_mainFrameIsRubberBanding; + ScrollPinningBehavior m_scrollPinningBehavior; bool m_scrollingPerformanceLoggingEnabled; bool m_isHandlingProgrammaticScroll; - -#if PLATFORM(MAC) - RetainPtr<CALayer> m_debugInfoLayer; -#endif }; } // namespace WebCore diff --git a/Source/WebCore/page/scrolling/ScrollingTreeNode.cpp b/Source/WebCore/page/scrolling/ScrollingTreeNode.cpp index 81e4e4407..d810b408f 100644 --- a/Source/WebCore/page/scrolling/ScrollingTreeNode.cpp +++ b/Source/WebCore/page/scrolling/ScrollingTreeNode.cpp @@ -32,9 +32,9 @@ namespace WebCore { -ScrollingTreeNode::ScrollingTreeNode(ScrollingTree* scrollingTree) +ScrollingTreeNode::ScrollingTreeNode(ScrollingTree* scrollingTree, ScrollingNodeID nodeID) : m_scrollingTree(scrollingTree) - , m_nodeID(0) + , m_nodeID(nodeID) , m_parent(0) { } @@ -58,7 +58,11 @@ void ScrollingTreeNode::removeChild(ScrollingTreeNode* node) if (!m_children) return; - if (size_t index = m_children->find(node)) { + size_t index = m_children->find(node); + + // The index will be notFound if the node to remove is a deeper-than-1-level descendant or + // if node is the root state node. + if (index != notFound) { m_children->remove(index); return; } diff --git a/Source/WebCore/page/scrolling/ScrollingTreeNode.h b/Source/WebCore/page/scrolling/ScrollingTreeNode.h index 06027ad50..56e100d0e 100644 --- a/Source/WebCore/page/scrolling/ScrollingTreeNode.h +++ b/Source/WebCore/page/scrolling/ScrollingTreeNode.h @@ -41,15 +41,15 @@ class ScrollingStateScrollingNode; class ScrollingTreeNode { public: - explicit ScrollingTreeNode(ScrollingTree*); + explicit ScrollingTreeNode(ScrollingTree*, ScrollingNodeID); virtual ~ScrollingTreeNode(); - virtual void update(ScrollingStateNode*) = 0; + virtual void updateBeforeChildren(ScrollingStateNode*) = 0; + virtual void updateAfterChildren(ScrollingStateNode*) { } - virtual void parentScrollPositionDidChange(const IntRect& viewportRect) = 0; + virtual void parentScrollPositionDidChange(const IntRect& viewportRect, const FloatSize& cumulativeDelta) = 0; ScrollingNodeID scrollingNodeID() const { return m_nodeID; } - void setScrollingNodeID(ScrollingNodeID nodeID) { m_nodeID = nodeID; } ScrollingTreeNode* parent() const { return m_parent; } void setParent(ScrollingTreeNode* parent) { m_parent = parent; } diff --git a/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.cpp b/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.cpp index 9d73f25f9..b99534e16 100644 --- a/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.cpp +++ b/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.cpp @@ -32,8 +32,9 @@ namespace WebCore { -ScrollingTreeScrollingNode::ScrollingTreeScrollingNode(ScrollingTree* scrollingTree) - : ScrollingTreeNode(scrollingTree) +ScrollingTreeScrollingNode::ScrollingTreeScrollingNode(ScrollingTree* scrollingTree, ScrollingNodeID nodeID) + : ScrollingTreeNode(scrollingTree, nodeID) + , m_frameScaleFactor(1) , m_shouldUpdateScrollLayerPositionOnMainThread(0) , m_horizontalScrollElasticity(ScrollElasticityNone) , m_verticalScrollElasticity(ScrollElasticityNone) @@ -41,6 +42,8 @@ ScrollingTreeScrollingNode::ScrollingTreeScrollingNode(ScrollingTree* scrollingT , m_hasEnabledVerticalScrollbar(false) , m_horizontalScrollbarMode(ScrollbarAuto) , m_verticalScrollbarMode(ScrollbarAuto) + , m_headerHeight(0) + , m_footerHeight(0) { } @@ -48,39 +51,48 @@ ScrollingTreeScrollingNode::~ScrollingTreeScrollingNode() { } -void ScrollingTreeScrollingNode::update(ScrollingStateNode* stateNode) +void ScrollingTreeScrollingNode::updateBeforeChildren(ScrollingStateNode* stateNode) { ScrollingStateScrollingNode* state = toScrollingStateScrollingNode(stateNode); - if (state->changedProperties() & ScrollingStateScrollingNode::ViewportRect) + if (state->hasChangedProperty(ScrollingStateScrollingNode::ViewportRect)) m_viewportRect = state->viewportRect(); - if (state->changedProperties() & ScrollingStateScrollingNode::ContentsSize) - m_contentsSize = state->contentsSize(); + if (state->hasChangedProperty(ScrollingStateScrollingNode::TotalContentsSize)) + m_totalContentsSize = state->totalContentsSize(); - if (state->changedProperties() & ScrollingStateScrollingNode::ShouldUpdateScrollLayerPositionOnMainThread) + if (state->hasChangedProperty(ScrollingStateScrollingNode::FrameScaleFactor)) + m_frameScaleFactor = state->frameScaleFactor(); + + if (state->hasChangedProperty(ScrollingStateScrollingNode::ShouldUpdateScrollLayerPositionOnMainThread)) m_shouldUpdateScrollLayerPositionOnMainThread = state->shouldUpdateScrollLayerPositionOnMainThread(); - if (state->changedProperties() & ScrollingStateScrollingNode::HorizontalScrollElasticity) + if (state->hasChangedProperty(ScrollingStateScrollingNode::HorizontalScrollElasticity)) m_horizontalScrollElasticity = state->horizontalScrollElasticity(); - if (state->changedProperties() & ScrollingStateScrollingNode::VerticalScrollElasticity) + if (state->hasChangedProperty(ScrollingStateScrollingNode::VerticalScrollElasticity)) m_verticalScrollElasticity = state->verticalScrollElasticity(); - if (state->changedProperties() & ScrollingStateScrollingNode::HasEnabledHorizontalScrollbar) + if (state->hasChangedProperty(ScrollingStateScrollingNode::HasEnabledHorizontalScrollbar)) m_hasEnabledHorizontalScrollbar = state->hasEnabledHorizontalScrollbar(); - if (state->changedProperties() & ScrollingStateScrollingNode::HasEnabledVerticalScrollbar) + if (state->hasChangedProperty(ScrollingStateScrollingNode::HasEnabledVerticalScrollbar)) m_hasEnabledVerticalScrollbar = state->hasEnabledVerticalScrollbar(); - if (state->changedProperties() & ScrollingStateScrollingNode::HorizontalScrollbarMode) + if (state->hasChangedProperty(ScrollingStateScrollingNode::HorizontalScrollbarMode)) m_horizontalScrollbarMode = state->horizontalScrollbarMode(); - if (state->changedProperties() & ScrollingStateScrollingNode::VerticalScrollbarMode) + if (state->hasChangedProperty(ScrollingStateScrollingNode::VerticalScrollbarMode)) m_verticalScrollbarMode = state->verticalScrollbarMode(); - if (state->changedProperties() & ScrollingStateScrollingNode::ScrollOrigin) + if (state->hasChangedProperty(ScrollingStateScrollingNode::ScrollOrigin)) m_scrollOrigin = state->scrollOrigin(); + + if (state->hasChangedProperty(ScrollingStateScrollingNode::HeaderHeight)) + m_headerHeight = state->headerHeight(); + + if (state->hasChangedProperty(ScrollingStateScrollingNode::FooterHeight)) + m_footerHeight = state->footerHeight(); } } // namespace WebCore diff --git a/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.h b/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.h index 7b62fd8e7..ce7f16709 100644 --- a/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.h +++ b/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.h @@ -42,13 +42,13 @@ class ScrollingStateScrollingNode; class ScrollingTreeScrollingNode : public ScrollingTreeNode { public: - static PassOwnPtr<ScrollingTreeScrollingNode> create(ScrollingTree*); + static PassOwnPtr<ScrollingTreeScrollingNode> create(ScrollingTree*, ScrollingNodeID); virtual ~ScrollingTreeScrollingNode(); - virtual void update(ScrollingStateNode*) OVERRIDE; + virtual void updateBeforeChildren(ScrollingStateNode*) OVERRIDE; // FIXME: We should implement this when we support ScrollingTreeScrollingNodes as children. - virtual void parentScrollPositionDidChange(const IntRect& /*viewportRect*/) OVERRIDE { } + virtual void parentScrollPositionDidChange(const IntRect& /*viewportRect*/, const FloatSize& /*cumulativeDelta*/) OVERRIDE { } virtual void handleWheelEvent(const PlatformWheelEvent&) = 0; virtual void setScrollPosition(const IntPoint&) = 0; @@ -56,10 +56,12 @@ public: MainThreadScrollingReasons shouldUpdateScrollLayerPositionOnMainThread() const { return m_shouldUpdateScrollLayerPositionOnMainThread; } protected: - explicit ScrollingTreeScrollingNode(ScrollingTree*); + explicit ScrollingTreeScrollingNode(ScrollingTree*, ScrollingNodeID); const IntRect& viewportRect() const { return m_viewportRect; } - const IntSize& contentsSize() const { return m_contentsSize; } + const IntSize& totalContentsSize() const { return m_totalContentsSize; } + + float frameScaleFactor() const { return m_frameScaleFactor; } ScrollElasticity horizontalScrollElasticity() const { return m_horizontalScrollElasticity; } ScrollElasticity verticalScrollElasticity() const { return m_verticalScrollElasticity; } @@ -71,10 +73,15 @@ protected: const IntPoint& scrollOrigin() const { return m_scrollOrigin; } + int headerHeight() const { return m_headerHeight; } + int footerHeight() const { return m_footerHeight; } + private: IntRect m_viewportRect; - IntSize m_contentsSize; + IntSize m_totalContentsSize; IntPoint m_scrollOrigin; + + float m_frameScaleFactor; MainThreadScrollingReasons m_shouldUpdateScrollLayerPositionOnMainThread; @@ -86,6 +93,9 @@ private: ScrollbarMode m_horizontalScrollbarMode; ScrollbarMode m_verticalScrollbarMode; + + int m_headerHeight; + int m_footerHeight; }; } // namespace WebCore diff --git a/Source/WebCore/page/scrolling/blackberry/ScrollingCoordinatorBlackBerry.cpp b/Source/WebCore/page/scrolling/blackberry/ScrollingCoordinatorBlackBerry.cpp new file mode 100644 index 000000000..39d902711 --- /dev/null +++ b/Source/WebCore/page/scrolling/blackberry/ScrollingCoordinatorBlackBerry.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2013 Research In Motion Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ScrollingCoordinatorBlackBerry.h" + +#include "Frame.h" +#include "FrameView.h" +#include "LayerWebKitThread.h" +#include "Page.h" +#include "PlatformLayer.h" +#include "RenderLayerCompositor.h" +#include "RenderView.h" + +namespace WebCore { + +ScrollingCoordinatorBlackBerry::ScrollingCoordinatorBlackBerry(Page* page) + : ScrollingCoordinator(page) +{ +} + +void ScrollingCoordinatorBlackBerry::setLayerIsContainerForFixedPositionLayers(GraphicsLayer* layer, bool isContainer) +{ + // We don't want to set this for the main frame, the main frame would be treated like a subframe + // by the LayerRenderer which would result in incorrect positioning. + if (m_page->mainFrame() && scrollLayerForFrameView(m_page->mainFrame()->view()) == layer) + isContainer = false; + + if (layer->platformLayer()) + layer->platformLayer()->setIsContainerForFixedPositionLayers(isContainer); +} + +void ScrollingCoordinatorBlackBerry::setLayerIsFixedToContainerLayer(GraphicsLayer* layer, bool isFixed) +{ + if (layer->platformLayer()) + layer->platformLayer()->setFixedPosition(isFixed); +} + +void ScrollingCoordinatorBlackBerry::setLayerFixedToContainerLayerEdge(GraphicsLayer* layer, bool fixedToTop, bool fixedToLeft) +{ + if (!layer->platformLayer()) + return; + + layer->platformLayer()->setFixedToTop(fixedToTop); + layer->platformLayer()->setFixedToLeft(fixedToLeft); +} + +void ScrollingCoordinatorBlackBerry::frameViewLayoutUpdated(FrameView* frameView) +{ + if (GraphicsLayer* scrollLayer = scrollLayerForFrameView(frameView)) { + scrollLayer->platformLayer()->setFrameContentsSize(frameView->contentsSize()); + scrollLayer->platformLayer()->setFrameVisibleRect(frameView->visibleContentRect()); + } +} + +} diff --git a/Source/WebCore/page/scrolling/chromium/ScrollingCoordinatorChromium.h b/Source/WebCore/page/scrolling/blackberry/ScrollingCoordinatorBlackBerry.h index f6948e240..1e6fcd509 100644 --- a/Source/WebCore/page/scrolling/chromium/ScrollingCoordinatorChromium.h +++ b/Source/WebCore/page/scrolling/blackberry/ScrollingCoordinatorBlackBerry.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Apple Inc. All rights reserved. + * Copyright (C) 2013 Research In Motion Limited. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,38 +23,20 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ScrollingCoordinatorChromium_h -#define ScrollingCoordinatorChromium_h +#ifndef ScrollingCoordinatorBlackBerry_h +#define ScrollingCoordinatorBlackBerry_h #include "ScrollingCoordinator.h" -namespace WebKit { -class WebScrollbarLayer; -class WebLayer; -} - namespace WebCore { -class Scrollbar; -class ScrollingCoordinatorPrivate; - -class ScrollingCoordinatorChromium : public ScrollingCoordinator { +class ScrollingCoordinatorBlackBerry : public ScrollingCoordinator { public: - explicit ScrollingCoordinatorChromium(Page*); - virtual ~ScrollingCoordinatorChromium(); + explicit ScrollingCoordinatorBlackBerry(Page*); // Should be called whenever the given frame view has been laid out. virtual void frameViewLayoutUpdated(FrameView*); - // Should be called whenever the root layer for the given frame view changes. - virtual void frameViewRootLayerDidChange(FrameView*); - - // Should be called whenever the horizontal scrollbar layer for the given frame view changes. - virtual void frameViewHorizontalScrollbarLayerDidChange(FrameView*, GraphicsLayer*); - - // Should be called whenever the vertical scrollbar layer for the given frame view changes. - virtual void frameViewVerticalScrollbarLayerDidChange(FrameView*, GraphicsLayer*); - // Return whether this scrolling coordinator can keep fixed position layers fixed to their // containers while scrolling. virtual bool supportsFixedPositionLayers() const { return true; } @@ -65,21 +47,10 @@ public: // Attach/detach layer position to ancestor fixed position container. virtual void setLayerIsFixedToContainerLayer(GraphicsLayer*, bool); - // Should be called whenever the scrollable layer for the given scroll area changes. - virtual void scrollableAreaScrollLayerDidChange(ScrollableArea*, GraphicsLayer*); - -private: - virtual void recomputeWheelEventHandlerCountForFrameView(FrameView*); - virtual void setShouldUpdateScrollLayerPositionOnMainThread(MainThreadScrollingReasons); - - void setScrollLayer(GraphicsLayer*); - void setNonFastScrollableRegion(const Region&); - void setWheelEventHandlerCount(unsigned); - PassOwnPtr<WebKit::WebScrollbarLayer> createScrollbarLayer(Scrollbar*, WebKit::WebLayer* scrollLayer, GraphicsLayer* scrollbarGraphicsLayer, FrameView*); - - ScrollingCoordinatorPrivate* m_private; + // Whether the layer is fixed the top or bottom edge, left or right edge. + void setLayerFixedToContainerLayerEdge(GraphicsLayer*, bool fixedToTop, bool fixedToLeft); }; } // namespace WebCore -#endif // ScrollingCoordinatorChromium_h +#endif // ScrollingCoordinatorBlackBerry_h diff --git a/Source/WebCore/page/scrolling/chromium/ScrollingCoordinatorChromium.cpp b/Source/WebCore/page/scrolling/chromium/ScrollingCoordinatorChromium.cpp deleted file mode 100644 index 9743289c1..000000000 --- a/Source/WebCore/page/scrolling/chromium/ScrollingCoordinatorChromium.cpp +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Copyright (C) 2012 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" - -#include "ScrollingCoordinatorChromium.h" - -#include "Frame.h" -#include "FrameView.h" -#include "GraphicsLayerChromium.h" -#include "Page.h" -#include "Region.h" -#include "RenderLayerCompositor.h" -#include "RenderView.h" -#include "ScrollbarThemeComposite.h" -#include "WebScrollbarImpl.h" -#include "WebScrollbarThemeGeometryNative.h" -#include <public/Platform.h> -#include <public/WebCompositorSupport.h> -#include <public/WebScrollbar.h> -#include <public/WebScrollbarLayer.h> -#include <public/WebScrollbarThemeGeometry.h> -#include <public/WebScrollbarThemePainter.h> - -using WebKit::WebLayer; -using WebKit::WebRect; -using WebKit::WebScrollbarLayer; -using WebKit::WebVector; - -namespace WebCore { - -class ScrollingCoordinatorPrivate { -WTF_MAKE_NONCOPYABLE(ScrollingCoordinatorPrivate); -public: - ScrollingCoordinatorPrivate() - : m_scrollLayer(0) - { - } - - ~ScrollingCoordinatorPrivate() - { - if (m_horizontalScrollbarLayer) - GraphicsLayerChromium::unregisterContentsLayer(m_horizontalScrollbarLayer->layer()); - if (m_verticalScrollbarLayer) - GraphicsLayerChromium::unregisterContentsLayer(m_verticalScrollbarLayer->layer()); - } - - void setScrollLayer(WebLayer* layer) - { - m_scrollLayer = layer; - - if (m_horizontalScrollbarLayer) - m_horizontalScrollbarLayer->setScrollLayer(layer); - if (m_verticalScrollbarLayer) - m_verticalScrollbarLayer->setScrollLayer(layer); - } - - void setHorizontalScrollbarLayer(PassOwnPtr<WebScrollbarLayer> layer) - { - m_horizontalScrollbarLayer = layer; - } - - void setVerticalScrollbarLayer(PassOwnPtr<WebScrollbarLayer> layer) - { - m_verticalScrollbarLayer = layer; - } - - WebLayer* scrollLayer() const { return m_scrollLayer; } - -private: - WebLayer* m_scrollLayer; - OwnPtr<WebScrollbarLayer> m_horizontalScrollbarLayer; - OwnPtr<WebScrollbarLayer> m_verticalScrollbarLayer; -}; - -ScrollingCoordinatorChromium::ScrollingCoordinatorChromium(Page* page) - : ScrollingCoordinator(page) - , m_private(new ScrollingCoordinatorPrivate) -{ -} - -ScrollingCoordinatorChromium::~ScrollingCoordinatorChromium() -{ - delete m_private; -} - -void ScrollingCoordinatorChromium::frameViewLayoutUpdated(FrameView*) -{ - ASSERT(m_page); - - // Compute the region of the page that we can't do fast scrolling for. This currently includes - // all scrollable areas, such as subframes, overflow divs and list boxes. We need to do this even if the - // frame view whose layout was updated is not the main frame. - Region nonFastScrollableRegion = computeNonFastScrollableRegion(m_page->mainFrame(), IntPoint()); - setNonFastScrollableRegion(nonFastScrollableRegion); -} - -void ScrollingCoordinatorChromium::frameViewRootLayerDidChange(FrameView* frameView) -{ - ScrollingCoordinator::frameViewRootLayerDidChange(frameView); - setScrollLayer(scrollLayerForFrameView(frameView)); -} - -static WebLayer* scrollableLayerForGraphicsLayer(GraphicsLayer* layer) -{ - return layer->platformLayer(); -} - -PassOwnPtr<WebScrollbarLayer> ScrollingCoordinatorChromium::createScrollbarLayer(Scrollbar* scrollbar, WebLayer* scrollLayer, GraphicsLayer* scrollbarGraphicsLayer, FrameView* frameView) -{ - ASSERT(scrollbar); - ASSERT(scrollbarGraphicsLayer); - - if (!scrollLayer) { - // FIXME: sometimes we get called before setScrollLayer, workaround by finding the scroll layout ourselves. - scrollLayer = scrollableLayerForGraphicsLayer(scrollLayerForFrameView(frameView)); - ASSERT(scrollLayer); - } - - // Root layer non-overlay scrollbars should be marked opaque to disable - // blending. - bool isOpaqueRootScrollbar = !frameView->parent() && !scrollbar->isOverlayScrollbar(); - if (!scrollbarGraphicsLayer->contentsOpaque()) - scrollbarGraphicsLayer->setContentsOpaque(isOpaqueRootScrollbar); - - // FIXME: Mac scrollbar themes are not thread-safe to paint. - bool platformSupported = true; -#if OS(DARWIN) - platformSupported = false; -#endif - - if (!platformSupported || scrollbar->isCustomScrollbar()) { - scrollbarGraphicsLayer->setContentsToMedia(0); - scrollbarGraphicsLayer->setDrawsContent(true); - return nullptr; - } - - // All Chromium scrollbar themes derive from ScrollbarThemeComposite. - ScrollbarThemeComposite* themeComposite = static_cast<ScrollbarThemeComposite*>(scrollbar->theme()); - WebKit::WebScrollbarThemePainter painter(themeComposite, scrollbar); - OwnPtr<WebKit::WebScrollbarThemeGeometry> geometry(WebKit::WebScrollbarThemeGeometryNative::create(themeComposite)); - - OwnPtr<WebScrollbarLayer> scrollbarLayer = adoptPtr(WebKit::Platform::current()->compositorSupport()->createScrollbarLayer(new WebKit::WebScrollbarImpl(scrollbar), painter, geometry.leakPtr())); - scrollbarLayer->setScrollLayer(scrollLayer); - - GraphicsLayerChromium::registerContentsLayer(scrollbarLayer->layer()); - scrollbarGraphicsLayer->setContentsToMedia(scrollbarLayer->layer()); - scrollbarGraphicsLayer->setDrawsContent(false); - scrollbarLayer->layer()->setOpaque(scrollbarGraphicsLayer->contentsOpaque()); - - return scrollbarLayer.release(); -} - -void ScrollingCoordinatorChromium::frameViewHorizontalScrollbarLayerDidChange(FrameView* frameView, GraphicsLayer* horizontalScrollbarLayer) -{ - if (!horizontalScrollbarLayer || !coordinatesScrollingForFrameView(frameView)) - return; - - setScrollLayer(scrollLayerForFrameView(m_page->mainFrame()->view())); - m_private->setHorizontalScrollbarLayer(createScrollbarLayer(frameView->horizontalScrollbar(), m_private->scrollLayer(), horizontalScrollbarLayer, frameView)); -} - -void ScrollingCoordinatorChromium::frameViewVerticalScrollbarLayerDidChange(FrameView* frameView, GraphicsLayer* verticalScrollbarLayer) -{ - if (!verticalScrollbarLayer || !coordinatesScrollingForFrameView(frameView)) - return; - - setScrollLayer(scrollLayerForFrameView(m_page->mainFrame()->view())); - m_private->setVerticalScrollbarLayer(createScrollbarLayer(frameView->verticalScrollbar(), m_private->scrollLayer(), verticalScrollbarLayer, frameView)); -} - -void ScrollingCoordinatorChromium::setScrollLayer(GraphicsLayer* scrollLayer) -{ - m_private->setScrollLayer(scrollLayer ? scrollableLayerForGraphicsLayer(scrollLayer) : 0); -} - -void ScrollingCoordinatorChromium::setNonFastScrollableRegion(const Region& region) -{ - // We won't necessarily get a setScrollLayer() call before this one, so grab the root ourselves. - setScrollLayer(scrollLayerForFrameView(m_page->mainFrame()->view())); - if (m_private->scrollLayer()) { - Vector<IntRect> rects = region.rects(); - WebVector<WebRect> webRects(rects.size()); - for (size_t i = 0; i < rects.size(); ++i) - webRects[i] = rects[i]; - m_private->scrollLayer()->setNonFastScrollableRegion(webRects); - } -} - -void ScrollingCoordinatorChromium::setWheelEventHandlerCount(unsigned wheelEventHandlerCount) -{ - // We won't necessarily get a setScrollLayer() call before this one, so grab the root ourselves. - setScrollLayer(scrollLayerForFrameView(m_page->mainFrame()->view())); - if (m_private->scrollLayer()) - m_private->scrollLayer()->setHaveWheelEventHandlers(wheelEventHandlerCount > 0); -} - -void ScrollingCoordinatorChromium::setShouldUpdateScrollLayerPositionOnMainThread(MainThreadScrollingReasons reasons) -{ - // We won't necessarily get a setScrollLayer() call before this one, so grab the root ourselves. - setScrollLayer(scrollLayerForFrameView(m_page->mainFrame()->view())); - if (m_private->scrollLayer()) - m_private->scrollLayer()->setShouldScrollOnMainThread(reasons); -} - -void ScrollingCoordinatorChromium::setLayerIsContainerForFixedPositionLayers(GraphicsLayer* layer, bool enable) -{ - if (WebLayer* scrollableLayer = scrollableLayerForGraphicsLayer(layer)) - scrollableLayer->setIsContainerForFixedPositionLayers(enable); -} - -void ScrollingCoordinatorChromium::setLayerIsFixedToContainerLayer(GraphicsLayer* layer, bool enable) -{ - if (WebLayer* scrollableLayer = scrollableLayerForGraphicsLayer(layer)) - scrollableLayer->setFixedToContainerLayer(enable); -} - -void ScrollingCoordinatorChromium::scrollableAreaScrollLayerDidChange(ScrollableArea* scrollableArea, GraphicsLayer* scrollLayer) -{ - if (!scrollLayer) - return; - GraphicsLayerChromium* layer = static_cast<GraphicsLayerChromium*>(scrollLayer); - layer->setScrollableArea(scrollableArea); - - if (WebLayer* webLayer = scrollLayer->platformLayer()) { - webLayer->setScrollable(true); - webLayer->setScrollPosition(scrollableArea->scrollPosition()); - webLayer->setMaxScrollPosition(IntSize(scrollableArea->scrollSize(HorizontalScrollbar), scrollableArea->scrollSize(VerticalScrollbar))); - } -} - -void ScrollingCoordinatorChromium::recomputeWheelEventHandlerCountForFrameView(FrameView* frameView) -{ - UNUSED_PARAM(frameView); - setWheelEventHandlerCount(computeCurrentWheelEventHandlerCount()); -} - -} diff --git a/Source/WebCore/page/scrolling/coordinatedgraphics/ScrollingCoordinatorCoordinatedGraphics.cpp b/Source/WebCore/page/scrolling/coordinatedgraphics/ScrollingCoordinatorCoordinatedGraphics.cpp new file mode 100644 index 000000000..40b3492da --- /dev/null +++ b/Source/WebCore/page/scrolling/coordinatedgraphics/ScrollingCoordinatorCoordinatedGraphics.cpp @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if USE(COORDINATED_GRAPHICS) + +#include "ScrollingCoordinatorCoordinatedGraphics.h" + +#include "CoordinatedGraphicsLayer.h" +#include "FrameView.h" +#include "Page.h" +#include "RenderLayer.h" +#include "RenderLayerBacking.h" +#include "ScrollingConstraints.h" +#include "ScrollingStateFixedNode.h" +#include "ScrollingStateScrollingNode.h" +#include "ScrollingStateStickyNode.h" +#include "ScrollingStateTree.h" +#include "Settings.h" + +namespace WebCore { + +ScrollingCoordinatorCoordinatedGraphics::ScrollingCoordinatorCoordinatedGraphics(Page* page) + : ScrollingCoordinator(page) + , m_scrollingStateTree(ScrollingStateTree::create()) +{ +} + +ScrollingCoordinatorCoordinatedGraphics::~ScrollingCoordinatorCoordinatedGraphics() +{ +} + +ScrollingNodeID ScrollingCoordinatorCoordinatedGraphics::attachToStateTree(ScrollingNodeType nodeType, ScrollingNodeID newNodeID, ScrollingNodeID parentID) +{ + return m_scrollingStateTree->attachNode(nodeType, newNodeID, parentID); +} + +void ScrollingCoordinatorCoordinatedGraphics::detachFromStateTree(ScrollingNodeID nodeID) +{ + ScrollingStateNode* node = m_scrollingStateTree->stateNodeForID(nodeID); + if (node && node->isFixedNode()) + toCoordinatedGraphicsLayer(node->graphicsLayer())->setFixedToViewport(false); + + m_scrollingStateTree->detachNode(nodeID); +} + +void ScrollingCoordinatorCoordinatedGraphics::clearStateTree() +{ + m_scrollingStateTree->clear(); +} + +void ScrollingCoordinatorCoordinatedGraphics::updateViewportConstrainedNode(ScrollingNodeID nodeID, const ViewportConstraints& constraints, GraphicsLayer* graphicsLayer) +{ + ASSERT(supportsFixedPositionLayers()); + + ScrollingStateNode* node = m_scrollingStateTree->stateNodeForID(nodeID); + if (!node) + return; + + switch (constraints.constraintType()) { + case ViewportConstraints::FixedPositionConstaint: { + toCoordinatedGraphicsLayer(graphicsLayer)->setFixedToViewport(true); // FIXME : Use constraints! + ScrollingStateFixedNode* fixedNode = toScrollingStateFixedNode(node); + fixedNode->setScrollLayer(graphicsLayer); + break; + } + case ViewportConstraints::StickyPositionConstraint: + break; // FIXME : Support sticky elements. + default: + ASSERT_NOT_REACHED(); + } +} + +void ScrollingCoordinatorCoordinatedGraphics::scrollableAreaScrollLayerDidChange(ScrollableArea* scrollableArea) +{ + CoordinatedGraphicsLayer* layer = toCoordinatedGraphicsLayer(scrollLayerForScrollableArea(scrollableArea)); + if (!layer) + return; + + layer->setScrollableArea(scrollableArea); +} + +void ScrollingCoordinatorCoordinatedGraphics::willDestroyScrollableArea(ScrollableArea* scrollableArea) +{ + CoordinatedGraphicsLayer* layer = toCoordinatedGraphicsLayer(scrollLayerForScrollableArea(scrollableArea)); + if (!layer) + return; + + layer->setScrollableArea(0); +} + +} // namespace WebCore + +#endif // USE(COORDINATED_GRAPHICS) diff --git a/Source/WebCore/page/scrolling/coordinatedgraphics/ScrollingCoordinatorCoordinatedGraphics.h b/Source/WebCore/page/scrolling/coordinatedgraphics/ScrollingCoordinatorCoordinatedGraphics.h new file mode 100644 index 000000000..6e84bc0bc --- /dev/null +++ b/Source/WebCore/page/scrolling/coordinatedgraphics/ScrollingCoordinatorCoordinatedGraphics.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ScrollingCoordinatorCoordinatedGraphics_h +#define ScrollingCoordinatorCoordinatedGraphics_h + +#if USE(COORDINATED_GRAPHICS) + +#include "ScrollingCoordinator.h" + +namespace WebCore { + +class ScrollingStateTree; + +class ScrollingCoordinatorCoordinatedGraphics : public ScrollingCoordinator { +public: + explicit ScrollingCoordinatorCoordinatedGraphics(Page*); + virtual ~ScrollingCoordinatorCoordinatedGraphics(); + + virtual bool supportsFixedPositionLayers() const OVERRIDE { return true; } + + virtual ScrollingNodeID attachToStateTree(ScrollingNodeType, ScrollingNodeID newNodeID, ScrollingNodeID parentID) OVERRIDE; + virtual void detachFromStateTree(ScrollingNodeID) OVERRIDE; + virtual void clearStateTree() OVERRIDE; + + virtual void updateViewportConstrainedNode(ScrollingNodeID, const ViewportConstraints&, GraphicsLayer*) OVERRIDE; + + virtual void scrollableAreaScrollLayerDidChange(ScrollableArea*) OVERRIDE; + virtual void willDestroyScrollableArea(ScrollableArea*) OVERRIDE; + +private: + OwnPtr<ScrollingStateTree> m_scrollingStateTree; +}; + +} // namespace WebCore + +#endif // USE(COORDINATED_GRAPHICS) + +#endif // ScrollingCoordinatorCoordinatedGraphics_h diff --git a/Source/WebCore/page/scrolling/coordinatedgraphics/ScrollingStateNodeCoordinatedGraphics.cpp b/Source/WebCore/page/scrolling/coordinatedgraphics/ScrollingStateNodeCoordinatedGraphics.cpp new file mode 100644 index 000000000..f2e48b5bf --- /dev/null +++ b/Source/WebCore/page/scrolling/coordinatedgraphics/ScrollingStateNodeCoordinatedGraphics.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2013 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ScrollingStateNode.h" + +#include "GraphicsLayer.h" +#include "NotImplemented.h" +#include "ScrollingStateTree.h" + +#if USE(COORDINATED_GRAPHICS) + +namespace WebCore { + +PlatformLayer* ScrollingStateNode::platformScrollLayer() const +{ + notImplemented(); + return 0; +} + +void ScrollingStateNode::setScrollPlatformLayer(PlatformLayer*) +{ + notImplemented(); +} + +void ScrollingStateNode::setScrollLayer(GraphicsLayer* graphicsLayer) +{ + m_graphicsLayer = graphicsLayer; +} + +} // namespace WebCore + +#endif // USE(COORDINATED_GRAPHICS) diff --git a/Source/WebCore/page/scrolling/coordinatedgraphics/ScrollingStateScrollingNodeCoordinatedGraphics.cpp b/Source/WebCore/page/scrolling/coordinatedgraphics/ScrollingStateScrollingNodeCoordinatedGraphics.cpp new file mode 100644 index 000000000..e85460dba --- /dev/null +++ b/Source/WebCore/page/scrolling/coordinatedgraphics/ScrollingStateScrollingNodeCoordinatedGraphics.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2013 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ScrollingStateScrollingNode.h" + +#include "GraphicsLayer.h" + +#if USE(COORDINATED_GRAPHICS) + +namespace WebCore { + +PlatformLayer* ScrollingStateScrollingNode::counterScrollingPlatformLayer() const +{ + ASSERT_NOT_REACHED(); // ScrollingStateTree in coord graphics is used only to handle constrained elements. + return 0; +} + +void ScrollingStateScrollingNode::setCounterScrollingLayer(GraphicsLayer*) +{ + ASSERT_NOT_REACHED(); // ScrollingStateTree in coord graphics is used only to handle constrained elements. +} + +PlatformLayer* ScrollingStateScrollingNode::headerPlatformLayer() const +{ + ASSERT_NOT_REACHED(); // ScrollingStateTree in coord graphics is used only to handle constrained elements. + return 0; +} + +void ScrollingStateScrollingNode::setHeaderLayer(GraphicsLayer*) +{ + ASSERT_NOT_REACHED(); // ScrollingStateTree in coord graphics is used only to handle constrained elements. +} + +PlatformLayer* ScrollingStateScrollingNode::footerPlatformLayer() const +{ + ASSERT_NOT_REACHED(); // ScrollingStateTree in coord graphics is used only to handle constrained elements. + return 0; +} + +void ScrollingStateScrollingNode::setFooterLayer(GraphicsLayer*) +{ + ASSERT_NOT_REACHED(); // ScrollingStateTree in coord graphics is used only to handle constrained elements. +} + +} // namespace WebCore + +#endif // USE(COORDINATED_GRAPHICS) diff --git a/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.h b/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.h index 10f235fa7..038fb5fbb 100644 --- a/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.h +++ b/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.h @@ -52,11 +52,8 @@ public: // Should be called whenever the root layer for the given frame view changes. virtual void frameViewRootLayerDidChange(FrameView*); - // Should be called whenever the horizontal scrollbar layer for the given frame view changes. - virtual void frameViewHorizontalScrollbarLayerDidChange(FrameView*, GraphicsLayer* horizontalScrollbarLayer); - - // Should be called whenever the vertical scrollbar layer for the given frame view changes. - virtual void frameViewVerticalScrollbarLayerDidChange(FrameView*, GraphicsLayer* verticalScrollbarLayer); + // Should be called whenever the scrollbar layer for the given scrollable area changes. + virtual void scrollableAreaScrollbarLayerDidChange(ScrollableArea*, ScrollbarOrientation); // Requests that the scrolling coordinator updates the scroll position of the given frame view. If this function returns true, it means that the // position will be updated asynchronously. If it returns false, the caller should update the scrolling position itself. @@ -75,6 +72,14 @@ public: virtual String scrollingStateTreeAsText() const OVERRIDE; + virtual bool isRubberBandInProgress() const OVERRIDE; + virtual bool rubberBandsAtBottom() const OVERRIDE; + virtual void setRubberBandsAtBottom(bool) OVERRIDE; + virtual bool rubberBandsAtTop() const OVERRIDE; + virtual void setRubberBandsAtTop(bool) OVERRIDE; + + virtual void setScrollPinningBehavior(ScrollPinningBehavior) OVERRIDE; + private: // Return whether this scrolling coordinator can keep fixed position layers fixed to their // containers while scrolling. @@ -83,16 +88,17 @@ private: // This function will update the ScrollingStateNode for the given viewport constrained object. virtual void updateViewportConstrainedNode(ScrollingNodeID, const ViewportConstraints&, GraphicsLayer*) OVERRIDE; + virtual void updateScrollingNode(ScrollingNodeID, GraphicsLayer* scrollLayer, GraphicsLayer* counterScrollingLayer) OVERRIDE; + // Called to synch the GraphicsLayer positions for child layers when their CALayers have been moved by the scrolling thread. virtual void syncChildPositions(const LayoutRect& viewportRect) OVERRIDE; virtual void recomputeWheelEventHandlerCountForFrameView(FrameView*); virtual void setShouldUpdateScrollLayerPositionOnMainThread(MainThreadScrollingReasons); - virtual bool hasVisibleSlowRepaintFixedObjects(FrameView*) const { return false; } + virtual bool hasVisibleSlowRepaintViewportConstrainedObjects(FrameView*) const { return false; } void ensureRootStateNodeForFrameView(FrameView*); - ScrollingStateNode* stateNodeForID(ScrollingNodeID); struct ScrollParameters { ScrollElasticity horizontalScrollElasticity; @@ -107,11 +113,19 @@ private: IntPoint scrollOrigin; IntRect viewportRect; - IntSize contentsSize; + IntSize totalContentsSize; + + float frameScaleFactor; + + int headerHeight; + int footerHeight; }; void setScrollParametersForNode(const ScrollParameters&, ScrollingStateScrollingNode*); void setScrollLayerForNode(GraphicsLayer*, ScrollingStateNode*); + void setCounterScrollingLayerForNode(GraphicsLayer*, ScrollingStateScrollingNode*); + void setHeaderLayerForNode(GraphicsLayer*, ScrollingStateScrollingNode*); + void setFooterLayerForNode(GraphicsLayer*, ScrollingStateScrollingNode*); void setNonFastScrollableRegionForNode(const Region&, ScrollingStateScrollingNode*); void setWheelEventHandlerCountForNode(unsigned, ScrollingStateScrollingNode*); @@ -122,13 +136,9 @@ private: void scrollingStateTreeCommitterTimerFired(Timer<ScrollingCoordinatorMac>*); void commitTreeState(); - void removeNode(ScrollingStateNode*); - OwnPtr<ScrollingStateTree> m_scrollingStateTree; RefPtr<ScrollingTree> m_scrollingTree; Timer<ScrollingCoordinatorMac> m_scrollingStateTreeCommitterTimer; - - HashMap<ScrollingNodeID, ScrollingStateNode*> m_stateNodeMap; }; } // namespace WebCore diff --git a/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.mm b/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.mm index d0c60e1ae..869bba947 100644 --- a/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.mm +++ b/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.mm @@ -29,6 +29,7 @@ #import "ScrollingCoordinatorMac.h" +#include "GraphicsLayer.h" #include "Frame.h" #include "FrameView.h" #include "IntRect.h" @@ -42,9 +43,11 @@ #include "ScrollingConstraints.h" #include "ScrollingStateFixedNode.h" #include "ScrollingStateScrollingNode.h" +#include "ScrollingStateStickyNode.h" #include "ScrollingStateTree.h" #include "ScrollingThread.h" #include "ScrollingTree.h" +#include "TiledBacking.h" #include <wtf/Functional.h> #include <wtf/MainThread.h> @@ -85,6 +88,36 @@ ScrollingTree* ScrollingCoordinatorMac::scrollingTree() const return m_scrollingTree.get(); } +bool ScrollingCoordinatorMac::isRubberBandInProgress() const +{ + return scrollingTree()->isRubberBandInProgress(); +} + +bool ScrollingCoordinatorMac::rubberBandsAtBottom() const +{ + return scrollingTree()->rubberBandsAtBottom(); +} + +void ScrollingCoordinatorMac::setRubberBandsAtBottom(bool rubberBandsAtBottom) +{ + scrollingTree()->setRubberBandsAtBottom(rubberBandsAtBottom); +} + +bool ScrollingCoordinatorMac::rubberBandsAtTop() const +{ + return scrollingTree()->rubberBandsAtTop(); +} + +void ScrollingCoordinatorMac::setRubberBandsAtTop(bool rubberBandsAtTop) +{ + scrollingTree()->setRubberBandsAtTop(rubberBandsAtTop); +} + +void ScrollingCoordinatorMac::setScrollPinningBehavior(ScrollPinningBehavior pinning) +{ + scrollingTree()->setScrollPinningBehavior(pinning); +} + void ScrollingCoordinatorMac::commitTreeStateIfNeeded() { if (!m_scrollingStateTree->hasChangedProperties()) @@ -99,6 +132,10 @@ void ScrollingCoordinatorMac::frameViewLayoutUpdated(FrameView* frameView) ASSERT(isMainThread()); ASSERT(m_page); + // If there isn't a root node yet, don't do anything. We'll be called again after creating one. + if (!m_scrollingStateTree->rootStateNode()) + return; + // Compute the region of the page that we can't do fast scrolling for. This currently includes // all scrollable areas, such as subframes, overflow divs and list boxes. We need to do this even if the // frame view whose layout was updated is not the main frame. @@ -111,7 +148,7 @@ void ScrollingCoordinatorMac::frameViewLayoutUpdated(FrameView* frameView) if (!coordinatesScrollingForFrameView(frameView)) return; - ScrollingStateScrollingNode* node = toScrollingStateScrollingNode(stateNodeForID(frameView->scrollLayerID())); + ScrollingStateScrollingNode* node = toScrollingStateScrollingNode(m_scrollingStateTree->stateNodeForID(frameView->scrollLayerID())); if (!node) return; @@ -125,14 +162,17 @@ void ScrollingCoordinatorMac::frameViewLayoutUpdated(FrameView* frameView) scrollParameters.scrollOrigin = frameView->scrollOrigin(); scrollParameters.viewportRect = IntRect(IntPoint(), frameView->visibleContentRect().size()); - scrollParameters.contentsSize = frameView->contentsSize(); + scrollParameters.totalContentsSize = frameView->totalContentsSize(); + scrollParameters.frameScaleFactor = frameView->frame()->frameScaleFactor(); + scrollParameters.headerHeight = frameView->headerHeight(); + scrollParameters.footerHeight = frameView->footerHeight(); setScrollParametersForNode(scrollParameters, node); } void ScrollingCoordinatorMac::recomputeWheelEventHandlerCountForFrameView(FrameView* frameView) { - ScrollingStateScrollingNode* node = toScrollingStateScrollingNode(stateNodeForID(frameView->scrollLayerID())); + ScrollingStateScrollingNode* node = toScrollingStateScrollingNode(m_scrollingStateTree->stateNodeForID(frameView->scrollLayerID())); if (!node) return; setWheelEventHandlerCountForNode(computeCurrentWheelEventHandlerCount(), node); @@ -152,26 +192,19 @@ void ScrollingCoordinatorMac::frameViewRootLayerDidChange(FrameView* frameView) ScrollingCoordinator::frameViewRootLayerDidChange(frameView); - setScrollLayerForNode(scrollLayerForFrameView(frameView), stateNodeForID(frameView->scrollLayerID())); + ScrollingStateScrollingNode* node = toScrollingStateScrollingNode(m_scrollingStateTree->stateNodeForID(frameView->scrollLayerID())); + setScrollLayerForNode(scrollLayerForFrameView(frameView), node); + setCounterScrollingLayerForNode(counterScrollingLayerForFrameView(frameView), node); + setHeaderLayerForNode(headerLayerForFrameView(frameView), node); + setFooterLayerForNode(footerLayerForFrameView(frameView), node); } -void ScrollingCoordinatorMac::frameViewHorizontalScrollbarLayerDidChange(FrameView* frameView, GraphicsLayer*) +void ScrollingCoordinatorMac::scrollableAreaScrollbarLayerDidChange(ScrollableArea* scrollableArea, ScrollbarOrientation) { ASSERT(isMainThread()); ASSERT(m_page); - if (frameView->frame() != m_page->mainFrame()) - return; - - // FIXME: Implement. -} - -void ScrollingCoordinatorMac::frameViewVerticalScrollbarLayerDidChange(FrameView* frameView, GraphicsLayer*) -{ - ASSERT(isMainThread()); - ASSERT(m_page); - - if (frameView->frame() != m_page->mainFrame()) + if (scrollableArea != static_cast<ScrollableArea*>(m_page->mainFrame()->view())) return; // FIXME: Implement. @@ -193,7 +226,7 @@ bool ScrollingCoordinatorMac::requestScrollPositionUpdate(FrameView* frameView, if (frameView->frame()->document()->inPageCache()) return true; - ScrollingStateScrollingNode* stateNode = toScrollingStateScrollingNode(stateNodeForID(frameView->scrollLayerID())); + ScrollingStateScrollingNode* stateNode = toScrollingStateScrollingNode(m_scrollingStateTree->stateNodeForID(frameView->scrollLayerID())); if (!stateNode) return false; @@ -217,95 +250,52 @@ bool ScrollingCoordinatorMac::handleWheelEvent(FrameView*, const PlatformWheelEv ScrollingNodeID ScrollingCoordinatorMac::attachToStateTree(ScrollingNodeType nodeType, ScrollingNodeID newNodeID, ScrollingNodeID parentID) { - ASSERT(newNodeID); - - if (stateNodeForID(newNodeID)) - return newNodeID; - - ScrollingStateNode* newNode; - if (!parentID) { - // If we're resetting the root node, we should clear the HashMap and destroy the current children. - clearStateTree(); - - m_scrollingStateTree->rootStateNode()->setScrollingNodeID(newNodeID); - newNode = m_scrollingStateTree->rootStateNode(); - } else { - ScrollingStateNode* parent = stateNodeForID(parentID); - switch (nodeType) { - case FixedNode: { - ASSERT(supportsFixedPositionLayers()); - OwnPtr<ScrollingStateFixedNode> fixedNode = ScrollingStateFixedNode::create(m_scrollingStateTree.get(), newNodeID); - newNode = fixedNode.get(); - parent->appendChild(fixedNode.release()); - break; - } - case ScrollingNode: { - // FIXME: We currently only support child nodes that are fixed. - ASSERT_NOT_REACHED(); - OwnPtr<ScrollingStateScrollingNode> scrollingNode = ScrollingStateScrollingNode::create(m_scrollingStateTree.get(), newNodeID); - newNode = scrollingNode.get(); - parent->appendChild(scrollingNode.release()); - break; - } - default: - ASSERT_NOT_REACHED(); - } - } - - m_stateNodeMap.set(newNodeID, newNode); - return newNodeID; + return m_scrollingStateTree->attachNode(nodeType, newNodeID, parentID); } -void ScrollingCoordinatorMac::removeNode(ScrollingStateNode* node) +void ScrollingCoordinatorMac::detachFromStateTree(ScrollingNodeID nodeID) { - m_scrollingStateTree->removeNode(node); - - // ScrollingStateTree::removeNode() will destroy children, so we have to make sure we remove those children - // from the HashMap. - const Vector<ScrollingNodeID>& removedNodes = m_scrollingStateTree->removedNodes(); - size_t size = removedNodes.size(); - for (size_t i = 0; i < size; ++i) - m_stateNodeMap.remove(removedNodes[i]); + m_scrollingStateTree->detachNode(nodeID); } -void ScrollingCoordinatorMac::detachFromStateTree(ScrollingNodeID scrollLayerID) +void ScrollingCoordinatorMac::clearStateTree() { - if (!scrollLayerID) - return; - - // The node may not be found if clearStateTree() was recently called. - ScrollingStateNode* node = m_stateNodeMap.take(scrollLayerID); - if (!node) - return; - - removeNode(node); + m_scrollingStateTree->clear(); } -void ScrollingCoordinatorMac::clearStateTree() +void ScrollingCoordinatorMac::ensureRootStateNodeForFrameView(FrameView* frameView) { - removeNode(m_scrollingStateTree->rootStateNode()); + ASSERT(frameView->scrollLayerID()); + attachToStateTree(ScrollingNode, frameView->scrollLayerID(), 0); } -ScrollingStateNode* ScrollingCoordinatorMac::stateNodeForID(ScrollingNodeID scrollLayerID) +void ScrollingCoordinatorMac::setScrollLayerForNode(GraphicsLayer* scrollLayer, ScrollingStateNode* node) { - if (!scrollLayerID) - return 0; - - HashMap<ScrollingNodeID, ScrollingStateNode*>::const_iterator it = m_stateNodeMap.find(scrollLayerID); - if (it == m_stateNodeMap.end()) - return 0; + node->setScrollLayer(scrollLayer); + scheduleTreeStateCommit(); +} - return it->value; +void ScrollingCoordinatorMac::setCounterScrollingLayerForNode(GraphicsLayer* layer, ScrollingStateScrollingNode* node) +{ + node->setCounterScrollingLayer(layer); + scheduleTreeStateCommit(); } -void ScrollingCoordinatorMac::ensureRootStateNodeForFrameView(FrameView* frameView) +void ScrollingCoordinatorMac::setHeaderLayerForNode(GraphicsLayer* headerLayer, ScrollingStateScrollingNode* node) { - attachToStateTree(ScrollingNode, frameView->scrollLayerID(), 0); + // Headers and footers are only supported on the root node. + ASSERT(node == m_scrollingStateTree->rootStateNode()); + + node->setHeaderLayer(headerLayer); + scheduleTreeStateCommit(); } -void ScrollingCoordinatorMac::setScrollLayerForNode(GraphicsLayer* scrollLayer, ScrollingStateNode* node) +void ScrollingCoordinatorMac::setFooterLayerForNode(GraphicsLayer* footerLayer, ScrollingStateScrollingNode* node) { - node->setScrollLayer(scrollLayer); + // Headers and footers are only supported on the root node. + ASSERT(node == m_scrollingStateTree->rootStateNode()); + + node->setFooterLayer(footerLayer); scheduleTreeStateCommit(); } @@ -326,7 +316,11 @@ void ScrollingCoordinatorMac::setScrollParametersForNode(const ScrollParameters& node->setScrollOrigin(scrollParameters.scrollOrigin); node->setViewportRect(scrollParameters.viewportRect); - node->setContentsSize(scrollParameters.contentsSize); + node->setTotalContentsSize(scrollParameters.totalContentsSize); + node->setFrameScaleFactor(scrollParameters.frameScaleFactor); + node->setHeaderHeight(scrollParameters.headerHeight); + node->setFooterHeight(scrollParameters.footerHeight); + scheduleTreeStateCommit(); } @@ -338,6 +332,9 @@ void ScrollingCoordinatorMac::setWheelEventHandlerCountForNode(unsigned wheelEve void ScrollingCoordinatorMac::setShouldUpdateScrollLayerPositionOnMainThread(MainThreadScrollingReasons reasons) { + if (!m_scrollingStateTree->rootStateNode()) + return; + // The FrameView's GraphicsLayer is likely to be out-of-synch with the PlatformLayer // at this point. So we'll update it before we switch back to main thread scrolling // in order to avoid layer positioning bugs. @@ -364,6 +361,9 @@ void ScrollingCoordinatorMac::updateMainFrameScrollLayerPosition() void ScrollingCoordinatorMac::syncChildPositions(const LayoutRect& viewportRect) { + if (!m_scrollingStateTree->rootStateNode()) + return; + Vector<OwnPtr<ScrollingStateNode> >* children = m_scrollingStateTree->rootStateNode()->children(); if (!children) return; @@ -371,23 +371,46 @@ void ScrollingCoordinatorMac::syncChildPositions(const LayoutRect& viewportRect) // FIXME: We'll have to traverse deeper into the tree at some point. size_t size = children->size(); for (size_t i = 0; i < size; ++i) { - ScrollingStateFixedNode* child = toScrollingStateFixedNode(children->at(i).get()); - FloatPoint position = child->viewportConstraints().layerPositionForViewportRect(viewportRect); - child->graphicsLayer()->syncPosition(position); + ScrollingStateNode* child = children->at(i).get(); + child->syncLayerPositionForViewportRect(viewportRect); } } +void ScrollingCoordinatorMac::updateScrollingNode(ScrollingNodeID nodeID, GraphicsLayer* scrollLayer, GraphicsLayer* counterScrollingLayer) +{ + ScrollingStateScrollingNode* node = toScrollingStateScrollingNode(m_scrollingStateTree->stateNodeForID(nodeID)); + ASSERT(node); + if (!node) + return; + + node->setScrollLayer(scrollLayer); + node->setCounterScrollingLayer(counterScrollingLayer); + scheduleTreeStateCommit(); +} + void ScrollingCoordinatorMac::updateViewportConstrainedNode(ScrollingNodeID nodeID, const ViewportConstraints& constraints, GraphicsLayer* graphicsLayer) { ASSERT(supportsFixedPositionLayers()); - // FIXME: We should support sticky position here! - if (constraints.constraintType() == ViewportConstraints::StickyPositionConstraint) + ScrollingStateNode* node = m_scrollingStateTree->stateNodeForID(nodeID); + if (!node) return; - ScrollingStateFixedNode* node = toScrollingStateFixedNode(stateNodeForID(nodeID)); - setScrollLayerForNode(graphicsLayer, node); - node->updateConstraints((const FixedPositionViewportConstraints&)constraints); + switch (constraints.constraintType()) { + case ViewportConstraints::FixedPositionConstaint: { + ScrollingStateFixedNode* fixedNode = toScrollingStateFixedNode(node); + setScrollLayerForNode(graphicsLayer, fixedNode); + fixedNode->updateConstraints((const FixedPositionViewportConstraints&)constraints); + break; + } + case ViewportConstraints::StickyPositionConstraint: { + ScrollingStateStickyNode* stickyNode = toScrollingStateStickyNode(node); + setScrollLayerForNode(graphicsLayer, stickyNode); + stickyNode->updateConstraints((const StickyPositionViewportConstraints&)constraints); + break; + } + } + scheduleTreeStateCommit(); } void ScrollingCoordinatorMac::scheduleTreeStateCommit() @@ -412,11 +435,32 @@ void ScrollingCoordinatorMac::commitTreeState() OwnPtr<ScrollingStateTree> treeState = m_scrollingStateTree->commit(); ScrollingThread::dispatch(bind(&ScrollingTree::commitNewTreeState, m_scrollingTree.get(), treeState.release())); + + FrameView* frameView = m_page->mainFrame()->view(); + if (!frameView) + return; + + TiledBacking* tiledBacking = frameView->tiledBacking(); + if (!tiledBacking) + return; + + ScrollingModeIndication indicatorMode; + if (shouldUpdateScrollLayerPositionOnMainThread()) + indicatorMode = MainThreadScrollingBecauseOfStyleIndication; + else if (m_scrollingStateTree->rootStateNode() && m_scrollingStateTree->rootStateNode()->wheelEventHandlerCount()) + indicatorMode = MainThreadScrollingBecauseOfEventHandlersIndication; + else + indicatorMode = ThreadedScrollingIndication; + + tiledBacking->setScrollingModeIndication(indicatorMode); } String ScrollingCoordinatorMac::scrollingStateTreeAsText() const { - return m_scrollingStateTree->rootStateNode()->scrollingStateTreeAsText(); + if (m_scrollingStateTree->rootStateNode()) + return m_scrollingStateTree->rootStateNode()->scrollingStateTreeAsText(); + + return String(); } } // namespace WebCore diff --git a/Source/WebCore/page/scrolling/mac/ScrollingStateNodeMac.mm b/Source/WebCore/page/scrolling/mac/ScrollingStateNodeMac.mm index 41f381b54..9e1b84b01 100644 --- a/Source/WebCore/page/scrolling/mac/ScrollingStateNodeMac.mm +++ b/Source/WebCore/page/scrolling/mac/ScrollingStateNodeMac.mm @@ -38,7 +38,7 @@ PlatformLayer* ScrollingStateNode::platformScrollLayer() const return m_platformScrollLayer.get(); } -void ScrollingStateNode::setScrollLayer(PlatformLayer* platformLayer) +void ScrollingStateNode::setScrollPlatformLayer(PlatformLayer* platformLayer) { m_platformScrollLayer = platformLayer; } @@ -53,10 +53,10 @@ void ScrollingStateNode::setScrollLayer(GraphicsLayer* graphicsLayer) m_platformScrollLayer = platformScrollLayer; m_graphicsLayer = graphicsLayer; - m_scrollLayerDidChange = true; + setPropertyChanged(ScrollLayer); m_scrollingStateTree->setHasChangedProperties(true); } } // namespace WebCore -#endif // ENABLE(THREADED_SCROLLING) +#endif diff --git a/Source/WebCore/page/scrolling/mac/ScrollingStateScrollingNodeMac.mm b/Source/WebCore/page/scrolling/mac/ScrollingStateScrollingNodeMac.mm new file mode 100644 index 000000000..61e000821 --- /dev/null +++ b/Source/WebCore/page/scrolling/mac/ScrollingStateScrollingNodeMac.mm @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2013 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ScrollingStateScrollingNode.h" + +#include "GraphicsLayer.h" +#include "ScrollingStateTree.h" + +#if ENABLE(THREADED_SCROLLING) + +namespace WebCore { + +PlatformLayer* ScrollingStateScrollingNode::counterScrollingPlatformLayer() const +{ + return m_counterScrollingPlatformLayer.get(); +} + +void ScrollingStateScrollingNode::setCounterScrollingLayer(GraphicsLayer* graphicsLayer) +{ + PlatformLayer* platformScrollLayer = graphicsLayer ? graphicsLayer->platformLayer() : nil; + if (m_counterScrollingPlatformLayer == platformScrollLayer) + return; + + m_counterScrollingPlatformLayer = platformScrollLayer; + m_counterScrollingLayer = graphicsLayer; + + setPropertyChanged(CounterScrollingLayer); + if (m_scrollingStateTree) + m_scrollingStateTree->setHasChangedProperties(true); +} + +PlatformLayer* ScrollingStateScrollingNode::headerPlatformLayer() const +{ + return m_headerPlatformLayer.get(); +} + +void ScrollingStateScrollingNode::setHeaderLayer(GraphicsLayer* graphicsLayer) +{ + PlatformLayer* platformHeaderLayer = graphicsLayer ? graphicsLayer->platformLayer() : nil; + if (m_headerPlatformLayer == platformHeaderLayer) + return; + + m_headerPlatformLayer = platformHeaderLayer; + m_headerLayer = graphicsLayer; + + setPropertyChanged(HeaderLayer); + if (m_scrollingStateTree) + m_scrollingStateTree->setHasChangedProperties(true); +} + +PlatformLayer* ScrollingStateScrollingNode::footerPlatformLayer() const +{ + return m_footerPlatformLayer.get(); +} + +void ScrollingStateScrollingNode::setFooterLayer(GraphicsLayer* graphicsLayer) +{ + PlatformLayer* platformFooterLayer = graphicsLayer ? graphicsLayer->platformLayer() : nil; + if (m_footerPlatformLayer == platformFooterLayer) + return; + + m_footerPlatformLayer = platformFooterLayer; + m_footerLayer = graphicsLayer; + + setPropertyChanged(FooterLayer); + if (m_scrollingStateTree) + m_scrollingStateTree->setHasChangedProperties(true); +} + +} // namespace WebCore + +#endif // ENABLE(THREADED_SCROLLING) diff --git a/Source/WebCore/page/scrolling/mac/ScrollingTreeFixedNode.h b/Source/WebCore/page/scrolling/mac/ScrollingTreeFixedNode.h index c3acfc6ed..4057e5585 100644 --- a/Source/WebCore/page/scrolling/mac/ScrollingTreeFixedNode.h +++ b/Source/WebCore/page/scrolling/mac/ScrollingTreeFixedNode.h @@ -40,15 +40,15 @@ class FixedPositionViewportConstraints; class ScrollingTreeFixedNode : public ScrollingTreeNode { public: - static PassOwnPtr<ScrollingTreeFixedNode> create(ScrollingTree*); + static PassOwnPtr<ScrollingTreeFixedNode> create(ScrollingTree*, ScrollingNodeID); virtual ~ScrollingTreeFixedNode(); private: - ScrollingTreeFixedNode(ScrollingTree*); + ScrollingTreeFixedNode(ScrollingTree*, ScrollingNodeID); - virtual void update(ScrollingStateNode*) OVERRIDE; - virtual void parentScrollPositionDidChange(const IntRect& viewportRect) OVERRIDE; + virtual void updateBeforeChildren(ScrollingStateNode*) OVERRIDE; + virtual void parentScrollPositionDidChange(const IntRect& viewportRect, const FloatSize& cumulativeDelta) OVERRIDE; FixedPositionViewportConstraints m_constraints; RetainPtr<CALayer> m_layer; diff --git a/Source/WebCore/page/scrolling/mac/ScrollingTreeFixedNode.mm b/Source/WebCore/page/scrolling/mac/ScrollingTreeFixedNode.mm index c4edfc234..d9e4ce595 100644 --- a/Source/WebCore/page/scrolling/mac/ScrollingTreeFixedNode.mm +++ b/Source/WebCore/page/scrolling/mac/ScrollingTreeFixedNode.mm @@ -33,14 +33,13 @@ namespace WebCore { -PassOwnPtr<ScrollingTreeFixedNode> ScrollingTreeFixedNode::create(ScrollingTree* scrollingTree) +PassOwnPtr<ScrollingTreeFixedNode> ScrollingTreeFixedNode::create(ScrollingTree* scrollingTree, ScrollingNodeID nodeID) { - return adoptPtr(new ScrollingTreeFixedNode(scrollingTree)); + return adoptPtr(new ScrollingTreeFixedNode(scrollingTree, nodeID)); } -ScrollingTreeFixedNode::ScrollingTreeFixedNode(ScrollingTree* scrollingTree) - : ScrollingTreeNode(scrollingTree) - , m_constraints(FixedPositionViewportConstraints()) +ScrollingTreeFixedNode::ScrollingTreeFixedNode(ScrollingTree* scrollingTree, ScrollingNodeID nodeID) + : ScrollingTreeNode(scrollingTree, nodeID) { } @@ -48,15 +47,15 @@ ScrollingTreeFixedNode::~ScrollingTreeFixedNode() { } -void ScrollingTreeFixedNode::update(ScrollingStateNode* stateNode) +void ScrollingTreeFixedNode::updateBeforeChildren(ScrollingStateNode* stateNode) { - ScrollingStateFixedNode* state = toScrollingStateFixedNode(stateNode); + ScrollingStateFixedNode* fixedStateNode = toScrollingStateFixedNode(stateNode); - if (state->scrollLayerDidChange()) - m_layer = state->platformScrollLayer(); + if (fixedStateNode->hasChangedProperty(ScrollingStateNode::ScrollLayer)) + m_layer = fixedStateNode->platformScrollLayer(); - if (stateNode->changedProperties() & ScrollingStateFixedNode::ViewportConstraints) - m_constraints = state->viewportConstraints(); + if (stateNode->hasChangedProperty(ScrollingStateFixedNode::ViewportConstraints)) + m_constraints = fixedStateNode->viewportConstraints(); } static inline CGPoint operator*(CGPoint& a, const CGSize& b) @@ -64,9 +63,10 @@ static inline CGPoint operator*(CGPoint& a, const CGSize& b) return CGPointMake(a.x * b.width, a.y * b.height); } -void ScrollingTreeFixedNode::parentScrollPositionDidChange(const IntRect& viewportRect) +void ScrollingTreeFixedNode::parentScrollPositionDidChange(const IntRect& viewportRect, const FloatSize& cumulativeDelta) { FloatPoint layerPosition = m_constraints.layerPositionForViewportRect(viewportRect); + layerPosition -= cumulativeDelta; CGRect layerBounds = [m_layer.get() bounds]; CGPoint anchorPoint = [m_layer.get() anchorPoint]; @@ -76,9 +76,11 @@ void ScrollingTreeFixedNode::parentScrollPositionDidChange(const IntRect& viewpo if (!m_children) return; + FloatSize newDelta = layerPosition - m_constraints.layerPositionAtLastLayout() + cumulativeDelta; + size_t size = m_children->size(); for (size_t i = 0; i < size; ++i) - m_children->at(i)->parentScrollPositionDidChange(viewportRect); + m_children->at(i)->parentScrollPositionDidChange(viewportRect, newDelta); } } // namespace WebCore diff --git a/Source/WebCore/page/scrolling/mac/ScrollingTreeMac.mm b/Source/WebCore/page/scrolling/mac/ScrollingTreeMac.mm deleted file mode 100644 index 4a11f249d..000000000 --- a/Source/WebCore/page/scrolling/mac/ScrollingTreeMac.mm +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2012 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#import "config.h" -#import "ScrollingTree.h" - -#if ENABLE(THREADED_SCROLLING) - -#import "AutodrainedPool.h" -#import "ScrollingTreeScrollingNodeMac.h" -#import <QuartzCore/CATextLayer.h> - -namespace WebCore { - -void ScrollingTree::setDebugRootLayer(CALayer *rootLayer) -{ - AutodrainedPool pool; - - [m_debugInfoLayer.get() removeFromSuperlayer]; - - if (!rootLayer) - return; - - m_debugInfoLayer = [CALayer layer]; - [rootLayer addSublayer:m_debugInfoLayer.get()]; - - [m_debugInfoLayer.get() setBorderWidth:1]; - [m_debugInfoLayer.get() setBorderColor:CGColorGetConstantColor(kCGColorBlack)]; - - [m_debugInfoLayer.get() setFrame:CGRectMake(0, 0, 25, 25)]; - updateDebugRootLayer(); -} - -void ScrollingTree::updateDebugRootLayer() -{ - if (!m_debugInfoLayer) - return; - - AutodrainedPool pool; - - RetainPtr<CGColorRef> backgroundColor; - - if (m_rootNode->shouldUpdateScrollLayerPositionOnMainThread()) - backgroundColor = adoptCF(CGColorCreateGenericRGB(1, 0, 0, .7)); - - { - MutexLocker lock(m_mutex); - if (m_hasWheelEventHandlers) { - if (!backgroundColor) - backgroundColor = adoptCF(CGColorCreateGenericRGB(1, 1, 0, .7)); - } - } - - if (!backgroundColor) - backgroundColor = adoptCF(CGColorCreateGenericRGB(0, 1, 0, .7)); - - [m_debugInfoLayer.get() setBackgroundColor:backgroundColor.get()]; -} - -} // namespace WebCore - -#endif // ENABLE(THREADED_SCROLLING) diff --git a/Source/WebCore/page/scrolling/mac/ScrollingTreeScrollingNodeMac.h b/Source/WebCore/page/scrolling/mac/ScrollingTreeScrollingNodeMac.h index 486e63973..85fb9c6ab 100644 --- a/Source/WebCore/page/scrolling/mac/ScrollingTreeScrollingNodeMac.h +++ b/Source/WebCore/page/scrolling/mac/ScrollingTreeScrollingNodeMac.h @@ -38,12 +38,13 @@ namespace WebCore { class ScrollingTreeScrollingNodeMac : public ScrollingTreeScrollingNode, private ScrollElasticityControllerClient { public: - explicit ScrollingTreeScrollingNodeMac(ScrollingTree*); + explicit ScrollingTreeScrollingNodeMac(ScrollingTree*, ScrollingNodeID); virtual ~ScrollingTreeScrollingNodeMac(); private: // ScrollingTreeNode member functions. - virtual void update(ScrollingStateNode*) OVERRIDE; + virtual void updateBeforeChildren(ScrollingStateNode*) OVERRIDE; + virtual void updateAfterChildren(ScrollingStateNode*) OVERRIDE; virtual void handleWheelEvent(const PlatformWheelEvent&) OVERRIDE; // ScrollElasticityController member functions. @@ -80,7 +81,11 @@ private: RetainPtr<CFRunLoopTimerRef> m_snapRubberbandTimer; RetainPtr<CALayer> m_scrollLayer; + RetainPtr<CALayer> m_counterScrollingLayer; + RetainPtr<CALayer> m_headerLayer; + RetainPtr<CALayer> m_footerLayer; IntPoint m_probableMainThreadScrollPosition; + bool m_lastScrollHadUnfilledPixels; }; } // namespace WebCore diff --git a/Source/WebCore/page/scrolling/mac/ScrollingTreeScrollingNodeMac.mm b/Source/WebCore/page/scrolling/mac/ScrollingTreeScrollingNodeMac.mm index 83ec43b30..6a0007579 100644 --- a/Source/WebCore/page/scrolling/mac/ScrollingTreeScrollingNodeMac.mm +++ b/Source/WebCore/page/scrolling/mac/ScrollingTreeScrollingNodeMac.mm @@ -28,12 +28,13 @@ #if ENABLE(THREADED_SCROLLING) +#include "FrameView.h" #include "PlatformWheelEvent.h" #include "ScrollingCoordinator.h" #include "ScrollingTree.h" #include "ScrollingStateTree.h" #include "Settings.h" -#include "TileCache.h" +#include "TileController.h" #include "WebTileLayer.h" #include <wtf/CurrentTime.h> @@ -44,15 +45,18 @@ namespace WebCore { static void logThreadedScrollingMode(unsigned mainThreadScrollingReasons); +static void logWheelEventHandlerCountChanged(unsigned); -PassOwnPtr<ScrollingTreeScrollingNode> ScrollingTreeScrollingNode::create(ScrollingTree* scrollingTree) + +PassOwnPtr<ScrollingTreeScrollingNode> ScrollingTreeScrollingNode::create(ScrollingTree* scrollingTree, ScrollingNodeID nodeID) { - return adoptPtr(new ScrollingTreeScrollingNodeMac(scrollingTree)); + return adoptPtr(new ScrollingTreeScrollingNodeMac(scrollingTree, nodeID)); } -ScrollingTreeScrollingNodeMac::ScrollingTreeScrollingNodeMac(ScrollingTree* scrollingTree) - : ScrollingTreeScrollingNode(scrollingTree) +ScrollingTreeScrollingNodeMac::ScrollingTreeScrollingNodeMac(ScrollingTree* scrollingTree, ScrollingNodeID nodeID) + : ScrollingTreeScrollingNode(scrollingTree, nodeID) , m_scrollElasticityController(this) + , m_lastScrollHadUnfilledPixels(false) { } @@ -62,28 +66,31 @@ ScrollingTreeScrollingNodeMac::~ScrollingTreeScrollingNodeMac() CFRunLoopTimerInvalidate(m_snapRubberbandTimer.get()); } -void ScrollingTreeScrollingNodeMac::update(ScrollingStateNode* stateNode) +void ScrollingTreeScrollingNodeMac::updateBeforeChildren(ScrollingStateNode* stateNode) { - ScrollingTreeScrollingNode::update(stateNode); - ScrollingStateScrollingNode* state = toScrollingStateScrollingNode(stateNode); + ScrollingTreeScrollingNode::updateBeforeChildren(stateNode); + ScrollingStateScrollingNode* scrollingStateNode = toScrollingStateScrollingNode(stateNode); - if (state->scrollLayerDidChange()) - m_scrollLayer = state->platformScrollLayer(); + if (scrollingStateNode->hasChangedProperty(ScrollingStateNode::ScrollLayer)) + m_scrollLayer = scrollingStateNode->platformScrollLayer(); - if (state->changedProperties() & ScrollingStateScrollingNode::RequestedScrollPosition) - setScrollPosition(state->requestedScrollPosition()); + if (scrollingStateNode->hasChangedProperty(ScrollingStateScrollingNode::CounterScrollingLayer)) + m_counterScrollingLayer = scrollingStateNode->counterScrollingPlatformLayer(); - if (state->scrollLayerDidChange() || state->changedProperties() & (ScrollingStateScrollingNode::ContentsSize | ScrollingStateScrollingNode::ViewportRect)) - updateMainFramePinState(scrollPosition()); + if (scrollingStateNode->hasChangedProperty(ScrollingStateScrollingNode::HeaderLayer)) + m_headerLayer = scrollingStateNode->headerPlatformLayer(); - if ((state->changedProperties() & ScrollingStateScrollingNode::ShouldUpdateScrollLayerPositionOnMainThread)) { + if (scrollingStateNode->hasChangedProperty(ScrollingStateScrollingNode::FooterLayer)) + m_footerLayer = scrollingStateNode->footerPlatformLayer(); + + if (scrollingStateNode->hasChangedProperty(ScrollingStateScrollingNode::ShouldUpdateScrollLayerPositionOnMainThread)) { unsigned mainThreadScrollingReasons = this->shouldUpdateScrollLayerPositionOnMainThread(); if (mainThreadScrollingReasons) { // We're transitioning to the slow "update scroll layer position on the main thread" mode. // Initialize the probable main thread scroll position with the current scroll layer position. - if (state->changedProperties() & ScrollingStateScrollingNode::RequestedScrollPosition) - m_probableMainThreadScrollPosition = state->requestedScrollPosition(); + if (scrollingStateNode->hasChangedProperty(ScrollingStateScrollingNode::RequestedScrollPosition)) + m_probableMainThreadScrollPosition = scrollingStateNode->requestedScrollPosition(); else { CGPoint scrollLayerPosition = m_scrollLayer.get().position; m_probableMainThreadScrollPosition = IntPoint(-scrollLayerPosition.x, -scrollLayerPosition.y); @@ -93,6 +100,25 @@ void ScrollingTreeScrollingNodeMac::update(ScrollingStateNode* stateNode) if (scrollingTree()->scrollingPerformanceLoggingEnabled()) logThreadedScrollingMode(mainThreadScrollingReasons); } + + if (scrollingStateNode->hasChangedProperty(ScrollingStateScrollingNode::WheelEventHandlerCount)) { + if (scrollingTree()->scrollingPerformanceLoggingEnabled()) + logWheelEventHandlerCountChanged(scrollingStateNode->wheelEventHandlerCount()); + } +} + +void ScrollingTreeScrollingNodeMac::updateAfterChildren(ScrollingStateNode* stateNode) +{ + ScrollingTreeScrollingNode::updateAfterChildren(stateNode); + + ScrollingStateScrollingNode* scrollingStateNode = toScrollingStateScrollingNode(stateNode); + + // Update the scroll position after child nodes have been updated, because they need to have updated their constraints before any scrolling happens. + if (scrollingStateNode->hasChangedProperty(ScrollingStateScrollingNode::RequestedScrollPosition)) + setScrollPosition(scrollingStateNode->requestedScrollPosition()); + + if (scrollingStateNode->hasChangedProperty(ScrollingStateNode::ScrollLayer) || scrollingStateNode->hasChangedProperty(ScrollingStateScrollingNode::TotalContentsSize) || scrollingStateNode->hasChangedProperty(ScrollingStateScrollingNode::ViewportRect)) + updateMainFramePinState(scrollPosition()); } void ScrollingTreeScrollingNodeMac::handleWheelEvent(const PlatformWheelEvent& wheelEvent) @@ -148,6 +174,13 @@ IntSize ScrollingTreeScrollingNodeMac::stretchAmount() else if (scrollPosition().x() > maximumScrollPosition().x()) stretch.setWidth(scrollPosition().x() - maximumScrollPosition().x()); + if (scrollingTree()->rootNode() == this) { + if (stretch.isZero()) + scrollingTree()->setMainFrameIsRubberBanding(false); + else + scrollingTree()->setMainFrameIsRubberBanding(true); + } + return stretch; } @@ -173,7 +206,7 @@ bool ScrollingTreeScrollingNodeMac::pinnedInDirection(const FloatSize& delta) } } - if ((delta.width() || delta.height()) && (limitDelta.width() < 1 && limitDelta.height() < 1)) + if ((delta.width() || delta.height()) && (limitDelta.width() < 1 && limitDelta.height() < 1)) return true; return false; @@ -232,6 +265,8 @@ void ScrollingTreeScrollingNodeMac::stopSnapRubberbandTimer() if (!m_snapRubberbandTimer) return; + scrollingTree()->setMainFrameIsRubberBanding(false); + CFRunLoopTimerInvalidate(m_snapRubberbandTimer.get()); m_snapRubberbandTimer = nullptr; } @@ -276,31 +311,55 @@ void ScrollingTreeScrollingNodeMac::setScrollLayerPosition(const IntPoint& posit ASSERT(!shouldUpdateScrollLayerPositionOnMainThread()); m_scrollLayer.get().position = CGPointMake(-position.x() + scrollOrigin().x(), -position.y() + scrollOrigin().y()); + IntPoint scrollOffset = position - toIntSize(scrollOrigin()); + IntSize scrollOffsetForFixedChildren = FrameView::scrollOffsetForFixedPosition(viewportRect(), totalContentsSize(), scrollOffset, scrollOrigin(), frameScaleFactor(), false, headerHeight(), footerHeight()); + if (m_counterScrollingLayer) + m_counterScrollingLayer.get().position = FloatPoint(scrollOffsetForFixedChildren); + + // Generally the banners should have the same horizontal-position computation as a fixed element. However, + // the banners are not affected by the frameScaleFactor(), so if there is currently a non-1 frameScaleFactor() + // then we should recompute scrollOffsetForFixedChildren for the banner with a scale factor of 1. + float horizontalScrollOffsetForBanner = scrollOffsetForFixedChildren.width(); + if (frameScaleFactor() != 1) + horizontalScrollOffsetForBanner = FrameView::scrollOffsetForFixedPosition(viewportRect(), totalContentsSize(), scrollOffset, scrollOrigin(), 1, false, headerHeight(), footerHeight()).width(); + + if (m_headerLayer) + m_headerLayer.get().position = FloatPoint(horizontalScrollOffsetForBanner, 0); + + if (m_footerLayer) + m_footerLayer.get().position = FloatPoint(horizontalScrollOffsetForBanner, totalContentsSize().height() - footerHeight()); + if (!m_children) return; - IntSize scrollOffsetForFixedChildren = WebCore::scrollOffsetForFixedPosition(viewportRect(), contentsSize(), position, - scrollOrigin(), 1, false); IntRect viewportRect = this->viewportRect(); - viewportRect.setLocation(toPoint(scrollOffsetForFixedChildren)); + viewportRect.setLocation(IntPoint(scrollOffsetForFixedChildren)); size_t size = m_children->size(); for (size_t i = 0; i < size; ++i) - m_children->at(i)->parentScrollPositionDidChange(viewportRect); + m_children->at(i)->parentScrollPositionDidChange(viewportRect, FloatSize()); } IntPoint ScrollingTreeScrollingNodeMac::minimumScrollPosition() const { - return IntPoint(0, 0); + IntPoint position; + + if (scrollingTree()->rootNode() == this && scrollingTree()->scrollPinningBehavior() == PinToBottom) + position.setY(maximumScrollPosition().y()); + + return position; } IntPoint ScrollingTreeScrollingNodeMac::maximumScrollPosition() const { - IntPoint position(contentsSize().width() - viewportRect().width(), - contentsSize().height() - viewportRect().height()); + IntPoint position(totalContentsSize().width() - viewportRect().width(), + totalContentsSize().height() - viewportRect().height()); position.clampNegativeToZero(); + if (scrollingTree()->rootNode() == this && scrollingTree()->scrollPinningBehavior() == PinToTop) + position.setY(minimumScrollPosition().y()); + return position; } @@ -318,8 +377,10 @@ void ScrollingTreeScrollingNodeMac::updateMainFramePinState(const IntPoint& scro { bool pinnedToTheLeft = scrollPosition.x() <= minimumScrollPosition().x(); bool pinnedToTheRight = scrollPosition.x() >= maximumScrollPosition().x(); + bool pinnedToTheTop = scrollPosition.y() <= minimumScrollPosition().y(); + bool pinnedToTheBottom = scrollPosition.y() >= maximumScrollPosition().y(); - scrollingTree()->setMainFramePinState(pinnedToTheLeft, pinnedToTheRight); + scrollingTree()->setMainFramePinState(pinnedToTheLeft, pinnedToTheRight, pinnedToTheTop, pinnedToTheBottom); } void ScrollingTreeScrollingNodeMac::logExposedUnfilledArea() @@ -330,7 +391,7 @@ void ScrollingTreeScrollingNodeMac::logExposedUnfilledArea() layerQueue.append(m_scrollLayer.get()); WebTileLayerList tiles; - while(!layerQueue.isEmpty() && tiles.isEmpty()) { + while (!layerQueue.isEmpty() && tiles.isEmpty()) { CALayer* layer = layerQueue.takeFirst(); NSArray* sublayers = [[layer sublayers] copy]; @@ -349,10 +410,12 @@ void ScrollingTreeScrollingNodeMac::logExposedUnfilledArea() } IntPoint scrollPosition = this->scrollPosition(); - unsigned unfilledArea = TileCache::blankPixelCountForTiles(tiles, viewportRect(), IntPoint(-scrollPosition.x(), -scrollPosition.y())); + unsigned unfilledArea = TileController::blankPixelCountForTiles(tiles, viewportRect(), IntPoint(-scrollPosition.x(), -scrollPosition.y())); - if (unfilledArea) + if (unfilledArea || m_lastScrollHadUnfilledPixels) WTFLogAlways("SCROLLING: Exposed tileless area. Time: %f Unfilled Pixels: %u\n", WTF::monotonicallyIncreasingTime(), unfilledArea); + + m_lastScrollHadUnfilledPixels = unfilledArea; } static void logThreadedScrollingMode(unsigned mainThreadScrollingReasons) @@ -366,7 +429,7 @@ static void logThreadedScrollingMode(unsigned mainThreadScrollingReasons) reasonsDescription.append("slow-repaint objects,"); if (mainThreadScrollingReasons & ScrollingCoordinator::HasViewportConstrainedObjectsWithoutSupportingFixedLayers) reasonsDescription.append("viewport-constrained objects,"); - if (mainThreadScrollingReasons & ScrollingCoordinator::HasNonLayerFixedObjects) + if (mainThreadScrollingReasons & ScrollingCoordinator::HasNonLayerViewportConstrainedObjects) reasonsDescription.append("non-layer viewport-constrained objects,"); if (mainThreadScrollingReasons & ScrollingCoordinator::IsImageDocument) reasonsDescription.append("image document,"); @@ -379,6 +442,11 @@ static void logThreadedScrollingMode(unsigned mainThreadScrollingReasons) WTFLogAlways("SCROLLING: Switching to threaded scrolling mode. Time: %f\n", WTF::monotonicallyIncreasingTime()); } +void logWheelEventHandlerCountChanged(unsigned count) +{ + WTFLogAlways("SCROLLING: Wheel event handler count changed. Time: %f Count: %u\n", WTF::monotonicallyIncreasingTime(), count); +} + } // namespace WebCore #endif // ENABLE(THREADED_SCROLLING) diff --git a/Source/WebCore/page/GeolocationClient.h b/Source/WebCore/page/scrolling/mac/ScrollingTreeStickyNode.h index d89387105..f56008fa7 100644 --- a/Source/WebCore/page/GeolocationClient.h +++ b/Source/WebCore/page/scrolling/mac/ScrollingTreeStickyNode.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2012 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,39 +23,39 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef GeolocationClient_h -#define GeolocationClient_h +#ifndef ScrollingTreeStickyNode_h +#define ScrollingTreeStickyNode_h + +#if ENABLE(THREADED_SCROLLING) + +#include "ScrollingConstraints.h" +#include "ScrollingTreeNode.h" +#include <wtf/RetainPtr.h> + +OBJC_CLASS CALayer; namespace WebCore { -class Geolocation; -class GeolocationPosition; -class Page; +class StickyPositionViewportConstraints; -class GeolocationClient { +class ScrollingTreeStickyNode : public ScrollingTreeNode { public: - virtual void geolocationDestroyed() = 0; + static PassOwnPtr<ScrollingTreeStickyNode> create(ScrollingTree*, ScrollingNodeID); - virtual void startUpdating() = 0; - virtual void stopUpdating() = 0; - // FIXME: The V2 Geolocation specification proposes that this property is - // renamed. See http://www.w3.org/2008/geolocation/track/issues/6 - // We should update WebKit to reflect this if and when the V2 specification - // is published. - virtual void setEnableHighAccuracy(bool) = 0; - virtual GeolocationPosition* lastPosition() = 0; + virtual ~ScrollingTreeStickyNode(); - virtual void requestPermission(Geolocation*) = 0; - virtual void cancelPermissionRequest(Geolocation*) = 0; +private: + ScrollingTreeStickyNode(ScrollingTree*, ScrollingNodeID); - void provideGeolocationTo(Page*, GeolocationClient*); + virtual void updateBeforeChildren(ScrollingStateNode*) OVERRIDE; + virtual void parentScrollPositionDidChange(const IntRect& viewportRect, const FloatSize& cumulativeDelta) OVERRIDE; -protected: - virtual ~GeolocationClient() { } + StickyPositionViewportConstraints m_constraints; + RetainPtr<CALayer> m_layer; }; -void provideGeolocationTo(Page*, GeolocationClient*); - } // namespace WebCore -#endif // GeolocationClient_h +#endif // ENABLE(THREADED_SCROLLING) + +#endif // ScrollingTreeStickyNode_h diff --git a/Source/WebCore/page/scrolling/mac/ScrollingTreeStickyNode.mm b/Source/WebCore/page/scrolling/mac/ScrollingTreeStickyNode.mm new file mode 100644 index 000000000..20f8474f6 --- /dev/null +++ b/Source/WebCore/page/scrolling/mac/ScrollingTreeStickyNode.mm @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ScrollingTreeStickyNode.h" + +#if ENABLE(THREADED_SCROLLING) + +#include "ScrollingStateStickyNode.h" +#include "ScrollingTree.h" + +namespace WebCore { + +PassOwnPtr<ScrollingTreeStickyNode> ScrollingTreeStickyNode::create(ScrollingTree* scrollingTree, ScrollingNodeID nodeID) +{ + return adoptPtr(new ScrollingTreeStickyNode(scrollingTree, nodeID)); +} + +ScrollingTreeStickyNode::ScrollingTreeStickyNode(ScrollingTree* scrollingTree, ScrollingNodeID nodeID) + : ScrollingTreeNode(scrollingTree, nodeID) +{ +} + +ScrollingTreeStickyNode::~ScrollingTreeStickyNode() +{ +} + +void ScrollingTreeStickyNode::updateBeforeChildren(ScrollingStateNode* stateNode) +{ + ScrollingStateStickyNode* stickyStateNode = toScrollingStateStickyNode(stateNode); + + if (stickyStateNode->hasChangedProperty(ScrollingStateNode::ScrollLayer)) + m_layer = stickyStateNode->platformScrollLayer(); + + if (stateNode->hasChangedProperty(ScrollingStateStickyNode::ViewportConstraints)) + m_constraints = stickyStateNode->viewportConstraints(); +} + +static inline CGPoint operator*(CGPoint& a, const CGSize& b) +{ + return CGPointMake(a.x * b.width, a.y * b.height); +} + +void ScrollingTreeStickyNode::parentScrollPositionDidChange(const IntRect& viewportRect, const FloatSize& cumulativeDelta) +{ + FloatPoint layerPosition = m_constraints.layerPositionForConstrainingRect(viewportRect); + + // FIXME: Subtracting the cumulativeDelta is not totally sufficient to get the new position right for nested + // sticky objects. We probably need a way to modify the containingBlockRect in the ViewportContraints + // to get this right in all cases. + layerPosition -= cumulativeDelta; + + CGRect layerBounds = [m_layer.get() bounds]; + CGPoint anchorPoint = [m_layer.get() anchorPoint]; + CGPoint newPosition = layerPosition - m_constraints.alignmentOffset() + anchorPoint * layerBounds.size; + [m_layer.get() setPosition:newPosition]; + + if (!m_children) + return; + + FloatSize newDelta = layerPosition - m_constraints.layerPositionAtLastLayout() + cumulativeDelta; + + size_t size = m_children->size(); + for (size_t i = 0; i < size; ++i) + m_children->at(i)->parentScrollPositionDidChange(viewportRect, newDelta); +} + +} // namespace WebCore + +#endif // ENABLE(THREADED_SCROLLING) diff --git a/Source/WebCore/page/win/EventHandlerWin.cpp b/Source/WebCore/page/win/EventHandlerWin.cpp index e391b7765..d3a0582f6 100644 --- a/Source/WebCore/page/win/EventHandlerWin.cpp +++ b/Source/WebCore/page/win/EventHandlerWin.cpp @@ -27,6 +27,8 @@ #include "config.h" #include "EventHandler.h" +#include "COMPtr.h" +#include "Clipboard.h" #include "Cursor.h" #include "FloatPoint.h" #include "FocusController.h" @@ -43,12 +45,6 @@ #include "WCDataObject.h" #include "NotImplemented.h" -#if OS(WINCE) -#include "Clipboard.h" -#else -#include "ClipboardWin.h" -#endif - namespace WebCore { #if ENABLE(DRAG_SUPPORT) @@ -82,7 +78,7 @@ bool EventHandler::passWheelEventToWidget(const PlatformWheelEvent& wheelEvent, if (!widget->isFrameView()) return false; - return static_cast<FrameView*>(widget)->frame()->eventHandler()->handleWheelEvent(wheelEvent); + return toFrameView(widget)->frame()->eventHandler()->handleWheelEvent(wheelEvent); } bool EventHandler::tabsToAllFormControls(KeyboardEvent*) const @@ -101,9 +97,7 @@ PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const #if OS(WINCE) return 0; #else - COMPtr<WCDataObject> dataObject; - WCDataObject::createInstance(&dataObject); - return ClipboardWin::create(Clipboard::DragAndDrop, dataObject.get(), ClipboardWritable, m_frame); + return Clipboard::createForDragAndDrop(); #endif } #endif diff --git a/Source/WebCore/page/win/FrameCGWin.cpp b/Source/WebCore/page/win/FrameCGWin.cpp index b5598826c..d9ffd6416 100644 --- a/Source/WebCore/page/win/FrameCGWin.cpp +++ b/Source/WebCore/page/win/FrameCGWin.cpp @@ -28,6 +28,7 @@ #include "BitmapInfo.h" #include "Frame.h" +#include "FrameSelection.h" #include "FrameView.h" #include "GraphicsContextCG.h" #include "RenderObject.h" diff --git a/Source/WebCore/page/win/FrameWin.cpp b/Source/WebCore/page/win/FrameWin.cpp index e425ed94e..c452559a7 100644 --- a/Source/WebCore/page/win/FrameWin.cpp +++ b/Source/WebCore/page/win/FrameWin.cpp @@ -30,7 +30,9 @@ #include "Document.h" #include "FloatRect.h" #include "Frame.h" +#include "FrameSelection.h" #include "PrintContext.h" +#include "Range.h" #include "RenderView.h" #include "Settings.h" #include "TransformationMatrix.h" diff --git a/Source/WebCore/page/wince/FrameWinCE.cpp b/Source/WebCore/page/wince/FrameWinCE.cpp index 09d6ffb3b..fa004209f 100644 --- a/Source/WebCore/page/wince/FrameWinCE.cpp +++ b/Source/WebCore/page/wince/FrameWinCE.cpp @@ -29,6 +29,7 @@ #include "Document.h" #include "FloatRect.h" +#include "FrameSelection.h" #include "FrameView.h" #include "GraphicsContext.h" #include "HTMLIFrameElement.h" diff --git a/Source/WebCore/page/wx/DragControllerWx.cpp b/Source/WebCore/page/wx/DragControllerWx.cpp deleted file mode 100644 index 5c19c47fd..000000000 --- a/Source/WebCore/page/wx/DragControllerWx.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2007 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "DragController.h" - -#include "DragData.h" -#include "Frame.h" -#include "FrameView.h" -#include "NotImplemented.h" -#include "Page.h" - -namespace WebCore { - -// FIXME: These values are straight out of DragControllerMac, so probably have -// little correlation with wx standards... -const int DragController::LinkDragBorderInset = 2; -const int DragController::MaxOriginalImageArea = 1500 * 1500; -const int DragController::DragIconRightInset = 7; -const int DragController::DragIconBottomInset = 3; - -const float DragController::DragImageAlpha = 0.75f; - -bool DragController::isCopyKeyDown(DragData*) -{ - notImplemented(); - return false; -} - -DragOperation DragController::dragOperation(DragData* dragData) -{ - //FIXME: This logic is incomplete - if (dragData->containsURL(0)) - return DragOperationCopy; - - return DragOperationNone; -} - -const IntSize& DragController::maxDragImageSize() -{ - static const IntSize maxDragImageSize(400, 400); - - return maxDragImageSize; -} - -void DragController::cleanupAfterSystemDrag() -{ -} - -} diff --git a/Source/WebCore/page/wx/EventHandlerWx.cpp b/Source/WebCore/page/wx/EventHandlerWx.cpp deleted file mode 100644 index 167cc930a..000000000 --- a/Source/WebCore/page/wx/EventHandlerWx.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (C) 2007 Kevin Ollivier <kevino@theolliviers.com>. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "EventHandler.h" - -#include "ClipboardWx.h" -#include "FocusController.h" -#include "Frame.h" -#include "FrameView.h" -#include "KeyboardEvent.h" -#include "MouseEventWithHitTestResults.h" -#include "NotImplemented.h" -#include "Page.h" -#include "PlatformKeyboardEvent.h" -#include "RenderWidget.h" -#include "Scrollbar.h" - -namespace WebCore { - -const double EventHandler::TextDragDelay = 0.0; - -bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe) -{ - subframe->eventHandler()->handleMousePressEvent(mev.event()); - return true; -} - -bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe, WebCore::HitTestResult* hittest) -{ - subframe->eventHandler()->handleMouseMoveEvent(mev.event(), hittest); - return true; -} - -bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe) -{ - subframe->eventHandler()->handleMouseReleaseEvent(mev.event()); - return true; -} - -bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults& event) -{ - // Figure out which view to send the event to. - if (!event.targetNode() || !event.targetNode()->renderer() || !event.targetNode()->renderer()->isWidget()) - return false; - - return passMouseDownEventToWidget(toRenderWidget(event.targetNode()->renderer())->widget()); -} - -bool EventHandler::passWidgetMouseDownEventToWidget(RenderWidget* renderWidget) -{ - return passMouseDownEventToWidget(renderWidget->widget()); -} - -bool EventHandler::passWheelEventToWidget(const PlatformWheelEvent& event, Widget* widget) -{ - if (!widget || !widget->isFrameView()) - return false; - - return static_cast<FrameView*>(widget)->frame()->eventHandler()->handleWheelEvent(event); -} - -bool EventHandler::tabsToAllFormControls(KeyboardEvent* event) const -{ - notImplemented(); - return false; -} - -bool EventHandler::passSubframeEventToSubframe(MouseEventWithHitTestResults&, Frame* subframe, HitTestResult*) -{ - notImplemented(); - return false; -} - -bool EventHandler::passMouseDownEventToWidget(Widget*) -{ - notImplemented(); - return false; -} - -void EventHandler::focusDocumentView() -{ - if (Page* page = m_frame->page()) - page->focusController()->setFocusedFrame(m_frame); -} - -bool EventHandler::eventActivatedView(const PlatformMouseEvent&) const -{ - // wx sends activate events separate from mouse events. - // We'll have to test the exact order of events, - // but for the moment just return false. - return false; -} - -PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const -{ - return ClipboardWx::create(ClipboardWritable, Clipboard::DragAndDrop); -} - -unsigned EventHandler::accessKeyModifiers() -{ - return PlatformEvent::AltKey; -} - -} |
