diff options
author | Lars Knoll <lars.knoll@nokia.com> | 2009-03-23 09:34:13 (GMT) |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2009-03-23 09:34:13 (GMT) |
commit | 67ad0519fd165acee4a4d2a94fa502e9e4847bd0 (patch) | |
tree | 1dbf50b3dff8d5ca7e9344733968c72704eb15ff /src/3rdparty/webkit/WebCore/page | |
download | Qt-67ad0519fd165acee4a4d2a94fa502e9e4847bd0.zip Qt-67ad0519fd165acee4a4d2a94fa502e9e4847bd0.tar.gz Qt-67ad0519fd165acee4a4d2a94fa502e9e4847bd0.tar.bz2 |
Long live Qt!
Diffstat (limited to 'src/3rdparty/webkit/WebCore/page')
132 files changed, 28929 insertions, 0 deletions
diff --git a/src/3rdparty/webkit/WebCore/page/AXObjectCache.cpp b/src/3rdparty/webkit/WebCore/page/AXObjectCache.cpp new file mode 100644 index 0000000..d9c4c9a --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/AXObjectCache.cpp @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2008 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 "AXObjectCache.h" + +#include "AccessibilityList.h" +#include "AccessibilityListBox.h" +#include "AccessibilityListBoxOption.h" +#include "AccessibilityImageMapLink.h" +#include "AccessibilityRenderObject.h" +#include "AccessibilityTable.h" +#include "AccessibilityTableCell.h" +#include "AccessibilityTableColumn.h" +#include "AccessibilityTableHeaderContainer.h" +#include "AccessibilityTableRow.h" +#include "HTMLNames.h" +#include "RenderObject.h" + +#include <wtf/PassRefPtr.h> + +namespace WebCore { + +using namespace HTMLNames; + +bool AXObjectCache::gAccessibilityEnabled = false; +bool AXObjectCache::gAccessibilityEnhancedUserInterfaceEnabled = false; + +AXObjectCache::~AXObjectCache() +{ + HashMap<AXID, RefPtr<AccessibilityObject> >::iterator end = m_objects.end(); + for (HashMap<AXID, RefPtr<AccessibilityObject> >::iterator it = m_objects.begin(); it != end; ++it) { + AccessibilityObject* obj = (*it).second.get(); + detachWrapper(obj); + obj->detach(); + } +} + +AccessibilityObject* AXObjectCache::get(RenderObject* renderer) +{ + if (!renderer) + return 0; + + RefPtr<AccessibilityObject> obj = 0; + AXID axID = m_renderObjectMapping.get(renderer); + ASSERT(!HashTraits<AXID>::isDeletedValue(axID)); + + if (axID) + obj = m_objects.get(axID).get(); + + Node* element = renderer->element(); + if (!obj) { + if (renderer->isListBox()) + obj = AccessibilityListBox::create(renderer); + else if (element && (element->hasTagName(ulTag) || element->hasTagName(olTag) || element->hasTagName(dlTag))) + obj = AccessibilityList::create(renderer); + else if (renderer->isTable()) + obj = AccessibilityTable::create(renderer); + else if (renderer->isTableRow()) + obj = AccessibilityTableRow::create(renderer); + else if (renderer->isTableCell()) + obj = AccessibilityTableCell::create(renderer); + else + obj = AccessibilityRenderObject::create(renderer); + + getAXID(obj.get()); + + m_renderObjectMapping.set(renderer, obj.get()->axObjectID()); + m_objects.set(obj.get()->axObjectID(), obj); + attachWrapper(obj.get()); + } + + return obj.get(); +} + +AccessibilityObject* AXObjectCache::get(AccessibilityRole role) +{ + RefPtr<AccessibilityObject> obj = 0; + + // will be filled in... + switch (role) { + case ListBoxOptionRole: + obj = AccessibilityListBoxOption::create(); + break; + case ImageMapLinkRole: + obj = AccessibilityImageMapLink::create(); + break; + case ColumnRole: + obj = AccessibilityTableColumn::create(); + break; + case TableHeaderContainerRole: + obj = AccessibilityTableHeaderContainer::create(); + break; + default: + obj = 0; + } + + if (obj) + getAXID(obj.get()); + else + return 0; + + m_objects.set(obj->axObjectID(), obj); + attachWrapper(obj.get()); + return obj.get(); +} + +void AXObjectCache::remove(AXID axID) +{ + if (!axID) + return; + + // first fetch object to operate some cleanup functions on it + AccessibilityObject* obj = m_objects.get(axID).get(); + if (!obj) + return; + + detachWrapper(obj); + obj->detach(); + removeAXID(obj); + + // finally remove the object + if (!m_objects.take(axID)) { + return; + } + + ASSERT(m_objects.size() >= m_idsInUse.size()); +} + +void AXObjectCache::remove(RenderObject* renderer) +{ + if (!renderer) + return; + + AXID axID = m_renderObjectMapping.get(renderer); + remove(axID); + m_renderObjectMapping.remove(renderer); +} + +AXID AXObjectCache::getAXID(AccessibilityObject* obj) +{ + // check for already-assigned ID + AXID objID = obj->axObjectID(); + if (objID) { + ASSERT(m_idsInUse.contains(objID)); + return objID; + } + + // generate a new ID + static AXID lastUsedID = 0; + objID = lastUsedID; + do + ++objID; + while (objID == 0 || HashTraits<AXID>::isDeletedValue(objID) || m_idsInUse.contains(objID)); + m_idsInUse.add(objID); + lastUsedID = objID; + obj->setAXObjectID(objID); + + return objID; +} + +void AXObjectCache::removeAXID(AccessibilityObject* obj) +{ + AXID objID = obj->axObjectID(); + if (objID == 0) + return; + ASSERT(!HashTraits<AXID>::isDeletedValue(objID)); + ASSERT(m_idsInUse.contains(objID)); + obj->setAXObjectID(0); + m_idsInUse.remove(objID); +} + +void AXObjectCache::childrenChanged(RenderObject* renderer) +{ + if (!renderer) + return; + + AXID axID = m_renderObjectMapping.get(renderer); + if (!axID) + return; + + AccessibilityObject* obj = m_objects.get(axID).get(); + if (obj) + obj->childrenChanged(); +} + +#if HAVE(ACCESSIBILITY) +void AXObjectCache::selectedChildrenChanged(RenderObject* renderer) +{ + postNotificationToElement(renderer, "AXSelectedChildrenChanged"); +} +#endif + +#if HAVE(ACCESSIBILITY) +void AXObjectCache::handleActiveDescendantChanged(RenderObject* renderer) +{ + if (!renderer) + return; + AccessibilityObject* obj = get(renderer); + if (obj) + obj->handleActiveDescendantChanged(); +} + +void AXObjectCache::handleAriaRoleChanged(RenderObject* renderer) +{ + if (!renderer) + return; + AccessibilityObject* obj = get(renderer); + if (obj && obj->isAccessibilityRenderObject()) + static_cast<AccessibilityRenderObject*>(obj)->setAriaRole(); +} +#endif + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/AXObjectCache.h b/src/3rdparty/webkit/WebCore/page/AXObjectCache.h new file mode 100644 index 0000000..5e95f74 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/AXObjectCache.h @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2003, 2006, 2007, 2008 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 AXObjectCache_h +#define AXObjectCache_h + +#include "AccessibilityObject.h" +#include <limits.h> +#include <wtf/HashMap.h> +#include <wtf/HashSet.h> +#include <wtf/RefPtr.h> + +#ifdef __OBJC__ +@class WebCoreTextMarker; +#else +class WebCoreTextMarker; +#endif + +namespace WebCore { + + class RenderObject; + class String; + class VisiblePosition; + class AccessibilityObject; + class Node; + + typedef unsigned AXID; + + struct TextMarkerData { + AXID axID; + Node* node; + int offset; + EAffinity affinity; + }; + + class AXObjectCache { + public: + ~AXObjectCache(); + + // to be used with render objects + AccessibilityObject* get(RenderObject*); + + // used for objects without backing elements + AccessibilityObject* get(AccessibilityRole); + + void remove(RenderObject*); + void remove(AXID); + + void detachWrapper(AccessibilityObject*); + void attachWrapper(AccessibilityObject*); + void postNotification(RenderObject*, const String&); + void postNotificationToElement(RenderObject*, const String&); + void childrenChanged(RenderObject*); + void selectedChildrenChanged(RenderObject*); + void handleActiveDescendantChanged(RenderObject*); + void handleAriaRoleChanged(RenderObject*); + void handleFocusedUIElementChanged(); + static void enableAccessibility() { gAccessibilityEnabled = true; } + static void enableEnhancedUserInterfaceAccessibility() { gAccessibilityEnhancedUserInterfaceEnabled = true; } + + static bool accessibilityEnabled() { return gAccessibilityEnabled; } + static bool accessibilityEnhancedUserInterfaceEnabled() { return gAccessibilityEnhancedUserInterfaceEnabled; } + + void removeAXID(AccessibilityObject*); + bool isIDinUse(AXID id) const { return m_idsInUse.contains(id); } + + private: + HashMap<AXID, RefPtr<AccessibilityObject> > m_objects; + HashMap<RenderObject*, AXID> m_renderObjectMapping; + static bool gAccessibilityEnabled; + static bool gAccessibilityEnhancedUserInterfaceEnabled; + + HashSet<AXID> m_idsInUse; + + AXID getAXID(AccessibilityObject*); + }; + +#if !HAVE(ACCESSIBILITY) + inline void AXObjectCache::handleActiveDescendantChanged(RenderObject*) { } + inline void AXObjectCache::handleAriaRoleChanged(RenderObject*) { } + inline void AXObjectCache::handleFocusedUIElementChanged() { } + inline void AXObjectCache::detachWrapper(AccessibilityObject*) { } + inline void AXObjectCache::attachWrapper(AccessibilityObject*) { } + inline void AXObjectCache::selectedChildrenChanged(RenderObject*) { } + inline void AXObjectCache::postNotification(RenderObject*, const String&) { } + inline void AXObjectCache::postNotificationToElement(RenderObject*, const String&) { } +#endif + +} + +#endif diff --git a/src/3rdparty/webkit/WebCore/page/AbstractView.idl b/src/3rdparty/webkit/WebCore/page/AbstractView.idl new file mode 100644 index 0000000..5b7ce89 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/AbstractView.idl @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com> + * + * 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. + */ + +module views { + + // Introduced in DOM Level 2: + interface [ + ObjCCustomImplementation + ] AbstractView { + readonly attribute Document document; + }; + +} diff --git a/src/3rdparty/webkit/WebCore/page/AccessibilityImageMapLink.cpp b/src/3rdparty/webkit/WebCore/page/AccessibilityImageMapLink.cpp new file mode 100644 index 0000000..5557446 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/AccessibilityImageMapLink.cpp @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2008 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 "AccessibilityImageMapLink.h" + +#include "AccessibilityRenderObject.h" +#include "AXObjectCache.h" +#include "Document.h" +#include "HTMLNames.h" +#include "IntRect.h" +#include "RenderObject.h" + +using namespace std; + +namespace WebCore { + +using namespace HTMLNames; + +AccessibilityImageMapLink::AccessibilityImageMapLink() + : m_areaElement(0), + m_mapElement(0) +{ +} + +AccessibilityImageMapLink::~AccessibilityImageMapLink() +{ +} + +PassRefPtr<AccessibilityImageMapLink> AccessibilityImageMapLink::create() +{ + return adoptRef(new AccessibilityImageMapLink()); +} + +AccessibilityObject* AccessibilityImageMapLink::parentObject() const +{ + if (m_parent) + return m_parent; + + if (!m_mapElement || !m_mapElement->renderer()) + return 0; + + return m_mapElement->document()->axObjectCache()->get(m_mapElement->renderer()); +} + +Element* AccessibilityImageMapLink::actionElement() const +{ + return anchorElement(); +} + +Element* AccessibilityImageMapLink::anchorElement() const +{ + return m_areaElement; +} + +String AccessibilityImageMapLink::accessibilityDescription() const +{ + if (!m_areaElement) + return String(); + + const AtomicString& alt = m_areaElement->getAttribute(altAttr); + if (!alt.isEmpty()) + return alt; + + return String(); +} + +String AccessibilityImageMapLink::title() const +{ + if (!m_areaElement) + return String(); + + const AtomicString& title = m_areaElement->getAttribute(titleAttr); + if (!title.isEmpty()) + return title; + const AtomicString& summary = m_areaElement->getAttribute(summaryAttr); + if (!summary.isEmpty()) + return summary; + + return String(); +} + +IntRect AccessibilityImageMapLink::elementRect() const +{ + if (!m_mapElement || !m_areaElement) + return IntRect(); + + RenderObject* renderer; + if (m_parent && m_parent->isAccessibilityRenderObject()) + renderer = static_cast<AccessibilityRenderObject*>(m_parent)->renderer(); + else + renderer = m_mapElement->renderer(); + + if (!renderer) + return IntRect(); + + return m_areaElement->getRect(renderer); +} + +IntSize AccessibilityImageMapLink::size() const +{ + return elementRect().size(); +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/AccessibilityImageMapLink.h b/src/3rdparty/webkit/WebCore/page/AccessibilityImageMapLink.h new file mode 100644 index 0000000..7fc8d3c --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/AccessibilityImageMapLink.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2008 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. + */ + +#ifndef AccessibilityImageMapLink_h +#define AccessibilityImageMapLink_h + +#include "AccessibilityObject.h" +#include "HTMLAreaElement.h" +#include "HTMLMapElement.h" + +namespace WebCore { + +class AccessibilityImageMapLink : public AccessibilityObject { + +private: + AccessibilityImageMapLink(); +public: + static PassRefPtr<AccessibilityImageMapLink> create(); + virtual ~AccessibilityImageMapLink(); + + void setHTMLAreaElement(HTMLAreaElement* element) { m_areaElement = element; } + void setHTMLMapElement(HTMLMapElement* element) { m_mapElement = element; } + void setParent(AccessibilityObject* parent) { m_parent = parent; } + + virtual AccessibilityRole roleValue() const { return WebCoreLinkRole; } + virtual bool accessibilityIsIgnored() const { return false; } + + virtual AccessibilityObject* parentObject() const; + virtual Element* anchorElement() const; + virtual Element* actionElement() const; + + virtual bool isLink() const { return true; } + virtual String title() const; + virtual String accessibilityDescription() const; + + virtual IntSize size() const; + virtual IntRect elementRect() const; + +private: + HTMLAreaElement* m_areaElement; + HTMLMapElement* m_mapElement; + AccessibilityObject* m_parent; +}; + +} // namespace WebCore + +#endif // AccessibilityImageMapLink_h diff --git a/src/3rdparty/webkit/WebCore/page/AccessibilityList.cpp b/src/3rdparty/webkit/WebCore/page/AccessibilityList.cpp new file mode 100644 index 0000000..ad71ff4 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/AccessibilityList.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2008 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 "AccessibilityList.h" + +#include "AXObjectCache.h" +#include "HTMLNames.h" +#include "RenderObject.h" + +using namespace std; + +namespace WebCore { + +using namespace HTMLNames; + +AccessibilityList::AccessibilityList(RenderObject* renderer) + : AccessibilityRenderObject(renderer) +{ +} + +AccessibilityList::~AccessibilityList() +{ +} + +PassRefPtr<AccessibilityList> AccessibilityList::create(RenderObject* renderer) +{ + return adoptRef(new AccessibilityList(renderer)); +} + +bool AccessibilityList::accessibilityIsIgnored() const +{ + // lists don't appear on tiger/leopard on the mac +#if PLATFORM(MAC) && (defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD)) + return true; +#else + return false; +#endif +} + +bool AccessibilityList::isUnorderedList() const +{ + if (!m_renderer) + return false; + + Node* element = m_renderer->element(); + return element && element->hasTagName(ulTag); +} + +bool AccessibilityList::isOrderedList() const +{ + if (!m_renderer) + return false; + + Node* element = m_renderer->element(); + return element && element->hasTagName(olTag); +} + +bool AccessibilityList::isDefinitionList() const +{ + if (!m_renderer) + return false; + + Node* element = m_renderer->element(); + return element && element->hasTagName(dlTag); +} + + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/AccessibilityList.h b/src/3rdparty/webkit/WebCore/page/AccessibilityList.h new file mode 100644 index 0000000..315ccac --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/AccessibilityList.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2008 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. + */ + +#ifndef AccessibilityList_h +#define AccessibilityList_h + +#include "AccessibilityRenderObject.h" + +namespace WebCore { + +class AccessibilityList : public AccessibilityRenderObject { + +private: + AccessibilityList(RenderObject*); +public: + static PassRefPtr<AccessibilityList> create(RenderObject*); + virtual ~AccessibilityList(); + + virtual bool isList() const { return true; }; + bool isUnorderedList() const; + bool isOrderedList() const; + bool isDefinitionList() const; + + virtual AccessibilityRole roleValue() const { return ListRole; } + virtual bool accessibilityIsIgnored() const; + +}; + +} // namespace WebCore + +#endif // AccessibilityList_h diff --git a/src/3rdparty/webkit/WebCore/page/AccessibilityListBox.cpp b/src/3rdparty/webkit/WebCore/page/AccessibilityListBox.cpp new file mode 100644 index 0000000..b94ccef --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/AccessibilityListBox.cpp @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2008 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 "AccessibilityListBox.h" + +#include "AXObjectCache.h" +#include "AccessibilityListBoxOption.h" +#include "HitTestResult.h" +#include "HTMLNames.h" +#include "HTMLSelectElement.h" +#include "RenderListBox.h" +#include "RenderObject.h" + +using namespace std; + +namespace WebCore { + +using namespace HTMLNames; + +AccessibilityListBox::AccessibilityListBox(RenderObject* renderer) + : AccessibilityRenderObject(renderer) +{ +} + +AccessibilityListBox::~AccessibilityListBox() +{ +} + +PassRefPtr<AccessibilityListBox> AccessibilityListBox::create(RenderObject* renderer) +{ + return adoptRef(new AccessibilityListBox(renderer)); +} + +bool AccessibilityListBox::canSetSelectedChildrenAttribute() const +{ + Node* selectNode = m_renderer->node(); + if (!selectNode) + return false; + + return !static_cast<HTMLSelectElement*>(selectNode)->disabled(); +} + +void AccessibilityListBox::addChildren() +{ + Node* selectNode = m_renderer->node(); + if (!selectNode) + return; + + m_haveChildren = true; + + const Vector<HTMLElement*>& listItems = static_cast<HTMLSelectElement*>(selectNode)->listItems(); + unsigned length = listItems.size(); + for (unsigned i = 0; i < length; i++) { + AccessibilityObject* listOption = listBoxOptionAccessibilityObject(listItems[i]); + if (listOption) + m_children.append(listOption); + } +} + +void AccessibilityListBox::setSelectedChildren(AccessibilityChildrenVector& children) +{ + if (!canSetSelectedChildrenAttribute()) + return; + + Node* selectNode = m_renderer->node(); + if (!selectNode) + return; + + // disable any selected options + unsigned length = m_children.size(); + for (unsigned i = 0; i < length; i++) { + AccessibilityListBoxOption* listBoxOption = static_cast<AccessibilityListBoxOption*>(m_children[i].get()); + if (listBoxOption->isSelected()) + listBoxOption->setSelected(false); + } + + length = children.size(); + for (unsigned i = 0; i < length; i++) { + AccessibilityObject* obj = children[i].get(); + if (obj->roleValue() != ListBoxOptionRole) + continue; + + static_cast<AccessibilityListBoxOption*>(obj)->setSelected(true); + } +} + +void AccessibilityListBox::selectedChildren(AccessibilityChildrenVector& result) +{ + ASSERT(result.isEmpty()); + + if (!hasChildren()) + addChildren(); + + unsigned length = m_children.size(); + for (unsigned i = 0; i < length; i++) { + if (static_cast<AccessibilityListBoxOption*>(m_children[i].get())->isSelected()) + result.append(m_children[i]); + } +} + +void AccessibilityListBox::visibleChildren(AccessibilityChildrenVector& result) +{ + ASSERT(result.isEmpty()); + + if (!hasChildren()) + addChildren(); + + unsigned length = m_children.size(); + for (unsigned i = 0; i < length; i++) { + if (static_cast<RenderListBox*>(m_renderer)->listIndexIsVisible(i)) + result.append(m_children[i]); + } +} + +AccessibilityObject* AccessibilityListBox::listBoxOptionAccessibilityObject(HTMLElement* element) const +{ + // skip hr elements + if (!element || element->hasTagName(hrTag)) + return 0; + + AccessibilityObject* listBoxObject = m_renderer->document()->axObjectCache()->get(ListBoxOptionRole); + static_cast<AccessibilityListBoxOption*>(listBoxObject)->setHTMLElement(element); + + return listBoxObject; +} + +AccessibilityObject* AccessibilityListBox::doAccessibilityHitTest(const IntPoint& point) const +{ + // the internal HTMLSelectElement methods for returning a listbox option at a point + // ignore optgroup elements. + if (!m_renderer) + return 0; + + Node* element = m_renderer->element(); + if (!element) + return 0; + + IntRect parentRect = boundingBoxRect(); + + const Vector<HTMLElement*>& listItems = static_cast<HTMLSelectElement*>(element)->listItems(); + unsigned length = listItems.size(); + for (unsigned i = 0; i < length; i++) { + IntRect rect = static_cast<RenderListBox*>(m_renderer)->itemBoundingBoxRect(parentRect.x(), parentRect.y(), i); + if (rect.contains(point)) + return listBoxOptionAccessibilityObject(listItems[i]); + } + + return axObjectCache()->get(m_renderer); +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/AccessibilityListBox.h b/src/3rdparty/webkit/WebCore/page/AccessibilityListBox.h new file mode 100644 index 0000000..3f3352d --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/AccessibilityListBox.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2008 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. + */ + +#ifndef AccessibilityListBox_h +#define AccessibilityListBox_h + +#include "AccessibilityObject.h" +#include "AccessibilityRenderObject.h" + +namespace WebCore { + +class AccessibilityListBox : public AccessibilityRenderObject { + +private: + AccessibilityListBox(RenderObject*); +public: + static PassRefPtr<AccessibilityListBox> create(RenderObject*); + virtual ~AccessibilityListBox(); + + virtual AccessibilityObject* doAccessibilityHitTest(const IntPoint&) const; + virtual bool isListBox() const { return true; }; + + virtual bool canSetFocusAttribute() const { return true; } + virtual bool canSetSelectedChildrenAttribute() const; + void setSelectedChildren(AccessibilityChildrenVector&); + virtual AccessibilityRole roleValue() const { return ListBoxRole; } + + virtual bool accessibilityIsIgnored() const { return false; } + + virtual void selectedChildren(AccessibilityChildrenVector&); + virtual void visibleChildren(AccessibilityChildrenVector&); + + virtual void addChildren(); + +private: + AccessibilityObject* listBoxOptionAccessibilityObject(HTMLElement*) const; +}; + +} // namespace WebCore + +#endif // AccessibilityListBox_h diff --git a/src/3rdparty/webkit/WebCore/page/AccessibilityListBoxOption.cpp b/src/3rdparty/webkit/WebCore/page/AccessibilityListBoxOption.cpp new file mode 100644 index 0000000..fedfe91 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/AccessibilityListBoxOption.cpp @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2008 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 "AccessibilityListBoxOption.h" + +#include "AXObjectCache.h" +#include "AccessibilityListBox.h" +#include "Element.h" +#include "HTMLElement.h" +#include "HTMLNames.h" +#include "HTMLOptionElement.h" +#include "HTMLOptGroupElement.h" +#include "HTMLSelectElement.h" +#include "IntRect.h" +#include "RenderObject.h" +#include "RenderListBox.h" + +using namespace std; + +namespace WebCore { + +using namespace HTMLNames; + +AccessibilityListBoxOption::AccessibilityListBoxOption() + : m_optionElement(0) +{ +} + +AccessibilityListBoxOption::~AccessibilityListBoxOption() +{ +} + +PassRefPtr<AccessibilityListBoxOption> AccessibilityListBoxOption::create() +{ + return adoptRef(new AccessibilityListBoxOption()); +} + +bool AccessibilityListBoxOption::isEnabled() const +{ + if (!m_optionElement) + return false; + + if (m_optionElement->hasTagName(optgroupTag)) + return false; + + return true; +} + +bool AccessibilityListBoxOption::isSelected() const +{ + if (!m_optionElement) + return false; + + if (!m_optionElement->hasTagName(optionTag)) + return false; + + return static_cast<HTMLOptionElement*>(m_optionElement)->selected(); +} + +IntRect AccessibilityListBoxOption::elementRect() const +{ + IntRect rect; + if (!m_optionElement) + return rect; + + HTMLSelectElement* listBoxParentNode = listBoxOptionParentNode(); + if (!listBoxParentNode) + return rect; + + RenderObject* listBoxRenderer = listBoxParentNode->renderer(); + if (!listBoxRenderer) + return rect; + + IntRect parentRect = listBoxRenderer->document()->axObjectCache()->get(listBoxRenderer)->boundingBoxRect(); + int index = listBoxOptionIndex(); + if (index != -1) + rect = static_cast<RenderListBox*>(listBoxRenderer)->itemBoundingBoxRect(parentRect.x(), parentRect.y(), index); + + return rect; +} + +bool AccessibilityListBoxOption::canSetSelectedAttribute() const +{ + if (!m_optionElement) + return false; + + if (!m_optionElement->hasTagName(optionTag)) + return false; + + if (m_optionElement->disabled()) + return false; + + HTMLSelectElement* selectElement = listBoxOptionParentNode(); + if (selectElement && selectElement->disabled()) + return false; + + return true; +} + +String AccessibilityListBoxOption::stringValue() const +{ + if (!m_optionElement) + return String(); + + if (m_optionElement->hasTagName(optionTag)) + return static_cast<HTMLOptionElement*>(m_optionElement)->text(); + + if (m_optionElement->hasTagName(optgroupTag)) + return static_cast<HTMLOptGroupElement*>(m_optionElement)->groupLabelText(); + + return String(); +} + +IntSize AccessibilityListBoxOption::size() const +{ + return elementRect().size(); +} + +Element* AccessibilityListBoxOption::actionElement() const +{ + return m_optionElement; +} + +AccessibilityObject* AccessibilityListBoxOption::parentObject() const +{ + HTMLSelectElement* parentNode = listBoxOptionParentNode(); + if (!parentNode) + return 0; + + return m_optionElement->document()->axObjectCache()->get(parentNode->renderer()); +} + +void AccessibilityListBoxOption::setSelected(bool selected) +{ + HTMLSelectElement* selectElement = listBoxOptionParentNode(); + if (!selectElement) + return; + + if (!canSetSelectedAttribute()) + return; + + bool isOptionSelected = isSelected(); + if ((isOptionSelected && selected) || (!isOptionSelected && !selected)) + return; + + selectElement->accessKeySetSelectedIndex(listBoxOptionIndex()); +} + +HTMLSelectElement* AccessibilityListBoxOption::listBoxOptionParentNode() const +{ + if (!m_optionElement) + return 0; + + if (m_optionElement->hasTagName(optionTag)) + return static_cast<HTMLOptionElement*>(m_optionElement)->ownerSelectElement(); + + if (m_optionElement->hasTagName(optgroupTag)) + return static_cast<HTMLOptGroupElement*>(m_optionElement)->ownerSelectElement(); + + return 0; +} + +int AccessibilityListBoxOption::listBoxOptionIndex() const +{ + if (!m_optionElement) + return -1; + + HTMLSelectElement* selectElement = listBoxOptionParentNode(); + if (!selectElement) + return -1; + + const Vector<HTMLElement*>& listItems = selectElement->listItems(); + unsigned length = listItems.size(); + for (unsigned i = 0; i < length; i++) + if (listItems[i] == m_optionElement) + return i; + + return -1; +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/AccessibilityListBoxOption.h b/src/3rdparty/webkit/WebCore/page/AccessibilityListBoxOption.h new file mode 100644 index 0000000..1b588cd --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/AccessibilityListBoxOption.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2008 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. + */ + +#ifndef AccessibilityListBoxOption_h +#define AccessibilityListBoxOption_h + +#include "AccessibilityObject.h" +#include "HTMLElement.h" + +namespace WebCore { + +class AccessibilityListBox; +class Element; +class HTMLElement; +class HTMLSelectElement; +class String; + +class AccessibilityListBoxOption : public AccessibilityObject { + +private: + AccessibilityListBoxOption(); +public: + static PassRefPtr<AccessibilityListBoxOption> create(); + virtual ~AccessibilityListBoxOption(); + + void setHTMLElement(HTMLElement* element) { m_optionElement = element; } + + virtual AccessibilityRole roleValue() const { return ListBoxOptionRole; } + virtual bool accessibilityIsIgnored() const { return false; } + virtual bool isSelected() const; + virtual bool isEnabled() const; + virtual String stringValue() const; + virtual Element* actionElement() const; + + virtual void setSelected(bool); + virtual bool canSetSelectedAttribute() const; + + virtual IntRect elementRect() const; + virtual IntSize size() const; + virtual AccessibilityObject* parentObject() const; + bool isListBoxOption() const { return true; }; + +private: + HTMLElement* m_optionElement; + + HTMLSelectElement* listBoxOptionParentNode() const; + int listBoxOptionIndex() const; + IntRect listBoxOptionRect() const; + AccessibilityObject* listBoxOptionAccessibilityObject(HTMLElement* element) const; +}; + +} // namespace WebCore + +#endif // AccessibilityListBoxOption_h diff --git a/src/3rdparty/webkit/WebCore/page/AccessibilityObject.cpp b/src/3rdparty/webkit/WebCore/page/AccessibilityObject.cpp new file mode 100644 index 0000000..0b072cf --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/AccessibilityObject.cpp @@ -0,0 +1,1031 @@ +/* + * Copyright (C) 2008 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 "AccessibilityObject.h" + +#include "AccessibilityRenderObject.h" +#include "AXObjectCache.h" +#include "CharacterNames.h" +#include "FloatRect.h" +#include "FocusController.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "LocalizedStrings.h" +#include "NodeList.h" +#include "NotImplemented.h" +#include "Page.h" +#include "RenderImage.h" +#include "RenderListMarker.h" +#include "RenderMenuList.h" +#include "RenderTextControl.h" +#include "RenderTheme.h" +#include "RenderView.h" +#include "RenderWidget.h" +#include "SelectionController.h" +#include "TextIterator.h" +#include "htmlediting.h" +#include "visible_units.h" +#include <wtf/StdLibExtras.h> + +using namespace std; + +namespace WebCore { + +using namespace HTMLNames; + +AccessibilityObject::AccessibilityObject() + : m_id(0) + , m_haveChildren(false) +#if PLATFORM(GTK) + , m_wrapper(0) +#endif +{ +} + +AccessibilityObject::~AccessibilityObject() +{ + ASSERT(isDetached()); +} + +void AccessibilityObject::detach() +{ + removeAXObjectID(); +#if HAVE(ACCESSIBILITY) + setWrapper(0); +#endif +} + +AccessibilityObject* AccessibilityObject::firstChild() const +{ + return 0; +} + +AccessibilityObject* AccessibilityObject::lastChild() const +{ + return 0; +} + +AccessibilityObject* AccessibilityObject::previousSibling() const +{ + return 0; +} + +AccessibilityObject* AccessibilityObject::nextSibling() const +{ + return 0; +} + +AccessibilityObject* AccessibilityObject::parentObject() const +{ + return 0; +} + +AccessibilityObject* AccessibilityObject::parentObjectUnignored() const +{ + AccessibilityObject* parent; + for (parent = parentObject(); parent && parent->accessibilityIsIgnored(); parent = parent->parentObject()) + ; + return parent; +} + +int AccessibilityObject::layoutCount() const +{ + return 0; +} + +String AccessibilityObject::text() const +{ + return String(); +} + +String AccessibilityObject::helpText() const +{ + return String(); +} + +String AccessibilityObject::textUnderElement() const +{ + return String(); +} + +bool AccessibilityObject::isARIAInput(AccessibilityRole ariaRole) +{ + return ariaRole == RadioButtonRole || ariaRole == CheckBoxRole || ariaRole == TextFieldRole; +} + +bool AccessibilityObject::isARIAControl(AccessibilityRole ariaRole) +{ + return isARIAInput(ariaRole) || ariaRole == TextAreaRole || ariaRole == ButtonRole + || ariaRole == ComboBoxRole || ariaRole == SliderRole; +} + +int AccessibilityObject::intValue() const +{ + return 0; +} + +String AccessibilityObject::stringValue() const +{ + return String(); +} + +String AccessibilityObject::ariaAccessiblityName(const String&) const +{ + return String(); +} + +String AccessibilityObject::ariaLabeledByAttribute() const +{ + return String(); +} + +String AccessibilityObject::title() const +{ + return String(); +} + +String AccessibilityObject::ariaDescribedByAttribute() const +{ + return String(); +} + +String AccessibilityObject::accessibilityDescription() const +{ + return String(); +} + +IntRect AccessibilityObject::boundingBoxRect() const +{ + return IntRect(); +} + +IntRect AccessibilityObject::elementRect() const +{ + return IntRect(); +} + +IntSize AccessibilityObject::size() const +{ + return IntSize(); +} + +IntPoint AccessibilityObject::clickPoint() const +{ + IntRect rect = elementRect(); + return IntPoint(rect.x() + rect.width() / 2, rect.y() + rect.height() / 2); +} + +void AccessibilityObject::linkedUIElements(AccessibilityChildrenVector&) const +{ + return; +} + +AccessibilityObject* AccessibilityObject::titleUIElement() const +{ + return 0; +} + +int AccessibilityObject::textLength() const +{ + return 0; +} + +PassRefPtr<Range> AccessibilityObject::ariaSelectedTextDOMRange() const +{ + return 0; +} + +String AccessibilityObject::selectedText() const +{ + return String(); +} + +const AtomicString& AccessibilityObject::accessKey() const +{ + return nullAtom; +} + +Selection AccessibilityObject::selection() const +{ + return Selection(); +} + +PlainTextRange AccessibilityObject::selectedTextRange() const +{ + return PlainTextRange(); +} + +unsigned AccessibilityObject::selectionStart() const +{ + return selectedTextRange().start; +} + +unsigned AccessibilityObject::selectionEnd() const +{ + return selectedTextRange().length; +} + +void AccessibilityObject::setSelectedText(const String&) +{ + // TODO: set selected text (ReplaceSelectionCommand). <rdar://problem/4712125> + notImplemented(); +} + +void AccessibilityObject::setSelectedTextRange(const PlainTextRange&) +{ +} + +void AccessibilityObject::makeRangeVisible(const PlainTextRange&) +{ + // TODO: make range visible (scrollRectToVisible). <rdar://problem/4712101> + notImplemented(); +} + +KURL AccessibilityObject::url() const +{ + return KURL(); +} + +void AccessibilityObject::setFocused(bool) +{ +} + +void AccessibilityObject::setValue(const String&) +{ +} + +void AccessibilityObject::setSelected(bool) +{ +} + +bool AccessibilityObject::press() const +{ + Element* actionElem = actionElement(); + if (!actionElem) + return false; + if (Frame* f = actionElem->document()->frame()) + f->loader()->resetMultipleFormSubmissionProtection(); + actionElem->accessKeyAction(true); + return true; +} + +AXObjectCache* AccessibilityObject::axObjectCache() const +{ + return 0; +} + +Widget* AccessibilityObject::widget() const +{ + return 0; +} + +Widget* AccessibilityObject::widgetForAttachmentView() const +{ + return 0; +} + +Element* AccessibilityObject::anchorElement() const +{ + return 0; +} + +Element* AccessibilityObject::actionElement() const +{ + return 0; +} + +// This function is like a cross-platform version of - (WebCoreTextMarkerRange*)textMarkerRange. It returns +// a Range that we can convert to a WebCoreRange in the Obj-C file +VisiblePositionRange AccessibilityObject::visiblePositionRange() const +{ + return VisiblePositionRange(); +} + +VisiblePositionRange AccessibilityObject::visiblePositionRangeForLine(unsigned) const +{ + return VisiblePositionRange(); +} + +VisiblePosition AccessibilityObject::visiblePositionForIndex(int) const +{ + return VisiblePosition(); +} + +int AccessibilityObject::indexForVisiblePosition(const VisiblePosition&) const +{ + return 0; +} + +VisiblePositionRange AccessibilityObject::visiblePositionRangeForUnorderedPositions(const VisiblePosition& visiblePos1, const VisiblePosition& visiblePos2) const +{ + if (visiblePos1.isNull() || visiblePos2.isNull()) + return VisiblePositionRange(); + + VisiblePosition startPos; + VisiblePosition endPos; + bool alreadyInOrder; + + // upstream is ordered before downstream for the same position + if (visiblePos1 == visiblePos2 && visiblePos2.affinity() == UPSTREAM) + alreadyInOrder = false; + + // use selection order to see if the positions are in order + else + alreadyInOrder = Selection(visiblePos1, visiblePos2).isBaseFirst(); + + if (alreadyInOrder) { + startPos = visiblePos1; + endPos = visiblePos2; + } else { + startPos = visiblePos2; + endPos = visiblePos1; + } + + return VisiblePositionRange(startPos, endPos); +} + +VisiblePositionRange AccessibilityObject::positionOfLeftWord(const VisiblePosition& visiblePos) const +{ + VisiblePosition startPosition = startOfWord(visiblePos, LeftWordIfOnBoundary); + VisiblePosition endPosition = endOfWord(startPosition); + return VisiblePositionRange(startPosition, endPosition); +} + +VisiblePositionRange AccessibilityObject::positionOfRightWord(const VisiblePosition& visiblePos) const +{ + VisiblePosition startPosition = startOfWord(visiblePos, RightWordIfOnBoundary); + VisiblePosition endPosition = endOfWord(startPosition); + return VisiblePositionRange(startPosition, endPosition); +} + +static VisiblePosition updateAXLineStartForVisiblePosition(const VisiblePosition& visiblePosition) +{ + // A line in the accessibility sense should include floating objects, such as aligned image, as part of a line. + // So let's update the position to include that. + VisiblePosition tempPosition; + VisiblePosition startPosition = visiblePosition; + Position p; + RenderObject* renderer; + while (true) { + tempPosition = startPosition.previous(); + if (tempPosition.isNull()) + break; + p = tempPosition.deepEquivalent(); + if (!p.node()) + break; + renderer = p.node()->renderer(); + if (!renderer || renderer->isRenderBlock() && !p.offset()) + break; + InlineBox* box; + int ignoredCaretOffset; + p.getInlineBoxAndOffset(tempPosition.affinity(), box, ignoredCaretOffset); + if (box) + break; + startPosition = tempPosition; + } + + return startPosition; +} + +VisiblePositionRange AccessibilityObject::leftLineVisiblePositionRange(const VisiblePosition& visiblePos) const +{ + if (visiblePos.isNull()) + return VisiblePositionRange(); + + // make a caret selection for the position before marker position (to make sure + // we move off of a line start) + VisiblePosition prevVisiblePos = visiblePos.previous(); + if (prevVisiblePos.isNull()) + return VisiblePositionRange(); + + VisiblePosition startPosition = startOfLine(prevVisiblePos); + + // keep searching for a valid line start position. Unless the VisiblePosition is at the very beginning, there should + // always be a valid line range. However, startOfLine will return null for position next to a floating object, + // since floating object doesn't really belong to any line. + // This check will reposition the marker before the floating object, to ensure we get a line start. + if (startPosition.isNull()) { + while (startPosition.isNull() && prevVisiblePos.isNotNull()) { + prevVisiblePos = prevVisiblePos.previous(); + startPosition = startOfLine(prevVisiblePos); + } + } else + startPosition = updateAXLineStartForVisiblePosition(startPosition); + + VisiblePosition endPosition = endOfLine(prevVisiblePos); + return VisiblePositionRange(startPosition, endPosition); +} + +VisiblePositionRange AccessibilityObject::rightLineVisiblePositionRange(const VisiblePosition& visiblePos) const +{ + if (visiblePos.isNull()) + return VisiblePositionRange(); + + // make sure we move off of a line end + VisiblePosition nextVisiblePos = visiblePos.next(); + if (nextVisiblePos.isNull()) + return VisiblePositionRange(); + + VisiblePosition startPosition = startOfLine(nextVisiblePos); + + // fetch for a valid line start position + if (startPosition.isNull() ) { + startPosition = visiblePos; + nextVisiblePos = nextVisiblePos.next(); + } else + startPosition = updateAXLineStartForVisiblePosition(startPosition); + + VisiblePosition endPosition = endOfLine(nextVisiblePos); + + // as long as the position hasn't reached the end of the doc, keep searching for a valid line end position + // Unless the VisiblePosition is at the very end, there should always be a valid line range. However, endOfLine will + // return null for position by a floating object, since floating object doesn't really belong to any line. + // This check will reposition the marker after the floating object, to ensure we get a line end. + while (endPosition.isNull() && nextVisiblePos.isNotNull()) { + nextVisiblePos = nextVisiblePos.next(); + endPosition = endOfLine(nextVisiblePos); + } + + return VisiblePositionRange(startPosition, endPosition); +} + +VisiblePositionRange AccessibilityObject::sentenceForPosition(const VisiblePosition& visiblePos) const +{ + // FIXME: FO 2 IMPLEMENT (currently returns incorrect answer) + // Related? <rdar://problem/3927736> Text selection broken in 8A336 + VisiblePosition startPosition = startOfSentence(visiblePos); + VisiblePosition endPosition = endOfSentence(startPosition); + return VisiblePositionRange(startPosition, endPosition); +} + +VisiblePositionRange AccessibilityObject::paragraphForPosition(const VisiblePosition& visiblePos) const +{ + VisiblePosition startPosition = startOfParagraph(visiblePos); + VisiblePosition endPosition = endOfParagraph(startPosition); + return VisiblePositionRange(startPosition, endPosition); +} + +static VisiblePosition startOfStyleRange(const VisiblePosition visiblePos) +{ + RenderObject* renderer = visiblePos.deepEquivalent().node()->renderer(); + RenderObject* startRenderer = renderer; + RenderStyle* style = renderer->style(); + + // traverse backward by renderer to look for style change + for (RenderObject* r = renderer->previousInPreOrder(); r; r = r->previousInPreOrder()) { + // skip non-leaf nodes + if (r->firstChild()) + continue; + + // stop at style change + if (r->style() != style) + break; + + // remember match + startRenderer = r; + } + + return VisiblePosition(startRenderer->node(), 0, VP_DEFAULT_AFFINITY); +} + +static VisiblePosition endOfStyleRange(const VisiblePosition visiblePos) +{ + RenderObject* renderer = visiblePos.deepEquivalent().node()->renderer(); + RenderObject* endRenderer = renderer; + RenderStyle* style = renderer->style(); + + // traverse forward by renderer to look for style change + for (RenderObject* r = renderer->nextInPreOrder(); r; r = r->nextInPreOrder()) { + // skip non-leaf nodes + if (r->firstChild()) + continue; + + // stop at style change + if (r->style() != style) + break; + + // remember match + endRenderer = r; + } + + return VisiblePosition(endRenderer->node(), maxDeepOffset(endRenderer->node()), VP_DEFAULT_AFFINITY); +} + +VisiblePositionRange AccessibilityObject::styleRangeForPosition(const VisiblePosition& visiblePos) const +{ + if (visiblePos.isNull()) + return VisiblePositionRange(); + + return VisiblePositionRange(startOfStyleRange(visiblePos), endOfStyleRange(visiblePos)); +} + +// NOTE: Consider providing this utility method as AX API +VisiblePositionRange AccessibilityObject::visiblePositionRangeForRange(const PlainTextRange& range) const +{ + if (range.start + range.length > text().length()) + return VisiblePositionRange(); + + VisiblePosition startPosition = visiblePositionForIndex(range.start); + startPosition.setAffinity(DOWNSTREAM); + VisiblePosition endPosition = visiblePositionForIndex(range.start + range.length); + return VisiblePositionRange(startPosition, endPosition); +} + +static bool replacedNodeNeedsCharacter(Node* replacedNode) +{ + // we should always be given a rendered node and a replaced node, but be safe + // replaced nodes are either attachments (widgets) or images + if (!replacedNode || !replacedNode->renderer() || !replacedNode->renderer()->isReplaced() || replacedNode->isTextNode()) { + return false; + } + + // create an AX object, but skip it if it is not supposed to be seen + AccessibilityObject* object = replacedNode->renderer()->document()->axObjectCache()->get(replacedNode->renderer()); + if (object->accessibilityIsIgnored()) + return false; + + return true; +} + +String AccessibilityObject::stringForVisiblePositionRange(const VisiblePositionRange& visiblePositionRange) const +{ + if (visiblePositionRange.isNull()) + return String(); + + Vector<UChar> resultVector; + RefPtr<Range> range = makeRange(visiblePositionRange.start, visiblePositionRange.end); + for (TextIterator it(range.get()); !it.atEnd(); it.advance()) { + // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX) + if (it.length() != 0) { + resultVector.append(it.characters(), it.length()); + } else { + // locate the node and starting offset for this replaced range + int exception = 0; + Node* node = it.range()->startContainer(exception); + ASSERT(node == it.range()->endContainer(exception)); + int offset = it.range()->startOffset(exception); + + if (replacedNodeNeedsCharacter(node->childNode(offset))) { + resultVector.append(objectReplacementCharacter); + } + } + } + + return String::adopt(resultVector); +} + +IntRect AccessibilityObject::boundsForVisiblePositionRange(const VisiblePositionRange&) const +{ + return IntRect(); +} + +int AccessibilityObject::lengthForVisiblePositionRange(const VisiblePositionRange& visiblePositionRange) const +{ + // FIXME: Multi-byte support + if (visiblePositionRange.isNull()) + return -1; + + int length = 0; + RefPtr<Range> range = makeRange(visiblePositionRange.start, visiblePositionRange.end); + for (TextIterator it(range.get()); !it.atEnd(); it.advance()) { + // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX) + if (it.length() != 0) { + length += it.length(); + } else { + // locate the node and starting offset for this replaced range + int exception = 0; + Node* node = it.range()->startContainer(exception); + ASSERT(node == it.range()->endContainer(exception)); + int offset = it.range()->startOffset(exception); + + if (replacedNodeNeedsCharacter(node->childNode(offset))) + length++; + } + } + + return length; +} + +void AccessibilityObject::setSelectedVisiblePositionRange(const VisiblePositionRange&) const +{ +} + +VisiblePosition AccessibilityObject::visiblePositionForPoint(const IntPoint&) const +{ + return VisiblePosition(); +} + +VisiblePosition AccessibilityObject::nextVisiblePosition(const VisiblePosition& visiblePos) const +{ + return visiblePos.next(); +} + +VisiblePosition AccessibilityObject::previousVisiblePosition(const VisiblePosition& visiblePos) const +{ + return visiblePos.previous(); +} + +VisiblePosition AccessibilityObject::nextWordEnd(const VisiblePosition& visiblePos) const +{ + if (visiblePos.isNull()) + return VisiblePosition(); + + // make sure we move off of a word end + VisiblePosition nextVisiblePos = visiblePos.next(); + if (nextVisiblePos.isNull()) + return VisiblePosition(); + + return endOfWord(nextVisiblePos, LeftWordIfOnBoundary); +} + +VisiblePosition AccessibilityObject::previousWordStart(const VisiblePosition& visiblePos) const +{ + if (visiblePos.isNull()) + return VisiblePosition(); + + // make sure we move off of a word start + VisiblePosition prevVisiblePos = visiblePos.previous(); + if (prevVisiblePos.isNull()) + return VisiblePosition(); + + return startOfWord(prevVisiblePos, RightWordIfOnBoundary); +} + +VisiblePosition AccessibilityObject::nextLineEndPosition(const VisiblePosition& visiblePos) const +{ + if (visiblePos.isNull()) + return VisiblePosition(); + + // to make sure we move off of a line end + VisiblePosition nextVisiblePos = visiblePos.next(); + if (nextVisiblePos.isNull()) + return VisiblePosition(); + + VisiblePosition endPosition = endOfLine(nextVisiblePos); + + // as long as the position hasn't reached the end of the doc, keep searching for a valid line end position + // There are cases like when the position is next to a floating object that'll return null for end of line. This code will avoid returning null. + while (endPosition.isNull() && nextVisiblePos.isNotNull()) { + nextVisiblePos = nextVisiblePos.next(); + endPosition = endOfLine(nextVisiblePos); + } + + return endPosition; +} + +VisiblePosition AccessibilityObject::previousLineStartPosition(const VisiblePosition& visiblePos) const +{ + if (visiblePos.isNull()) + return VisiblePosition(); + + // make sure we move off of a line start + VisiblePosition prevVisiblePos = visiblePos.previous(); + if (prevVisiblePos.isNull()) + return VisiblePosition(); + + VisiblePosition startPosition = startOfLine(prevVisiblePos); + + // as long as the position hasn't reached the beginning of the doc, keep searching for a valid line start position + // There are cases like when the position is next to a floating object that'll return null for start of line. This code will avoid returning null. + if (startPosition.isNull()) { + while (startPosition.isNull() && prevVisiblePos.isNotNull()) { + prevVisiblePos = prevVisiblePos.previous(); + startPosition = startOfLine(prevVisiblePos); + } + } else + startPosition = updateAXLineStartForVisiblePosition(startPosition); + + return startPosition; +} + +VisiblePosition AccessibilityObject::nextSentenceEndPosition(const VisiblePosition& visiblePos) const +{ + // FIXME: FO 2 IMPLEMENT (currently returns incorrect answer) + // Related? <rdar://problem/3927736> Text selection broken in 8A336 + if (visiblePos.isNull()) + return VisiblePosition(); + + // make sure we move off of a sentence end + VisiblePosition nextVisiblePos = visiblePos.next(); + if (nextVisiblePos.isNull()) + return VisiblePosition(); + + // an empty line is considered a sentence. If it's skipped, then the sentence parser will not + // see this empty line. Instead, return the end position of the empty line. + VisiblePosition endPosition; + String lineString = plainText(makeRange(startOfLine(visiblePos), endOfLine(visiblePos)).get()); + if (lineString.isEmpty()) + endPosition = nextVisiblePos; + else + endPosition = endOfSentence(nextVisiblePos); + + return endPosition; +} + +VisiblePosition AccessibilityObject::previousSentenceStartPosition(const VisiblePosition& visiblePos) const +{ + // FIXME: FO 2 IMPLEMENT (currently returns incorrect answer) + // Related? <rdar://problem/3927736> Text selection broken in 8A336 + if (visiblePos.isNull()) + return VisiblePosition(); + + // make sure we move off of a sentence start + VisiblePosition previousVisiblePos = visiblePos.previous(); + if (previousVisiblePos.isNull()) + return VisiblePosition(); + + // treat empty line as a separate sentence. + VisiblePosition startPosition; + String lineString = plainText(makeRange(startOfLine(previousVisiblePos), endOfLine(previousVisiblePos)).get()); + if (lineString.isEmpty()) + startPosition = previousVisiblePos; + else + startPosition = startOfSentence(previousVisiblePos); + + return startPosition; +} + +VisiblePosition AccessibilityObject::nextParagraphEndPosition(const VisiblePosition& visiblePos) const +{ + if (visiblePos.isNull()) + return VisiblePosition(); + + // make sure we move off of a paragraph end + VisiblePosition nextPos = visiblePos.next(); + if (nextPos.isNull()) + return VisiblePosition(); + + return endOfParagraph(nextPos); +} + +VisiblePosition AccessibilityObject::previousParagraphStartPosition(const VisiblePosition& visiblePos) const +{ + if (visiblePos.isNull()) + return VisiblePosition(); + + // make sure we move off of a paragraph start + VisiblePosition previousPos = visiblePos.previous(); + if (previousPos.isNull()) + return VisiblePosition(); + + return startOfParagraph(previousPos); +} + +// NOTE: Consider providing this utility method as AX API +VisiblePosition AccessibilityObject::visiblePositionForIndex(unsigned, bool) const +{ + return VisiblePosition(); +} + +AccessibilityObject* AccessibilityObject::accessibilityObjectForPosition(const VisiblePosition& visiblePos) const +{ + if (visiblePos.isNull()) + return 0; + + RenderObject* obj = visiblePos.deepEquivalent().node()->renderer(); + if (!obj) + return 0; + + return obj->document()->axObjectCache()->get(obj); +} + +int AccessibilityObject::lineForPosition(const VisiblePosition& visiblePos) const +{ + if (visiblePos.isNull()) + return 0; + + unsigned lineCount = 0; + VisiblePosition currentVisiblePos = visiblePos; + VisiblePosition savedVisiblePos; + + // move up until we get to the top + // FIXME: This only takes us to the top of the rootEditableElement, not the top of the + // top document. + while (currentVisiblePos.isNotNull() && !(inSameLine(currentVisiblePos, savedVisiblePos))) { + ++lineCount; + savedVisiblePos = currentVisiblePos; + VisiblePosition prevVisiblePos = previousLinePosition(currentVisiblePos, 0); + currentVisiblePos = prevVisiblePos; + } + + return lineCount - 1; +} + +// NOTE: Consider providing this utility method as AX API +PlainTextRange AccessibilityObject::plainTextRangeForVisiblePositionRange(const VisiblePositionRange& positionRange) const +{ + int index1 = index(positionRange.start); + int index2 = index(positionRange.end); + if (index1 < 0 || index2 < 0 || index1 > index2) + return PlainTextRange(); + + return PlainTextRange(index1, index2 - index1); +} + +// NOTE: Consider providing this utility method as AX API +int AccessibilityObject::index(const VisiblePosition&) const +{ + return -1; +} + +// Given a line number, the range of characters of the text associated with this accessibility +// object that contains the line number. +PlainTextRange AccessibilityObject::doAXRangeForLine(unsigned) const +{ + return PlainTextRange(); +} + +// The composed character range in the text associated with this accessibility object that +// is specified by the given screen coordinates. This parameterized attribute returns the +// complete range of characters (including surrogate pairs of multi-byte glyphs) at the given +// screen coordinates. +// NOTE: This varies from AppKit when the point is below the last line. AppKit returns an +// an error in that case. We return textControl->text().length(), 1. Does this matter? +PlainTextRange AccessibilityObject::doAXRangeForPosition(const IntPoint& point) const +{ + int i = index(visiblePositionForPoint(point)); + if (i < 0) + return PlainTextRange(); + + return PlainTextRange(i, 1); +} + +// The composed character range in the text associated with this accessibility object that +// is specified by the given index value. This parameterized attribute returns the complete +// range of characters (including surrogate pairs of multi-byte glyphs) at the given index. +PlainTextRange AccessibilityObject::doAXRangeForIndex(unsigned) const +{ + return PlainTextRange(); +} + +// Given a character index, the range of text associated with this accessibility object +// over which the style in effect at that character index applies. +PlainTextRange AccessibilityObject::doAXStyleRangeForIndex(unsigned index) const +{ + VisiblePositionRange range = styleRangeForPosition(visiblePositionForIndex(index, false)); + return plainTextRangeForVisiblePositionRange(range); +} + +// A substring of the text associated with this accessibility object that is +// specified by the given character range. +String AccessibilityObject::doAXStringForRange(const PlainTextRange&) const +{ + return String(); +} + +// The bounding rectangle of the text associated with this accessibility object that is +// specified by the given range. This is the bounding rectangle a sighted user would see +// on the display screen, in pixels. +IntRect AccessibilityObject::doAXBoundsForRange(const PlainTextRange&) const +{ + return IntRect(); +} + +// Given an indexed character, the line number of the text associated with this accessibility +// object that contains the character. +unsigned AccessibilityObject::doAXLineForIndex(unsigned index) +{ + return lineForPosition(visiblePositionForIndex(index, false)); +} + +FrameView* AccessibilityObject::documentFrameView() const +{ + const AccessibilityObject* object = this; + while (object && !object->isAccessibilityRenderObject()) + object = object->parentObject(); + + if (!object) + return 0; + + return object->documentFrameView(); +} + +AccessibilityObject* AccessibilityObject::doAccessibilityHitTest(const IntPoint&) const +{ + return 0; +} + +AccessibilityObject* AccessibilityObject::focusedUIElement() const +{ + return 0; +} + +AccessibilityObject* AccessibilityObject::observableObject() const +{ + return 0; +} + +AccessibilityRole AccessibilityObject::roleValue() const +{ + return UnknownRole; +} + +AccessibilityRole AccessibilityObject::ariaRoleAttribute() const +{ + return UnknownRole; +} + +bool AccessibilityObject::isPresentationalChildOfAriaRole() const +{ + return false; +} + +bool AccessibilityObject::ariaRoleHasPresentationalChildren() const +{ + return false; +} + +void AccessibilityObject::clearChildren() +{ + m_haveChildren = false; + m_children.clear(); +} + +void AccessibilityObject::childrenChanged() +{ + return; +} + +void AccessibilityObject::addChildren() +{ +} + +void AccessibilityObject::selectedChildren(AccessibilityChildrenVector&) +{ +} + +void AccessibilityObject::visibleChildren(AccessibilityChildrenVector&) +{ +} + +unsigned AccessibilityObject::axObjectID() const +{ + return m_id; +} + +void AccessibilityObject::setAXObjectID(unsigned axObjectID) +{ + m_id = axObjectID; +} + +void AccessibilityObject::removeAXObjectID() +{ + return; +} + +const String& AccessibilityObject::actionVerb() const +{ + // FIXME: Need to add verbs for select elements. + DEFINE_STATIC_LOCAL(const String, buttonAction, (AXButtonActionVerb())); + DEFINE_STATIC_LOCAL(const String, textFieldAction, (AXTextFieldActionVerb())); + DEFINE_STATIC_LOCAL(const String, radioButtonAction, (AXRadioButtonActionVerb())); + DEFINE_STATIC_LOCAL(const String, checkedCheckBoxAction, (AXCheckedCheckBoxActionVerb())); + DEFINE_STATIC_LOCAL(const String, uncheckedCheckBoxAction, (AXUncheckedCheckBoxActionVerb())); + DEFINE_STATIC_LOCAL(const String, linkAction, (AXLinkActionVerb())); + DEFINE_STATIC_LOCAL(const String, noAction, ()); + + switch (roleValue()) { + case ButtonRole: + return buttonAction; + case TextFieldRole: + case TextAreaRole: + return textFieldAction; + case RadioButtonRole: + return radioButtonAction; + case CheckBoxRole: + return isChecked() ? checkedCheckBoxAction : uncheckedCheckBoxAction; + case LinkRole: + case WebCoreLinkRole: + return linkAction; + default: + return noAction; + } +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/AccessibilityObject.h b/src/3rdparty/webkit/WebCore/page/AccessibilityObject.h new file mode 100644 index 0000000..e177ee7 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/AccessibilityObject.h @@ -0,0 +1,424 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008 Nuanti Ltd. + * + * 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. + */ + +#ifndef AccessibilityObject_h +#define AccessibilityObject_h + +#include "VisiblePosition.h" +#include <wtf/Platform.h> +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> + +#if PLATFORM(MAC) +#include <wtf/RetainPtr.h> +#elif PLATFORM(WIN) +#include "AccessibilityObjectWrapperWin.h" +#include "COMPtr.h" +#elif PLATFORM(CHROMIUM) +#include "AccessibilityObjectWrapper.h" +#endif + +typedef struct _NSRange NSRange; + +#ifdef __OBJC__ +@class AccessibilityObjectWrapper; +@class NSArray; +@class NSAttributedString; +@class NSData; +@class NSMutableAttributedString; +@class NSString; +@class NSValue; +@class NSView; +#else +class NSArray; +class NSAttributedString; +class NSData; +class NSMutableAttributedString; +class NSString; +class NSValue; +class NSView; +#if PLATFORM(GTK) +typedef struct _AtkObject AtkObject; +typedef struct _AtkObject AccessibilityObjectWrapper; +#else +class AccessibilityObjectWrapper; +#endif +#endif + +namespace WebCore { + +class AXObjectCache; +class Element; +class Frame; +class FrameView; +class HTMLAnchorElement; +class HTMLAreaElement; +class IntPoint; +class IntSize; +class Node; +class RenderObject; +class Selection; +class String; +class Widget; + +enum AccessibilityRole { + UnknownRole = 1, + ButtonRole, + RadioButtonRole, + CheckBoxRole, + SliderRole, + TabGroupRole, + TextFieldRole, + StaticTextRole, + TextAreaRole, + ScrollAreaRole, + PopUpButtonRole, + MenuButtonRole, + TableRole, + ApplicationRole, + GroupRole, + RadioGroupRole, + ListRole, + ScrollBarRole, + ValueIndicatorRole, + ImageRole, + MenuBarRole, + MenuRole, + MenuItemRole, + ColumnRole, + RowRole, + ToolbarRole, + BusyIndicatorRole, + ProgressIndicatorRole, + WindowRole, + DrawerRole, + SystemWideRole, + OutlineRole, + IncrementorRole, + BrowserRole, + ComboBoxRole, + SplitGroupRole, + SplitterRole, + ColorWellRole, + GrowAreaRole, + SheetRole, + HelpTagRole, + MatteRole, + RulerRole, + RulerMarkerRole, + LinkRole, + DisclosureTriangleRole, + GridRole, + CellRole, + // AppKit includes SortButtonRole but it is misnamed and really a subrole of ButtonRole so we do not include it here. + + // WebCore-specific roles + WebCoreLinkRole, + ImageMapLinkRole, + ImageMapRole, + ListMarkerRole, + WebAreaRole, + HeadingRole, + ListBoxRole, + ListBoxOptionRole, + TableHeaderContainerRole, + DefinitionListTermRole, + DefinitionListDefinitionRole +}; + +struct VisiblePositionRange { + + VisiblePosition start; + VisiblePosition end; + + VisiblePositionRange() {} + + VisiblePositionRange(const VisiblePosition& s, const VisiblePosition& e) + : start(s) + , end(e) + { } + + bool isNull() const { return start.isNull() || end.isNull(); } +}; + +struct PlainTextRange { + + unsigned start; + unsigned length; + + PlainTextRange() + : start(0) + , length(0) + { } + + PlainTextRange(unsigned s, unsigned l) + : start(s) + , length(l) + { } + + bool isNull() const { return start == 0 && length == 0; } +}; + +class AccessibilityObject : public RefCounted<AccessibilityObject> { +protected: + AccessibilityObject(); +public: + virtual ~AccessibilityObject(); + + typedef Vector<RefPtr<AccessibilityObject> > AccessibilityChildrenVector; + + virtual bool isAccessibilityRenderObject() const { return false; }; + virtual bool isAnchor() const { return false; }; + virtual bool isAttachment() const { return false; }; + virtual bool isHeading() const { return false; }; + virtual bool isLink() const { return false; }; + virtual bool isImage() const { return false; }; + virtual bool isNativeImage() const { return false; }; + virtual bool isImageButton() const { return false; }; + virtual bool isPasswordField() const { return false; }; + virtual bool isTextControl() const { return false; }; + virtual bool isNativeTextControl() const { return false; }; + virtual bool isWebArea() const { return false; }; + virtual bool isCheckboxOrRadio() const { return false; }; + virtual bool isListBox() const { return roleValue() == ListBoxRole; }; + virtual bool isMenuRelated() const { return false; } + virtual bool isMenu() const { return false; } + virtual bool isMenuBar() const { return false; } + virtual bool isMenuButton() const { return false; } + virtual bool isMenuItem() const { return false; } + virtual bool isFileUploadButton() const { return false; }; + virtual bool isProgressIndicator() const { return false; }; + virtual bool isSlider() const { return false; }; + virtual bool isControl() const { return false; }; + virtual bool isList() const { return false; }; + virtual bool isDataTable() const { return false; }; + virtual bool isTableRow() const { return false; }; + virtual bool isTableColumn() const { return false; }; + virtual bool isTableCell() const { return false; }; + virtual bool isFieldset() const { return false; }; + virtual bool isGroup() const { return false; }; + + virtual bool isChecked() const { return false; }; + virtual bool isEnabled() const { return false; }; + virtual bool isSelected() const { return false; }; + virtual bool isFocused() const { return false; }; + virtual bool isHovered() const { return false; }; + virtual bool isIndeterminate() const { return false; }; + virtual bool isLoaded() const { return false; }; + virtual bool isMultiSelect() const { return false; }; + virtual bool isOffScreen() const { return false; }; + virtual bool isPressed() const { return false; }; + virtual bool isReadOnly() const { return false; }; + virtual bool isVisited() const { return false; }; + + virtual bool canSetFocusAttribute() const { return false; }; + virtual bool canSetTextRangeAttributes() const { return false; }; + virtual bool canSetValueAttribute() const { return false; }; + virtual bool canSetSelectedAttribute() const { return false; } + virtual bool canSetSelectedChildrenAttribute() const { return false; } + + virtual bool hasIntValue() const { return false; }; + + bool accessibilityShouldUseUniqueId() const { return true; }; + virtual bool accessibilityIsIgnored() const { return true; }; + + virtual int intValue() const; + virtual float valueForRange() const { return 0.0f; } + virtual float maxValueForRange() const { return 0.0f; } + virtual float minValueForRange() const {return 0.0f; } + virtual int layoutCount() const; + static bool isARIAControl(AccessibilityRole); + static bool isARIAInput(AccessibilityRole); + unsigned axObjectID() const; + + virtual AccessibilityObject* doAccessibilityHitTest(const IntPoint&) const; + virtual AccessibilityObject* focusedUIElement() const; + virtual AccessibilityObject* firstChild() const; + virtual AccessibilityObject* lastChild() const; + virtual AccessibilityObject* previousSibling() const; + virtual AccessibilityObject* nextSibling() const; + virtual AccessibilityObject* parentObject() const; + virtual AccessibilityObject* parentObjectUnignored() const; + virtual AccessibilityObject* observableObject() const; + virtual void linkedUIElements(AccessibilityChildrenVector&) const; + virtual AccessibilityObject* titleUIElement() const; + virtual AccessibilityRole ariaRoleAttribute() const; + virtual bool isPresentationalChildOfAriaRole() const; + virtual bool ariaRoleHasPresentationalChildren() const; + + virtual AccessibilityRole roleValue() const; + virtual AXObjectCache* axObjectCache() const; + + virtual Element* anchorElement() const; + virtual Element* actionElement() const; + virtual IntRect boundingBoxRect() const; + virtual IntRect elementRect() const; + virtual IntSize size() const; + IntPoint clickPoint() const; + + virtual KURL url() const; + virtual PlainTextRange selectedTextRange() const; + virtual Selection selection() const; + unsigned selectionStart() const; + unsigned selectionEnd() const; + virtual String stringValue() const; + virtual String ariaAccessiblityName(const String&) const; + virtual String ariaLabeledByAttribute() const; + virtual String title() const; + virtual String ariaDescribedByAttribute() const; + virtual String accessibilityDescription() const; + virtual String helpText() const; + virtual String textUnderElement() const; + virtual String text() const; + virtual int textLength() const; + virtual PassRefPtr<Range> ariaSelectedTextDOMRange() const; + virtual String selectedText() const; + virtual const AtomicString& accessKey() const; + const String& actionVerb() const; + virtual Widget* widget() const; + virtual Widget* widgetForAttachmentView() const; + virtual Document* document() const { return 0; } + virtual FrameView* topDocumentFrameView() const { return 0; } + virtual FrameView* documentFrameView() const; + + void setAXObjectID(unsigned); + virtual void setFocused(bool); + virtual void setSelectedText(const String&); + virtual void setSelectedTextRange(const PlainTextRange&); + virtual void setValue(const String&); + virtual void setSelected(bool); + + virtual void detach(); + virtual void makeRangeVisible(const PlainTextRange&); + virtual bool press() const; + bool performDefaultAction() const { return press(); } + + virtual void childrenChanged(); + virtual const AccessibilityChildrenVector& children() { return m_children; } + virtual void addChildren(); + virtual bool canHaveChildren() const { return true; } + virtual bool hasChildren() const { return m_haveChildren; }; + virtual void selectedChildren(AccessibilityChildrenVector&); + virtual void visibleChildren(AccessibilityChildrenVector&); + virtual bool shouldFocusActiveDescendant() const { return false; } + virtual AccessibilityObject* activeDescendant() const { return 0; } + virtual void handleActiveDescendantChanged() { } + + virtual VisiblePositionRange visiblePositionRange() const; + virtual VisiblePositionRange visiblePositionRangeForLine(unsigned) const; + + VisiblePositionRange visiblePositionRangeForUnorderedPositions(const VisiblePosition&, const VisiblePosition&) const; + VisiblePositionRange positionOfLeftWord(const VisiblePosition&) const; + VisiblePositionRange positionOfRightWord(const VisiblePosition&) const; + VisiblePositionRange leftLineVisiblePositionRange(const VisiblePosition&) const; + VisiblePositionRange rightLineVisiblePositionRange(const VisiblePosition&) const; + VisiblePositionRange sentenceForPosition(const VisiblePosition&) const; + VisiblePositionRange paragraphForPosition(const VisiblePosition&) const; + VisiblePositionRange styleRangeForPosition(const VisiblePosition&) const; + VisiblePositionRange visiblePositionRangeForRange(const PlainTextRange&) const; + + String stringForVisiblePositionRange(const VisiblePositionRange&) const; + virtual IntRect boundsForVisiblePositionRange(const VisiblePositionRange&) const; + int lengthForVisiblePositionRange(const VisiblePositionRange&) const; + virtual void setSelectedVisiblePositionRange(const VisiblePositionRange&) const; + + virtual VisiblePosition visiblePositionForPoint(const IntPoint&) const; + VisiblePosition nextVisiblePosition(const VisiblePosition&) const; + VisiblePosition previousVisiblePosition(const VisiblePosition&) const; + VisiblePosition nextWordEnd(const VisiblePosition&) const; + VisiblePosition previousWordStart(const VisiblePosition&) const; + VisiblePosition nextLineEndPosition(const VisiblePosition&) const; + VisiblePosition previousLineStartPosition(const VisiblePosition&) const; + VisiblePosition nextSentenceEndPosition(const VisiblePosition&) const; + VisiblePosition previousSentenceStartPosition(const VisiblePosition&) const; + VisiblePosition nextParagraphEndPosition(const VisiblePosition&) const; + VisiblePosition previousParagraphStartPosition(const VisiblePosition&) const; + virtual VisiblePosition visiblePositionForIndex(unsigned indexValue, bool lastIndexOK) const; + + virtual VisiblePosition visiblePositionForIndex(int) const; + virtual int indexForVisiblePosition(const VisiblePosition&) const; + + AccessibilityObject* accessibilityObjectForPosition(const VisiblePosition&) const; + int lineForPosition(const VisiblePosition&) const; + PlainTextRange plainTextRangeForVisiblePositionRange(const VisiblePositionRange&) const; + virtual int index(const VisiblePosition&) const; + + virtual PlainTextRange doAXRangeForLine(unsigned) const; + PlainTextRange doAXRangeForPosition(const IntPoint&) const; + virtual PlainTextRange doAXRangeForIndex(unsigned) const; + PlainTextRange doAXStyleRangeForIndex(unsigned) const; + + virtual String doAXStringForRange(const PlainTextRange&) const; + virtual IntRect doAXBoundsForRange(const PlainTextRange&) const; + + unsigned doAXLineForIndex(unsigned); + +#if HAVE(ACCESSIBILITY) +#if PLATFORM(GTK) + AccessibilityObjectWrapper* wrapper() const; + void setWrapper(AccessibilityObjectWrapper*); +#else + AccessibilityObjectWrapper* wrapper() const { return m_wrapper.get(); } + void setWrapper(AccessibilityObjectWrapper* wrapper) + { + m_wrapper = wrapper; + } +#endif +#endif + + // a platform-specific method for determining if an attachment is ignored +#if HAVE(ACCESSIBILITY) + bool accessibilityIgnoreAttachment() const; +#else + bool accessibilityIgnoreAttachment() const { return true; } +#endif + +protected: + unsigned m_id; + AccessibilityChildrenVector m_children; + mutable bool m_haveChildren; + + virtual void clearChildren(); + virtual void removeAXObjectID(); + virtual bool isDetached() const { return true; } + +#if PLATFORM(MAC) + RetainPtr<AccessibilityObjectWrapper> m_wrapper; +#elif PLATFORM(WIN) + COMPtr<AccessibilityObjectWrapper> m_wrapper; +#elif PLATFORM(GTK) + AtkObject* m_wrapper; +#elif PLATFORM(CHROMIUM) + RefPtr<AccessibilityObjectWrapper> m_wrapper; +#endif +}; + +} // namespace WebCore + +#endif // AccessibilityObject_h diff --git a/src/3rdparty/webkit/WebCore/page/AccessibilityRenderObject.cpp b/src/3rdparty/webkit/WebCore/page/AccessibilityRenderObject.cpp new file mode 100644 index 0000000..dee7eea --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/AccessibilityRenderObject.cpp @@ -0,0 +1,2387 @@ +/* +* Copyright (C) 2008 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 "AccessibilityRenderObject.h" + +#include "AXObjectCache.h" +#include "AccessibilityListBox.h" +#include "AccessibilityImageMapLink.h" +#include "CharacterNames.h" +#include "EventNames.h" +#include "FloatRect.h" +#include "FocusController.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "HTMLAreaElement.h" +#include "HTMLFrameElementBase.h" +#include "HTMLImageElement.h" +#include "HTMLInputElement.h" +#include "HTMLLabelElement.h" +#include "HTMLMapElement.h" +#include "HTMLOptGroupElement.h" +#include "HTMLOptionElement.h" +#include "HTMLOptionsCollection.h" +#include "HTMLSelectElement.h" +#include "HTMLTextAreaElement.h" +#include "HitTestRequest.h" +#include "HitTestResult.h" +#include "LocalizedStrings.h" +#include "NodeList.h" +#include "NotImplemented.h" +#include "Page.h" +#include "RenderFieldset.h" +#include "RenderFileUploadControl.h" +#include "RenderImage.h" +#include "RenderListBox.h" +#include "RenderListMarker.h" +#include "RenderMenuList.h" +#include "RenderTextControl.h" +#include "RenderTheme.h" +#include "RenderView.h" +#include "RenderWidget.h" +#include "SelectionController.h" +#include "Text.h" +#include "TextIterator.h" +#include "htmlediting.h" +#include "visible_units.h" +#include <wtf/StdLibExtras.h> + +using namespace std; + +namespace WebCore { + +using namespace HTMLNames; + +AccessibilityRenderObject::AccessibilityRenderObject(RenderObject* renderer) + : m_renderer(renderer) + , m_ariaRole(UnknownRole) +{ + setAriaRole(); +#ifndef NDEBUG + m_renderer->setHasAXObject(true); +#endif +} + +AccessibilityRenderObject::~AccessibilityRenderObject() +{ + ASSERT(isDetached()); +} + +PassRefPtr<AccessibilityRenderObject> AccessibilityRenderObject::create(RenderObject* renderer) +{ + return adoptRef(new AccessibilityRenderObject(renderer)); +} + +void AccessibilityRenderObject::detach() +{ + clearChildren(); + AccessibilityObject::detach(); + +#ifndef NDEBUG + if (m_renderer) + m_renderer->setHasAXObject(false); +#endif + m_renderer = 0; +} + +AccessibilityObject* AccessibilityRenderObject::firstChild() const +{ + if (!m_renderer) + return 0; + + RenderObject* firstChild = m_renderer->firstChild(); + if (!firstChild) + return 0; + + return m_renderer->document()->axObjectCache()->get(firstChild); +} + +AccessibilityObject* AccessibilityRenderObject::lastChild() const +{ + if (!m_renderer) + return 0; + + RenderObject* lastChild = m_renderer->lastChild(); + if (!lastChild) + return 0; + + return m_renderer->document()->axObjectCache()->get(lastChild); +} + +AccessibilityObject* AccessibilityRenderObject::previousSibling() const +{ + if (!m_renderer) + return 0; + + RenderObject* previousSibling = m_renderer->previousSibling(); + if (!previousSibling) + return 0; + + return m_renderer->document()->axObjectCache()->get(previousSibling); +} + +AccessibilityObject* AccessibilityRenderObject::nextSibling() const +{ + if (!m_renderer) + return 0; + + RenderObject* nextSibling = m_renderer->nextSibling(); + if (!nextSibling) + return 0; + + return m_renderer->document()->axObjectCache()->get(nextSibling); +} + +AccessibilityObject* AccessibilityRenderObject::parentObject() const +{ + if (!m_renderer) + return 0; + + RenderObject *parent = m_renderer->parent(); + if (!parent) + return 0; + + if (ariaRoleAttribute() == MenuBarRole) + return m_renderer->document()->axObjectCache()->get(parent); + + // menuButton and its corresponding menu are DOM siblings, but Accessibility needs them to be parent/child + if (ariaRoleAttribute() == MenuRole) { + AccessibilityObject* parent = menuButtonForMenu(); + if (parent) + return parent; + } + + return m_renderer->document()->axObjectCache()->get(parent); +} + +bool AccessibilityRenderObject::isWebArea() const +{ + return roleValue() == WebAreaRole; +} + +bool AccessibilityRenderObject::isImageButton() const +{ + return isNativeImage() && roleValue() == ButtonRole; +} + +bool AccessibilityRenderObject::isAnchor() const +{ + return !isNativeImage() && isLink(); +} + +bool AccessibilityRenderObject::isNativeTextControl() const +{ + return m_renderer->isTextField() || m_renderer->isTextArea(); +} + +bool AccessibilityRenderObject::isTextControl() const +{ + AccessibilityRole role = roleValue(); + return role == TextAreaRole || role == TextFieldRole; +} + +bool AccessibilityRenderObject::isNativeImage() const +{ + return m_renderer->isImage(); +} + +bool AccessibilityRenderObject::isImage() const +{ + return roleValue() == ImageRole; +} + +bool AccessibilityRenderObject::isAttachment() const +{ + // Widgets are the replaced elements that we represent to AX as attachments + bool isWidget = m_renderer && m_renderer->isWidget(); + ASSERT(!isWidget || (m_renderer->isReplaced() && !isImage())); + return isWidget && ariaRoleAttribute() == UnknownRole; +} + +bool AccessibilityRenderObject::isPasswordField() const +{ + ASSERT(m_renderer); + if (!m_renderer->element() || !m_renderer->element()->isHTMLElement()) + return false; + return static_cast<HTMLElement*>(m_renderer->element())->isPasswordField() && ariaRoleAttribute() == UnknownRole; +} + +bool AccessibilityRenderObject::isCheckboxOrRadio() const +{ + AccessibilityRole role = roleValue(); + return role == RadioButtonRole || role == CheckBoxRole; +} + +bool AccessibilityRenderObject::isFileUploadButton() const +{ + if (m_renderer && m_renderer->element() && m_renderer->element()->hasTagName(inputTag)) { + HTMLInputElement* input = static_cast<HTMLInputElement*>(m_renderer->element()); + return input->inputType() == HTMLInputElement::FILE; + } + + return false; +} + +bool AccessibilityRenderObject::isProgressIndicator() const +{ + return roleValue() == ProgressIndicatorRole; +} + +bool AccessibilityRenderObject::isSlider() const +{ + return roleValue() == SliderRole; +} + +bool AccessibilityRenderObject::isMenuRelated() const +{ + AccessibilityRole role = roleValue(); + return role == MenuRole || + role == MenuBarRole || + role == MenuButtonRole || + role == MenuItemRole; +} + +bool AccessibilityRenderObject::isMenu() const +{ + return roleValue() == MenuRole; +} + +bool AccessibilityRenderObject::isMenuBar() const +{ + return roleValue() == MenuBarRole; +} + +bool AccessibilityRenderObject::isMenuButton() const +{ + return roleValue() == MenuButtonRole; +} + +bool AccessibilityRenderObject::isMenuItem() const +{ + return roleValue() == MenuItemRole; +} + +bool AccessibilityRenderObject::isPressed() const +{ + ASSERT(m_renderer); + if (roleValue() != ButtonRole) + return false; + + Node* node = m_renderer->node(); + if (!node) + return false; + + // If this is an ARIA button, check the aria-pressed attribute rather than node()->active() + if (ariaRoleAttribute() == ButtonRole) { + if (equalIgnoringCase(getAttribute(aria_pressedAttr).string(), "true")) + return true; + return false; + } + + return node->active(); +} + +bool AccessibilityRenderObject::isIndeterminate() const +{ + ASSERT(m_renderer); + return m_renderer->node() && m_renderer->node()->isIndeterminate(); +} + +bool AccessibilityRenderObject::isChecked() const +{ + ASSERT(m_renderer); + return m_renderer->node() && m_renderer->node()->isChecked(); +} + +bool AccessibilityRenderObject::isHovered() const +{ + ASSERT(m_renderer); + return m_renderer->node() && m_renderer->node()->hovered(); +} + +bool AccessibilityRenderObject::isMultiSelect() const +{ + ASSERT(m_renderer); + if (!m_renderer->isListBox()) + return false; + return m_renderer->element() && static_cast<HTMLSelectElement*>(m_renderer->element())->multiple(); +} + +bool AccessibilityRenderObject::isReadOnly() const +{ + ASSERT(m_renderer); + + if (isWebArea()) { + Document* document = m_renderer->document(); + if (!document) + return true; + + HTMLElement* body = document->body(); + if (body && body->isContentEditable()) + return false; + + Frame* frame = document->frame(); + if (!frame) + return true; + + return !frame->isContentEditable(); + } + + return !m_renderer->node() || !m_renderer->node()->isContentEditable(); +} + +bool AccessibilityRenderObject::isOffScreen() const +{ + ASSERT(m_renderer); + IntRect contentRect = m_renderer->absoluteClippedOverflowRect(); + FrameView* view = m_renderer->document()->frame()->view(); + FloatRect viewRect = view->visibleContentRect(); + viewRect.intersect(contentRect); + return viewRect.isEmpty(); +} + +int AccessibilityRenderObject::headingLevel(Node* node) +{ + // headings can be in block flow and non-block flow + if (!node) + return 0; + + if (RenderObject* renderer = node->renderer()) { + AccessibilityObject* axObjectForNode = node->document()->axObjectCache()->get(renderer); + if (axObjectForNode->ariaRoleAttribute() == HeadingRole) { + if (!node->isElementNode()) + return 0; + Element* element = static_cast<Element*>(node); + return element->getAttribute(aria_levelAttr).toInt(); + } + } + + + if (node->hasTagName(h1Tag)) + return 1; + + if (node->hasTagName(h2Tag)) + return 2; + + if (node->hasTagName(h3Tag)) + return 3; + + if (node->hasTagName(h4Tag)) + return 4; + + if (node->hasTagName(h5Tag)) + return 5; + + if (node->hasTagName(h6Tag)) + return 6; + + return 0; +} + +bool AccessibilityRenderObject::isHeading() const +{ + return roleValue() == HeadingRole; +} + +bool AccessibilityRenderObject::isLink() const +{ + return roleValue() == WebCoreLinkRole; +} + +bool AccessibilityRenderObject::isControl() const +{ + if (!m_renderer) + return false; + + Node* node = m_renderer->element(); + return node && (node->isControl() || AccessibilityObject::isARIAControl(ariaRoleAttribute())); +} + +bool AccessibilityRenderObject::isFieldset() const +{ + if (!m_renderer) + return false; + + return m_renderer->isFieldset(); +} + +bool AccessibilityRenderObject::isGroup() const +{ + return roleValue() == GroupRole; +} + +const AtomicString& AccessibilityRenderObject::getAttribute(const QualifiedName& attribute) const +{ + Node* node = m_renderer->element(); + if (!node) + return nullAtom; + + if (!node->isElementNode()) + return nullAtom; + + Element* element = static_cast<Element*>(node); + return element->getAttribute(attribute); +} + +Element* AccessibilityRenderObject::anchorElement() const +{ + if (!m_renderer) + return 0; + + AXObjectCache* cache = axObjectCache(); + RenderObject* currRenderer; + + // Search up the render tree for a RenderObject with a DOM node. Defer to an earlier continuation, though. + for (currRenderer = m_renderer; currRenderer && !currRenderer->element(); currRenderer = currRenderer->parent()) { + if (currRenderer->continuation()) + return cache->get(currRenderer->continuation())->anchorElement(); + } + + // bail if none found + if (!currRenderer) + return 0; + + // search up the DOM tree for an anchor element + // NOTE: this assumes that any non-image with an anchor is an HTMLAnchorElement + Node* node = currRenderer->node(); + for ( ; node; node = node->parentNode()) { + if (node->hasTagName(aTag) || (node->renderer() && cache->get(node->renderer())->isAnchor())) + return static_cast<Element*>(node); + } + + return 0; +} + +Element* AccessibilityRenderObject::actionElement() const +{ + if (m_renderer->element() && m_renderer->element()->hasTagName(inputTag)) { + HTMLInputElement* input = static_cast<HTMLInputElement*>(m_renderer->element()); + if (!input->disabled() && (isCheckboxOrRadio() || input->isTextButton())) + return input; + } + + if (isFileUploadButton()) + return static_cast<Element*>(m_renderer->element()); + + if (AccessibilityObject::isARIAInput(ariaRoleAttribute())) + return static_cast<Element*>(m_renderer->element()); + + if (isImageButton()) + return static_cast<Element*>(m_renderer->element()); + + if (m_renderer->isMenuList()) + return static_cast<RenderMenuList*>(m_renderer)->selectElement(); + + Element* elt = anchorElement(); + if (!elt) + elt = mouseButtonListener(); + return elt; +} + +Element* AccessibilityRenderObject::mouseButtonListener() const +{ + Node* node = m_renderer->element(); + if (!node) + return 0; + if (!node->isEventTargetNode()) + return 0; + + // FIXME: Do the continuation search like anchorElement does + for (EventTargetNode* elt = static_cast<EventTargetNode*>(node); elt; elt = static_cast<EventTargetNode*>(elt->parentNode())) { + if (elt->inlineEventListenerForType(eventNames().clickEvent) || elt->inlineEventListenerForType(eventNames().mousedownEvent) || elt->inlineEventListenerForType(eventNames().mouseupEvent)) + return static_cast<Element*>(elt); + } + + return 0; +} + +static Element* siblingWithAriaRole(String role, Node* node) +{ + Node* sibling = node->parent()->firstChild(); + while (sibling) { + if (sibling->isElementNode()) { + String siblingAriaRole = static_cast<Element*>(sibling)->getAttribute(roleAttr).string(); + if (equalIgnoringCase(siblingAriaRole, role)) + return static_cast<Element*>(sibling); + } + sibling = sibling->nextSibling(); + } + + return 0; +} + +Element* AccessibilityRenderObject::menuElementForMenuButton() const +{ + if (ariaRoleAttribute() != MenuButtonRole) + return 0; + + return siblingWithAriaRole("menu", renderer()->node()); +} + +AccessibilityObject* AccessibilityRenderObject::menuForMenuButton() const +{ + Element* menu = menuElementForMenuButton(); + if (menu && menu->renderer()) + return m_renderer->document()->axObjectCache()->get(menu->renderer()); + return 0; +} + +Element* AccessibilityRenderObject::menuItemElementForMenu() const +{ + if (ariaRoleAttribute() != MenuRole) + return 0; + + return siblingWithAriaRole("menuitem", renderer()->node()); +} + +AccessibilityObject* AccessibilityRenderObject::menuButtonForMenu() const +{ + Element* menuItem = menuItemElementForMenu(); + + if (menuItem && menuItem->renderer()) { + // ARIA just has generic menu items. AppKit needs to know if this is a top level items like MenuBarButton or MenuBarItem + AccessibilityObject* menuItemAX = m_renderer->document()->axObjectCache()->get(menuItem->renderer()); + if (menuItemAX->isMenuButton()) + return menuItemAX; + } + return 0; +} + +String AccessibilityRenderObject::helpText() const +{ + if (!m_renderer) + return String(); + + for (RenderObject* curr = m_renderer; curr; curr = curr->parent()) { + if (curr->element() && curr->element()->isHTMLElement()) { + const AtomicString& summary = static_cast<Element*>(curr->element())->getAttribute(summaryAttr); + if (!summary.isEmpty()) + return summary; + const AtomicString& title = static_cast<Element*>(curr->element())->getAttribute(titleAttr); + if (!title.isEmpty()) + return title; + } + } + + return String(); +} + +String AccessibilityRenderObject::textUnderElement() const +{ + if (!m_renderer) + return String(); + + if (isFileUploadButton()) { + RenderFileUploadControl* uploadControl = static_cast<RenderFileUploadControl*>(m_renderer); + return uploadControl->buttonValue(); + } + + Node* node = m_renderer->element(); + if (node) { + if (Frame* frame = node->document()->frame()) { + // catch stale WebCoreAXObject (see <rdar://problem/3960196>) + if (frame->document() != node->document()) + return String(); + return plainText(rangeOfContents(node).get()); + } + } + + // return the null string for anonymous text because it is non-trivial to get + // the actual text and, so far, that is not needed + return String(); +} + +bool AccessibilityRenderObject::hasIntValue() const +{ + if (isHeading()) + return true; + + if (m_renderer->element() && isCheckboxOrRadio()) + return true; + + return false; +} + +int AccessibilityRenderObject::intValue() const +{ + if (!m_renderer || isPasswordField()) + return 0; + + if (isHeading()) + return headingLevel(m_renderer->element()); + + Node* node = m_renderer->element(); + if (!node || !isCheckboxOrRadio()) + return 0; + + // If this is an ARIA checkbox or radio, check the aria-checked attribute rather than node()->checked() + AccessibilityRole ariaRole = ariaRoleAttribute(); + if (ariaRole == RadioButtonRole || ariaRole == CheckBoxRole) { + if (equalIgnoringCase(getAttribute(aria_checkedAttr).string(), "true")) + return true; + return false; + } + + return static_cast<HTMLInputElement*>(node)->checked(); +} + +float AccessibilityRenderObject::valueForRange() const +{ + if (!isProgressIndicator() && !isSlider()) + return 0.0f; + + return getAttribute(aria_valuenowAttr).toFloat(); +} + +float AccessibilityRenderObject::maxValueForRange() const +{ + if (!isProgressIndicator() && !isSlider()) + return 0.0f; + + return getAttribute(aria_valuemaxAttr).toFloat(); +} + +float AccessibilityRenderObject::minValueForRange() const +{ + if (!isProgressIndicator() && !isSlider()) + return 0.0f; + + return getAttribute(aria_valueminAttr).toFloat(); +} + +String AccessibilityRenderObject::stringValue() const +{ + if (!m_renderer || isPasswordField()) + return String(); + + if (m_renderer->isText()) + return textUnderElement(); + + if (m_renderer->isMenuList()) + return static_cast<RenderMenuList*>(m_renderer)->text(); + + if (m_renderer->isListMarker()) + return static_cast<RenderListMarker*>(m_renderer)->text(); + + if (isWebArea()) { + if (m_renderer->document()->frame()) + return String(); + + // FIXME: should use startOfDocument and endOfDocument (or rangeForDocument?) here + VisiblePosition startVisiblePosition = m_renderer->positionForCoordinates(0, 0); + VisiblePosition endVisiblePosition = m_renderer->positionForCoordinates(INT_MAX, INT_MAX); + if (startVisiblePosition.isNull() || endVisiblePosition.isNull()) + return String(); + + return plainText(makeRange(startVisiblePosition, endVisiblePosition).get()); + } + + if (isTextControl()) + return text(); + + if (isFileUploadButton()) { + RenderFileUploadControl* uploadControl = static_cast<RenderFileUploadControl*>(m_renderer); + return uploadControl->fileTextValue(); + } + + // FIXME: We might need to implement a value here for more types + // FIXME: It would be better not to advertise a value at all for the types for which we don't implement one; + // this would require subclassing or making accessibilityAttributeNames do something other than return a + // single static array. + return String(); +} + +// This function implements the ARIA accessible name as described by the Mozilla +// ARIA Implementer's Guide. +static String accessibleNameForNode(Node* node) +{ + if (node->isTextNode()) + return static_cast<Text*>(node)->data(); + + if (node->hasTagName(inputTag)) + return static_cast<HTMLInputElement*>(node)->value(); + + if (node->isHTMLElement()) { + const AtomicString& alt = static_cast<HTMLElement*>(node)->getAttribute(altAttr); + if (!alt.isEmpty()) + return alt; + } + + return String(); +} + +String AccessibilityRenderObject::ariaAccessiblityName(const String& s) const +{ + Document* document = m_renderer->document(); + if (!document) + return String(); + + String idList = s; + idList.replace('\n', ' '); + Vector<String> idVector; + idList.split(' ', idVector); + + Vector<UChar> ariaLabel; + unsigned size = idVector.size(); + for (unsigned i = 0; i < size; ++i) { + String idName = idVector[i]; + Element* idElement = document->getElementById(idName); + if (idElement) { + String nameFragment = accessibleNameForNode(idElement); + ariaLabel.append(nameFragment.characters(), nameFragment.length()); + for (Node* n = idElement->firstChild(); n; n = n->traverseNextNode(idElement->nextSibling())) { + nameFragment = accessibleNameForNode(n); + ariaLabel.append(nameFragment.characters(), nameFragment.length()); + } + ariaLabel.append(' '); + } + } + return String::adopt(ariaLabel); +} + +String AccessibilityRenderObject::ariaLabeledByAttribute() const +{ + Node* node = m_renderer->node(); + if (!node) + return String(); + + if (!node->isElementNode()) + return String(); + + // The ARIA spec uses the British spelling: "labelled." It seems prudent to support the American + // spelling ("labeled") as well. + String idList = getAttribute(aria_labeledbyAttr).string(); + if (idList.isEmpty()) { + idList = getAttribute(aria_labelledbyAttr).string(); + if (idList.isEmpty()) + return String(); + } + + return ariaAccessiblityName(idList); +} + +static HTMLLabelElement* labelForElement(Element* element) +{ + RefPtr<NodeList> list = element->document()->getElementsByTagName("label"); + unsigned len = list->length(); + for (unsigned i = 0; i < len; i++) { + if (list->item(i)->hasTagName(labelTag)) { + HTMLLabelElement* label = static_cast<HTMLLabelElement*>(list->item(i)); + if (label->correspondingControl() == element) + return label; + } + } + + return 0; +} + +HTMLLabelElement* AccessibilityRenderObject::labelElementContainer() const +{ + if (!m_renderer) + return false; + + // the control element should not be considered part of the label + if (isControl()) + return false; + + // find if this has a parent that is a label + for (Node* parentNode = m_renderer->element(); parentNode; parentNode = parentNode->parentNode()) { + if (parentNode->hasTagName(labelTag)) + return static_cast<HTMLLabelElement*>(parentNode); + } + + return 0; +} + +String AccessibilityRenderObject::title() const +{ + AccessibilityRole ariaRole = ariaRoleAttribute(); + + if (!m_renderer) + return String(); + + Node* node = m_renderer->element(); + if (!node) + return String(); + + String ariaLabel = ariaLabeledByAttribute(); + if (!ariaLabel.isEmpty()) + return ariaLabel; + + const AtomicString& title = getAttribute(titleAttr); + if (!title.isEmpty()) + return title; + + bool isInputTag = node->hasTagName(inputTag); + if (isInputTag) { + HTMLInputElement* input = static_cast<HTMLInputElement*>(node); + if (input->isTextButton()) + return input->value(); + } + + if (isInputTag || AccessibilityObject::isARIAInput(ariaRole) || isControl()) { + HTMLLabelElement* label = labelForElement(static_cast<Element*>(node)); + if (label) + return label->innerText(); + } + + if (roleValue() == ButtonRole + || ariaRole == ListBoxOptionRole + || ariaRole == MenuItemRole + || ariaRole == MenuButtonRole + || isHeading()) + return textUnderElement(); + + if (isLink()) + return textUnderElement(); + + return String(); +} + +String AccessibilityRenderObject::ariaDescribedByAttribute() const +{ + String idList = getAttribute(aria_describedbyAttr).string(); + if (idList.isEmpty()) + return String(); + + return ariaAccessiblityName(idList); +} + +String AccessibilityRenderObject::accessibilityDescription() const +{ + if (!m_renderer) + return String(); + + String ariaDescription = ariaDescribedByAttribute(); + if (!ariaDescription.isEmpty()) + return ariaDescription; + + if (isImage()) { + if (m_renderer->element() && m_renderer->element()->isHTMLElement()) { + const AtomicString& alt = static_cast<HTMLElement*>(m_renderer->element())->getAttribute(altAttr); + if (alt.isEmpty()) + return String(); + return alt; + } + } + + if (isWebArea()) { + Document *document = m_renderer->document(); + Node* owner = document->ownerElement(); + if (owner) { + if (owner->hasTagName(frameTag) || owner->hasTagName(iframeTag)) { + const AtomicString& title = static_cast<HTMLFrameElementBase*>(owner)->getAttribute(titleAttr); + if (!title.isEmpty()) + return title; + return static_cast<HTMLFrameElementBase*>(owner)->name(); + } + if (owner->isHTMLElement()) + return static_cast<HTMLElement*>(owner)->getAttribute(nameAttr); + } + owner = document->body(); + if (owner && owner->isHTMLElement()) + return static_cast<HTMLElement*>(owner)->getAttribute(nameAttr); + } + + if (roleValue() == DefinitionListTermRole) + return AXDefinitionListTermText(); + if (roleValue() == DefinitionListDefinitionRole) + return AXDefinitionListDefinitionText(); + + return String(); +} + +IntRect AccessibilityRenderObject::boundingBoxRect() const +{ + IntRect rect; + RenderObject* obj = m_renderer; + + if (!obj) + return IntRect(); + + if (obj->isInlineContinuation()) + obj = obj->element()->renderer(); + + // FIXME: This doesn't work correctly with transforms. + Vector<IntRect> rects; + FloatPoint absPos = obj->localToAbsolute(); + obj->absoluteRects(rects, absPos.x(), absPos.y()); + const size_t n = rects.size(); + for (size_t i = 0; i < n; ++i) { + IntRect r = rects[i]; + if (!r.isEmpty()) { + if (obj->style()->hasAppearance()) + theme()->adjustRepaintRect(obj, r); + rect.unite(r); + } + } + return rect; +} + +IntRect AccessibilityRenderObject::checkboxOrRadioRect() const +{ + if (!m_renderer) + return IntRect(); + + HTMLLabelElement* label = labelForElement(static_cast<Element*>(m_renderer->element())); + if (!label || !label->renderer()) + return boundingBoxRect(); + + IntRect labelRect = axObjectCache()->get(label->renderer())->elementRect(); + labelRect.unite(boundingBoxRect()); + return labelRect; +} + +IntRect AccessibilityRenderObject::elementRect() const +{ + // a checkbox or radio button should encompass its label + if (isCheckboxOrRadio()) + return checkboxOrRadioRect(); + + return boundingBoxRect(); +} + +IntSize AccessibilityRenderObject::size() const +{ + IntRect rect = elementRect(); + return rect.size(); +} + +AccessibilityObject* AccessibilityRenderObject::internalLinkElement() const +{ + Element* element = anchorElement(); + if (!element) + return 0; + + // Right now, we do not support ARIA links as internal link elements + if (!element->hasTagName(aTag)) + return 0; + HTMLAnchorElement* anchor = static_cast<HTMLAnchorElement*>(element); + + KURL linkURL = anchor->href(); + String ref = linkURL.ref(); + if (ref.isEmpty()) + return 0; + + // check if URL is the same as current URL + linkURL.removeRef(); + if (m_renderer->document()->url() != linkURL) + return 0; + + Node* linkedNode = m_renderer->document()->findAnchor(ref); + if (!linkedNode) + return 0; + + // the element we find may not be accessible, keep searching until we find a good one + AccessibilityObject* linkedAXElement = m_renderer->document()->axObjectCache()->get(linkedNode->renderer()); + while (linkedAXElement && linkedAXElement->accessibilityIsIgnored()) { + linkedNode = linkedNode->traverseNextNode(); + + while (linkedNode && !linkedNode->renderer()) + linkedNode = linkedNode->traverseNextSibling(); + + if (!linkedNode) + return 0; + linkedAXElement = m_renderer->document()->axObjectCache()->get(linkedNode->renderer()); + } + + return linkedAXElement; +} + +void AccessibilityRenderObject::addRadioButtonGroupMembers(AccessibilityChildrenVector& linkedUIElements) const +{ + if (!m_renderer || roleValue() != RadioButtonRole) + return; + + Node* node = m_renderer->node(); + if (!node || !node->hasTagName(inputTag)) + return; + + HTMLInputElement* input = static_cast<HTMLInputElement*>(node); + // if there's a form, then this is easy + if (input->form()) { + Vector<RefPtr<Node> > formElements; + input->form()->getNamedElements(input->name(), formElements); + + unsigned len = formElements.size(); + for (unsigned i = 0; i < len; ++i) { + Node* associateElement = formElements[i].get(); + if (AccessibilityObject* object = m_renderer->document()->axObjectCache()->get(associateElement->renderer())) + linkedUIElements.append(object); + } + } else { + RefPtr<NodeList> list = node->document()->getElementsByTagName("input"); + unsigned len = list->length(); + for (unsigned i = 0; i < len; ++i) { + if (list->item(i)->hasTagName(inputTag)) { + HTMLInputElement* associateElement = static_cast<HTMLInputElement*>(list->item(i)); + if (associateElement->isRadioButton() && associateElement->name() == input->name()) { + if (AccessibilityObject* object = m_renderer->document()->axObjectCache()->get(associateElement->renderer())) + linkedUIElements.append(object); + } + } + } + } +} + +// linked ui elements could be all the related radio buttons in a group +// or an internal anchor connection +void AccessibilityRenderObject::linkedUIElements(AccessibilityChildrenVector& linkedUIElements) const +{ + if (isAnchor()) { + AccessibilityObject* linkedAXElement = internalLinkElement(); + if (linkedAXElement) + linkedUIElements.append(linkedAXElement); + } + + if (roleValue() == RadioButtonRole) + addRadioButtonGroupMembers(linkedUIElements); +} + +AccessibilityObject* AccessibilityRenderObject::titleUIElement() const +{ + if (!m_renderer) + return 0; + + // if isFieldset is true, the renderer is guaranteed to be a RenderFieldset + if (isFieldset()) + return axObjectCache()->get(static_cast<RenderFieldset*>(m_renderer)->findLegend()); + + // checkbox and radio hide their labels. Only controls get titleUIElements for now + if (isCheckboxOrRadio() || !isControl()) + return 0; + + Node* element = m_renderer->element(); + HTMLLabelElement* label = labelForElement(static_cast<Element*>(element)); + if (label && label->renderer()) + return axObjectCache()->get(label->renderer()); + + return 0; +} + +bool AccessibilityRenderObject::accessibilityIsIgnored() const +{ + // ignore invisible element + if (!m_renderer || m_renderer->style()->visibility() != VISIBLE) + return true; + + if (isPresentationalChildOfAriaRole()) + return true; + + // ignore popup menu items because AppKit does + for (RenderObject* parent = m_renderer->parent(); parent; parent = parent->parent()) { + if (parent->isMenuList()) + return true; + } + + // find out if this element is inside of a label element. + // if so, it may be ignored because it's the label for a checkbox or radio button + HTMLLabelElement* labelElement = labelElementContainer(); + if (labelElement) { + HTMLElement* correspondingControl = labelElement->correspondingControl(); + if (correspondingControl && correspondingControl->renderer()) { + AccessibilityObject* controlObject = axObjectCache()->get(correspondingControl->renderer()); + if (controlObject->isCheckboxOrRadio()) + return true; + } + } + + AccessibilityRole ariaRole = ariaRoleAttribute(); + if (ariaRole == TextAreaRole || ariaRole == StaticTextRole) { + String ariaText = text(); + return ariaText.isNull() || ariaText.isEmpty(); + } + + // NOTE: BRs always have text boxes now, so the text box check here can be removed + if (m_renderer->isText()) { + // static text beneath MenuItems and MenuButtons are just reported along with the menu item, so it's ignored on an individual level + if (parentObjectUnignored()->ariaRoleAttribute() == MenuItemRole || + parentObjectUnignored()->ariaRoleAttribute() == MenuButtonRole) + return true; + return m_renderer->isBR() || !static_cast<RenderText*>(m_renderer)->firstTextBox(); + } + + if (isHeading()) + return false; + + if (isLink()) + return false; + + // all controls are accessible + if (isControl()) + return false; + + // don't ignore labels, because they serve as TitleUIElements + Node* node = m_renderer->element(); + if (node && node->hasTagName(labelTag)) + return false; + + if (m_renderer->isBlockFlow() && m_renderer->childrenInline()) + return !static_cast<RenderBlock*>(m_renderer)->firstLineBox() && !mouseButtonListener(); + + // ignore images seemingly used as spacers + if (isImage()) { + if (node && node->isElementNode()) { + Element* elt = static_cast<Element*>(node); + const AtomicString& alt = elt->getAttribute(altAttr); + // don't ignore an image that has an alt tag + if (!alt.isEmpty()) + return false; + // informal standard is to ignore images with zero-length alt strings + if (!alt.isNull()) + return true; + } + + // check for one-dimensional image + if (m_renderer->height() <= 1 || m_renderer->width() <= 1) + return true; + + // check whether rendered image was stretched from one-dimensional file image + if (isNativeImage()) { + RenderImage* image = static_cast<RenderImage*>(m_renderer); + if (image->cachedImage()) { + IntSize imageSize = image->cachedImage()->imageSize(image->view()->zoomFactor()); + return imageSize.height() <= 1 || imageSize.width() <= 1; + } + } + return false; + } + + if (ariaRole != UnknownRole) + return false; + + // make a platform-specific decision + if (isAttachment()) + return accessibilityIgnoreAttachment(); + + return !m_renderer->isListMarker() && !isWebArea(); +} + +bool AccessibilityRenderObject::isLoaded() const +{ + return !m_renderer->document()->tokenizer(); +} + +int AccessibilityRenderObject::layoutCount() const +{ + if (!m_renderer->isRenderView()) + return 0; + return static_cast<RenderView*>(m_renderer)->frameView()->layoutCount(); +} + +String AccessibilityRenderObject::text() const +{ + if (!isTextControl() || isPasswordField()) + return String(); + + if (isNativeTextControl()) + return static_cast<RenderTextControl*>(m_renderer)->text(); + + Node* node = m_renderer->element(); + if (!node) + return String(); + if (!node->isElementNode()) + return String(); + + return static_cast<Element*>(node)->innerText(); +} + +int AccessibilityRenderObject::textLength() const +{ + ASSERT(isTextControl()); + + if (isPasswordField()) + return -1; // need to return something distinct from 0 + + return text().length(); +} + +PassRefPtr<Range> AccessibilityRenderObject::ariaSelectedTextDOMRange() const +{ + Node* node = m_renderer->element(); + if (!node) + return 0; + + RefPtr<Range> currentSelectionRange = selection().toRange(); + if (!currentSelectionRange) + return 0; + + ExceptionCode ec = 0; + if (!currentSelectionRange->intersectsNode(node, ec)) + return Range::create(currentSelectionRange->ownerDocument()); + + RefPtr<Range> ariaRange = rangeOfContents(node); + Position startPosition, endPosition; + + // Find intersection of currentSelectionRange and ariaRange + if (ariaRange->startOffset() > currentSelectionRange->startOffset()) + startPosition = ariaRange->startPosition(); + else + startPosition = currentSelectionRange->startPosition(); + + if (ariaRange->endOffset() < currentSelectionRange->endOffset()) + endPosition = ariaRange->endPosition(); + else + endPosition = currentSelectionRange->endPosition(); + + return Range::create(ariaRange->ownerDocument(), startPosition, endPosition); +} + +String AccessibilityRenderObject::selectedText() const +{ + ASSERT(isTextControl()); + + if (isPasswordField()) + return String(); // need to return something distinct from empty string + + if (isNativeTextControl()) { + RenderTextControl* textControl = static_cast<RenderTextControl*>(m_renderer); + return textControl->text().substring(textControl->selectionStart(), textControl->selectionEnd() - textControl->selectionStart()); + } + + if (ariaRoleAttribute() == UnknownRole) + return String(); + + RefPtr<Range> ariaRange = ariaSelectedTextDOMRange(); + if (!ariaRange) + return String(); + return ariaRange->text(); +} + +const AtomicString& AccessibilityRenderObject::accessKey() const +{ + Node* node = m_renderer->element(); + if (!node) + return nullAtom; + if (!node->isElementNode()) + return nullAtom; + return static_cast<Element*>(node)->getAttribute(accesskeyAttr); +} + +Selection AccessibilityRenderObject::selection() const +{ + return m_renderer->document()->frame()->selection()->selection(); +} + +PlainTextRange AccessibilityRenderObject::selectedTextRange() const +{ + ASSERT(isTextControl()); + + if (isPasswordField()) + return PlainTextRange(); + + AccessibilityRole ariaRole = ariaRoleAttribute(); + if (isNativeTextControl() && ariaRole == UnknownRole) { + RenderTextControl* textControl = static_cast<RenderTextControl*>(m_renderer); + return PlainTextRange(textControl->selectionStart(), textControl->selectionEnd() - textControl->selectionStart()); + } + + if (ariaRole == UnknownRole) + return PlainTextRange(); + + RefPtr<Range> ariaRange = ariaSelectedTextDOMRange(); + if (!ariaRange) + return PlainTextRange(); + return PlainTextRange(ariaRange->startOffset(), ariaRange->endOffset()); +} + +void AccessibilityRenderObject::setSelectedTextRange(const PlainTextRange& range) +{ + if (isNativeTextControl()) { + RenderTextControl* textControl = static_cast<RenderTextControl*>(m_renderer); + textControl->setSelectionRange(range.start, range.start + range.length); + return; + } + + Document* document = m_renderer->document(); + if (!document) + return; + Frame* frame = document->frame(); + if (!frame) + return; + Node* node = m_renderer->element(); + frame->selection()->setSelection(Selection(Position(node, range.start), + Position(node, range.start + range.length), DOWNSTREAM)); +} + +KURL AccessibilityRenderObject::url() const +{ + if (isAnchor() && m_renderer->element()->hasTagName(aTag)) { + if (HTMLAnchorElement* anchor = static_cast<HTMLAnchorElement*>(anchorElement())) + return anchor->href(); + } + + if (isWebArea()) + return m_renderer->document()->url(); + + if (isImage() && m_renderer->element() && m_renderer->element()->hasTagName(imgTag)) + return static_cast<HTMLImageElement*>(m_renderer->element())->src(); + + return KURL(); +} + +bool AccessibilityRenderObject::isVisited() const +{ + return m_renderer->style()->pseudoState() == PseudoVisited; +} + +bool AccessibilityRenderObject::isSelected() const +{ + if (!m_renderer) + return false; + + Node* node = m_renderer->node(); + if (!node) + return false; + + return false; +} + +bool AccessibilityRenderObject::isFocused() const +{ + if (!m_renderer) + return false; + + Document* document = m_renderer->document(); + if (!document) + return false; + + Node* focusedNode = document->focusedNode(); + if (!focusedNode) + return false; + + // A web area is represented by the Document node in the DOM tree, which isn't focusable. + // Check instead if the frame's selection controller is focused + if (focusedNode == m_renderer->element() || + (roleValue() == WebAreaRole && document->frame()->selection()->isFocusedAndActive())) + return true; + + return false; +} + +void AccessibilityRenderObject::setFocused(bool on) +{ + if (!canSetFocusAttribute()) + return; + + if (!on) + m_renderer->document()->setFocusedNode(0); + else { + if (m_renderer->element()->isElementNode()) + static_cast<Element*>(m_renderer->element())->focus(); + else + m_renderer->document()->setFocusedNode(m_renderer->element()); + } +} + +void AccessibilityRenderObject::setValue(const String& string) +{ + // FIXME: Do we want to do anything here for ARIA textboxes? + if (m_renderer->isTextField()) { + HTMLInputElement* input = static_cast<HTMLInputElement*>(m_renderer->element()); + input->setValue(string); + } else if (m_renderer->isTextArea()) { + HTMLTextAreaElement* textArea = static_cast<HTMLTextAreaElement*>(m_renderer->element()); + textArea->setValue(string); + } +} + +bool AccessibilityRenderObject::isEnabled() const +{ + return m_renderer->element() ? m_renderer->element()->isEnabled() : true; +} + +RenderObject* AccessibilityRenderObject::topRenderer() const +{ + return m_renderer->document()->topDocument()->renderer(); +} + +Document* AccessibilityRenderObject::document() const +{ + return m_renderer->document(); +} + +FrameView* AccessibilityRenderObject::topDocumentFrameView() const +{ + return topRenderer()->view()->frameView(); +} + +Widget* AccessibilityRenderObject::widget() const +{ + if (!m_renderer->isWidget()) + return 0; + + return static_cast<RenderWidget*>(m_renderer)->widget(); +} + +AXObjectCache* AccessibilityRenderObject::axObjectCache() const +{ + return m_renderer->document()->axObjectCache(); +} + +AccessibilityObject* AccessibilityRenderObject::accessibilityParentForImageMap(HTMLMapElement* map) const +{ + // find an image that is using this map + if (!m_renderer || !map) + return 0; + + RefPtr<HTMLCollection> coll = m_renderer->document()->images(); + for (Node* curr = coll->firstItem(); curr; curr = coll->nextItem()) { + RenderObject* obj = curr->renderer(); + if (!obj || !curr->hasTagName(imgTag)) + continue; + + // The HTMLImageElement's useMap() value includes the '#' symbol at the beginning, + // which has to be stripped off + if (static_cast<HTMLImageElement*>(curr)->useMap().substring(1) == map->getName()) + return axObjectCache()->get(obj); + } + + return 0; +} + +void AccessibilityRenderObject::getDocumentLinks(AccessibilityChildrenVector& result) +{ + Document* document = m_renderer->document(); + RefPtr<HTMLCollection> coll = document->links(); + Node* curr = coll->firstItem(); + while (curr) { + RenderObject* obj = curr->renderer(); + if (obj) { + RefPtr<AccessibilityObject> axobj = document->axObjectCache()->get(obj); + ASSERT(axobj); + ASSERT(axobj->roleValue() == WebCoreLinkRole); + if (!axobj->accessibilityIsIgnored()) + result.append(axobj); + } else { + Node* parent = curr->parent(); + if (parent && curr->hasTagName(areaTag) && parent->hasTagName(mapTag)) { + AccessibilityImageMapLink* areaObject = static_cast<AccessibilityImageMapLink*>(axObjectCache()->get(ImageMapLinkRole)); + areaObject->setHTMLAreaElement(static_cast<HTMLAreaElement*>(curr)); + areaObject->setHTMLMapElement(static_cast<HTMLMapElement*>(parent)); + areaObject->setParent(accessibilityParentForImageMap(static_cast<HTMLMapElement*>(parent))); + + result.append(areaObject); + } + } + curr = coll->nextItem(); + } +} + +FrameView* AccessibilityRenderObject::documentFrameView() const +{ + if (!m_renderer || !m_renderer->document()) + return 0; + + // this is the RenderObject's Document's Frame's FrameView + return m_renderer->document()->view(); +} + +Widget* AccessibilityRenderObject::widgetForAttachmentView() const +{ + if (!isAttachment()) + return 0; + return static_cast<RenderWidget*>(m_renderer)->widget(); +} + +FrameView* AccessibilityRenderObject::frameViewIfRenderView() const +{ + if (!m_renderer->isRenderView()) + return 0; + // this is the RenderObject's Document's renderer's FrameView + return m_renderer->view()->frameView(); +} + +// This function is like a cross-platform version of - (WebCoreTextMarkerRange*)textMarkerRange. It returns +// a Range that we can convert to a WebCoreTextMarkerRange in the Obj-C file +VisiblePositionRange AccessibilityRenderObject::visiblePositionRange() const +{ + if (!m_renderer) + return VisiblePositionRange(); + + // construct VisiblePositions for start and end + Node* node = m_renderer->element(); + if (!node) + return VisiblePositionRange(); + + VisiblePosition startPos = VisiblePosition(node, 0, VP_DEFAULT_AFFINITY); + VisiblePosition endPos = VisiblePosition(node, maxDeepOffset(node), VP_DEFAULT_AFFINITY); + + // the VisiblePositions are equal for nodes like buttons, so adjust for that + if (startPos == endPos) { + endPos = endPos.next(); + if (endPos.isNull()) + endPos = startPos; + } + + return VisiblePositionRange(startPos, endPos); +} + +VisiblePositionRange AccessibilityRenderObject::visiblePositionRangeForLine(unsigned lineCount) const +{ + if (lineCount == 0 || !m_renderer) + return VisiblePositionRange(); + + // iterate over the lines + // FIXME: this is wrong when lineNumber is lineCount+1, because nextLinePosition takes you to the + // last offset of the last line + VisiblePosition visiblePos = m_renderer->document()->renderer()->positionForCoordinates(0, 0); + VisiblePosition savedVisiblePos; + while (--lineCount != 0) { + savedVisiblePos = visiblePos; + visiblePos = nextLinePosition(visiblePos, 0); + if (visiblePos.isNull() || visiblePos == savedVisiblePos) + return VisiblePositionRange(); + } + + // make a caret selection for the marker position, then extend it to the line + // NOTE: ignores results of sel.modify because it returns false when + // starting at an empty line. The resulting selection in that case + // will be a caret at visiblePos. + SelectionController selection; + selection.setSelection(Selection(visiblePos)); + selection.modify(SelectionController::EXTEND, SelectionController::RIGHT, LineBoundary); + + return VisiblePositionRange(selection.selection().visibleStart(), selection.selection().visibleEnd()); +} + +VisiblePosition AccessibilityRenderObject::visiblePositionForIndex(int index) const +{ + if (!m_renderer) + return VisiblePosition(); + + if (isNativeTextControl()) + return static_cast<RenderTextControl*>(m_renderer)->visiblePositionForIndex(index); + + if (!isTextControl() && !m_renderer->isText()) + return VisiblePosition(); + + Node* node = m_renderer->node(); + if (!node) + return VisiblePosition(); + + if (index <= 0) + return VisiblePosition(node, 0, DOWNSTREAM); + + ExceptionCode ec = 0; + RefPtr<Range> range = Range::create(m_renderer->document()); + range->selectNodeContents(node, ec); + CharacterIterator it(range.get()); + it.advance(index - 1); + return VisiblePosition(it.range()->endContainer(ec), it.range()->endOffset(ec), UPSTREAM); +} + +int AccessibilityRenderObject::indexForVisiblePosition(const VisiblePosition& pos) const +{ + if (isNativeTextControl()) + return static_cast<RenderTextControl*>(m_renderer)->indexForVisiblePosition(pos); + + if (!isTextControl()) + return 0; + + Node* node = m_renderer->node(); + if (!node) + return 0; + + Position indexPosition = pos.deepEquivalent(); + if (!indexPosition.node() || indexPosition.node()->rootEditableElement() != node) + return 0; + + ExceptionCode ec = 0; + RefPtr<Range> range = Range::create(m_renderer->document()); + range->setStart(node, 0, ec); + range->setEnd(indexPosition.node(), indexPosition.offset(), ec); + return TextIterator::rangeLength(range.get()); +} + +IntRect AccessibilityRenderObject::boundsForVisiblePositionRange(const VisiblePositionRange& visiblePositionRange) const +{ + if (visiblePositionRange.isNull()) + return IntRect(); + + // Create a mutable VisiblePositionRange. + VisiblePositionRange range(visiblePositionRange); + IntRect rect1 = range.start.absoluteCaretBounds(); + IntRect rect2 = range.end.absoluteCaretBounds(); + + // readjust for position at the edge of a line. This is to exclude line rect that doesn't need to be accounted in the range bounds + if (rect2.y() != rect1.y()) { + VisiblePosition endOfFirstLine = endOfLine(range.start); + if (range.start == endOfFirstLine) { + range.start.setAffinity(DOWNSTREAM); + rect1 = range.start.absoluteCaretBounds(); + } + if (range.end == endOfFirstLine) { + range.end.setAffinity(UPSTREAM); + rect2 = range.end.absoluteCaretBounds(); + } + } + + IntRect ourrect = rect1; + ourrect.unite(rect2); + + // if the rectangle spans lines and contains multiple text chars, use the range's bounding box intead + if (rect1.bottom() != rect2.bottom()) { + RefPtr<Range> dataRange = makeRange(range.start, range.end); + IntRect boundingBox = dataRange->boundingBox(); + String rangeString = plainText(dataRange.get()); + if (rangeString.length() > 1 && !boundingBox.isEmpty()) + ourrect = boundingBox; + } + +#if PLATFORM(MAC) + return m_renderer->document()->view()->contentsToScreen(ourrect); +#else + return ourrect; +#endif +} + +void AccessibilityRenderObject::setSelectedVisiblePositionRange(const VisiblePositionRange& range) const +{ + if (range.start.isNull() || range.end.isNull()) + return; + + // make selection and tell the document to use it. if it's zero length, then move to that position + if (range.start == range.end) { + m_renderer->document()->frame()->selection()->moveTo(range.start, true); + } + else { + Selection newSelection = Selection(range.start, range.end); + m_renderer->document()->frame()->selection()->setSelection(newSelection); + } +} + +VisiblePosition AccessibilityRenderObject::visiblePositionForPoint(const IntPoint& point) const +{ + // convert absolute point to view coordinates + FrameView* frameView = m_renderer->document()->topDocument()->renderer()->view()->frameView(); + RenderObject* renderer = topRenderer(); + Node* innerNode = 0; + + // locate the node containing the point + IntPoint pointResult; + while (1) { + IntPoint ourpoint; +#if PLATFORM(MAC) + ourpoint = frameView->screenToContents(point); +#else + ourpoint = point; +#endif + HitTestRequest request(true, true); + HitTestResult result(ourpoint); + renderer->layer()->hitTest(request, result); + innerNode = result.innerNode(); + if (!innerNode || !innerNode->renderer()) + return VisiblePosition(); + + pointResult = result.localPoint(); + + // done if hit something other than a widget + renderer = innerNode->renderer(); + if (!renderer->isWidget()) + break; + + // descend into widget (FRAME, IFRAME, OBJECT...) + Widget* widget = static_cast<RenderWidget*>(renderer)->widget(); + if (!widget || !widget->isFrameView()) + break; + Frame* frame = static_cast<FrameView*>(widget)->frame(); + if (!frame) + break; + Document* document = frame->document(); + if (!document) + break; + renderer = document->renderer(); + frameView = static_cast<FrameView*>(widget); + } + + return innerNode->renderer()->positionForPoint(pointResult); +} + +// NOTE: Consider providing this utility method as AX API +VisiblePosition AccessibilityRenderObject::visiblePositionForIndex(unsigned indexValue, bool lastIndexOK) const +{ + if (!isTextControl()) + return VisiblePosition(); + + // lastIndexOK specifies whether the position after the last character is acceptable + if (indexValue >= text().length()) { + if (!lastIndexOK || indexValue > text().length()) + return VisiblePosition(); + } + VisiblePosition position = visiblePositionForIndex(indexValue); + position.setAffinity(DOWNSTREAM); + return position; +} + +// NOTE: Consider providing this utility method as AX API +int AccessibilityRenderObject::index(const VisiblePosition& position) const +{ + if (!isTextControl()) + return -1; + + Node* node = position.deepEquivalent().node(); + if (!node) + return -1; + + for (RenderObject* renderer = node->renderer(); renderer && renderer->element(); renderer = renderer->parent()) { + if (renderer == m_renderer) + return indexForVisiblePosition(position); + } + + return -1; +} + +// Given a line number, the range of characters of the text associated with this accessibility +// object that contains the line number. +PlainTextRange AccessibilityRenderObject::doAXRangeForLine(unsigned lineNumber) const +{ + if (!isTextControl()) + return PlainTextRange(); + + // iterate to the specified line + VisiblePosition visiblePos = visiblePositionForIndex(0); + VisiblePosition savedVisiblePos; + for (unsigned lineCount = lineNumber; lineCount != 0; lineCount -= 1) { + savedVisiblePos = visiblePos; + visiblePos = nextLinePosition(visiblePos, 0); + if (visiblePos.isNull() || visiblePos == savedVisiblePos) + return PlainTextRange(); + } + + // make a caret selection for the marker position, then extend it to the line + // NOTE: ignores results of selection.modify because it returns false when + // starting at an empty line. The resulting selection in that case + // will be a caret at visiblePos. + SelectionController selection; + selection.setSelection(Selection(visiblePos)); + selection.modify(SelectionController::EXTEND, SelectionController::LEFT, LineBoundary); + selection.modify(SelectionController::EXTEND, SelectionController::RIGHT, LineBoundary); + + // calculate the indices for the selection start and end + VisiblePosition startPosition = selection.selection().visibleStart(); + VisiblePosition endPosition = selection.selection().visibleEnd(); + int index1 = indexForVisiblePosition(startPosition); + int index2 = indexForVisiblePosition(endPosition); + + // add one to the end index for a line break not caused by soft line wrap (to match AppKit) + if (endPosition.affinity() == DOWNSTREAM && endPosition.next().isNotNull()) + index2 += 1; + + // return nil rather than an zero-length range (to match AppKit) + if (index1 == index2) + return PlainTextRange(); + + return PlainTextRange(index1, index2 - index1); +} + +// The composed character range in the text associated with this accessibility object that +// is specified by the given index value. This parameterized attribute returns the complete +// range of characters (including surrogate pairs of multi-byte glyphs) at the given index. +PlainTextRange AccessibilityRenderObject::doAXRangeForIndex(unsigned index) const +{ + if (!isTextControl()) + return PlainTextRange(); + + String elementText = text(); + if (!elementText.length() || index > elementText.length() - 1) + return PlainTextRange(); + + return PlainTextRange(index, 1); +} + +// A substring of the text associated with this accessibility object that is +// specified by the given character range. +String AccessibilityRenderObject::doAXStringForRange(const PlainTextRange& range) const +{ + if (isPasswordField()) + return String(); + + if (range.length == 0) + return ""; + + if (!isTextControl()) + return String(); + + String elementText = text(); + if (range.start + range.length > elementText.length()) + return String(); + + return elementText.substring(range.start, range.length); +} + +// The bounding rectangle of the text associated with this accessibility object that is +// specified by the given range. This is the bounding rectangle a sighted user would see +// on the display screen, in pixels. +IntRect AccessibilityRenderObject::doAXBoundsForRange(const PlainTextRange& range) const +{ + if (isTextControl()) + return boundsForVisiblePositionRange(visiblePositionRangeForRange(range)); + return IntRect(); +} + +AccessibilityObject* AccessibilityRenderObject::doAccessibilityHitTest(const IntPoint& point) const +{ + if (!m_renderer) + return 0; + + RenderLayer* layer = m_renderer->layer(); + if (!layer) + return 0; + + HitTestRequest request(true, true); + HitTestResult hitTestResult = HitTestResult(point); + layer->hitTest(request, hitTestResult); + if (!hitTestResult.innerNode()) + return 0; + Node* node = hitTestResult.innerNode()->shadowAncestorNode(); + RenderObject* obj = node->renderer(); + if (!obj) + return 0; + + AccessibilityObject *result = obj->document()->axObjectCache()->get(obj); + + if (obj->isListBox()) + return static_cast<AccessibilityListBox*>(result)->doAccessibilityHitTest(point); + + if (result->accessibilityIsIgnored()) + result = result->parentObjectUnignored(); + + return result; +} + +AccessibilityObject* AccessibilityRenderObject::focusedUIElement() const +{ + // get the focused node in the page + Page* page = m_renderer->document()->page(); + if (!page) + return 0; + + Document* focusedDocument = page->focusController()->focusedOrMainFrame()->document(); + Node* focusedNode = focusedDocument->focusedNode(); + if (!focusedNode) + focusedNode = focusedDocument; + + RenderObject* focusedNodeRenderer = focusedNode->renderer(); + if (!focusedNodeRenderer) + return 0; + + AccessibilityObject* obj = focusedNodeRenderer->document()->axObjectCache()->get(focusedNodeRenderer); + + if (obj->shouldFocusActiveDescendant()) { + if (AccessibilityObject* descendant = obj->activeDescendant()) + obj = descendant; + } + + // the HTML element, for example, is focusable but has an AX object that is ignored + if (obj->accessibilityIsIgnored()) + obj = obj->parentObjectUnignored(); + + return obj; +} + +bool AccessibilityRenderObject::shouldFocusActiveDescendant() const +{ + switch (ariaRoleAttribute()) { + case GroupRole: + case ComboBoxRole: + case ListBoxRole: + case MenuRole: + case MenuBarRole: + case RadioGroupRole: + case RowRole: + case PopUpButtonRole: + case ProgressIndicatorRole: + case ToolbarRole: + case OutlineRole: + /* FIXME: replace these with actual roles when they are added to AccessibilityRole + composite + alert + alertdialog + grid + status + timer + tree + */ + return true; + default: + return false; + } +} + +AccessibilityObject* AccessibilityRenderObject::activeDescendant() const +{ + if (renderer()->element() && !renderer()->element()->isElementNode()) + return 0; + Element* element = static_cast<Element*>(renderer()->element()); + + String activeDescendantAttrStr = element->getAttribute(aria_activedescendantAttr).string(); + if (activeDescendantAttrStr.isNull() || activeDescendantAttrStr.isEmpty()) + return 0; + + Element* target = renderer()->document()->getElementById(activeDescendantAttrStr); + if (!target) + return 0; + + AccessibilityObject* obj = renderer()->document()->axObjectCache()->get(target->renderer()); + if (obj->isAccessibilityRenderObject()) + // an activedescendant is only useful if it has a renderer, because that's what's needed to post the notification + return obj; + return 0; +} + + +void AccessibilityRenderObject::handleActiveDescendantChanged() +{ + Element* element = static_cast<Element*>(renderer()->element()); + if (!element) + return; + Document* doc = renderer()->document(); + if (!doc->frame()->selection()->isFocusedAndActive() || doc->focusedNode() != element) + return; + AccessibilityRenderObject* activedescendant = static_cast<AccessibilityRenderObject*>(activeDescendant()); + + if (activedescendant && shouldFocusActiveDescendant()) + doc->axObjectCache()->postNotificationToElement(activedescendant->renderer(), "AXFocusedUIElementChanged"); +} + + +AccessibilityObject* AccessibilityRenderObject::observableObject() const +{ + for (RenderObject* renderer = m_renderer; renderer && renderer->element(); renderer = renderer->parent()) { + if (renderer->isTextField() || renderer->isTextArea()) + return renderer->document()->axObjectCache()->get(renderer); + } + + return 0; +} + +typedef HashMap<String, AccessibilityRole, CaseFoldingHash> ARIARoleMap; + +static const ARIARoleMap& createARIARoleMap() +{ + struct RoleEntry { + String ariaRole; + AccessibilityRole webcoreRole; + }; + + const RoleEntry roles[] = { + { "button", ButtonRole }, + { "checkbox", CheckBoxRole }, + { "group", GroupRole }, + { "heading", HeadingRole }, + { "img", ImageRole }, + { "link", WebCoreLinkRole }, + { "listbox", ListBoxRole }, + // "option" isn't here because it may map to different roles depending on the parent element's role + { "menu", MenuRole }, + { "menubar", GroupRole }, + // "menuitem" isn't here because it may map to different roles depending on the parent element's role + { "menuitemcheckbox", MenuItemRole }, + { "menuitemradio", MenuItemRole }, + { "progressbar", ProgressIndicatorRole }, + { "radio", RadioButtonRole }, + { "range", SliderRole }, + { "slider", SliderRole }, + { "spinbutton", ProgressIndicatorRole }, + { "textbox", TextAreaRole } + }; + ARIARoleMap& roleMap = *new ARIARoleMap; + + const unsigned numRoles = sizeof(roles) / sizeof(roles[0]); + for (unsigned i = 0; i < numRoles; ++i) + roleMap.set(roles[i].ariaRole, roles[i].webcoreRole); + return roleMap; +} + +static AccessibilityRole ariaRoleToWebCoreRole(String value) +{ + ASSERT(!value.isEmpty() && !value.isNull()); + static const ARIARoleMap& roleMap = createARIARoleMap(); + return roleMap.get(value); +} + +AccessibilityRole AccessibilityRenderObject::determineAriaRoleAttribute() const +{ + String ariaRole = getAttribute(roleAttr).string(); + if (ariaRole.isNull() || ariaRole.isEmpty()) + return UnknownRole; + + AccessibilityRole role = ariaRoleToWebCoreRole(ariaRole); + if (role) + return role; + // selects and listboxes both have options as child roles, but they map to different roles within WebCore + if (equalIgnoringCase(ariaRole,"option")) { + if (parentObjectUnignored()->ariaRoleAttribute() == MenuRole) + return MenuItemRole; + if (parentObjectUnignored()->ariaRoleAttribute() == ListBoxRole) + return ListBoxOptionRole; + } + // an aria "menuitem" may map to MenuButton or MenuItem depending on its parent + if (equalIgnoringCase(ariaRole,"menuitem")) { + if (parentObjectUnignored()->ariaRoleAttribute() == GroupRole) + return MenuButtonRole; + if (parentObjectUnignored()->ariaRoleAttribute() == MenuRole) + return MenuItemRole; + } + + return UnknownRole; +} + +void AccessibilityRenderObject::setAriaRole() +{ + m_ariaRole = determineAriaRoleAttribute(); +} + +AccessibilityRole AccessibilityRenderObject::ariaRoleAttribute() const +{ + return m_ariaRole; +} + +AccessibilityRole AccessibilityRenderObject::roleValue() const +{ + if (!m_renderer) + return UnknownRole; + + Node* node = m_renderer->element(); + AccessibilityRole ariaRole = ariaRoleAttribute(); + if (ariaRole != UnknownRole) + return ariaRole; + + if (node && node->isLink()) { + if (m_renderer->isImage()) + return ImageMapRole; + return WebCoreLinkRole; + } + if (m_renderer->isListMarker()) + return ListMarkerRole; + if (node && node->hasTagName(buttonTag)) + return ButtonRole; + if (m_renderer->isText()) + return StaticTextRole; + if (m_renderer->isImage()) { + if (node && node->hasTagName(inputTag)) + return ButtonRole; + return ImageRole; + } + if (m_renderer->isRenderView()) + return WebAreaRole; + + if (m_renderer->isTextField()) + return TextFieldRole; + + if (m_renderer->isTextArea()) + return TextAreaRole; + + if (node && node->hasTagName(inputTag)) { + HTMLInputElement* input = static_cast<HTMLInputElement*>(node); + if (input->inputType() == HTMLInputElement::CHECKBOX) + return CheckBoxRole; + if (input->inputType() == HTMLInputElement::RADIO) + return RadioButtonRole; + if (input->isTextButton()) + return ButtonRole; + } + + if (node && node->hasTagName(buttonTag)) + return ButtonRole; + + if (isFileUploadButton()) + return ButtonRole; + + if (m_renderer->isMenuList()) + return PopUpButtonRole; + + if (headingLevel(m_renderer->element()) != 0) + return HeadingRole; + + if (node && node->hasTagName(ddTag)) + return DefinitionListDefinitionRole; + + if (node && node->hasTagName(dtTag)) + return DefinitionListTermRole; + + if (m_renderer->isBlockFlow() || (node && node->hasTagName(labelTag))) + return GroupRole; + + return UnknownRole; +} + +bool AccessibilityRenderObject::isPresentationalChildOfAriaRole() const +{ + // Walk the parent chain looking for a parent that has presentational children + AccessibilityObject* parent; + for (parent = parentObject(); parent && !parent->ariaRoleHasPresentationalChildren(); parent = parent->parentObject()) + ; + return parent; +} + +bool AccessibilityRenderObject::ariaRoleHasPresentationalChildren() const +{ + switch (m_ariaRole) { + case ButtonRole: + case SliderRole: + case ImageRole: + case ProgressIndicatorRole: + //case SeparatorRole: + return true; + default: + return false; + } +} + +bool AccessibilityRenderObject::canSetFocusAttribute() const +{ + // NOTE: It would be more accurate to ask the document whether setFocusedNode() would + // do anything. For example, it setFocusedNode() will do nothing if the current focused + // node will not relinquish the focus. + if (!m_renderer->element() || !m_renderer->element()->isEnabled()) + return false; + + switch (roleValue()) { + case WebCoreLinkRole: + case ImageMapLinkRole: + case TextFieldRole: + case TextAreaRole: + case ButtonRole: + case PopUpButtonRole: + case CheckBoxRole: + case RadioButtonRole: + return true; + default: + return false; + } +} + +bool AccessibilityRenderObject::canSetValueAttribute() const +{ + if (isWebArea()) + return !isReadOnly(); + + return isTextControl() || isProgressIndicator() || isSlider(); +} + +bool AccessibilityRenderObject::canSetTextRangeAttributes() const +{ + return isTextControl(); +} + +void AccessibilityRenderObject::childrenChanged() +{ + clearChildren(); + + if (accessibilityIsIgnored()) { + AccessibilityObject* parent = parentObject(); + if (parent) + parent->childrenChanged(); + } +} + +bool AccessibilityRenderObject::canHaveChildren() const +{ + if (!m_renderer) + return false; + + // Elements that should not have children + switch (roleValue()) { + case ImageRole: + case ButtonRole: + case PopUpButtonRole: + case CheckBoxRole: + case RadioButtonRole: + return false; + default: + return true; + } +} + +const AccessibilityObject::AccessibilityChildrenVector& AccessibilityRenderObject::children() +{ + if (!m_haveChildren) + addChildren(); + return m_children; +} + +void AccessibilityRenderObject::addChildren() +{ + // If the need to add more children in addition to existing children arises, + // childrenChanged should have been called, leaving the object with no children. + ASSERT(!m_haveChildren); + + // nothing to add if there is no RenderObject + if (!m_renderer) + return; + + m_haveChildren = true; + + if (!canHaveChildren()) + return; + + // add all unignored acc children + for (RefPtr<AccessibilityObject> obj = firstChild(); obj; obj = obj->nextSibling()) { + if (obj->accessibilityIsIgnored()) { + if (!obj->hasChildren()) + obj->addChildren(); + AccessibilityChildrenVector children = obj->children(); + unsigned length = children.size(); + for (unsigned i = 0; i < length; ++i) + m_children.append(children[i]); + } else + m_children.append(obj); + } + + // for a RenderImage, add the <area> elements as individual accessibility objects + if (m_renderer->isRenderImage()) { + HTMLMapElement* map = static_cast<RenderImage*>(m_renderer)->imageMap(); + if (map) { + for (Node* current = map->firstChild(); current; current = current->traverseNextNode(map)) { + + // add an <area> element for this child if it has a link + if (current->isLink()) { + AccessibilityImageMapLink* areaObject = static_cast<AccessibilityImageMapLink*>(m_renderer->document()->axObjectCache()->get(ImageMapLinkRole)); + areaObject->setHTMLAreaElement(static_cast<HTMLAreaElement*>(current)); + areaObject->setHTMLMapElement(map); + areaObject->setParent(this); + + m_children.append(areaObject); + } + } + } + } +} + +void AccessibilityRenderObject::ariaListboxSelectedChildren(AccessibilityChildrenVector& result) +{ + AccessibilityObject* child = firstChild(); + bool isMultiselectable = false; + + Element* element = static_cast<Element*>(renderer()->element()); + if (!element || !element->isElementNode()) // do this check to ensure safety of static_cast above + return; + + String multiselectablePropertyStr = element->getAttribute("aria-multiselectable").string(); + isMultiselectable = equalIgnoringCase(multiselectablePropertyStr, "true"); + + while (child) { + // every child should have aria-role option, and if so, check for selected attribute/state + AccessibilityRole ariaRole = child->ariaRoleAttribute(); + RenderObject* childRenderer = 0; + if (child->isAccessibilityRenderObject()) + childRenderer = static_cast<AccessibilityRenderObject*>(child)->renderer(); + if (childRenderer && ariaRole == ListBoxOptionRole) { + Element* childElement = static_cast<Element*>(childRenderer->element()); + if (childElement && childElement->isElementNode()) { // do this check to ensure safety of static_cast above + String selectedAttrString = childElement->getAttribute("aria-selected").string(); + if (equalIgnoringCase(selectedAttrString, "true")) { + result.append(child); + if (isMultiselectable) + return; + } + } + } + child = child->nextSibling(); + } +} + +void AccessibilityRenderObject::selectedChildren(AccessibilityChildrenVector& result) +{ + ASSERT(result.isEmpty()); + + // only listboxes should be asked for their selected children. + if (ariaRoleAttribute() != ListBoxRole) { // native list boxes would be AccessibilityListBoxes, so only check for aria list boxes + ASSERT_NOT_REACHED(); + return; + } + return ariaListboxSelectedChildren(result); +} + +void AccessibilityRenderObject::ariaListboxVisibleChildren(AccessibilityChildrenVector& result) +{ + if (!hasChildren()) + addChildren(); + + unsigned length = m_children.size(); + for (unsigned i = 0; i < length; i++) { + if (!m_children[i]->isOffScreen()) + result.append(m_children[i]); + } +} + +void AccessibilityRenderObject::visibleChildren(AccessibilityChildrenVector& result) +{ + ASSERT(result.isEmpty()); + + // only listboxes are asked for their visible children. + if (ariaRoleAttribute() != ListBoxRole) { // native list boxes would be AccessibilityListBoxes, so only check for aria list boxes + ASSERT_NOT_REACHED(); + return; + } + return ariaListboxVisibleChildren(result); +} + +void AccessibilityRenderObject::removeAXObjectID() +{ + if (!m_id) + return; +#if PLATFORM(MAC) + m_renderer->document()->axObjectCache()->removeAXID(this); +#endif +} + +const String& AccessibilityRenderObject::actionVerb() const +{ + // FIXME: Need to add verbs for select elements. + DEFINE_STATIC_LOCAL(const String, buttonAction, (AXButtonActionVerb())); + DEFINE_STATIC_LOCAL(const String, textFieldAction, (AXTextFieldActionVerb())); + DEFINE_STATIC_LOCAL(const String, radioButtonAction, (AXRadioButtonActionVerb())); + DEFINE_STATIC_LOCAL(const String, checkedCheckBoxAction, (AXCheckedCheckBoxActionVerb())); + DEFINE_STATIC_LOCAL(const String, uncheckedCheckBoxAction, (AXUncheckedCheckBoxActionVerb())); + DEFINE_STATIC_LOCAL(const String, linkAction, (AXLinkActionVerb())); + DEFINE_STATIC_LOCAL(const String, noAction, ()); + + switch (roleValue()) { + case ButtonRole: + return buttonAction; + case TextFieldRole: + case TextAreaRole: + return textFieldAction; + case RadioButtonRole: + return radioButtonAction; + case CheckBoxRole: + return isChecked() ? checkedCheckBoxAction : uncheckedCheckBoxAction; + case LinkRole: + case WebCoreLinkRole: + return linkAction; + default: + return noAction; + } +} + + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/AccessibilityRenderObject.h b/src/3rdparty/webkit/WebCore/page/AccessibilityRenderObject.h new file mode 100644 index 0000000..9d43ad8 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/AccessibilityRenderObject.h @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2008 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. + */ + +#ifndef AccessibilityRenderObject_h +#define AccessibilityRenderObject_h + +#include "AccessibilityObject.h" + +namespace WebCore { + +class AXObjectCache; +class Element; +class Frame; +class FrameView; +class HitTestResult; +class HTMLAnchorElement; +class HTMLAreaElement; +class HTMLElement; +class HTMLLabelElement; +class HTMLMapElement; +class HTMLSelectElement; +class IntPoint; +class IntSize; +class Node; +class RenderObject; +class RenderListBox; +class RenderTextControl; +class Selection; +class String; +class Widget; + +class AccessibilityRenderObject : public AccessibilityObject { +protected: + AccessibilityRenderObject(RenderObject*); +public: + static PassRefPtr<AccessibilityRenderObject> create(RenderObject*); + virtual ~AccessibilityRenderObject(); + + bool isAccessibilityRenderObject() const { return true; }; + + virtual bool isAnchor() const; + virtual bool isAttachment() const; + virtual bool isHeading() const; + virtual bool isLink() const; + virtual bool isImageButton() const; + virtual bool isImage() const; + virtual bool isNativeImage() const; + virtual bool isPasswordField() const; + virtual bool isTextControl() const; + virtual bool isNativeTextControl() const; + virtual bool isWebArea() const; + virtual bool isCheckboxOrRadio() const; + virtual bool isFileUploadButton() const; + virtual bool isProgressIndicator() const; + virtual bool isSlider() const; + virtual bool isMenuRelated() const; + virtual bool isMenu() const; + virtual bool isMenuBar() const; + virtual bool isMenuButton() const; + virtual bool isMenuItem() const; + virtual bool isControl() const; + virtual bool isFieldset() const; + virtual bool isGroup() const; + + virtual bool isEnabled() const; + virtual bool isSelected() const; + virtual bool isFocused() const; + virtual bool isChecked() const; + virtual bool isHovered() const; + virtual bool isIndeterminate() const; + virtual bool isLoaded() const; + virtual bool isMultiSelect() const; + virtual bool isOffScreen() const; + virtual bool isPressed() const; + virtual bool isReadOnly() const; + virtual bool isVisited() const; + + const AtomicString& getAttribute(const QualifiedName&) const; + virtual bool canSetFocusAttribute() const; + virtual bool canSetTextRangeAttributes() const; + virtual bool canSetValueAttribute() const; + + virtual bool hasIntValue() const; + + virtual bool accessibilityIsIgnored() const; + + static int headingLevel(Node*); + virtual int intValue() const; + virtual float valueForRange() const; + virtual float maxValueForRange() const; + virtual float minValueForRange() const; + virtual int layoutCount() const; + + virtual AccessibilityObject* doAccessibilityHitTest(const IntPoint&) const; + virtual AccessibilityObject* focusedUIElement() const; + virtual AccessibilityObject* firstChild() const; + virtual AccessibilityObject* lastChild() const; + virtual AccessibilityObject* previousSibling() const; + virtual AccessibilityObject* nextSibling() const; + virtual AccessibilityObject* parentObject() const; + virtual AccessibilityObject* observableObject() const; + virtual void linkedUIElements(AccessibilityChildrenVector&) const; + virtual AccessibilityObject* titleUIElement() const; + virtual AccessibilityRole ariaRoleAttribute() const; + virtual bool isPresentationalChildOfAriaRole() const; + virtual bool ariaRoleHasPresentationalChildren() const; + void setAriaRole(); + virtual AccessibilityRole roleValue() const; + virtual AXObjectCache* axObjectCache() const; + + virtual Element* actionElement() const; + Element* mouseButtonListener() const; + FrameView* frameViewIfRenderView() const; + virtual Element* anchorElement() const; + AccessibilityObject* menuForMenuButton() const; + AccessibilityObject* menuButtonForMenu() const; + + virtual IntRect boundingBoxRect() const; + virtual IntRect elementRect() const; + virtual IntSize size() const; + + void setRenderer(RenderObject* renderer) { m_renderer = renderer; } + RenderObject* renderer() const { return m_renderer; } + RenderObject* topRenderer() const; + RenderTextControl* textControl() const; + Document* document() const; + FrameView* topDocumentFrameView() const; + HTMLLabelElement* labelElementContainer() const; + + virtual KURL url() const; + virtual PlainTextRange selectedTextRange() const; + virtual Selection selection() const; + virtual String stringValue() const; + virtual String ariaAccessiblityName(const String&) const; + virtual String ariaLabeledByAttribute() const; + virtual String title() const; + virtual String ariaDescribedByAttribute() const; + virtual String accessibilityDescription() const; + virtual String helpText() const; + virtual String textUnderElement() const; + virtual String text() const; + virtual int textLength() const; + virtual PassRefPtr<Range> ariaSelectedTextDOMRange() const; + virtual String selectedText() const; + virtual const AtomicString& accessKey() const; + virtual const String& actionVerb() const; + virtual Widget* widget() const; + virtual Widget* widgetForAttachmentView() const; + virtual void getDocumentLinks(AccessibilityChildrenVector&); + virtual FrameView* documentFrameView() const; + + virtual const AccessibilityChildrenVector& children(); + + virtual void setFocused(bool); + virtual void setSelectedTextRange(const PlainTextRange&); + virtual void setValue(const String&); + + virtual void detach(); + virtual void childrenChanged(); + virtual void addChildren(); + virtual bool canHaveChildren() const; + virtual void selectedChildren(AccessibilityChildrenVector&); + virtual void visibleChildren(AccessibilityChildrenVector&); + virtual bool shouldFocusActiveDescendant() const; + virtual AccessibilityObject* activeDescendant() const; + virtual void handleActiveDescendantChanged(); + + virtual VisiblePositionRange visiblePositionRange() const; + virtual VisiblePositionRange visiblePositionRangeForLine(unsigned) const; + virtual IntRect boundsForVisiblePositionRange(const VisiblePositionRange&) const; + virtual void setSelectedVisiblePositionRange(const VisiblePositionRange&) const; + + virtual VisiblePosition visiblePositionForPoint(const IntPoint&) const; + virtual VisiblePosition visiblePositionForIndex(unsigned indexValue, bool lastIndexOK) const; + virtual int index(const VisiblePosition&) const; + + virtual VisiblePosition visiblePositionForIndex(int) const; + virtual int indexForVisiblePosition(const VisiblePosition&) const; + + virtual PlainTextRange doAXRangeForLine(unsigned) const; + virtual PlainTextRange doAXRangeForIndex(unsigned) const; + + virtual String doAXStringForRange(const PlainTextRange&) const; + virtual IntRect doAXBoundsForRange(const PlainTextRange&) const; + +protected: + RenderObject* m_renderer; + AccessibilityRole m_ariaRole; + + void setRenderObject(RenderObject* renderer) { m_renderer = renderer; } + virtual void removeAXObjectID(); + + virtual bool isDetached() const { return !m_renderer; } + +private: + void ariaListboxSelectedChildren(AccessibilityChildrenVector&); + void ariaListboxVisibleChildren(AccessibilityChildrenVector&); + + Element* menuElementForMenuButton() const; + Element* menuItemElementForMenu() const; + AccessibilityRole determineAriaRoleAttribute() const; + + IntRect checkboxOrRadioRect() const; + void addRadioButtonGroupMembers(AccessibilityChildrenVector& linkedUIElements) const; + AccessibilityObject* internalLinkElement() const; + AccessibilityObject* accessibilityParentForImageMap(HTMLMapElement* map) const; + +}; + +} // namespace WebCore + +#endif // AccessibilityRenderObject_h diff --git a/src/3rdparty/webkit/WebCore/page/AccessibilityTable.cpp b/src/3rdparty/webkit/WebCore/page/AccessibilityTable.cpp new file mode 100644 index 0000000..ee54496 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/AccessibilityTable.cpp @@ -0,0 +1,491 @@ +/* + * Copyright (C) 2008 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 "AccessibilityTable.h" + +#include "AccessibilityTableCell.h" +#include "AccessibilityTableColumn.h" +#include "AccessibilityTableHeaderContainer.h" +#include "AccessibilityTableRow.h" +#include "AXObjectCache.h" +#include "HTMLNames.h" +#include "HTMLTableElement.h" +#include "HTMLTableCaptionElement.h" +#include "HTMLTableCellElement.h" +#include "RenderObject.h" +#include "RenderTable.h" +#include "RenderTableCell.h" +#include "RenderTableSection.h" + +using namespace std; + +namespace WebCore { + +using namespace HTMLNames; + +AccessibilityTable::AccessibilityTable(RenderObject* renderer) + : AccessibilityRenderObject(renderer), + m_headerContainer(0) +{ + // FIXME: We need to disable Accessibility Tables entirely on the Mac until <rdar://problem/6372481> is resolved. +#if PLATFORM(MAC) + m_isAccessibilityTable = false; +#else + m_isAccessibilityTable = isTableExposableThroughAccessibility(); +#endif + +} + +AccessibilityTable::~AccessibilityTable() +{ +} + +PassRefPtr<AccessibilityTable> AccessibilityTable::create(RenderObject* renderer) +{ + return adoptRef(new AccessibilityTable(renderer)); +} + +bool AccessibilityTable::isTableExposableThroughAccessibility() +{ + // the following is a heuristic used to determine if a + // <table> should be exposed as an AXTable. The goal + // is to only show "data" tables + + if (!m_renderer || !m_renderer->isTable()) + return false; + + // if the developer assigned an aria role to this, then we shouldn't + // expose it as a table, unless, of course, the aria role is a table + AccessibilityRole ariaRole = ariaRoleAttribute(); + if (ariaRole == TableRole) + return true; + if (ariaRole != UnknownRole) + return false; + + RenderTable* table = static_cast<RenderTable*>(m_renderer); + + // this employs a heuristic to determine if this table should appear. + // Only "data" tables should be exposed as tables. + // Unfortunately, there is no good way to determine the difference + // between a "layout" table and a "data" table + + Node* tableNode = table->element(); + if (!tableNode || !tableNode->hasTagName(tableTag)) + return false; + + // if there is a caption element, summary, THEAD, or TFOOT section, it's most certainly a data table + HTMLTableElement* tableElement = static_cast<HTMLTableElement*>(tableNode); + if (!tableElement->summary().isEmpty() || tableElement->tHead() || tableElement->tFoot() || tableElement->caption()) + return true; + + // if someone used "rules" attribute than the table should appear + if (!tableElement->rules().isEmpty()) + return true; + + // go through the cell's and check for tell-tale signs of "data" table status + // cells have borders, or use attributes like headers, abbr, scope or axis + RenderTableSection* firstBody = table->firstBody(); + if (!firstBody) + return false; + + int numCols = firstBody->numColumns(); + int numRows = firstBody->numRows(); + + // if there's only one cell, it's not a good AXTable candidate + if (numRows == 1 && numCols == 1) + return false; + + // store the background color of the table to check against cell's background colors + RenderStyle* tableStyle = table->style(); + if (!tableStyle) + return false; + Color tableBGColor = tableStyle->backgroundColor(); + + // check enough of the cells to find if the table matches our criteria + // Criteria: + // 1) must have at least one valid cell (and) + // 2) at least half of cells have borders (or) + // 3) at least half of cells have different bg colors than the table, and there is cell spacing + unsigned validCellCount = 0; + unsigned borderedCellCount = 0; + unsigned backgroundDifferenceCellCount = 0; + + for (int row = 0; row < numRows; ++row) { + for (int col = 0; col < numCols; ++col) { + RenderTableCell* cell = firstBody->cellAt(row, col).cell; + if (!cell) + continue; + Node* cellNode = cell->element(); + if (!cellNode) + continue; + + if (cell->width() < 1 || cell->height() < 1) + continue; + + validCellCount++; + + HTMLTableCellElement* cellElement = static_cast<HTMLTableCellElement*>(cellNode); + + // in this case, the developer explicitly assigned a "data" table attribute + if (!cellElement->headers().isEmpty() || !cellElement->abbr().isEmpty() || + !cellElement->axis().isEmpty() || !cellElement->scope().isEmpty()) + return true; + + RenderStyle* renderStyle = cell->style(); + if (!renderStyle) + continue; + + // a cell needs to have matching bordered sides, before it can be considered a bordered cell. + if ((cell->borderTop() > 0 && cell->borderBottom() > 0) || + (cell->borderLeft() > 0 && cell->borderRight() > 0)) + borderedCellCount++; + + // if the cell has a different color from the table and there is cell spacing, + // then it is probably a data table cell (spacing and colors take the place of borders) + Color cellColor = renderStyle->backgroundColor(); + if (table->hBorderSpacing() > 0 && table->vBorderSpacing() > 0 && + tableBGColor != cellColor && cellColor.alpha() != 1) + backgroundDifferenceCellCount++; + + // if we've found 10 "good" cells, we don't need to keep searching + if (borderedCellCount >= 10 || backgroundDifferenceCellCount >= 10) + return true; + } + } + + // if there is less than two valid cells, it's not a data table + if (validCellCount <= 1) + return false; + + // half of the cells had borders, it's a data table + unsigned neededCellCount = validCellCount / 2; + if (borderedCellCount >= neededCellCount) + return true; + + // half had different background colors, it's a data table + if (backgroundDifferenceCellCount >= neededCellCount) + return true; + + return false; +} + +void AccessibilityTable::clearChildren() +{ + m_children.clear(); + m_rows.clear(); + m_columns.clear(); + m_haveChildren = false; +} + +void AccessibilityTable::addChildren() +{ + if (!isDataTable()) { + AccessibilityRenderObject::addChildren(); + return; + } + + ASSERT(!m_haveChildren); + + m_haveChildren = true; + if (!m_renderer) + return; + + RenderTable* table = static_cast<RenderTable*>(m_renderer); + AXObjectCache* axCache = m_renderer->document()->axObjectCache(); + + // go through all the available sections to pull out the rows + // and add them as children + RenderTableSection* tableSection = table->header(); + if (!tableSection) + tableSection = table->firstBody(); + + if (!tableSection) + return; + + RenderTableSection* initialTableSection = tableSection; + + while (tableSection) { + + HashSet<AccessibilityObject*> appendedRows; + + unsigned numRows = tableSection->numRows(); + unsigned numCols = tableSection->numColumns(); + for (unsigned rowIndex = 0; rowIndex < numRows; ++rowIndex) { + for (unsigned colIndex = 0; colIndex < numCols; ++colIndex) { + + RenderTableCell* cell = tableSection->cellAt(rowIndex, colIndex).cell; + if (!cell) + continue; + + AccessibilityObject* rowObject = axCache->get(cell->parent()); + if (!rowObject->isTableRow()) + continue; + + AccessibilityTableRow* row = static_cast<AccessibilityTableRow*>(rowObject); + // we need to check every cell for a new row, because cell spans + // can cause us to mess rows if we just check the first column + if (appendedRows.contains(row)) + continue; + + row->setRowIndex((int)m_rows.size()); + m_rows.append(row); + m_children.append(row); + appendedRows.add(row); + } + } + + tableSection = table->sectionBelow(tableSection, true); + } + + // make the columns based on the number of columns in the first body + unsigned length = initialTableSection->numColumns(); + for (unsigned i = 0; i < length; ++i) { + AccessibilityTableColumn* column = static_cast<AccessibilityTableColumn*>(axCache->get(ColumnRole)); + column->setColumnIndex((int)i); + column->setParentTable(this); + m_columns.append(column); + m_children.append(column); + } + + AccessibilityObject* headerContainerObject = headerContainer(); + if (headerContainerObject) + m_children.append(headerContainerObject); +} + +AccessibilityObject* AccessibilityTable::headerContainer() +{ + if (m_headerContainer) + return m_headerContainer; + + m_headerContainer = static_cast<AccessibilityTableHeaderContainer*>(axObjectCache()->get(TableHeaderContainerRole)); + m_headerContainer->setParentTable(this); + + return m_headerContainer; +} + +AccessibilityObject::AccessibilityChildrenVector& AccessibilityTable::columns() +{ + if (!hasChildren()) + addChildren(); + + return m_columns; +} + +AccessibilityObject::AccessibilityChildrenVector& AccessibilityTable::rows() +{ + if (!hasChildren()) + addChildren(); + + return m_rows; +} + +void AccessibilityTable::rowHeaders(AccessibilityChildrenVector& headers) +{ + if (!m_renderer) + return; + + if (!hasChildren()) + addChildren(); + + unsigned rowCount = m_rows.size(); + for (unsigned k = 0; k < rowCount; ++k) { + AccessibilityObject* header = static_cast<AccessibilityTableRow*>(m_rows[k].get())->headerObject(); + if (!header) + continue; + headers.append(header); + } +} + +void AccessibilityTable::columnHeaders(AccessibilityChildrenVector& headers) +{ + if (!m_renderer) + return; + + if (!hasChildren()) + addChildren(); + + unsigned colCount = m_columns.size(); + for (unsigned k = 0; k < colCount; ++k) { + AccessibilityObject* header = static_cast<AccessibilityTableColumn*>(m_columns[k].get())->headerObject(); + if (!header) + continue; + headers.append(header); + } +} + +void AccessibilityTable::cells(AccessibilityObject::AccessibilityChildrenVector& cells) +{ + if (!m_renderer) + return; + + if (!hasChildren()) + addChildren(); + + int numRows = m_rows.size(); + for (int row = 0; row < numRows; ++row) { + AccessibilityChildrenVector rowChildren = m_rows[row]->children(); + cells.append(rowChildren); + } +} + +const unsigned AccessibilityTable::columnCount() +{ + if (!hasChildren()) + addChildren(); + + return m_columns.size(); +} + +const unsigned AccessibilityTable::rowCount() +{ + if (!hasChildren()) + addChildren(); + + return m_rows.size(); +} + +AccessibilityTableCell* AccessibilityTable::cellForColumnAndRow(unsigned column, unsigned row) +{ + if (!m_renderer) + return 0; + + if (!hasChildren()) + addChildren(); + + RenderTable* table = static_cast<RenderTable*>(m_renderer); + RenderTableSection* tableSection = table->header(); + if (!tableSection) + tableSection = table->firstBody(); + + RenderTableCell* cell = 0; + unsigned rowCount = 0; + unsigned rowOffset = 0; + while (tableSection) { + + rowCount += tableSection->numRows(); + unsigned numCols = tableSection->numColumns(); + + if (row < rowCount && column < numCols) { + int sectionSpecificRow = row - rowOffset; + cell = tableSection->cellAt(sectionSpecificRow, column).cell; + + // we didn't find the cell, which means there's spanning happening + // search backwards to find the spanning cell + if (!cell) { + + // first try rows + for (int testRow = sectionSpecificRow-1; testRow >= 0; --testRow) { + cell = tableSection->cellAt(testRow, column).cell; + // cell overlapped. use this one + if (cell && ((cell->row() + (cell->rowSpan()-1)) >= (int)sectionSpecificRow)) + break; + cell = 0; + } + + if (!cell) { + // try cols + for (int testCol = column-1; testCol >= 0; --testCol) { + cell = tableSection->cellAt(sectionSpecificRow, testCol).cell; + // cell overlapped. use this one + if (cell && ((cell->col() + (cell->colSpan()-1)) >= (int)column)) + break; + cell = 0; + } + } + } + } + + if (cell) + break; + + rowOffset += rowCount; + // we didn't find anything between the rows we should have + if (row < rowOffset) + break; + tableSection = table->sectionBelow(tableSection, true); + } + + if (!cell) + return 0; + + AccessibilityObject* cellObject = axObjectCache()->get(cell); + ASSERT(cellObject->isTableCell()); + + return static_cast<AccessibilityTableCell*>(cellObject); +} + +AccessibilityRole AccessibilityTable::roleValue() const +{ + if (!isDataTable()) + return AccessibilityRenderObject::roleValue(); + + return TableRole; +} + +bool AccessibilityTable::accessibilityIsIgnored() const +{ + if (!isDataTable()) + return AccessibilityRenderObject::accessibilityIsIgnored(); + + return false; +} + +String AccessibilityTable::title() const +{ + if (!isDataTable()) + return AccessibilityRenderObject::title(); + + String title; + if (!m_renderer) + return title; + + // see if there is a caption + Node *tableElement = m_renderer->element(); + if (tableElement) { + HTMLTableCaptionElement* caption = static_cast<HTMLTableElement*>(tableElement)->caption(); + if (caption) + title = caption->innerText(); + } + + // try the standard + if (title.isEmpty()) + title = AccessibilityRenderObject::title(); + + return title; +} + +bool AccessibilityTable::isDataTable() const +{ + if (!m_renderer) + return false; + + return m_isAccessibilityTable; +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/AccessibilityTable.h b/src/3rdparty/webkit/WebCore/page/AccessibilityTable.h new file mode 100644 index 0000000..b98b6b7 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/AccessibilityTable.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2008 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. + */ + +#ifndef AccessibilityTable_h +#define AccessibilityTable_h + +#include "AccessibilityRenderObject.h" + +namespace WebCore { + +class String; +class AccessibilityTableCell; +class AccessibilityTableHeaderContainer; + +class AccessibilityTable : public AccessibilityRenderObject { + +private: + AccessibilityTable(RenderObject*); +public: + static PassRefPtr<AccessibilityTable> create(RenderObject*); + virtual ~AccessibilityTable(); + + virtual bool isDataTable() const; + virtual AccessibilityRole roleValue() const; + + virtual bool accessibilityIsIgnored() const; + + virtual void addChildren(); + virtual void clearChildren(); + + AccessibilityChildrenVector& columns(); + AccessibilityChildrenVector& rows(); + + const unsigned columnCount(); + const unsigned rowCount(); + + virtual String title() const; + + // all the cells in the table + void cells(AccessibilityChildrenVector&); + AccessibilityTableCell* cellForColumnAndRow(unsigned column, unsigned row); + + void columnHeaders(AccessibilityChildrenVector&); + void rowHeaders(AccessibilityChildrenVector&); + + // an object that contains, as children, all the objects that act as headers + AccessibilityObject* headerContainer(); + +private: + AccessibilityChildrenVector m_rows; + AccessibilityChildrenVector m_columns; + + AccessibilityTableHeaderContainer* m_headerContainer; + mutable bool m_isAccessibilityTable; + + bool isTableExposableThroughAccessibility(); +}; + +} // namespace WebCore + +#endif // AccessibilityTable_h diff --git a/src/3rdparty/webkit/WebCore/page/AccessibilityTableCell.cpp b/src/3rdparty/webkit/WebCore/page/AccessibilityTableCell.cpp new file mode 100644 index 0000000..ff82811 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/AccessibilityTableCell.cpp @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2008 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 "AccessibilityTableCell.h" + +#include "AXObjectCache.h" +#include "HTMLNames.h" +#include "RenderObject.h" +#include "RenderTableCell.h" + +using namespace std; + +namespace WebCore { + +using namespace HTMLNames; + +AccessibilityTableCell::AccessibilityTableCell(RenderObject* renderer) + : AccessibilityRenderObject(renderer) +{ +} + +AccessibilityTableCell::~AccessibilityTableCell() +{ +} + +PassRefPtr<AccessibilityTableCell> AccessibilityTableCell::create(RenderObject* renderer) +{ + return adoptRef(new AccessibilityTableCell(renderer)); +} + +bool AccessibilityTableCell::accessibilityIsIgnored() const +{ + if (!isTableCell()) + return AccessibilityRenderObject::accessibilityIsIgnored(); + + return false; +} + +bool AccessibilityTableCell::isTableCell() const +{ + if (!m_renderer) + return false; + + AccessibilityObject* renderTable = axObjectCache()->get(static_cast<RenderTableCell*>(m_renderer)->table()); + if (!renderTable->isDataTable()) + return false; + + return true; +} + +AccessibilityRole AccessibilityTableCell::roleValue() const +{ + if (!isTableCell()) + return AccessibilityRenderObject::roleValue(); + + return CellRole; +} + +void AccessibilityTableCell::rowIndexRange(pair<int, int>& rowRange) +{ + if (!m_renderer) + return; + + RenderTableCell* renderCell = static_cast<RenderTableCell*>(m_renderer); + rowRange.first = renderCell->row(); + rowRange.second = renderCell->rowSpan(); + + // since our table might have multiple sections, we have to offset our row appropriately + RenderTableSection* section = renderCell->section(); + RenderTable* table = renderCell->table(); + if (!table || !section) + return; + + RenderTableSection* tableSection = table->header(); + if (!tableSection) + tableSection = table->firstBody(); + + unsigned rowOffset = 0; + while (tableSection) { + if (tableSection == section) + break; + rowOffset += tableSection->numRows(); + tableSection = table->sectionBelow(tableSection, true); + } + + rowRange.first += rowOffset; +} + +void AccessibilityTableCell::columnIndexRange(pair<int, int>& columnRange) +{ + if (!m_renderer) + return; + + RenderTableCell* renderCell = static_cast<RenderTableCell*>(m_renderer); + columnRange.first = renderCell->col(); + columnRange.second = renderCell->colSpan(); +} + +AccessibilityObject* AccessibilityTableCell::titleUIElement() const +{ + // Try to find if the first cell in this row is a <th>. If it is, + // then it can act as the title ui element. (This is only in the + // case when the table is not appearing as an AXTable.) + if (!m_renderer || isTableCell()) + return 0; + + RenderTableCell* renderCell = static_cast<RenderTableCell*>(m_renderer); + + // If this cell is in the first column, there is no need to continue. + int col = renderCell->col(); + if (!col) + return 0; + + int row = renderCell->row(); + + RenderTableSection* section = renderCell->section(); + if (!section) + return 0; + + RenderTableCell* headerCell = section->cellAt(row, 0).cell; + if (!headerCell || headerCell == renderCell) + return 0; + + Node* cellElement = headerCell->element(); + if (!cellElement || !cellElement->hasTagName(thTag)) + return 0; + + return axObjectCache()->get(headerCell); +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/AccessibilityTableCell.h b/src/3rdparty/webkit/WebCore/page/AccessibilityTableCell.h new file mode 100644 index 0000000..8f8dd77 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/AccessibilityTableCell.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2008 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. + */ + +#ifndef AccessibilityTableCell_h +#define AccessibilityTableCell_h + +#include "AccessibilityRenderObject.h" + +namespace WebCore { + +class AccessibilityTableCell : public AccessibilityRenderObject { + +private: + AccessibilityTableCell(RenderObject*); +public: + static PassRefPtr<AccessibilityTableCell> create(RenderObject*); + virtual ~AccessibilityTableCell(); + + virtual bool isTableCell() const; + virtual AccessibilityRole roleValue() const; + + virtual bool accessibilityIsIgnored() const; + + // fills in the start location and row span of cell + void rowIndexRange(pair<int, int>& rowRange); + // fills in the start location and column span of cell + void columnIndexRange(pair<int, int>& columnRange); + + // if a table cell is not exposed as a table cell, a TH element can + // serve as its title ui element + AccessibilityObject* titleUIElement() const; + +private: + int m_rowIndex; + +}; + +} // namespace WebCore + +#endif // AccessibilityTableCell_h diff --git a/src/3rdparty/webkit/WebCore/page/AccessibilityTableColumn.cpp b/src/3rdparty/webkit/WebCore/page/AccessibilityTableColumn.cpp new file mode 100644 index 0000000..6e03af9 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/AccessibilityTableColumn.cpp @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2008 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 "AccessibilityTableColumn.h" + +#include "AccessibilityTableCell.h" +#include "AXObjectCache.h" +#include "HTMLNames.h" +#include "RenderTable.h" +#include "RenderTableSection.h" +#include "RenderTableCell.h" + +using namespace std; + +namespace WebCore { + +using namespace HTMLNames; + +AccessibilityTableColumn::AccessibilityTableColumn() + : m_parentTable(0) +{ +} + +AccessibilityTableColumn::~AccessibilityTableColumn() +{ +} + +PassRefPtr<AccessibilityTableColumn> AccessibilityTableColumn::create() +{ + return adoptRef(new AccessibilityTableColumn()); +} + +void AccessibilityTableColumn::setParentTable(AccessibilityTable* table) +{ + m_parentTable = table; + + clearChildren(); + addChildren(); +} + +IntRect AccessibilityTableColumn::elementRect() const +{ + // this will be filled in when addChildren is called + return m_columnRect; +} + +IntSize AccessibilityTableColumn::size() const +{ + return elementRect().size(); +} + +const AccessibilityObject::AccessibilityChildrenVector& AccessibilityTableColumn::children() +{ + if (!m_haveChildren) + addChildren(); + return m_children; +} + +AccessibilityObject* AccessibilityTableColumn::headerObject() +{ + if (!m_parentTable) + return 0; + + RenderTable* table = static_cast<RenderTable*>(m_parentTable->renderer()); + + AccessibilityObject* headerObject = 0; + + // try the <thead> section first. this doesn't require th tags + headerObject = headerObjectForSection(table->header(), false); + + if (headerObject) + return headerObject; + + // now try for <th> tags in the first body + headerObject = headerObjectForSection(table->firstBody(), true); + + return headerObject; +} + +AccessibilityObject* AccessibilityTableColumn::headerObjectForSection(RenderTableSection* section, bool thTagRequired) +{ + if (!section) + return 0; + + int numCols = section->numColumns(); + if (m_columnIndex >= numCols) + return 0; + + RenderTableCell* cell = 0; + // also account for cells that have a span + for (int testCol = m_columnIndex; testCol >= 0; --testCol) { + RenderTableCell* testCell = section->cellAt(0, testCol).cell; + if (!testCell) + continue; + + // we've reached a cell that doesn't even overlap our column + // it can't be our header + if ((testCell->col() + (testCell->colSpan()-1)) < m_columnIndex) + break; + + Node* node = testCell->element(); + if (!node) + continue; + + if (thTagRequired && !node->hasTagName(thTag)) + continue; + + cell = testCell; + } + + if (!cell) + return 0; + + return m_parentTable->axObjectCache()->get(cell); +} + +void AccessibilityTableColumn::addChildren() +{ + ASSERT(!m_haveChildren); + + m_haveChildren = true; + if (!m_parentTable) + return; + + int numRows = m_parentTable->rowCount(); + + for (int i = 0; i < numRows; i++) { + AccessibilityTableCell* cell = m_parentTable->cellForColumnAndRow(m_columnIndex, i); + if (!cell) + continue; + + // make sure the last one isn't the same as this one (rowspan cells) + if (m_children.size() > 0 && m_children.last() == cell) + continue; + + m_children.append(cell); + m_columnRect.unite(cell->elementRect()); + } +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/AccessibilityTableColumn.h b/src/3rdparty/webkit/WebCore/page/AccessibilityTableColumn.h new file mode 100644 index 0000000..6270398 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/AccessibilityTableColumn.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2008 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. + */ + +#ifndef AccessibilityTableColumn_h +#define AccessibilityTableColumn_h + +#include "AccessibilityObject.h" +#include "AccessibilityTable.h" +#include "IntRect.h" + +namespace WebCore { + +class RenderTableSection; + +class AccessibilityTableColumn : public AccessibilityObject { + +private: + AccessibilityTableColumn(); +public: + static PassRefPtr<AccessibilityTableColumn> create(); + virtual ~AccessibilityTableColumn(); + + void setParentTable(AccessibilityTable*); + virtual AccessibilityObject* parentObject() const { return m_parentTable; } + AccessibilityObject* headerObject(); + + virtual AccessibilityRole roleValue() const { return ColumnRole; } + virtual bool accessibilityIsIgnored() const { return false; } + virtual bool isTableColumn() const { return true; } + + void setColumnIndex(int columnIndex) { m_columnIndex = columnIndex; } + int columnIndex() const { return m_columnIndex; } + + virtual const AccessibilityChildrenVector& children(); + virtual void addChildren(); + + virtual IntSize size() const; + virtual IntRect elementRect() const; + +private: + AccessibilityTable* m_parentTable; + int m_columnIndex; + IntRect m_columnRect; + + AccessibilityObject* headerObjectForSection(RenderTableSection*, bool thTagRequired); +}; + +} // namespace WebCore + +#endif // AccessibilityTableColumn_h diff --git a/src/3rdparty/webkit/WebCore/page/AccessibilityTableHeaderContainer.cpp b/src/3rdparty/webkit/WebCore/page/AccessibilityTableHeaderContainer.cpp new file mode 100644 index 0000000..af9de39 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/AccessibilityTableHeaderContainer.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2008 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 "AccessibilityTableHeaderContainer.h" + +#include "AccessibilityTable.h" +#include "AXObjectCache.h" + +using namespace std; + +namespace WebCore { + +AccessibilityTableHeaderContainer::AccessibilityTableHeaderContainer() + : m_parentTable(0) +{ +} + +AccessibilityTableHeaderContainer::~AccessibilityTableHeaderContainer() +{ +} + +PassRefPtr<AccessibilityTableHeaderContainer> AccessibilityTableHeaderContainer::create() +{ + return adoptRef(new AccessibilityTableHeaderContainer()); +} + +const AccessibilityObject::AccessibilityChildrenVector& AccessibilityTableHeaderContainer::children() +{ + if (!m_haveChildren) + addChildren(); + return m_children; +} + +IntRect AccessibilityTableHeaderContainer::elementRect() const +{ + // this will be filled in when addChildren is called + return m_headerRect; +} + +IntSize AccessibilityTableHeaderContainer::size() const +{ + return elementRect().size(); +} + +void AccessibilityTableHeaderContainer::addChildren() +{ + ASSERT(!m_haveChildren); + + m_haveChildren = true; + if (!m_parentTable || !m_parentTable->isDataTable()) + return; + + static_cast<AccessibilityTable*>(m_parentTable)->columnHeaders(m_children); + + unsigned length = m_children.size(); + for (unsigned k = 0; k < length; ++k) { + m_headerRect.unite(m_children[k]->elementRect()); + } +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/AccessibilityTableHeaderContainer.h b/src/3rdparty/webkit/WebCore/page/AccessibilityTableHeaderContainer.h new file mode 100644 index 0000000..8a9448a --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/AccessibilityTableHeaderContainer.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2008 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. + */ + +#ifndef AccessibilityTableHeaderContainer_h +#define AccessibilityTableHeaderContainer_h + +#include "AccessibilityObject.h" +#include "AccessibilityTable.h" +#include "IntRect.h" + +namespace WebCore { + +class AccessibilityTableHeaderContainer : public AccessibilityObject { + +private: + AccessibilityTableHeaderContainer(); +public: + static PassRefPtr<AccessibilityTableHeaderContainer> create(); + virtual ~AccessibilityTableHeaderContainer(); + + virtual AccessibilityRole roleValue() const { return TableHeaderContainerRole; } + + void setParentTable(AccessibilityTable* table) { m_parentTable = table; } + virtual AccessibilityObject* parentObject() const { return m_parentTable; } + + virtual bool accessibilityIsIgnored() const { return false; } + + virtual const AccessibilityChildrenVector& children(); + virtual void addChildren(); + + virtual IntSize size() const; + virtual IntRect elementRect() const; + +private: + AccessibilityTable* m_parentTable; + IntRect m_headerRect; + +}; + +} // namespace WebCore + +#endif // AccessibilityTableHeaderContainer_h diff --git a/src/3rdparty/webkit/WebCore/page/AccessibilityTableRow.cpp b/src/3rdparty/webkit/WebCore/page/AccessibilityTableRow.cpp new file mode 100644 index 0000000..caccff5 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/AccessibilityTableRow.cpp @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2008 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 "AccessibilityTableRow.h" + +#include "AccessibilityTableCell.h" +#include "AXObjectCache.h" +#include "HTMLNames.h" +#include "HTMLTableRowElement.h" +#include "RenderObject.h" +#include "RenderTableCell.h" +#include "RenderTableRow.h" + +using namespace std; + +namespace WebCore { + +using namespace HTMLNames; + +AccessibilityTableRow::AccessibilityTableRow(RenderObject* renderer) + : AccessibilityRenderObject(renderer) +{ +} + +AccessibilityTableRow::~AccessibilityTableRow() +{ +} + +PassRefPtr<AccessibilityTableRow> AccessibilityTableRow::create(RenderObject* renderer) +{ + return adoptRef(new AccessibilityTableRow(renderer)); +} + +AccessibilityRole AccessibilityTableRow::roleValue() const +{ + if (!isTableRow()) + return AccessibilityRenderObject::roleValue(); + + return RowRole; +} + +bool AccessibilityTableRow::isTableRow() const +{ + if (!m_renderer) + return true; + + AccessibilityObject* renderTable = axObjectCache()->get(static_cast<RenderTableRow*>(m_renderer)->table()); + if (!renderTable->isDataTable()) + return false; + + return true; +} + +bool AccessibilityTableRow::accessibilityIsIgnored() const +{ + if (!isTableRow()) + return AccessibilityRenderObject::accessibilityIsIgnored(); + + return false; +} + +AccessibilityObject* AccessibilityTableRow::headerObject() +{ + AccessibilityChildrenVector rowChildren = children(); + if (!rowChildren.size()) + return 0; + + // check the first element in the row to see if it is a TH element + AccessibilityObject* cell = rowChildren[0].get(); + if (!cell->isTableCell()) + return 0; + + RenderObject* cellRenderer = static_cast<AccessibilityTableCell*>(cell)->renderer(); + if (!cellRenderer) + return 0; + + Node* cellNode = cellRenderer->element(); + if (!cellNode || !cellNode->hasTagName(thTag)) + return 0; + + return cell; +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/AccessibilityTableRow.h b/src/3rdparty/webkit/WebCore/page/AccessibilityTableRow.h new file mode 100644 index 0000000..0ec7f04 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/AccessibilityTableRow.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2008 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. + */ + +#ifndef AccessibilityTableRow_h +#define AccessibilityTableRow_h + +#include "AccessibilityRenderObject.h" + +namespace WebCore { + +class AccessibilityTableRow : public AccessibilityRenderObject { + +private: + AccessibilityTableRow(RenderObject*); +public: + static PassRefPtr<AccessibilityTableRow> create(RenderObject*); + virtual ~AccessibilityTableRow(); + + virtual bool isTableRow() const; + virtual AccessibilityRole roleValue() const; + + // retrieves the "row" header (a th tag in the rightmost column) + AccessibilityObject* headerObject(); + + virtual bool accessibilityIsIgnored() const; + + void setRowIndex(int rowIndex) { m_rowIndex = rowIndex; } + int rowIndex() const { return m_rowIndex; } + + // allows the table to add other children that may not originate + // in the row, but their col/row spans overlap into it + void appendChild(AccessibilityObject*); + +private: + int m_rowIndex; +}; + +} // namespace WebCore + +#endif // AccessibilityTableRow_h diff --git a/src/3rdparty/webkit/WebCore/page/BarInfo.cpp b/src/3rdparty/webkit/WebCore/page/BarInfo.cpp new file mode 100644 index 0000000..153aee0 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/BarInfo.cpp @@ -0,0 +1,72 @@ +/* + * 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. + * 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 "BarInfo.h" + +#include "Chrome.h" +#include "Frame.h" +#include "Page.h" + +namespace WebCore { + +BarInfo::BarInfo(Frame* frame, Type type) + : m_frame(frame) + , m_type(type) +{ +} + +void BarInfo::disconnectFrame() +{ + m_frame = 0; +} + +bool BarInfo::visible() const +{ + if (!m_frame) + return false; + + switch (m_type) { + case Locationbar: + return m_frame->page()->chrome()->toolbarsVisible(); + case Toolbar: + return m_frame->page()->chrome()->toolbarsVisible(); + case Personalbar: + return m_frame->page()->chrome()->toolbarsVisible(); + case Menubar: + return m_frame->page()->chrome()->menubarVisible(); + case Scrollbars: + return m_frame->page()->chrome()->scrollbarsVisible(); + case Statusbar: + return m_frame->page()->chrome()->statusbarVisible(); + default: + return false; + } +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/BarInfo.h b/src/3rdparty/webkit/WebCore/page/BarInfo.h new file mode 100644 index 0000000..4cbbcfc --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/BarInfo.h @@ -0,0 +1,57 @@ +/* + * 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. + * 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. + */ + +#ifndef BarInfo_h +#define BarInfo_h + +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + + class Frame; + + class BarInfo : public RefCounted<BarInfo> { + public: + enum Type { Locationbar, Menubar, Personalbar, Scrollbars, Statusbar, Toolbar }; + + static PassRefPtr<BarInfo> create(Frame* frame, Type type) { return adoptRef(new BarInfo(frame, type)); } + + void disconnectFrame(); + + bool visible() const; + + private: + BarInfo(Frame*, Type); + Frame* m_frame; + Type m_type; + }; + +} // namespace WebCore + +#endif // BarInfo_h diff --git a/src/3rdparty/webkit/WebCore/page/BarInfo.idl b/src/3rdparty/webkit/WebCore/page/BarInfo.idl new file mode 100644 index 0000000..42041c5 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/BarInfo.idl @@ -0,0 +1,35 @@ +/* + * 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. + * 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. + */ + +module window { + + interface BarInfo { + readonly attribute boolean visible; + }; + +} diff --git a/src/3rdparty/webkit/WebCore/page/Chrome.cpp b/src/3rdparty/webkit/WebCore/page/Chrome.cpp new file mode 100644 index 0000000..1f6e198 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/Chrome.cpp @@ -0,0 +1,505 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "Chrome.h" + +#include "ChromeClient.h" +#include "DNS.h" +#include "Document.h" +#include "FileList.h" +#include "FloatRect.h" +#include "Frame.h" +#include "FrameTree.h" +#include "HTMLFormElement.h" +#include "HTMLInputElement.h" +#include "HTMLNames.h" +#include "HitTestResult.h" +#include "InspectorController.h" +#include "Page.h" +#include "PageGroup.h" +#include "ResourceHandle.h" +#include "ScriptController.h" +#include "SecurityOrigin.h" +#include "Settings.h" +#include "WindowFeatures.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> + +#if ENABLE(DOM_STORAGE) +#include "SessionStorage.h" +#endif + +namespace WebCore { + +using namespace HTMLNames; +using namespace std; + +class PageGroupLoadDeferrer : Noncopyable { +public: + PageGroupLoadDeferrer(Page*, bool deferSelf); + ~PageGroupLoadDeferrer(); +private: + Vector<RefPtr<Frame>, 16> m_deferredFrames; +}; + +Chrome::Chrome(Page* page, ChromeClient* client) + : m_page(page) + , m_client(client) +{ + ASSERT(m_client); +} + +Chrome::~Chrome() +{ + m_client->chromeDestroyed(); +} + +void Chrome::repaint(const IntRect& windowRect, bool contentChanged, bool immediate, bool repaintContentOnly) +{ + m_client->repaint(windowRect, contentChanged, immediate, repaintContentOnly); +} + +void Chrome::scroll(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect) +{ + m_client->scroll(scrollDelta, rectToScroll, clipRect); +} + +IntPoint Chrome::screenToWindow(const IntPoint& point) const +{ + return m_client->screenToWindow(point); +} + +IntRect Chrome::windowToScreen(const IntRect& rect) const +{ + return m_client->windowToScreen(rect); +} + +PlatformWidget Chrome::platformWindow() const +{ + return m_client->platformWindow(); +} + +void Chrome::contentsSizeChanged(Frame* frame, const IntSize& size) const +{ + m_client->contentsSizeChanged(frame, size); +} + +void Chrome::scrollRectIntoView(const IntRect& rect, const ScrollView* scrollView) const +{ + m_client->scrollRectIntoView(rect, scrollView); +} + +void Chrome::setWindowRect(const FloatRect& rect) const +{ + m_client->setWindowRect(rect); +} + +FloatRect Chrome::windowRect() const +{ + return m_client->windowRect(); +} + +FloatRect Chrome::pageRect() const +{ + return m_client->pageRect(); +} + +float Chrome::scaleFactor() +{ + return m_client->scaleFactor(); +} + +void Chrome::focus() const +{ + m_client->focus(); +} + +void Chrome::unfocus() const +{ + m_client->unfocus(); +} + +bool Chrome::canTakeFocus(FocusDirection direction) const +{ + return m_client->canTakeFocus(direction); +} + +void Chrome::takeFocus(FocusDirection direction) const +{ + m_client->takeFocus(direction); +} + +Page* Chrome::createWindow(Frame* frame, const FrameLoadRequest& request, const WindowFeatures& features) const +{ + Page* newPage = m_client->createWindow(frame, request, features); +#if ENABLE(DOM_STORAGE) + + if (newPage) { + if (SessionStorage* oldSessionStorage = m_page->sessionStorage(false)) + newPage->setSessionStorage(oldSessionStorage->copy(newPage)); + } +#endif + return newPage; +} + +void Chrome::show() const +{ + m_client->show(); +} + +bool Chrome::canRunModal() const +{ + return m_client->canRunModal(); +} + +bool Chrome::canRunModalNow() const +{ + // If loads are blocked, we can't run modal because the contents + // of the modal dialog will never show up! + return canRunModal() && !ResourceHandle::loadsBlocked(); +} + +void Chrome::runModal() const +{ + // Defer callbacks in all the other pages in this group, so we don't try to run JavaScript + // in a way that could interact with this view. + PageGroupLoadDeferrer deferrer(m_page, false); + + TimerBase::fireTimersInNestedEventLoop(); + m_client->runModal(); +} + +void Chrome::setToolbarsVisible(bool b) const +{ + m_client->setToolbarsVisible(b); +} + +bool Chrome::toolbarsVisible() const +{ + return m_client->toolbarsVisible(); +} + +void Chrome::setStatusbarVisible(bool b) const +{ + m_client->setStatusbarVisible(b); +} + +bool Chrome::statusbarVisible() const +{ + return m_client->statusbarVisible(); +} + +void Chrome::setScrollbarsVisible(bool b) const +{ + m_client->setScrollbarsVisible(b); +} + +bool Chrome::scrollbarsVisible() const +{ + return m_client->scrollbarsVisible(); +} + +void Chrome::setMenubarVisible(bool b) const +{ + m_client->setMenubarVisible(b); +} + +bool Chrome::menubarVisible() const +{ + return m_client->menubarVisible(); +} + +void Chrome::setResizable(bool b) const +{ + m_client->setResizable(b); +} + +bool Chrome::canRunBeforeUnloadConfirmPanel() +{ + return m_client->canRunBeforeUnloadConfirmPanel(); +} + +bool Chrome::runBeforeUnloadConfirmPanel(const String& message, Frame* frame) +{ + // Defer loads in case the client method runs a new event loop that would + // 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); +} + +void Chrome::closeWindowSoon() +{ + m_client->closeWindowSoon(); +} + +void Chrome::runJavaScriptAlert(Frame* frame, const String& message) +{ + // Defer loads in case the client method runs a new event loop that would + // otherwise cause the load to continue while we're in the middle of executing JavaScript. + PageGroupLoadDeferrer deferrer(m_page, true); + + ASSERT(frame); + String text = message; + text.replace('\\', frame->backslashAsCurrencySymbol()); + + m_client->runJavaScriptAlert(frame, text); +} + +bool Chrome::runJavaScriptConfirm(Frame* frame, const String& message) +{ + // Defer loads in case the client method runs a new event loop that would + // otherwise cause the load to continue while we're in the middle of executing JavaScript. + PageGroupLoadDeferrer deferrer(m_page, true); + + ASSERT(frame); + String text = message; + text.replace('\\', frame->backslashAsCurrencySymbol()); + + return m_client->runJavaScriptConfirm(frame, text); +} + +bool Chrome::runJavaScriptPrompt(Frame* frame, const String& prompt, const String& defaultValue, String& result) +{ + // Defer loads in case the client method runs a new event loop that would + // otherwise cause the load to continue while we're in the middle of executing JavaScript. + PageGroupLoadDeferrer deferrer(m_page, true); + + ASSERT(frame); + String promptText = prompt; + promptText.replace('\\', frame->backslashAsCurrencySymbol()); + String defaultValueText = defaultValue; + defaultValueText.replace('\\', frame->backslashAsCurrencySymbol()); + + bool ok = m_client->runJavaScriptPrompt(frame, promptText, defaultValueText, result); + + if (ok) + result.replace(frame->backslashAsCurrencySymbol(), '\\'); + + return ok; +} + +void Chrome::setStatusbarText(Frame* frame, const String& status) +{ + ASSERT(frame); + String text = status; + text.replace('\\', frame->backslashAsCurrencySymbol()); + + m_client->setStatusbarText(text); +} + +bool Chrome::shouldInterruptJavaScript() +{ + // Defer loads in case the client method runs a new event loop that would + // otherwise cause the load to continue while we're in the middle of executing JavaScript. + PageGroupLoadDeferrer deferrer(m_page, true); + + return m_client->shouldInterruptJavaScript(); +} + +IntRect Chrome::windowResizerRect() const +{ + return m_client->windowResizerRect(); +} + +void Chrome::mouseDidMoveOverElement(const HitTestResult& result, unsigned modifierFlags) +{ + if (result.innerNode()) { + Document* document = result.innerNode()->document(); + if (document && document->isDNSPrefetchEnabled()) + prefetchDNS(result.absoluteLinkURL().host()); + } + m_client->mouseDidMoveOverElement(result, modifierFlags); + + if (InspectorController* inspector = m_page->inspectorController()) + inspector->mouseDidMoveOverElement(result, modifierFlags); +} + +void Chrome::setToolTip(const HitTestResult& result) +{ + // First priority is a potential toolTip representing a spelling or grammar error + String toolTip = result.spellingToolTip(); + + // Next priority is a toolTip from a URL beneath the mouse (if preference is set to show those). + 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 (input->inputType() == HTMLInputElement::SUBMIT) + if (HTMLFormElement* form = input->form()) + toolTip = form->action(); + } + } + + // Get tooltip representing link's URL + if (toolTip.isEmpty()) + // FIXME: Need to pass this URL through userVisibleString once that's in WebCore + toolTip = result.absoluteLinkURL().string(); + } + + // Next we'll consider a tooltip for element with "title" attribute + if (toolTip.isEmpty()) + toolTip = result.title(); + + // 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 (input->inputType() == HTMLInputElement::FILE) { + FileList* files = input->files(); + unsigned listSize = files->length(); + if (files && listSize > 1) { + Vector<UChar> names; + for (size_t i = 0; i < listSize; ++i) { + append(names, files->item(i)->fileName()); + if (i != listSize - 1) + names.append('\n'); + } + toolTip = String::adopt(names); + } + } + } + } + } + + m_client->setToolTip(toolTip); +} + +void Chrome::print(Frame* frame) +{ + m_client->print(frame); +} + +void Chrome::disableSuddenTermination() +{ + m_client->disableSuddenTermination(); +} + +void Chrome::enableSuddenTermination() +{ + m_client->enableSuddenTermination(); +} + +void Chrome::runOpenPanel(Frame* frame, PassRefPtr<FileChooser> fileChooser) +{ + m_client->runOpenPanel(frame, fileChooser); +} +// -------- + +#if ENABLE(DASHBOARD_SUPPORT) +void ChromeClient::dashboardRegionsChanged() +{ +} +#endif + +void ChromeClient::populateVisitedLinks() +{ +} + +FloatRect ChromeClient::customHighlightRect(Node*, const AtomicString&, const FloatRect&) +{ + return FloatRect(); +} + +void ChromeClient::paintCustomHighlight(Node*, const AtomicString&, const FloatRect&, const FloatRect&, bool, bool) +{ +} + +bool ChromeClient::shouldReplaceWithGeneratedFileForUpload(const String&, String&) +{ + return false; +} + +String ChromeClient::generateReplacementFile(const String&) +{ + ASSERT_NOT_REACHED(); + return String(); +} + +void ChromeClient::disableSuddenTermination() +{ +} + +void ChromeClient::enableSuddenTermination() +{ +} + +bool ChromeClient::paintCustomScrollbar(GraphicsContext*, const FloatRect&, ScrollbarControlSize, + ScrollbarControlState, ScrollbarPart, bool, + float, float, ScrollbarControlPartMask) +{ + return false; +} + +bool ChromeClient::paintCustomScrollCorner(GraphicsContext*, const FloatRect&) +{ + return false; +} + +// -------- + +PageGroupLoadDeferrer::PageGroupLoadDeferrer(Page* page, bool deferSelf) +{ + const HashSet<Page*>& pages = page->group().pages(); + + HashSet<Page*>::const_iterator end = pages.end(); + for (HashSet<Page*>::const_iterator it = pages.begin(); it != end; ++it) { + Page* otherPage = *it; + if ((deferSelf || otherPage != page)) { + if (!otherPage->defersLoading()) + m_deferredFrames.append(otherPage->mainFrame()); + +#if !PLATFORM(MAC) + for (Frame* frame = otherPage->mainFrame(); frame; frame = frame->tree()->traverseNext()) { + if (Document* document = frame->document()) + document->suspendActiveDOMObjects(); + } +#endif + } + } + + size_t count = m_deferredFrames.size(); + for (size_t i = 0; i < count; ++i) + if (Page* page = m_deferredFrames[i]->page()) + page->setDefersLoading(true); +} + +PageGroupLoadDeferrer::~PageGroupLoadDeferrer() +{ + for (size_t i = 0; i < m_deferredFrames.size(); ++i) { + if (Page* page = m_deferredFrames[i]->page()) { + page->setDefersLoading(false); + +#if !PLATFORM(MAC) + for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext()) { + if (Document* document = frame->document()) + document->resumeActiveDOMObjects(); + } +#endif + } + } +} + + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/Chrome.h b/src/3rdparty/webkit/WebCore/page/Chrome.h new file mode 100644 index 0000000..47b912d --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/Chrome.h @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef Chrome_h +#define Chrome_h + +#include "FileChooser.h" +#include "FocusDirection.h" +#include "HostWindow.h" +#include <wtf/Forward.h> +#include <wtf/RefPtr.h> + +#if PLATFORM(MAC) +#ifndef __OBJC__ +class NSView; +#endif +#endif + +namespace WebCore { + + class ChromeClient; + class ContextMenu; + class FloatRect; + class Frame; + class HitTestResult; + class IntRect; + class Page; + class String; + + struct FrameLoadRequest; + struct WindowFeatures; + + class Chrome : public HostWindow { + public: + Chrome(Page*, ChromeClient*); + ~Chrome(); + + ChromeClient* client() { return m_client; } + + // HostWindow methods. + virtual void repaint(const IntRect&, bool contentChanged, bool immediate = false, bool repaintContentOnly = false); + virtual void scroll(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect); + virtual IntPoint screenToWindow(const IntPoint&) const; + virtual IntRect windowToScreen(const IntRect&) const; + virtual PlatformWidget platformWindow() const; + virtual void scrollRectIntoView(const IntRect&, const ScrollView*) const; + + void contentsSizeChanged(Frame*, const IntSize&) const; + + void setWindowRect(const FloatRect&) const; + FloatRect windowRect() const; + + FloatRect pageRect() const; + + float scaleFactor(); + + void focus() const; + void unfocus() const; + + bool canTakeFocus(FocusDirection) const; + void takeFocus(FocusDirection) const; + + Page* createWindow(Frame*, const FrameLoadRequest&, const WindowFeatures&) const; + void show() const; + + bool canRunModal() const; + bool canRunModalNow() const; + void runModal() 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; + + bool canRunBeforeUnloadConfirmPanel(); + bool runBeforeUnloadConfirmPanel(const String& message, Frame* frame); + + void closeWindowSoon(); + + 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(); + + IntRect windowResizerRect() const; + + void mouseDidMoveOverElement(const HitTestResult&, unsigned modifierFlags); + + void setToolTip(const HitTestResult&); + + void print(Frame*); + + void enableSuddenTermination(); + void disableSuddenTermination(); + + void runOpenPanel(Frame*, PassRefPtr<FileChooser>); + +#if PLATFORM(MAC) + void focusNSView(NSView*); +#endif + + private: + Page* m_page; + ChromeClient* m_client; + }; +} + +#endif // Chrome_h diff --git a/src/3rdparty/webkit/WebCore/page/ChromeClient.h b/src/3rdparty/webkit/WebCore/page/ChromeClient.h new file mode 100644 index 0000000..5d90b2f --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/ChromeClient.h @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2006, 2007, 2008 Apple, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef ChromeClient_h +#define ChromeClient_h + +#include "GraphicsContext.h" +#include "FocusDirection.h" +#include "ScrollTypes.h" +#include "HostWindow.h" +#include <wtf/Forward.h> +#include <wtf/Vector.h> + +#if PLATFORM(MAC) +#include "WebCoreKeyboardUIMode.h" +#endif + +#ifndef __OBJC__ +class NSMenu; +class NSResponder; +#endif + +namespace WebCore { + + class AtomicString; + class FileChooser; + class FloatRect; + class Frame; + class HitTestResult; + class IntRect; + class Node; + class Page; + class String; + class Widget; + + struct FrameLoadRequest; + struct WindowFeatures; + + class ChromeClient { + public: + virtual void chromeDestroyed() = 0; + + virtual void setWindowRect(const FloatRect&) = 0; + virtual FloatRect windowRect() = 0; + + virtual FloatRect pageRect() = 0; + + virtual float scaleFactor() = 0; + + virtual void focus() = 0; + virtual void unfocus() = 0; + + virtual bool canTakeFocus(FocusDirection) = 0; + virtual void takeFocus(FocusDirection) = 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. + virtual Page* createWindow(Frame*, const FrameLoadRequest&, const WindowFeatures&) = 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(const String& message, unsigned int lineNumber, const String& sourceID) = 0; + + virtual bool canRunBeforeUnloadConfirmPanel() = 0; + virtual bool runBeforeUnloadConfirmPanel(const String& message, Frame* 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 bool tabsToLinks() const = 0; + + virtual IntRect windowResizerRect() const = 0; + + // Methods used by HostWindow. + virtual void repaint(const IntRect&, bool contentChanged, bool immediate = false, bool repaintContentOnly = false) = 0; + virtual void scroll(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect) = 0; + virtual IntPoint screenToWindow(const IntPoint&) const = 0; + virtual IntRect windowToScreen(const IntRect&) const = 0; + virtual PlatformWidget platformWindow() const = 0; + virtual void contentsSizeChanged(Frame*, const IntSize&) const = 0; + virtual void scrollRectIntoView(const IntRect&, const ScrollView*) const {} // Platforms other than Mac can implement this if it ever becomes necessary for them to do so. + // End methods used by HostWindow. + + virtual void mouseDidMoveOverElement(const HitTestResult&, unsigned modifierFlags) = 0; + + virtual void setToolTip(const String&) = 0; + + virtual void print(Frame*) = 0; + + virtual void exceededDatabaseQuota(Frame*, const String& databaseName) = 0; + +#if ENABLE(DASHBOARD_SUPPORT) + virtual void dashboardRegionsChanged(); +#endif + + 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 bool shouldReplaceWithGeneratedFileForUpload(const String& path, String& generatedFilename); + virtual String generateReplacementFile(const String& path); + + virtual void enableSuddenTermination(); + virtual void disableSuddenTermination(); + + virtual bool paintCustomScrollbar(GraphicsContext*, const FloatRect&, ScrollbarControlSize, + ScrollbarControlState, ScrollbarPart pressedPart, bool vertical, + float value, float proportion, ScrollbarControlPartMask); + virtual bool paintCustomScrollCorner(GraphicsContext*, const FloatRect&); + + virtual void runOpenPanel(Frame*, PassRefPtr<FileChooser>) = 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; + +#if PLATFORM(MAC) + virtual KeyboardUIMode keyboardUIMode() { return KeyboardAccessDefault; } + + virtual NSResponder *firstResponder() { return 0; } + virtual void makeFirstResponder(NSResponder *) { } + + virtual void willPopUpMenu(NSMenu *) { } +#endif + + protected: + virtual ~ChromeClient() { } + }; + +} + +#endif // ChromeClient_h diff --git a/src/3rdparty/webkit/WebCore/page/Console.cpp b/src/3rdparty/webkit/WebCore/page/Console.cpp new file mode 100644 index 0000000..8755f0e --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/Console.cpp @@ -0,0 +1,369 @@ +/* + * 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. + * 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 "Console.h" + +#include "ChromeClient.h" +#include "CString.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameTree.h" +#include "InspectorController.h" +#include "Page.h" +#include "PageGroup.h" +#include "PlatformString.h" + +#if USE(JSC) +#include <profiler/Profiler.h> +#endif + +#include "ScriptCallStack.h" +#include <stdio.h> + +namespace WebCore { + +Console::Console(Frame* frame) + : m_frame(frame) +{ +} + +void Console::disconnectFrame() +{ + m_frame = 0; +} + +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 bool getFirstArgumentAsString(const ScriptCallFrame& callFrame, String& result, bool checkForNullOrUndefined = false) +{ + if (!callFrame.argumentCount()) + return false; + + const ScriptValue& value = callFrame.argumentAt(0); + if (checkForNullOrUndefined && (value.isNull() || value.isUndefined())) + return false; + + return value.getString(result); +} + +static void printMessageSourceAndLevelPrefix(MessageSource source, MessageLevel level) +{ + const char* sourceString; + switch (source) { + case HTMLMessageSource: + sourceString = "HTML"; + break; + case WMLMessageSource: + sourceString = "WML"; + break; + case XMLMessageSource: + sourceString = "XML"; + break; + case JSMessageSource: + sourceString = "JS"; + break; + case CSSMessageSource: + sourceString = "CSS"; + break; + default: + ASSERT_NOT_REACHED(); + // Fall thru. + case OtherMessageSource: + sourceString = "OTHER"; + break; + } + + const char* levelString; + switch (level) { + case TipMessageLevel: + levelString = "TIP"; + break; + default: + ASSERT_NOT_REACHED(); + // Fall thru. + case LogMessageLevel: + levelString = "LOG"; + break; + case WarningMessageLevel: + levelString = "WARN"; + break; + case ErrorMessageLevel: + levelString = "ERROR"; + break; + } + + printf("%s %s:", sourceString, levelString); +} + +void Console::addMessage(MessageSource source, MessageLevel level, const String& message, unsigned lineNumber, const String& sourceURL) +{ + Page* page = this->page(); + if (!page) + return; + + if (source == JSMessageSource || source == WMLMessageSource) + page->chrome()->client()->addMessageToConsole(message, lineNumber, sourceURL); + + page->inspectorController()->addMessageToConsole(source, level, message, lineNumber, sourceURL); + + if (!Console::shouldPrintExceptions()) + return; + + printSourceURLAndLine(sourceURL, lineNumber); + printMessageSourceAndLevelPrefix(source, level); + + printf(" %s\n", message.utf8().data()); +} + +void Console::addMessage(MessageLevel level, ScriptCallStack* callStack, bool acceptNoArguments) { + Page* page = this->page(); + if (!page) + return; + + const ScriptCallFrame& lastCaller = callStack->at(0); + + if (!acceptNoArguments && !lastCaller.argumentCount()) + return; + + String message; + if (getFirstArgumentAsString(lastCaller, message)) + page->chrome()->client()->addMessageToConsole(message, lastCaller.lineNumber(), lastCaller.sourceURL().prettyURL()); + + page->inspectorController()->addMessageToConsole(JSMessageSource, level, callStack); + + if (!Console::shouldPrintExceptions()) + return; + + printSourceURLAndLine(lastCaller.sourceURL().prettyURL(), 0); + printMessageSourceAndLevelPrefix(JSMessageSource, level); + + for (unsigned i = 0; i < lastCaller.argumentCount(); ++i) { + String argAsString; + if (lastCaller.argumentAt(i).getString(argAsString)) + printf(" %s", argAsString.utf8().data()); + } + printf("\n"); +} + +void Console::debug(ScriptCallStack* callStack) +{ + // In Firebug, console.debug has the same behavior as console.log. So we'll do the same. + log(callStack); +} + +void Console::error(ScriptCallStack* callStack) +{ + addMessage(ErrorMessageLevel, callStack); +} + +void Console::info(ScriptCallStack* callStack) +{ + log(callStack); +} + +void Console::log(ScriptCallStack* callStack) +{ + addMessage(LogMessageLevel, callStack); +} + +void Console::dir(ScriptCallStack* callStack) +{ + addMessage(ObjectMessageLevel, callStack); +} + +void Console::dirxml(ScriptCallStack* callStack) +{ + addMessage(NodeMessageLevel, callStack); +} + +void Console::trace(ScriptCallStack* callStack) +{ + addMessage(TraceMessageLevel, callStack, true); + + if (!shouldPrintExceptions()) + return; + + printf("Stack Trace\n"); + for (unsigned i = 0; i < callStack->size(); ++i) { + String functionName = String(callStack->at(i).functionName()); + printf("\t%s\n", functionName.utf8().data()); + } +} + +void Console::assertCondition(bool condition, ScriptCallStack* callStack) +{ + if (condition) + return; + + // FIXME: <https://bugs.webkit.org/show_bug.cgi?id=19135> It would be nice to prefix assertion failures with a message like "Assertion failed: ". + addMessage(ErrorMessageLevel, callStack, true); +} + +void Console::count(ScriptCallStack* callStack) +{ + Page* page = this->page(); + if (!page) + return; + + const ScriptCallFrame& lastCaller = callStack->at(0); + // Follow Firebug's behavior of counting with null and undefined title in + // the same bucket as no argument + String title; + getFirstArgumentAsString(lastCaller, title); + + page->inspectorController()->count(title, lastCaller.lineNumber(), lastCaller.sourceURL().string()); +} + +#if USE(JSC) + +void Console::profile(const JSC::UString& title, ScriptCallStack* callStack) +{ + Page* page = this->page(); + if (!page) + return; + + if (title.isNull()) + return; + + // FIXME: log a console message when profiling is disabled. + if (!page->inspectorController()->profilerEnabled()) + return; + + JSC::Profiler::profiler()->startProfiling(callStack->state(), title); +} + +void Console::profileEnd(const JSC::UString& title, ScriptCallStack* callStack) +{ + Page* page = this->page(); + if (!page) + return; + + if (!page->inspectorController()->profilerEnabled()) + return; + + RefPtr<JSC::Profile> profile = JSC::Profiler::profiler()->stopProfiling(callStack->state(), title); + if (!profile) + return; + + m_profiles.append(profile); + + if (Page* page = this->page()) { + const ScriptCallFrame& lastCaller = callStack->at(0); + page->inspectorController()->addProfile(profile, lastCaller.lineNumber(), lastCaller.sourceURL()); + } +} + +#endif + +void Console::time(const String& title) +{ + Page* page = this->page(); + if (!page) + return; + + // Follow Firebug's behavior of requiring a title that is not null or + // undefined for timing functions + if (title.isNull()) + return; + + page->inspectorController()->startTiming(title); +} + +void Console::timeEnd(const String& title, ScriptCallStack* callStack) +{ + Page* page = this->page(); + if (!page) + return; + + // Follow Firebug's behavior of requiring a title that is not null or + // undefined for timing functions + if (title.isNull()) + return; + + double elapsed; + if (!page->inspectorController()->stopTiming(title, elapsed)) + return; + + String message = title + String::format(": %.0fms", elapsed); + + const ScriptCallFrame& lastCaller = callStack->at(0); + page->inspectorController()->addMessageToConsole(JSMessageSource, LogMessageLevel, message, lastCaller.lineNumber(), lastCaller.sourceURL().string()); +} + +void Console::group(ScriptCallStack* callStack) +{ + Page* page = this->page(); + if (!page) + return; + + page->inspectorController()->startGroup(JSMessageSource, callStack); +} + +void Console::groupEnd() +{ + Page* page = this->page(); + if (!page) + return; + + page->inspectorController()->endGroup(JSMessageSource, 0, String()); +} + +void Console::warn(ScriptCallStack* callStack) +{ + addMessage(WarningMessageLevel, callStack); +} + +static bool printExceptions = false; + +bool Console::shouldPrintExceptions() +{ + return printExceptions; +} + +void Console::setShouldPrintExceptions(bool print) +{ + printExceptions = print; +} + +Page* Console::page() const +{ + if (!m_frame) + return 0; + return m_frame->page(); +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/Console.h b/src/3rdparty/webkit/WebCore/page/Console.h new file mode 100644 index 0000000..7301fc9 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/Console.h @@ -0,0 +1,122 @@ +/* + * 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. + * 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. + */ + +#ifndef Console_h +#define Console_h + +#include "PlatformString.h" + +#if USE(JSC) +#include <profiler/Profile.h> +#endif + +#include <wtf/RefCounted.h> +#include <wtf/PassRefPtr.h> + +namespace WebCore { + +#if USE(JSC) + typedef Vector<RefPtr<JSC::Profile> > ProfilesArray; +#endif + + class Frame; + class Page; + class String; + class ScriptCallStack; + + // Keep in sync with inspector/front-end/Console.js + enum MessageSource { + HTMLMessageSource, + WMLMessageSource, + XMLMessageSource, + JSMessageSource, + CSSMessageSource, + OtherMessageSource + }; + + enum MessageLevel { + TipMessageLevel, + LogMessageLevel, + WarningMessageLevel, + ErrorMessageLevel, + ObjectMessageLevel, + NodeMessageLevel, + TraceMessageLevel, + StartGroupMessageLevel, + EndGroupMessageLevel + }; + + class Console : public RefCounted<Console> { + public: + static PassRefPtr<Console> create(Frame* frame) { return adoptRef(new Console(frame)); } + + void disconnectFrame(); + + void addMessage(MessageSource, MessageLevel, const String& message, unsigned lineNumber, const String& sourceURL); + + void debug(ScriptCallStack*); + void error(ScriptCallStack*); + void info(ScriptCallStack*); + void log(ScriptCallStack*); + void warn(ScriptCallStack*); + void dir(ScriptCallStack*); + void dirxml(ScriptCallStack*); + void trace(ScriptCallStack*); + void assertCondition(bool condition, ScriptCallStack*); + void count(ScriptCallStack*); +#if USE(JSC) + void profile(const JSC::UString&, ScriptCallStack*); + void profileEnd(const JSC::UString&, ScriptCallStack*); +#endif + void time(const String&); + void timeEnd(const String&, ScriptCallStack*); + void group(ScriptCallStack*); + void groupEnd(); + + static bool shouldPrintExceptions(); + static void setShouldPrintExceptions(bool); + +#if USE(JSC) + const ProfilesArray& profiles() const { return m_profiles; } +#endif + + private: + inline Page* page() const; + void addMessage(MessageLevel, ScriptCallStack*, bool acceptNoArguments = false); + + Console(Frame*); + + Frame* m_frame; +#if USE(JSC) + ProfilesArray m_profiles; +#endif + }; + +} // namespace WebCore + +#endif // Console_h diff --git a/src/3rdparty/webkit/WebCore/page/Console.idl b/src/3rdparty/webkit/WebCore/page/Console.idl new file mode 100644 index 0000000..fb7688d --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/Console.idl @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2007, 2008 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. + */ + +module window { + + interface Console { + +#if !defined(V8_BINDING) + readonly attribute [CustomGetter] Array profiles; +#endif + + [CustomArgumentHandling] void debug(); + [CustomArgumentHandling] void error(); + [CustomArgumentHandling] void info(); + [CustomArgumentHandling] void log(); + [CustomArgumentHandling] void warn(); + [CustomArgumentHandling] void dir(); + [CustomArgumentHandling] void dirxml(); + [CustomArgumentHandling] void trace(); + [CustomArgumentHandling, ImplementationFunction=assertCondition] void assert(in boolean condition); + [CustomArgumentHandling] void count(); + +#if !defined(V8_BINDING) + [CustomArgumentHandling] void profile(in [ConvertUndefinedOrNullToNullString] DOMString title); + [CustomArgumentHandling] void profileEnd(in [ConvertUndefinedOrNullToNullString] DOMString title); +#endif + + void time(in [ConvertUndefinedOrNullToNullString] DOMString title); + [CustomArgumentHandling] void timeEnd(in [ConvertUndefinedOrNullToNullString] DOMString title); + [CustomArgumentHandling] void group(); + void groupEnd(); + }; + +} diff --git a/src/3rdparty/webkit/WebCore/page/ContextMenuClient.h b/src/3rdparty/webkit/WebCore/page/ContextMenuClient.h new file mode 100644 index 0000000..775adc5 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/ContextMenuClient.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2006 Apple Computer, 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 ContextMenuClient_h +#define ContextMenuClient_h + +#include "PlatformMenuDescription.h" + +namespace WebCore { + class ContextMenu; + class ContextMenuItem; + class Frame; + class HitTestResult; + class KURL; + class String; + + class ContextMenuClient { + public: + virtual ~ContextMenuClient() { } + virtual void contextMenuDestroyed() = 0; + + virtual PlatformMenuDescription getCustomMenuFromDefaultItems(ContextMenu*) = 0; + virtual void contextMenuItemSelected(ContextMenuItem*, const ContextMenu*) = 0; + + virtual void downloadURL(const KURL& url) = 0; + virtual void searchWithGoogle(const Frame*) = 0; + virtual void lookUpInDictionary(Frame*) = 0; + virtual void speak(const String&) = 0; + virtual void stopSpeaking() = 0; + +#if PLATFORM(MAC) + virtual void searchWithSpotlight() = 0; +#endif + }; +} + +#endif diff --git a/src/3rdparty/webkit/WebCore/page/ContextMenuController.cpp b/src/3rdparty/webkit/WebCore/page/ContextMenuController.cpp new file mode 100644 index 0000000..5e9f8b5 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/ContextMenuController.cpp @@ -0,0 +1,310 @@ +/* + * Copyright (C) 2006, 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 "ContextMenuController.h" + +#include "Chrome.h" +#include "ContextMenu.h" +#include "ContextMenuClient.h" +#include "Document.h" +#include "DocumentFragment.h" +#include "DocumentLoader.h" +#include "Editor.h" +#include "EditorClient.h" +#include "Event.h" +#include "EventHandler.h" +#include "EventNames.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameLoadRequest.h" +#include "HitTestRequest.h" +#include "HitTestResult.h" +#include "InspectorController.h" +#include "MouseEvent.h" +#include "Node.h" +#include "Page.h" +#include "RenderLayer.h" +#include "RenderObject.h" +#include "ReplaceSelectionCommand.h" +#include "ResourceRequest.h" +#include "SelectionController.h" +#include "Settings.h" +#include "TextIterator.h" +#include "WindowFeatures.h" +#include "markup.h" + +namespace WebCore { + +ContextMenuController::ContextMenuController(Page* page, ContextMenuClient* client) + : m_page(page) + , m_client(client) + , m_contextMenu(0) +{ + ASSERT_ARG(page, page); + ASSERT_ARG(client, client); +} + +ContextMenuController::~ContextMenuController() +{ + m_client->contextMenuDestroyed(); +} + +void ContextMenuController::clearContextMenu() +{ + m_contextMenu.set(0); +} + +void ContextMenuController::handleContextMenuEvent(Event* event) +{ + ASSERT(event->type() == eventNames().contextmenuEvent); + if (!event->isMouseEvent()) + return; + MouseEvent* mouseEvent = static_cast<MouseEvent*>(event); + IntPoint point = IntPoint(mouseEvent->pageX(), mouseEvent->pageY()); + HitTestResult result(point); + + if (Frame* frame = event->target()->toNode()->document()->frame()) { + float zoomFactor = frame->pageZoomFactor(); + point.setX(static_cast<int>(point.x() * zoomFactor)); + point.setY(static_cast<int>(point.y() * zoomFactor)); + result = frame->eventHandler()->hitTestResultAtPoint(point, false); + } + + if (!result.innerNonSharedNode()) + return; + + m_contextMenu.set(new ContextMenu(result)); + m_contextMenu->populate(); + if (m_page->inspectorController()->enabled()) + m_contextMenu->addInspectElementItem(); + + PlatformMenuDescription customMenu = m_client->getCustomMenuFromDefaultItems(m_contextMenu.get()); + m_contextMenu->setPlatformDescription(customMenu); + + event->setDefaultHandled(); +} + +static void openNewWindow(const KURL& urlToLoad, Frame* frame) +{ + if (Page* oldPage = frame->page()) { + WindowFeatures features; + if (Page* newPage = oldPage->chrome()->createWindow(frame, + FrameLoadRequest(ResourceRequest(urlToLoad, frame->loader()->outgoingReferrer())), features)) + newPage->chrome()->show(); + } +} + +void ContextMenuController::contextMenuItemSelected(ContextMenuItem* item) +{ + ASSERT(item->type() == ActionType || item->type() == CheckableActionType); + + if (item->action() >= ContextMenuItemBaseApplicationTag) { + m_client->contextMenuItemSelected(item, m_contextMenu.get()); + return; + } + + HitTestResult result = m_contextMenu->hitTestResult(); + Frame* frame = result.innerNonSharedNode()->document()->frame(); + if (!frame) + return; + + switch (item->action()) { + case ContextMenuItemTagOpenLinkInNewWindow: + openNewWindow(result.absoluteLinkURL(), frame); + break; + case ContextMenuItemTagDownloadLinkToDisk: + // FIXME: Some day we should be able to do this from within WebCore. + m_client->downloadURL(result.absoluteLinkURL()); + break; + case ContextMenuItemTagCopyLinkToClipboard: + frame->editor()->copyURL(result.absoluteLinkURL(), result.textContent()); + break; + case ContextMenuItemTagOpenImageInNewWindow: + openNewWindow(result.absoluteImageURL(), frame); + break; + case ContextMenuItemTagDownloadImageToDisk: + // FIXME: Some day we should be able to do this from within WebCore. + m_client->downloadURL(result.absoluteImageURL()); + break; + case ContextMenuItemTagCopyImageToClipboard: + // FIXME: The Pasteboard class is not written yet + // For now, call into the client. This is temporary! + frame->editor()->copyImage(result); + break; + case ContextMenuItemTagOpenFrameInNewWindow: { + DocumentLoader* loader = frame->loader()->documentLoader(); + if (!loader->unreachableURL().isEmpty()) + openNewWindow(loader->unreachableURL(), frame); + else + openNewWindow(loader->url(), frame); + break; + } + case ContextMenuItemTagCopy: + frame->editor()->copy(); + break; + case ContextMenuItemTagGoBack: + frame->loader()->goBackOrForward(-1); + break; + case ContextMenuItemTagGoForward: + frame->loader()->goBackOrForward(1); + break; + case ContextMenuItemTagStop: + frame->loader()->stop(); + break; + case ContextMenuItemTagReload: + frame->loader()->reload(); + break; + case ContextMenuItemTagCut: + frame->editor()->cut(); + break; + case ContextMenuItemTagPaste: + frame->editor()->paste(); + break; +#if PLATFORM(GTK) + case ContextMenuItemTagDelete: + frame->editor()->performDelete(); + break; + case ContextMenuItemTagSelectAll: + frame->editor()->command("SelectAll").execute(); + break; +#endif + case ContextMenuItemTagSpellingGuess: + ASSERT(frame->selectedText().length()); + if (frame->editor()->shouldInsertText(item->title(), frame->selection()->toRange().get(), + EditorInsertActionPasted)) { + Document* document = frame->document(); + RefPtr<ReplaceSelectionCommand> command = + ReplaceSelectionCommand::create(document, createFragmentFromMarkup(document, item->title(), ""), + true, false, true); + applyCommand(command); + frame->revealSelection(RenderLayer::gAlignToEdgeIfNeeded); + } + break; + case ContextMenuItemTagIgnoreSpelling: + frame->editor()->ignoreSpelling(); + break; + case ContextMenuItemTagLearnSpelling: + frame->editor()->learnSpelling(); + break; + case ContextMenuItemTagSearchWeb: + m_client->searchWithGoogle(frame); + break; + case ContextMenuItemTagLookUpInDictionary: + // FIXME: Some day we may be able to do this from within WebCore. + m_client->lookUpInDictionary(frame); + break; + case ContextMenuItemTagOpenLink: + if (Frame* targetFrame = result.targetFrame()) + targetFrame->loader()->loadFrameRequestWithFormAndValues(FrameLoadRequest(ResourceRequest(result.absoluteLinkURL(), + frame->loader()->outgoingReferrer())), false, 0, 0, HashMap<String, String>()); + else + openNewWindow(result.absoluteLinkURL(), frame); + break; + case ContextMenuItemTagBold: + frame->editor()->command("ToggleBold").execute(); + break; + case ContextMenuItemTagItalic: + frame->editor()->command("ToggleItalic").execute(); + break; + case ContextMenuItemTagUnderline: + 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()->toRange(); + if (!selectedRange || selectedRange->collapsed(ec)) { + Document* document = result.innerNonSharedNode()->document(); + selectedRange = document->createRange(); + selectedRange->selectNode(document->documentElement(), ec); + } + m_client->speak(plainText(selectedRange.get())); + break; + } + case ContextMenuItemTagStopSpeaking: + m_client->stopSpeaking(); + break; + case ContextMenuItemTagDefaultDirection: + frame->editor()->setBaseWritingDirection(NaturalWritingDirection); + break; + case ContextMenuItemTagLeftToRight: + frame->editor()->setBaseWritingDirection(LeftToRightWritingDirection); + break; + case ContextMenuItemTagRightToLeft: + frame->editor()->setBaseWritingDirection(RightToLeftWritingDirection); + break; + case ContextMenuItemTagTextDirectionDefault: + frame->editor()->command("MakeTextWritingDirectionNatural").execute(); + break; + case ContextMenuItemTagTextDirectionLeftToRight: + frame->editor()->command("MakeTextWritingDirectionLeftToRight").execute(); + break; + case ContextMenuItemTagTextDirectionRightToLeft: + frame->editor()->command("MakeTextWritingDirectionRightToLeft").execute(); + break; +#if PLATFORM(MAC) + case ContextMenuItemTagSearchInSpotlight: + m_client->searchWithSpotlight(); + break; +#endif + case ContextMenuItemTagShowSpellingPanel: + frame->editor()->showSpellingGuessPanel(); + break; + case ContextMenuItemTagCheckSpelling: + frame->editor()->advanceToNextMisspelling(); + break; + case ContextMenuItemTagCheckSpellingWhileTyping: + frame->editor()->toggleContinuousSpellChecking(); + break; +#ifndef BUILDING_ON_TIGER + case ContextMenuItemTagCheckGrammarWithSpelling: + frame->editor()->toggleGrammarChecking(); + break; +#endif +#if PLATFORM(MAC) + case ContextMenuItemTagShowFonts: + frame->editor()->showFontPanel(); + break; + case ContextMenuItemTagStyles: + frame->editor()->showStylesPanel(); + break; + case ContextMenuItemTagShowColors: + frame->editor()->showColorPanel(); + break; +#endif + case ContextMenuItemTagInspectElement: + if (Page* page = frame->page()) + page->inspectorController()->inspect(result.innerNonSharedNode()); + break; + default: + break; + } +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/ContextMenuController.h b/src/3rdparty/webkit/WebCore/page/ContextMenuController.h new file mode 100644 index 0000000..cb7e6ee --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/ContextMenuController.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2006, 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. + */ + +#ifndef ContextMenuController_h +#define ContextMenuController_h + +#include <wtf/Noncopyable.h> +#include <wtf/OwnPtr.h> + +namespace WebCore { + + class ContextMenu; + class ContextMenuClient; + class ContextMenuItem; + class Event; + class Page; + + class ContextMenuController : Noncopyable { + public: + ContextMenuController(Page*, ContextMenuClient*); + ~ContextMenuController(); + + ContextMenuClient* client() { return m_client; } + + ContextMenu* contextMenu() const { return m_contextMenu.get(); } + void clearContextMenu(); + + void handleContextMenuEvent(Event*); + void contextMenuItemSelected(ContextMenuItem*); + + private: + Page* m_page; + ContextMenuClient* m_client; + OwnPtr<ContextMenu> m_contextMenu; + }; + +} + +#endif diff --git a/src/3rdparty/webkit/WebCore/page/DOMSelection.cpp b/src/3rdparty/webkit/WebCore/page/DOMSelection.cpp new file mode 100644 index 0000000..5dab325 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/DOMSelection.cpp @@ -0,0 +1,424 @@ +/* + * 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. + * 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 "DOMSelection.h" + +#include "ExceptionCode.h" +#include "Frame.h" +#include "htmlediting.h" +#include "Node.h" +#include "PlatformString.h" +#include "Range.h" +#include "SelectionController.h" +#include "TextIterator.h" + +namespace WebCore { + +DOMSelection::DOMSelection(Frame* frame) + : m_frame(frame) +{ +} + +Frame* DOMSelection::frame() const +{ + return m_frame; +} + +void DOMSelection::disconnectFrame() +{ + m_frame = 0; +} + +Node* DOMSelection::anchorNode() const +{ + if (!m_frame) + return 0; + + const Selection& selection = m_frame->selection()->selection(); + Position anchor = selection.isBaseFirst() ? selection.start() : selection.end(); + anchor = rangeCompliantEquivalent(anchor); + return anchor.node(); +} + +Node* DOMSelection::baseNode() const +{ + if (!m_frame) + return 0; + return rangeCompliantEquivalent(m_frame->selection()->selection().base()).node(); +} + +int DOMSelection::anchorOffset() const +{ + if (!m_frame) + return 0; + + const Selection& selection = m_frame->selection()->selection(); + Position anchor = selection.isBaseFirst() ? selection.start() : selection.end(); + anchor = rangeCompliantEquivalent(anchor); + return anchor.offset(); +} + +int DOMSelection::baseOffset() const +{ + if (!m_frame) + return 0; + return rangeCompliantEquivalent(m_frame->selection()->selection().base()).offset(); +} + +Node* DOMSelection::focusNode() const +{ + if (!m_frame) + return 0; + + const Selection& selection = m_frame->selection()->selection(); + Position focus = selection.isBaseFirst() ? selection.end() : selection.start(); + focus = rangeCompliantEquivalent(focus); + return focus.node(); +} + +Node* DOMSelection::extentNode() const +{ + if (!m_frame) + return 0; + return rangeCompliantEquivalent(m_frame->selection()->selection().extent()).node(); +} + +int DOMSelection::focusOffset() const +{ + if (!m_frame) + return 0; + + const Selection& selection = m_frame->selection()->selection(); + Position focus = selection.isBaseFirst() ? selection.end() : selection.start(); + focus = rangeCompliantEquivalent(focus); + return focus.offset(); +} + +int DOMSelection::extentOffset() const +{ + if (!m_frame) + return 0; + return rangeCompliantEquivalent(m_frame->selection()->selection().extent()).offset(); +} + +bool DOMSelection::isCollapsed() const +{ + if (!m_frame) + return false; + return !m_frame->selection()->isRange(); +} + +String DOMSelection::type() const +{ + if (!m_frame) + return String(); + + SelectionController* selection = m_frame->selection(); + + if (selection->isNone()) + return "None"; + if (selection->isCaret()) + return "Caret"; + return "Range"; +} + +int DOMSelection::rangeCount() const +{ + if (!m_frame) + return 0; + return m_frame->selection()->isNone() ? 0 : 1; +} + +void DOMSelection::collapse(Node* node, int offset, ExceptionCode& ec) +{ + if (!m_frame) + return; + + if (offset < 0) { + ec = INDEX_SIZE_ERR; + return; + } + m_frame->selection()->moveTo(VisiblePosition(node, offset, DOWNSTREAM)); +} + +void DOMSelection::collapseToEnd() +{ + if (!m_frame) + return; + + const Selection& selection = m_frame->selection()->selection(); + m_frame->selection()->moveTo(VisiblePosition(selection.end(), DOWNSTREAM)); +} + +void DOMSelection::collapseToStart() +{ + if (!m_frame) + return; + + const Selection& selection = m_frame->selection()->selection(); + m_frame->selection()->moveTo(VisiblePosition(selection.start(), DOWNSTREAM)); +} + +void DOMSelection::empty() +{ + if (!m_frame) + return; + m_frame->selection()->moveTo(VisiblePosition()); +} + +void DOMSelection::setBaseAndExtent(Node* baseNode, int baseOffset, Node* extentNode, int extentOffset, ExceptionCode& ec) +{ + if (!m_frame) + return; + + if (baseOffset < 0 || extentOffset < 0) { + ec = INDEX_SIZE_ERR; + return; + } + VisiblePosition visibleBase = VisiblePosition(baseNode, baseOffset, DOWNSTREAM); + VisiblePosition visibleExtent = VisiblePosition(extentNode, extentOffset, DOWNSTREAM); + + m_frame->selection()->moveTo(visibleBase, visibleExtent); +} + +void DOMSelection::setPosition(Node* node, int offset, ExceptionCode& ec) +{ + if (!m_frame) + return; + if (offset < 0) { + ec = INDEX_SIZE_ERR; + return; + } + m_frame->selection()->moveTo(VisiblePosition(node, offset, DOWNSTREAM)); +} + +void DOMSelection::modify(const String& alterString, const String& directionString, const String& granularityString) +{ + if (!m_frame) + return; + + SelectionController::EAlteration alter; + if (equalIgnoringCase(alterString, "extend")) + alter = SelectionController::EXTEND; + else if (equalIgnoringCase(alterString, "move")) + alter = SelectionController::MOVE; + else + return; + + SelectionController::EDirection direction; + if (equalIgnoringCase(directionString, "forward")) + direction = SelectionController::FORWARD; + else if (equalIgnoringCase(directionString, "backward")) + direction = SelectionController::BACKWARD; + else if (equalIgnoringCase(directionString, "left")) + direction = SelectionController::LEFT; + else if (equalIgnoringCase(directionString, "right")) + direction = SelectionController::RIGHT; + else + return; + + TextGranularity granularity; + if (equalIgnoringCase(granularityString, "character")) + granularity = CharacterGranularity; + else if (equalIgnoringCase(granularityString, "word")) + granularity = WordGranularity; + else if (equalIgnoringCase(granularityString, "sentence")) + granularity = SentenceGranularity; + else if (equalIgnoringCase(granularityString, "line")) + granularity = LineGranularity; + else if (equalIgnoringCase(granularityString, "paragraph")) + granularity = ParagraphGranularity; + else if (equalIgnoringCase(granularityString, "lineboundary")) + granularity = LineBoundary; + else if (equalIgnoringCase(granularityString, "sentenceboundary")) + granularity = SentenceBoundary; + else if (equalIgnoringCase(granularityString, "paragraphboundary")) + granularity = ParagraphBoundary; + else if (equalIgnoringCase(granularityString, "documentboundary")) + granularity = DocumentBoundary; + else + return; + + m_frame->selection()->modify(alter, direction, granularity, false); +} + +void DOMSelection::extend(Node* node, int offset, ExceptionCode& ec) +{ + if (!m_frame) + return; + + if (!node) { + ec = TYPE_MISMATCH_ERR; + return; + } + if (offset < 0 || offset > (node->offsetInCharacters() ? caretMaxOffset(node) : (int)node->childNodeCount())) { + ec = INDEX_SIZE_ERR; + return; + } + + SelectionController* selection = m_frame->selection(); + selection->expandUsingGranularity(CharacterGranularity); + selection->setExtent(VisiblePosition(node, offset, DOWNSTREAM)); +} + +PassRefPtr<Range> DOMSelection::getRangeAt(int index, ExceptionCode& ec) +{ + if (!m_frame) + return 0; + + if (index < 0 || index >= rangeCount()) { + ec = INDEX_SIZE_ERR; + return 0; + } + + const Selection& selection = m_frame->selection()->selection(); + return selection.toRange(); +} + +void DOMSelection::removeAllRanges() +{ + if (!m_frame) + return; + m_frame->selection()->clear(); +} + +void DOMSelection::addRange(Range* r) +{ + if (!m_frame) + return; + if (!r) + return; + + SelectionController* selection = m_frame->selection(); + + if (selection->isNone()) { + selection->setSelection(Selection(r)); + return; + } + + RefPtr<Range> range = selection->selection().toRange(); + ExceptionCode ec = 0; + if (r->compareBoundaryPoints(Range::START_TO_START, range.get(), ec) == -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) + // The original range and r intersect. + selection->setSelection(Selection(r->startPosition(), range->endPosition(), DOWNSTREAM)); + else + // r contains the original range. + selection->setSelection(Selection(r)); + } + } else { + // We don't support discontiguous selection. We don't do anything if r and range don't intersect. + if (r->compareBoundaryPoints(Range::END_TO_START, range.get(), ec) < 1) { + if (r->compareBoundaryPoints(Range::END_TO_END, range.get(), ec) == -1) + // The original range contains r. + selection->setSelection(Selection(range.get())); + else + // The original range and r intersect. + selection->setSelection(Selection(range->startPosition(), r->endPosition(), DOWNSTREAM)); + } + } +} + +void DOMSelection::deleteFromDocument() +{ + if (!m_frame) + return; + + SelectionController* selection = m_frame->selection(); + + if (selection->isNone()) + return; + + if (isCollapsed()) + selection->modify(SelectionController::EXTEND, SelectionController::BACKWARD, CharacterGranularity); + + RefPtr<Range> selectedRange = selection->selection().toRange(); + + ExceptionCode ec = 0; + selectedRange->deleteContents(ec); + ASSERT(!ec); + + setBaseAndExtent(selectedRange->startContainer(ec), selectedRange->startOffset(ec), selectedRange->startContainer(ec), selectedRange->startOffset(ec), ec); + ASSERT(!ec); +} + +bool DOMSelection::containsNode(const Node* n, bool allowPartial) const +{ + if (!m_frame) + return false; + + SelectionController* selection = m_frame->selection(); + + if (!n || selection->isNone()) + return false; + + Node* parentNode = n->parentNode(); + unsigned nodeIndex = n->nodeIndex(); + RefPtr<Range> selectedRange = selection->selection().toRange(); + + if (!parentNode) + return false; + + ExceptionCode ec = 0; + bool nodeFullySelected = Range::compareBoundaryPoints(parentNode, nodeIndex, selectedRange->startContainer(ec), selectedRange->startOffset(ec)) >= 0 + && Range::compareBoundaryPoints(parentNode, nodeIndex + 1, selectedRange->endContainer(ec), selectedRange->endOffset(ec)) <= 0; + ASSERT(!ec); + if (nodeFullySelected) + return true; + + bool nodeFullyUnselected = Range::compareBoundaryPoints(parentNode, nodeIndex, selectedRange->endContainer(ec), selectedRange->endOffset(ec)) > 0 + || Range::compareBoundaryPoints(parentNode, nodeIndex + 1, selectedRange->startContainer(ec), selectedRange->startOffset(ec)) < 0; + ASSERT(!ec); + if (nodeFullyUnselected) + return false; + + return allowPartial || n->isTextNode(); +} + +void DOMSelection::selectAllChildren(Node* n, ExceptionCode& ec) +{ + if (!n) + return; + + // This doesn't (and shouldn't) select text node characters. + setBaseAndExtent(n, 0, n, n->childNodeCount(), ec); +} + +String DOMSelection::toString() +{ + if (!m_frame) + return String(); + + return plainText(m_frame->selection()->selection().toRange().get()); +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/DOMSelection.h b/src/3rdparty/webkit/WebCore/page/DOMSelection.h new file mode 100644 index 0000000..fd8d1fc --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/DOMSelection.h @@ -0,0 +1,102 @@ +/* + * 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. + * 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. + */ + + +#ifndef DOMSelection_h +#define DOMSelection_h + +#include <wtf/RefCounted.h> +#include <wtf/Forward.h> +#include <wtf/PassRefPtr.h> + +namespace WebCore { + + class Frame; + class Range; + class Node; + class String; + + typedef int ExceptionCode; + + class DOMSelection : public RefCounted<DOMSelection> { + public: + static PassRefPtr<DOMSelection> create(Frame* frame) { return adoptRef(new DOMSelection(frame)); } + + Frame* frame() const; + void disconnectFrame(); + + // Safari Selection Object API + // These methods return the valid equivalents of internal editing positions. + Node* baseNode() const; + Node* extentNode() const; + int baseOffset() const; + int extentOffset() const; + String type() const; + void setBaseAndExtent(Node* baseNode, int baseOffset, Node* extentNode, int extentOffset, ExceptionCode&); + void setPosition(Node*, int offset, ExceptionCode&); + void modify(const String& alter, const String& direction, const String& granularity); + + // Mozilla Selection Object API + // In Firefox, anchor/focus are the equal to the start/end of the selection, + // but reflect the direction in which the selection was made by the user. That does + // not mean that they are base/extent, since the base/extent don't reflect + // expansion. + // These methods return the valid equivalents of internal editing positions. + Node* anchorNode() const; + int anchorOffset() const; + Node* focusNode() const; + int focusOffset() const; + bool isCollapsed() const; + int rangeCount() const; + void collapse(Node*, int offset, ExceptionCode&); + void collapseToEnd(); + void collapseToStart(); + void extend(Node*, int offset, ExceptionCode&); + PassRefPtr<Range> getRangeAt(int, ExceptionCode&); + void removeAllRanges(); + void addRange(Range*); + void deleteFromDocument(); + bool containsNode(const Node*, bool partlyContained) const; + void selectAllChildren(Node*, ExceptionCode&); + + String toString(); + + // Microsoft Selection Object API + void empty(); + //void clear(); + //TextRange *createRange(); + + private: + DOMSelection(Frame*); + + Frame* m_frame; + }; + +} // namespace WebCore + +#endif // DOMSelection_h diff --git a/src/3rdparty/webkit/WebCore/page/DOMSelection.idl b/src/3rdparty/webkit/WebCore/page/DOMSelection.idl new file mode 100644 index 0000000..85d23bf --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/DOMSelection.idl @@ -0,0 +1,70 @@ +/* + * 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. + * 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. + */ + +module window { + + interface DOMSelection { + readonly attribute Node anchorNode; + readonly attribute long anchorOffset; + readonly attribute Node focusNode; + readonly attribute long focusOffset; + readonly attribute Node baseNode; + readonly attribute long baseOffset; + readonly attribute Node extentNode; + readonly attribute long extentOffset; + readonly attribute boolean isCollapsed; + readonly attribute DOMString type; + readonly attribute long rangeCount; + + void collapse(in Node node, in long index) + raises(DOMException); + void collapseToEnd(); + void collapseToStart(); + void deleteFromDocument(); + boolean containsNode(in Node node, in boolean allowPartial); + void selectAllChildren(in Node node) + raises(DOMException); + void empty(); + void setBaseAndExtent(in Node baseNode, in long baseOffset, in Node extentNode, in long extentOffset) + raises(DOMException); + void setPosition(in Node node, in long offset) + raises(DOMException); + void modify(in DOMString alter, in DOMString direction, in DOMString granularity); + void extend(in Node node, in long offset) + raises(DOMException); + Range getRangeAt(in long index) + raises(DOMException); + void removeAllRanges(); + void addRange(in Range range); + +#if defined(LANGUAGE_JAVASCRIPT) + [DontEnum] DOMString toString(); +#endif + }; + +} diff --git a/src/3rdparty/webkit/WebCore/page/DOMWindow.cpp b/src/3rdparty/webkit/WebCore/page/DOMWindow.cpp new file mode 100644 index 0000000..42d2e90 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/DOMWindow.cpp @@ -0,0 +1,1244 @@ +/* + * Copyright (C) 2006, 2007, 2008 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 "DOMWindow.h" + +#include "BarInfo.h" +#include "CSSComputedStyleDeclaration.h" +#include "CSSRuleList.h" +#include "CSSStyleSelector.h" +#include "CString.h" +#include "Chrome.h" +#include "Console.h" +#include "DOMSelection.h" +#include "Document.h" +#include "Element.h" +#include "EventListener.h" +#include "EventNames.h" +#include "ExceptionCode.h" +#include "FloatRect.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameTree.h" +#include "FrameView.h" +#include "HTMLFrameOwnerElement.h" +#include "History.h" +#include "Location.h" +#include "MessageEvent.h" +#include "Navigator.h" +#include "Page.h" +#include "PageGroup.h" +#include "PlatformScreen.h" +#include "PlatformString.h" +#include "Screen.h" +#include "SecurityOrigin.h" +#include "Settings.h" +#include <algorithm> +#include <wtf/MathExtras.h> + +#if ENABLE(DATABASE) +#include "Database.h" +#endif + +#if ENABLE(DOM_STORAGE) +#include "LocalStorage.h" +#include "SessionStorage.h" +#include "Storage.h" +#include "StorageArea.h" +#endif + +#if ENABLE(OFFLINE_WEB_APPLICATIONS) +#include "DOMApplicationCache.h" +#endif + +using std::min; +using std::max; + +namespace WebCore { + +class PostMessageTimer : public TimerBase { +public: + PostMessageTimer(DOMWindow* window, PassRefPtr<MessageEvent> event, SecurityOrigin* targetOrigin) + : m_window(window) + , m_event(event) + , m_targetOrigin(targetOrigin) + { + } + + MessageEvent* event() const { return m_event.get(); } + SecurityOrigin* targetOrigin() const { return m_targetOrigin.get(); } + +private: + virtual void fired() + { + m_window->postMessageTimerFired(this); + } + + RefPtr<DOMWindow> m_window; + RefPtr<MessageEvent> m_event; + RefPtr<SecurityOrigin> m_targetOrigin; +}; + +// This function: +// 1) Validates the pending changes are not changing to NaN +// 2) Constrains the window rect to no smaller than 100 in each dimension and no +// bigger than the the float rect's dimensions. +// 3) Constrain window rect to within the top and left boundaries of the screen rect +// 4) Constraint the window rect to within the bottom and right boundaries of the +// screen rect. +// 5) Translate the window rect coordinates to be within the coordinate space of +// the screen rect. +void DOMWindow::adjustWindowRect(const FloatRect& screen, FloatRect& window, const FloatRect& pendingChanges) +{ + // 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())); + + // Update window values if new requested values are not NaN. + if (!isnan(pendingChanges.x())) + window.setX(pendingChanges.x()); + if (!isnan(pendingChanges.y())) + window.setY(pendingChanges.y()); + if (!isnan(pendingChanges.width())) + window.setWidth(pendingChanges.width()); + if (!isnan(pendingChanges.height())) + window.setHeight(pendingChanges.height()); + + // Resize the window to between 100 and the screen width and height. + window.setWidth(min(max(100.0f, window.width()), screen.width())); + window.setHeight(min(max(100.0f, window.height()), screen.height())); + + // Constrain the window position to the screen. + window.setX(max(screen.x(), min(window.x(), screen.right() - window.width()))); + window.setY(max(screen.y(), min(window.y(), screen.bottom() - window.height()))); +} + +DOMWindow::DOMWindow(Frame* frame) + : m_frame(frame) +{ +} + +DOMWindow::~DOMWindow() +{ + if (m_frame) + m_frame->clearFormerDOMWindow(this); +} + +void DOMWindow::disconnectFrame() +{ + m_frame = 0; + clear(); +} + +void DOMWindow::clear() +{ + if (m_screen) + m_screen->disconnectFrame(); + m_screen = 0; + + if (m_selection) + m_selection->disconnectFrame(); + m_selection = 0; + + if (m_history) + m_history->disconnectFrame(); + m_history = 0; + + if (m_locationbar) + m_locationbar->disconnectFrame(); + m_locationbar = 0; + + if (m_menubar) + m_menubar->disconnectFrame(); + m_menubar = 0; + + if (m_personalbar) + m_personalbar->disconnectFrame(); + m_personalbar = 0; + + if (m_scrollbars) + m_scrollbars->disconnectFrame(); + m_scrollbars = 0; + + if (m_statusbar) + m_statusbar->disconnectFrame(); + m_statusbar = 0; + + if (m_toolbar) + m_toolbar->disconnectFrame(); + m_toolbar = 0; + + if (m_console) + m_console->disconnectFrame(); + m_console = 0; + + if (m_navigator) + m_navigator->disconnectFrame(); + m_navigator = 0; + + if (m_location) + m_location->disconnectFrame(); + m_location = 0; + +#if ENABLE(DOM_STORAGE) + if (m_sessionStorage) + m_sessionStorage->disconnectFrame(); + m_sessionStorage = 0; + + if (m_localStorage) + m_localStorage->disconnectFrame(); + m_localStorage = 0; +#endif + +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + if (m_applicationCache) + m_applicationCache->disconnectFrame(); + m_applicationCache = 0; +#endif +} + +Screen* DOMWindow::screen() const +{ + if (!m_screen) + m_screen = Screen::create(m_frame); + return m_screen.get(); +} + +History* DOMWindow::history() const +{ + if (!m_history) + m_history = History::create(m_frame); + return m_history.get(); +} + +BarInfo* DOMWindow::locationbar() const +{ + if (!m_locationbar) + m_locationbar = BarInfo::create(m_frame, BarInfo::Locationbar); + return m_locationbar.get(); +} + +BarInfo* DOMWindow::menubar() const +{ + if (!m_menubar) + m_menubar = BarInfo::create(m_frame, BarInfo::Menubar); + return m_menubar.get(); +} + +BarInfo* DOMWindow::personalbar() const +{ + if (!m_personalbar) + m_personalbar = BarInfo::create(m_frame, BarInfo::Personalbar); + return m_personalbar.get(); +} + +BarInfo* DOMWindow::scrollbars() const +{ + if (!m_scrollbars) + m_scrollbars = BarInfo::create(m_frame, BarInfo::Scrollbars); + return m_scrollbars.get(); +} + +BarInfo* DOMWindow::statusbar() const +{ + if (!m_statusbar) + m_statusbar = BarInfo::create(m_frame, BarInfo::Statusbar); + return m_statusbar.get(); +} + +BarInfo* DOMWindow::toolbar() const +{ + if (!m_toolbar) + m_toolbar = BarInfo::create(m_frame, BarInfo::Toolbar); + return m_toolbar.get(); +} + +Console* DOMWindow::console() const +{ + if (!m_console) + m_console = Console::create(m_frame); + return m_console.get(); +} + +#if ENABLE(OFFLINE_WEB_APPLICATIONS) +DOMApplicationCache* DOMWindow::applicationCache() const +{ + if (!m_applicationCache) + m_applicationCache = DOMApplicationCache::create(m_frame); + return m_applicationCache.get(); +} +#endif + +Navigator* DOMWindow::navigator() const +{ + if (!m_navigator) + m_navigator = Navigator::create(m_frame); + return m_navigator.get(); +} + +Location* DOMWindow::location() const +{ + if (!m_location) + m_location = Location::create(m_frame); + return m_location.get(); +} + +#if ENABLE(DOM_STORAGE) +Storage* DOMWindow::sessionStorage() const +{ + if (m_sessionStorage) + return m_sessionStorage.get(); + + Page* page = m_frame->page(); + if (!page) + return 0; + + Document* document = m_frame->document(); + if (!document) + return 0; + + RefPtr<StorageArea> storageArea = page->sessionStorage()->storageArea(document->securityOrigin()); + m_sessionStorage = Storage::create(m_frame, storageArea.release()); + return m_sessionStorage.get(); +} + +Storage* DOMWindow::localStorage() const +{ + Document* document = this->document(); + if (!document) + return 0; + + Page* page = document->page(); + if (!page) + return 0; + + Settings* settings = document->settings(); + if (!settings || !settings->localStorageEnabled()) + return 0; + + LocalStorage* localStorage = page->group().localStorage(); + RefPtr<StorageArea> storageArea = localStorage ? localStorage->storageArea(m_frame, document->securityOrigin()) : 0; + if (storageArea) + m_localStorage = Storage::create(m_frame, storageArea.release()); + + return m_localStorage.get(); +} +#endif + +void DOMWindow::postMessage(const String& message, MessagePort* messagePort, const String& targetOrigin, DOMWindow* source, ExceptionCode& ec) +{ + if (!m_frame) + return; + + // Compute the target origin. We need to do this synchronously in order + // to generate the SYNTAX_ERR exception correctly. + RefPtr<SecurityOrigin> target; + if (targetOrigin != "*") { + target = SecurityOrigin::create(KURL(targetOrigin)); + if (target->isEmpty()) { + ec = SYNTAX_ERR; + return; + } + } + + RefPtr<MessagePort> newMessagePort; + if (messagePort) + newMessagePort = messagePort->clone(ec); + if (ec) + return; + + // Capture the source of the message. We need to do this synchronously + // in order to capture the source of the message correctly. + Document* sourceDocument = source->document(); + if (!sourceDocument) + return; + String sourceOrigin = sourceDocument->securityOrigin()->toString(); + + // Schedule the message. + PostMessageTimer* timer = new PostMessageTimer(this, MessageEvent::create(message, sourceOrigin, "", source, newMessagePort), target.get()); + timer->startOneShot(0); +} + +void DOMWindow::postMessageTimerFired(PostMessageTimer* t) +{ + OwnPtr<PostMessageTimer> timer(t); + + if (!document()) + return; + + if (timer->targetOrigin()) { + // Check target origin now since the target document may have changed since the simer was scheduled. + if (!timer->targetOrigin()->isSameSchemeHostPort(document()->securityOrigin())) { + String message = String::format("Unable to post message to %s. Recipient has origin %s.\n", + timer->targetOrigin()->toString().utf8().data(), document()->securityOrigin()->toString().utf8().data()); + console()->addMessage(JSMessageSource, ErrorMessageLevel, message, 0, String()); + return; + } + } + + MessagePort* messagePort = timer->event()->messagePort(); + ASSERT(!messagePort || !messagePort->scriptExecutionContext()); + if (messagePort) + messagePort->attachToContext(document()); + + document()->dispatchWindowEvent(timer->event()); +} + +DOMSelection* DOMWindow::getSelection() +{ + if (!m_selection) + m_selection = DOMSelection::create(m_frame); + return m_selection.get(); +} + +Element* DOMWindow::frameElement() const +{ + if (!m_frame) + return 0; + + return m_frame->ownerElement(); +} + +void DOMWindow::focus() +{ + if (!m_frame) + return; + + m_frame->focusWindow(); +} + +void DOMWindow::blur() +{ + if (!m_frame) + return; + + m_frame->unfocusWindow(); +} + +void DOMWindow::close() +{ + if (!m_frame) + return; + + if (m_frame->loader()->openedByDOM() || m_frame->loader()->getHistoryLength() <= 1) + m_frame->scheduleClose(); +} + +void DOMWindow::print() +{ + if (!m_frame) + return; + + Page* page = m_frame->page(); + if (!page) + return; + + page->chrome()->print(m_frame); +} + +void DOMWindow::stop() +{ + if (!m_frame) + return; + + // We must check whether the load is complete asynchronously, because we might still be parsing + // the document until the callstack unwinds. + m_frame->loader()->stopForUserCancel(true); +} + +void DOMWindow::alert(const String& message) +{ + if (!m_frame) + return; + + Document* doc = m_frame->document(); + ASSERT(doc); + if (doc) + doc->updateRendering(); + + Page* page = m_frame->page(); + if (!page) + return; + + page->chrome()->runJavaScriptAlert(m_frame, message); +} + +bool DOMWindow::confirm(const String& message) +{ + if (!m_frame) + return false; + + Document* doc = m_frame->document(); + ASSERT(doc); + if (doc) + doc->updateRendering(); + + Page* page = m_frame->page(); + if (!page) + return false; + + return page->chrome()->runJavaScriptConfirm(m_frame, message); +} + +String DOMWindow::prompt(const String& message, const String& defaultValue) +{ + if (!m_frame) + return String(); + + Document* doc = m_frame->document(); + ASSERT(doc); + if (doc) + doc->updateRendering(); + + Page* page = m_frame->page(); + if (!page) + return String(); + + String returnValue; + if (page->chrome()->runJavaScriptPrompt(m_frame, message, defaultValue, returnValue)) + return returnValue; + + return String(); +} + +bool DOMWindow::find(const String& string, bool caseSensitive, bool backwards, bool wrap, bool /*wholeWord*/, bool /*searchInFrames*/, bool /*showDialog*/) const +{ + if (!m_frame) + return false; + + // FIXME (13016): Support wholeWord, searchInFrames and showDialog + return m_frame->findString(string, !backwards, caseSensitive, wrap, false); +} + +bool DOMWindow::offscreenBuffering() const +{ + return true; +} + +int DOMWindow::outerHeight() const +{ + if (!m_frame) + return 0; + + Page* page = m_frame->page(); + if (!page) + return 0; + + return static_cast<int>(page->chrome()->windowRect().height()); +} + +int DOMWindow::outerWidth() const +{ + if (!m_frame) + return 0; + + Page* page = m_frame->page(); + if (!page) + return 0; + + return static_cast<int>(page->chrome()->windowRect().width()); +} + +int DOMWindow::innerHeight() const +{ + if (!m_frame) + return 0; + + FrameView* view = m_frame->view(); + if (!view) + return 0; + + return static_cast<int>(view->height() / m_frame->pageZoomFactor()); +} + +int DOMWindow::innerWidth() const +{ + if (!m_frame) + return 0; + + FrameView* view = m_frame->view(); + if (!view) + return 0; + + return static_cast<int>(view->width() / m_frame->pageZoomFactor()); +} + +int DOMWindow::screenX() const +{ + if (!m_frame) + return 0; + + Page* page = m_frame->page(); + if (!page) + return 0; + + return static_cast<int>(page->chrome()->windowRect().x()); +} + +int DOMWindow::screenY() const +{ + if (!m_frame) + return 0; + + Page* page = m_frame->page(); + if (!page) + return 0; + + return static_cast<int>(page->chrome()->windowRect().y()); +} + +int DOMWindow::scrollX() const +{ + if (!m_frame) + return 0; + + FrameView* view = m_frame->view(); + if (!view) + return 0; + + Document* doc = m_frame->document(); + ASSERT(doc); + if (doc) + doc->updateLayoutIgnorePendingStylesheets(); + + return static_cast<int>(view->scrollX() / m_frame->pageZoomFactor()); +} + +int DOMWindow::scrollY() const +{ + if (!m_frame) + return 0; + + FrameView* view = m_frame->view(); + if (!view) + return 0; + + Document* doc = m_frame->document(); + ASSERT(doc); + if (doc) + doc->updateLayoutIgnorePendingStylesheets(); + + return static_cast<int>(view->scrollY() / m_frame->pageZoomFactor()); +} + +bool DOMWindow::closed() const +{ + return !m_frame; +} + +unsigned DOMWindow::length() const +{ + if (!m_frame) + return 0; + + return m_frame->tree()->childCount(); +} + +String DOMWindow::name() const +{ + if (!m_frame) + return String(); + + return m_frame->tree()->name(); +} + +void DOMWindow::setName(const String& string) +{ + if (!m_frame) + return; + + m_frame->tree()->setName(string); +} + +String DOMWindow::status() const +{ + if (!m_frame) + return String(); + + return m_frame->jsStatusBarText(); +} + +void DOMWindow::setStatus(const String& string) +{ + if (!m_frame) + return; + + m_frame->setJSStatusBarText(string); +} + +String DOMWindow::defaultStatus() const +{ + if (!m_frame) + return String(); + + return m_frame->jsDefaultStatusBarText(); +} + +void DOMWindow::setDefaultStatus(const String& string) +{ + if (!m_frame) + return; + + m_frame->setJSDefaultStatusBarText(string); +} + +DOMWindow* DOMWindow::self() const +{ + if (!m_frame) + return 0; + + return m_frame->domWindow(); +} + +DOMWindow* DOMWindow::opener() const +{ + if (!m_frame) + return 0; + + Frame* opener = m_frame->loader()->opener(); + if (!opener) + return 0; + + return opener->domWindow(); +} + +DOMWindow* DOMWindow::parent() const +{ + if (!m_frame) + return 0; + + Frame* parent = m_frame->tree()->parent(true); + if (parent) + return parent->domWindow(); + + return m_frame->domWindow(); +} + +DOMWindow* DOMWindow::top() const +{ + if (!m_frame) + return 0; + + Page* page = m_frame->page(); + if (!page) + return 0; + + return m_frame->tree()->top(true)->domWindow(); +} + +Document* DOMWindow::document() const +{ + if (!m_frame) + return 0; + + ASSERT(m_frame->document()); + return m_frame->document(); +} + +PassRefPtr<CSSStyleDeclaration> DOMWindow::getComputedStyle(Element* elt, const String&) const +{ + if (!elt) + return 0; + + // FIXME: This needs take pseudo elements into account. + return computedStyle(elt); +} + +PassRefPtr<CSSRuleList> DOMWindow::getMatchedCSSRules(Element* elt, const String& pseudoElt, bool authorOnly) const +{ + if (!m_frame) + return 0; + + Document* doc = m_frame->document(); + ASSERT(doc); + if (!doc) + return 0; + + if (!pseudoElt.isEmpty()) + return doc->styleSelector()->pseudoStyleRulesForElement(elt, pseudoElt, authorOnly); + return doc->styleSelector()->styleRulesForElement(elt, authorOnly); +} + +double DOMWindow::devicePixelRatio() const +{ + if (!m_frame) + return 0.0; + + Page* page = m_frame->page(); + if (!page) + return 0.0; + + return page->chrome()->scaleFactor(); +} + +#if ENABLE(DATABASE) +PassRefPtr<Database> DOMWindow::openDatabase(const String& name, const String& version, const String& displayName, unsigned long estimatedSize, ExceptionCode& ec) +{ + if (!m_frame) + return 0; + + Document* doc = m_frame->document(); + ASSERT(doc); + if (!doc) + return 0; + + Settings* settings = m_frame->settings(); + if (!settings || !settings->databasesEnabled()) + return 0; + + return Database::openDatabase(doc, name, version, displayName, estimatedSize, ec); +} +#endif + +void DOMWindow::scrollBy(int x, int y) const +{ + if (!m_frame) + return; + + Document* doc = m_frame->document(); + ASSERT(doc); + if (doc) + doc->updateLayoutIgnorePendingStylesheets(); + + FrameView* view = m_frame->view(); + if (!view) + return; + + view->scrollBy(IntSize(x, y)); +} + +void DOMWindow::scrollTo(int x, int y) const +{ + if (!m_frame) + return; + + Document* doc = m_frame->document(); + ASSERT(doc); + if (doc) + doc->updateLayoutIgnorePendingStylesheets(); + + FrameView* view = m_frame->view(); + if (!view) + return; + + int zoomedX = static_cast<int>(x * m_frame->pageZoomFactor()); + int zoomedY = static_cast<int>(y * m_frame->pageZoomFactor()); + view->setScrollPosition(IntPoint(zoomedX, zoomedY)); +} + +void DOMWindow::moveBy(float x, float y) const +{ + if (!m_frame) + return; + + Page* page = m_frame->page(); + if (!page) + return; + + if (m_frame != page->mainFrame()) + return; + + FloatRect fr = page->chrome()->windowRect(); + FloatRect update = fr; + update.move(x, y); + // Security check (the spec talks about UniversalBrowserWrite to disable this check...) + adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), fr, update); + page->chrome()->setWindowRect(fr); +} + +void DOMWindow::moveTo(float x, float y) const +{ + if (!m_frame) + return; + + Page* page = m_frame->page(); + if (!page) + return; + + if (m_frame != page->mainFrame()) + return; + + 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...) + adjustWindowRect(sr, fr, update); + page->chrome()->setWindowRect(fr); +} + +void DOMWindow::resizeBy(float x, float y) const +{ + if (!m_frame) + return; + + Page* page = m_frame->page(); + if (!page) + return; + + if (m_frame != page->mainFrame()) + return; + + FloatRect fr = page->chrome()->windowRect(); + FloatSize dest = fr.size() + FloatSize(x, y); + FloatRect update(fr.location(), dest); + adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), fr, update); + page->chrome()->setWindowRect(fr); +} + +void DOMWindow::resizeTo(float width, float height) const +{ + if (!m_frame) + return; + + Page* page = m_frame->page(); + if (!page) + return; + + if (m_frame != page->mainFrame()) + return; + + FloatRect fr = page->chrome()->windowRect(); + FloatSize dest = FloatSize(width, height); + FloatRect update(fr.location(), dest); + adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), fr, update); + page->chrome()->setWindowRect(fr); +} + +inline void DOMWindow::setInlineEventListenerForType(const AtomicString& eventType, PassRefPtr<EventListener> eventListener) +{ + Document* document = this->document(); + if (!document) + return; + document->setWindowInlineEventListenerForType(eventType, eventListener); +} + +inline EventListener* DOMWindow::inlineEventListenerForType(const AtomicString& eventType) const +{ + Document* document = this->document(); + if (!document) + return 0; + return document->windowInlineEventListenerForType(eventType); +} + +EventListener* DOMWindow::onabort() const +{ + return inlineEventListenerForType(eventNames().abortEvent); +} + +void DOMWindow::setOnabort(PassRefPtr<EventListener> eventListener) +{ + setInlineEventListenerForType(eventNames().abortEvent, eventListener); +} + +EventListener* DOMWindow::onblur() const +{ + return inlineEventListenerForType(eventNames().blurEvent); +} + +void DOMWindow::setOnblur(PassRefPtr<EventListener> eventListener) +{ + setInlineEventListenerForType(eventNames().blurEvent, eventListener); +} + +EventListener* DOMWindow::onchange() const +{ + return inlineEventListenerForType(eventNames().changeEvent); +} + +void DOMWindow::setOnchange(PassRefPtr<EventListener> eventListener) +{ + setInlineEventListenerForType(eventNames().changeEvent, eventListener); +} + +EventListener* DOMWindow::onclick() const +{ + return inlineEventListenerForType(eventNames().clickEvent); +} + +void DOMWindow::setOnclick(PassRefPtr<EventListener> eventListener) +{ + setInlineEventListenerForType(eventNames().clickEvent, eventListener); +} + +EventListener* DOMWindow::ondblclick() const +{ + return inlineEventListenerForType(eventNames().dblclickEvent); +} + +void DOMWindow::setOndblclick(PassRefPtr<EventListener> eventListener) +{ + setInlineEventListenerForType(eventNames().dblclickEvent, eventListener); +} + +EventListener* DOMWindow::onerror() const +{ + return inlineEventListenerForType(eventNames().errorEvent); +} + +void DOMWindow::setOnerror(PassRefPtr<EventListener> eventListener) +{ + setInlineEventListenerForType(eventNames().errorEvent, eventListener); +} + +EventListener* DOMWindow::onfocus() const +{ + return inlineEventListenerForType(eventNames().focusEvent); +} + +void DOMWindow::setOnfocus(PassRefPtr<EventListener> eventListener) +{ + setInlineEventListenerForType(eventNames().focusEvent, eventListener); +} + +EventListener* DOMWindow::onkeydown() const +{ + return inlineEventListenerForType(eventNames().keydownEvent); +} + +void DOMWindow::setOnkeydown(PassRefPtr<EventListener> eventListener) +{ + setInlineEventListenerForType(eventNames().keydownEvent, eventListener); +} + +EventListener* DOMWindow::onkeypress() const +{ + return inlineEventListenerForType(eventNames().keypressEvent); +} + +void DOMWindow::setOnkeypress(PassRefPtr<EventListener> eventListener) +{ + setInlineEventListenerForType(eventNames().keypressEvent, eventListener); +} + +EventListener* DOMWindow::onkeyup() const +{ + return inlineEventListenerForType(eventNames().keyupEvent); +} + +void DOMWindow::setOnkeyup(PassRefPtr<EventListener> eventListener) +{ + setInlineEventListenerForType(eventNames().keyupEvent, eventListener); +} + +EventListener* DOMWindow::onload() const +{ + return inlineEventListenerForType(eventNames().loadEvent); +} + +void DOMWindow::setOnload(PassRefPtr<EventListener> eventListener) +{ + setInlineEventListenerForType(eventNames().loadEvent, eventListener); +} + +EventListener* DOMWindow::onmousedown() const +{ + return inlineEventListenerForType(eventNames().mousedownEvent); +} + +void DOMWindow::setOnmousedown(PassRefPtr<EventListener> eventListener) +{ + setInlineEventListenerForType(eventNames().mousedownEvent, eventListener); +} + +EventListener* DOMWindow::onmousemove() const +{ + return inlineEventListenerForType(eventNames().mousemoveEvent); +} + +void DOMWindow::setOnmousemove(PassRefPtr<EventListener> eventListener) +{ + setInlineEventListenerForType(eventNames().mousemoveEvent, eventListener); +} + +EventListener* DOMWindow::onmouseout() const +{ + return inlineEventListenerForType(eventNames().mouseoutEvent); +} + +void DOMWindow::setOnmouseout(PassRefPtr<EventListener> eventListener) +{ + setInlineEventListenerForType(eventNames().mouseoutEvent, eventListener); +} + +EventListener* DOMWindow::onmouseover() const +{ + return inlineEventListenerForType(eventNames().mouseoverEvent); +} + +void DOMWindow::setOnmouseover(PassRefPtr<EventListener> eventListener) +{ + setInlineEventListenerForType(eventNames().mouseoverEvent, eventListener); +} + +EventListener* DOMWindow::onmouseup() const +{ + return inlineEventListenerForType(eventNames().mouseupEvent); +} + +void DOMWindow::setOnmouseup(PassRefPtr<EventListener> eventListener) +{ + setInlineEventListenerForType(eventNames().mouseupEvent, eventListener); +} + +EventListener* DOMWindow::onmousewheel() const +{ + return inlineEventListenerForType(eventNames().mousewheelEvent); +} + +void DOMWindow::setOnmousewheel(PassRefPtr<EventListener> eventListener) +{ + setInlineEventListenerForType(eventNames().mousewheelEvent, eventListener); +} + +EventListener* DOMWindow::onreset() const +{ + return inlineEventListenerForType(eventNames().resetEvent); +} + +void DOMWindow::setOnreset(PassRefPtr<EventListener> eventListener) +{ + setInlineEventListenerForType(eventNames().resetEvent, eventListener); +} + +EventListener* DOMWindow::onresize() const +{ + return inlineEventListenerForType(eventNames().resizeEvent); +} + +void DOMWindow::setOnresize(PassRefPtr<EventListener> eventListener) +{ + setInlineEventListenerForType(eventNames().resizeEvent, eventListener); +} + +EventListener* DOMWindow::onscroll() const +{ + return inlineEventListenerForType(eventNames().scrollEvent); +} + +void DOMWindow::setOnscroll(PassRefPtr<EventListener> eventListener) +{ + setInlineEventListenerForType(eventNames().scrollEvent, eventListener); +} + +EventListener* DOMWindow::onsearch() const +{ + return inlineEventListenerForType(eventNames().searchEvent); +} + +void DOMWindow::setOnsearch(PassRefPtr<EventListener> eventListener) +{ + setInlineEventListenerForType(eventNames().searchEvent, eventListener); +} + +EventListener* DOMWindow::onselect() const +{ + return inlineEventListenerForType(eventNames().selectEvent); +} + +void DOMWindow::setOnselect(PassRefPtr<EventListener> eventListener) +{ + setInlineEventListenerForType(eventNames().selectEvent, eventListener); +} + +EventListener* DOMWindow::onsubmit() const +{ + return inlineEventListenerForType(eventNames().submitEvent); +} + +void DOMWindow::setOnsubmit(PassRefPtr<EventListener> eventListener) +{ + setInlineEventListenerForType(eventNames().submitEvent, eventListener); +} + +EventListener* DOMWindow::onunload() const +{ + return inlineEventListenerForType(eventNames().unloadEvent); +} + +void DOMWindow::setOnunload(PassRefPtr<EventListener> eventListener) +{ + setInlineEventListenerForType(eventNames().unloadEvent, eventListener); +} + +EventListener* DOMWindow::onbeforeunload() const +{ + return inlineEventListenerForType(eventNames().beforeunloadEvent); +} + +void DOMWindow::setOnbeforeunload(PassRefPtr<EventListener> eventListener) +{ + setInlineEventListenerForType(eventNames().beforeunloadEvent, eventListener); +} + +EventListener* DOMWindow::onwebkitanimationstart() const +{ + return inlineEventListenerForType(eventNames().webkitAnimationStartEvent); +} + +void DOMWindow::setOnwebkitanimationstart(PassRefPtr<EventListener> eventListener) +{ + setInlineEventListenerForType(eventNames().webkitAnimationStartEvent, eventListener); +} + +EventListener* DOMWindow::onwebkitanimationiteration() const +{ + return inlineEventListenerForType(eventNames().webkitAnimationIterationEvent); +} + +void DOMWindow::setOnwebkitanimationiteration(PassRefPtr<EventListener> eventListener) +{ + setInlineEventListenerForType(eventNames().webkitAnimationIterationEvent, eventListener); +} + +EventListener* DOMWindow::onwebkitanimationend() const +{ + return inlineEventListenerForType(eventNames().webkitAnimationEndEvent); +} + +void DOMWindow::setOnwebkitanimationend(PassRefPtr<EventListener> eventListener) +{ + setInlineEventListenerForType(eventNames().webkitAnimationEndEvent, eventListener); +} + +EventListener* DOMWindow::onwebkittransitionend() const +{ + return inlineEventListenerForType(eventNames().webkitTransitionEndEvent); +} + +void DOMWindow::setOnwebkittransitionend(PassRefPtr<EventListener> eventListener) +{ + setInlineEventListenerForType(eventNames().webkitTransitionEndEvent, eventListener); +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/DOMWindow.h b/src/3rdparty/webkit/WebCore/page/DOMWindow.h new file mode 100644 index 0000000..0277441 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/DOMWindow.h @@ -0,0 +1,307 @@ +/* + * Copyright (C) 2006, 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. + */ + +#ifndef DOMWindow_h +#define DOMWindow_h + +#include "KURL.h" +#include "PlatformString.h" +#include "SecurityOrigin.h" +#include <wtf/Forward.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + + class BarInfo; + class CSSRuleList; + class CSSStyleDeclaration; + class Console; + class DOMSelection; + class Database; + class Document; + class Element; + class EventListener; + class FloatRect; + class Frame; + class History; + class Location; + class MessagePort; + class Navigator; + class PostMessageTimer; + class Screen; + +#if ENABLE(DOM_STORAGE) + class SessionStorage; + class Storage; +#endif + +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + class DOMApplicationCache; +#endif + + typedef int ExceptionCode; + + class DOMWindow : public RefCounted<DOMWindow> { + public: + static PassRefPtr<DOMWindow> create(Frame* frame) { return adoptRef(new DOMWindow(frame)); } + virtual ~DOMWindow(); + + Frame* frame() { return m_frame; } + void disconnectFrame(); + + void clear(); + + void setSecurityOrigin(SecurityOrigin* securityOrigin) { m_securityOrigin = securityOrigin; } + SecurityOrigin* securityOrigin() const { return m_securityOrigin.get(); } + + void setURL(const KURL& url) { m_url = url; } + KURL url() const { return m_url; } + + static void adjustWindowRect(const FloatRect& screen, FloatRect& window, const FloatRect& pendingChanges); + + // DOM Level 0 + Screen* screen() const; + History* history() const; + BarInfo* locationbar() const; + BarInfo* menubar() const; + BarInfo* personalbar() const; + BarInfo* scrollbars() const; + BarInfo* statusbar() const; + BarInfo* toolbar() const; + Navigator* navigator() const; + Navigator* clientInformation() const { return navigator(); } + Location* location() const; + + DOMSelection* getSelection(); + + Element* frameElement() const; + + void focus(); + void blur(); + void close(); + void print(); + void stop(); + + void alert(const String& message); + bool confirm(const String& message); + String prompt(const String& message, const String& defaultValue); + + bool find(const String&, bool caseSensitive, bool backwards, bool wrap, bool wholeWord, bool searchInFrames, bool showDialog) const; + + bool offscreenBuffering() const; + + int outerHeight() const; + int outerWidth() const; + int innerHeight() const; + int innerWidth() const; + int screenX() const; + int screenY() const; + int screenLeft() const { return screenX(); } + int screenTop() const { return screenY(); } + int scrollX() const; + int scrollY() const; + int pageXOffset() const { return scrollX(); } + int pageYOffset() const { return scrollY(); } + + bool closed() const; + + unsigned length() const; + + String name() const; + void setName(const String&); + + String status() const; + void setStatus(const String&); + String defaultStatus() const; + void setDefaultStatus(const String&); + // This attribute is an alias of defaultStatus and is necessary for legacy uses. + String defaultstatus() const { return defaultStatus(); } + void setDefaultstatus(const String& status) { setDefaultStatus(status); } + + // Self referential attributes + DOMWindow* self() const; + DOMWindow* window() const { return self(); } + DOMWindow* frames() const { return self(); } + + DOMWindow* opener() const; + DOMWindow* parent() const; + DOMWindow* top() const; + + // DOM Level 2 AbstractView Interface + Document* document() const; + + // DOM Level 2 Style Interface + PassRefPtr<CSSStyleDeclaration> getComputedStyle(Element*, const String& pseudoElt) const; + + // WebKit extensions + PassRefPtr<CSSRuleList> getMatchedCSSRules(Element*, const String& pseudoElt, bool authorOnly = true) const; + double devicePixelRatio() const; + +#if ENABLE(DATABASE) + // HTML 5 client-side database + PassRefPtr<Database> openDatabase(const String& name, const String& version, const String& displayName, unsigned long estimatedSize, ExceptionCode&); +#endif + +#if ENABLE(DOM_STORAGE) + // HTML 5 key/value storage + Storage* sessionStorage() const; + Storage* localStorage() const; +#endif + + Console* console() const; + +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + DOMApplicationCache* applicationCache() const; +#endif + + void postMessage(const String& message, MessagePort*, const String& targetOrigin, DOMWindow* source, ExceptionCode&); + void postMessageTimerFired(PostMessageTimer*); + + void scrollBy(int x, int y) const; + void scrollTo(int x, int y) const; + void scroll(int x, int y) const { scrollTo(x, y); } + + void moveBy(float x, float y) const; + void moveTo(float x, float y) const; + + void resizeBy(float x, float y) const; + void resizeTo(float width, float height) const; + + EventListener* onabort() const; + void setOnabort(PassRefPtr<EventListener>); + EventListener* onblur() const; + void setOnblur(PassRefPtr<EventListener>); + EventListener* onchange() const; + void setOnchange(PassRefPtr<EventListener>); + EventListener* onclick() const; + void setOnclick(PassRefPtr<EventListener>); + EventListener* ondblclick() const; + void setOndblclick(PassRefPtr<EventListener>); + EventListener* onerror() const; + void setOnerror(PassRefPtr<EventListener>); + EventListener* onfocus() const; + void setOnfocus(PassRefPtr<EventListener>); + EventListener* onkeydown() const; + void setOnkeydown(PassRefPtr<EventListener>); + EventListener* onkeypress() const; + void setOnkeypress(PassRefPtr<EventListener>); + EventListener* onkeyup() const; + void setOnkeyup(PassRefPtr<EventListener>); + EventListener* onload() const; + void setOnload(PassRefPtr<EventListener>); + EventListener* onmousedown() const; + void setOnmousedown(PassRefPtr<EventListener>); + EventListener* onmousemove() const; + void setOnmousemove(PassRefPtr<EventListener>); + EventListener* onmouseout() const; + void setOnmouseout(PassRefPtr<EventListener>); + EventListener* onmouseover() const; + void setOnmouseover(PassRefPtr<EventListener>); + EventListener* onmouseup() const; + void setOnmouseup(PassRefPtr<EventListener>); + EventListener* onmousewheel() const; + void setOnmousewheel(PassRefPtr<EventListener>); + EventListener* onreset() const; + void setOnreset(PassRefPtr<EventListener>); + EventListener* onresize() const; + void setOnresize(PassRefPtr<EventListener>); + EventListener* onscroll() const; + void setOnscroll(PassRefPtr<EventListener>); + EventListener* onsearch() const; + void setOnsearch(PassRefPtr<EventListener>); + EventListener* onselect() const; + void setOnselect(PassRefPtr<EventListener>); + EventListener* onsubmit() const; + void setOnsubmit(PassRefPtr<EventListener>); + EventListener* onunload() const; + void setOnunload(PassRefPtr<EventListener>); + EventListener* onbeforeunload() const; + void setOnbeforeunload(PassRefPtr<EventListener>); + EventListener* onwebkitanimationstart() const; + void setOnwebkitanimationstart(PassRefPtr<EventListener>); + EventListener* onwebkitanimationiteration() const; + void setOnwebkitanimationiteration(PassRefPtr<EventListener>); + EventListener* onwebkitanimationend() const; + void setOnwebkitanimationend(PassRefPtr<EventListener>); + EventListener* onwebkittransitionend() const; + void setOnwebkittransitionend(PassRefPtr<EventListener>); + + // These methods are used for GC marking. See JSDOMWindow::mark() in + // JSDOMWindowCustom.cpp. + Screen* optionalScreen() const { return m_screen.get(); } + DOMSelection* optionalSelection() const { return m_selection.get(); } + History* optionalHistory() const { return m_history.get(); } + BarInfo* optionalLocationbar() const { return m_locationbar.get(); } + BarInfo* optionalMenubar() const { return m_menubar.get(); } + BarInfo* optionalPersonalbar() const { return m_personalbar.get(); } + BarInfo* optionalScrollbars() const { return m_scrollbars.get(); } + BarInfo* optionalStatusbar() const { return m_statusbar.get(); } + BarInfo* optionalToolbar() const { return m_toolbar.get(); } + Console* optionalConsole() const { return m_console.get(); } + Navigator* optionalNavigator() const { return m_navigator.get(); } + Location* optionalLocation() const { return m_location.get(); } +#if ENABLE(DOM_STORAGE) + Storage* optionalSessionStorage() const { return m_sessionStorage.get(); } + Storage* optionalLocalStorage() const { return m_sessionStorage.get(); } +#endif +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + DOMApplicationCache* optionalApplicationCache() const { return m_applicationCache.get(); } +#endif + + private: + DOMWindow(Frame*); + + void setInlineEventListenerForType(const AtomicString& eventType, PassRefPtr<EventListener>); + EventListener* inlineEventListenerForType(const AtomicString& eventType) const; + + RefPtr<SecurityOrigin> m_securityOrigin; + KURL m_url; + + Frame* m_frame; + mutable RefPtr<Screen> m_screen; + mutable RefPtr<DOMSelection> m_selection; + mutable RefPtr<History> m_history; + 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<Console> m_console; + mutable RefPtr<Navigator> m_navigator; + mutable RefPtr<Location> m_location; +#if ENABLE(DOM_STORAGE) + mutable RefPtr<Storage> m_sessionStorage; + mutable RefPtr<Storage> m_localStorage; +#endif +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + mutable RefPtr<DOMApplicationCache> m_applicationCache; +#endif + }; + +} // namespace WebCore + +#endif diff --git a/src/3rdparty/webkit/WebCore/page/DOMWindow.idl b/src/3rdparty/webkit/WebCore/page/DOMWindow.idl new file mode 100644 index 0000000..504b705 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/DOMWindow.idl @@ -0,0 +1,431 @@ +/* + * Copyright (C) 2006, 2007, 2008 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. + */ + +module window { + + interface [ + CheckDomainSecurity, + CustomDefineGetter, + CustomDefineSetter, + CustomDeleteProperty, + CustomGetOwnPropertySlot, + CustomGetPropertyAttributes, + CustomGetPropertyNames, + CustomLookupGetter, + CustomLookupSetter, + CustomMarkFunction, + CustomNativeConverter, + CustomPutFunction, + ExtendsDOMGlobalObject, + GenerateNativeConverter, + LegacyParent=JSDOMWindowBase + ] DOMWindow { + // DOM Level 0 + readonly attribute Screen screen; + readonly attribute [DoNotCheckDomainSecurity] History history; + attribute [Replaceable] BarInfo locationbar; + attribute [Replaceable] BarInfo menubar; + attribute [Replaceable] BarInfo personalbar; + attribute [Replaceable] BarInfo scrollbars; + attribute [Replaceable] BarInfo statusbar; + attribute [Replaceable] BarInfo toolbar; + attribute [Replaceable] Navigator navigator; + attribute [Replaceable] Navigator clientInformation; + attribute [DoNotCheckDomainSecurity, CustomSetter] Location location; + + DOMSelection getSelection(); + + readonly attribute [CheckNodeSecurity] Element frameElement; + + [DoNotCheckDomainSecurity] void focus(); + [DoNotCheckDomainSecurity] void blur(); + [DoNotCheckDomainSecurity] void close(); + + void print(); + void stop(); + + void alert(in DOMString message); + boolean confirm(in DOMString message); + [ConvertNullStringTo=Null] DOMString prompt(in DOMString message, + in [ConvertUndefinedOrNullToNullString] DOMString defaultValue); + + boolean find(in DOMString string, + in boolean caseSensitive, + in boolean backwards, + in boolean wrap, + in boolean wholeWord, + in boolean searchInFrames, + in boolean showDialog); + + attribute [Replaceable] boolean offscreenBuffering; + + attribute [Replaceable] long outerHeight; + attribute [Replaceable] long outerWidth; + attribute [Replaceable] long innerHeight; + attribute [Replaceable] long innerWidth; + attribute [Replaceable] long screenX; + attribute [Replaceable] long screenY; + attribute [Replaceable] long screenLeft; + attribute [Replaceable] long screenTop; + attribute [Replaceable] long scrollX; + attribute [Replaceable] long scrollY; + readonly attribute long pageXOffset; + readonly attribute long pageYOffset; + + [RequiresAllArguments] void scrollBy(in long x, in long y); + [RequiresAllArguments] void scrollTo(in long x, in long y); + [RequiresAllArguments] void scroll(in long x, in long y); + [RequiresAllArguments] void moveBy(in float x, in float y); // FIXME: this should take longs not floats. + [RequiresAllArguments] void moveTo(in float x, in float y); // FIXME: this should take longs not floats. + [RequiresAllArguments] void resizeBy(in float x, in float y); // FIXME: this should take longs not floats. + [RequiresAllArguments] void resizeTo(in float width, in float height); // FIXME: this should take longs not floats. + + readonly attribute [DoNotCheckDomainSecurity] boolean closed; + + attribute [Replaceable, DoNotCheckDomainSecurityOnGet] unsigned long length; + + attribute DOMString name; + + attribute DOMString status; + attribute DOMString defaultStatus; +#if defined(LANGUAGE_JAVASCRIPT) + // This attribute is an alias of defaultStatus and is necessary for legacy uses. + attribute DOMString defaultstatus; +#endif + + // Self referential attributes + attribute [Replaceable, DoNotCheckDomainSecurityOnGet] DOMWindow self; + readonly attribute [DoNotCheckDomainSecurity] DOMWindow window; + attribute [Replaceable, DoNotCheckDomainSecurityOnGet] DOMWindow frames; + + attribute [Replaceable, DoNotCheckDomainSecurityOnGet] DOMWindow opener; + attribute [Replaceable, DoNotCheckDomainSecurity] DOMWindow parent; + attribute [Replaceable, DoNotCheckDomainSecurity] DOMWindow top; + + // DOM Level 2 AbstractView Interface + readonly attribute Document document; + + // DOM Level 2 Style Interface + CSSStyleDeclaration getComputedStyle(in Element element, + in DOMString pseudoElement); + + // WebKit extensions + CSSRuleList getMatchedCSSRules(in Element element, + in DOMString pseudoElement, + in [Optional] boolean authorOnly); + attribute [Replaceable] double devicePixelRatio; + +#if ENABLE_OFFLINE_WEB_APPLICATIONS + readonly attribute DOMApplicationCache applicationCache; +#endif +#if ENABLE_DATABASE + Database openDatabase(in DOMString name, in DOMString version, in DOMString displayName, in unsigned long estimatedSize) + raises(DOMException); +#endif +#if ENABLE_DOM_STORAGE + readonly attribute Storage sessionStorage; + readonly attribute Storage localStorage; +#endif + + attribute [Replaceable] Console console; + + // cross-document messaging + [DoNotCheckDomainSecurity, Custom] void postMessage(in DOMString message, in [Optional] MessagePort messagePort, in DOMString targetOrigin) + raises(DOMException); + + // Timers + [Custom] long setTimeout(in TimeoutHandler handler, in long timeout); + // [Custom] long setTimeout(in DOMString code, in long timeout); + [Custom] void clearTimeout(in long handle); + + [Custom] long setInterval(in TimeoutHandler handler, in long timeout); + // [Custom] long setInterval(in DOMString code, in long timeout); + [Custom] void clearInterval(in long handle); + + // Base64 + [Custom] DOMString atob(in DOMString string) + raises(DOMException); + [Custom] DOMString btoa(in DOMString string) + raises(DOMException); + + // Events + attribute [ProtectedListener] EventListener onabort; + attribute [ProtectedListener] EventListener onblur; + attribute [ProtectedListener] EventListener onchange; + attribute [ProtectedListener] EventListener onclick; + attribute [ProtectedListener] EventListener ondblclick; + attribute [ProtectedListener] EventListener onerror; + attribute [ProtectedListener] EventListener onfocus; + attribute [ProtectedListener] EventListener onkeydown; + attribute [ProtectedListener] EventListener onkeypress; + attribute [ProtectedListener] EventListener onkeyup; + attribute [ProtectedListener] EventListener onload; + attribute [ProtectedListener] EventListener onmousedown; + attribute [ProtectedListener] EventListener onmousemove; + attribute [ProtectedListener] EventListener onmouseout; + attribute [ProtectedListener] EventListener onmouseover; + attribute [ProtectedListener] EventListener onmouseup; + attribute [ProtectedListener] EventListener onmousewheel; + attribute [ProtectedListener] EventListener onreset; + attribute [ProtectedListener] EventListener onresize; + attribute [ProtectedListener] EventListener onscroll; + attribute [ProtectedListener] EventListener onsearch; + attribute [ProtectedListener] EventListener onselect; + attribute [ProtectedListener] EventListener onsubmit; + attribute [ProtectedListener] EventListener onunload; + attribute [ProtectedListener] EventListener onbeforeunload; + attribute [ProtectedListener] EventListener onwebkitanimationstart; + attribute [ProtectedListener] EventListener onwebkitanimationiteration; + attribute [ProtectedListener] EventListener onwebkitanimationend; + attribute [ProtectedListener] EventListener onwebkittransitionend; + + // EventTarget interface + [Custom] void addEventListener(in DOMString type, + in EventListener listener, + in boolean useCapture); + [Custom] void removeEventListener(in DOMString type, + in EventListener listener, + in boolean useCapture); + // FIXME: Implement dispatchEvent + +#if defined(LANGUAGE_JAVASCRIPT) + // Global constructors + attribute StyleSheetConstructor StyleSheet; + attribute CSSStyleSheetConstructor CSSStyleSheet; + + attribute CSSValueConstructor CSSValue; + attribute CSSPrimitiveValueConstructor CSSPrimitiveValue; + attribute CSSValueListConstructor CSSValueList; + attribute WebKitCSSTransformValueConstructor WebKitCSSTransformValue; + + attribute CSSRuleConstructor CSSRule; + attribute CSSCharsetRuleConstructor CSSCharsetRule; + attribute CSSFontFaceRuleConstructor CSSFontFaceRule; + attribute CSSImportRuleConstructor CSSImportRule; + attribute CSSMediaRuleConstructor CSSMediaRule; + attribute CSSPageRuleConstructor CSSPageRule; + attribute CSSStyleRuleConstructor CSSStyleRule; + + attribute CSSVariablesRuleConstructor CSSVariablesRule; + attribute CSSVariablesDeclarationConstructor CSSVariablesDeclaration; + + attribute CSSStyleDeclarationConstructor CSSStyleDeclaration; + attribute MediaListConstructor MediaList; + attribute CounterConstructor Counter; + attribute CSSRuleListConstructor CSSRuleList; + attribute RectConstructor Rect; + 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 DocumentFragmentConstructor DocumentFragment; + attribute DocumentConstructor Document; + attribute NodeConstructor Node; + attribute NodeListConstructor NodeList; + 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; + + 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 HTMLBlockquoteElementConstructor HTMLBlockquoteElement; + attribute HTMLBodyElementConstructor HTMLBodyElement; + attribute HTMLButtonElementConstructor HTMLButtonElement; + attribute HTMLCanvasElementConstructor HTMLCanvasElement; + attribute HTMLDListElementConstructor HTMLDListElement; + 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 HTMLIsIndexElementConstructor HTMLIsIndexElement; + attribute HTMLLIElementConstructor HTMLLIElement; + attribute HTMLLabelElementConstructor HTMLLabelElement; + attribute HTMLLegendElementConstructor HTMLLegendElement; + attribute HTMLLinkElementConstructor HTMLLinkElement; + attribute HTMLMapElementConstructor HTMLMapElement; + attribute HTMLMarqueeElementConstructor HTMLMarqueeElement; + attribute HTMLMenuElementConstructor HTMLMenuElement; + attribute HTMLMetaElementConstructor HTMLMetaElement; + attribute HTMLModElementConstructor HTMLModElement; + attribute HTMLOListElementConstructor HTMLOListElement; + attribute HTMLObjectElementConstructor HTMLObjectElement; + attribute HTMLOptGroupElementConstructor HTMLOptGroupElement; + attribute HTMLOptionElementConstructor HTMLOptionElement; + attribute HTMLParagraphElementConstructor HTMLParagraphElement; + attribute HTMLParamElementConstructor HTMLParamElement; + attribute HTMLPreElementConstructor HTMLPreElement; + attribute HTMLQuoteElementConstructor HTMLQuoteElement; + attribute HTMLScriptElementConstructor HTMLScriptElement; + attribute HTMLSelectElementConstructor HTMLSelectElement; + 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 CanvasRenderingContext2DConstructor CanvasRenderingContext2D; + attribute TextMetricsConstructor TextMetrics; + + attribute EventConstructor Event; + attribute KeyboardEventConstructor KeyboardEvent; + attribute MouseEventConstructor MouseEvent; + attribute MutationEventConstructor MutationEvent; + attribute OverflowEventConstructor OverflowEvent; + attribute ProgressEventConstructor ProgressEvent; + attribute TextEventConstructor TextEvent; + attribute UIEventConstructor UIEvent; + attribute WebKitAnimationEventConstructor WebKitAnimationEvent; + attribute WebKitTransitionEventConstructor WebKitTransitionEvent; + attribute WheelEventConstructor WheelEvent; + attribute MessageEventConstructor MessageEvent; + attribute EventExceptionConstructor EventException; + + attribute WebKitCSSKeyframeRuleConstructor WebKitCSSKeyframeRule; + attribute WebKitCSSKeyframesRuleConstructor WebKitCSSKeyframesRule; + +#if ENABLE_CHANNEL_MESSAGING + attribute MessagePortConstructor MessagePort; +#endif + + attribute ClipboardConstructor Clipboard; + + attribute FileConstructor File; + attribute FileListConstructor FileList; + + attribute NodeFilterConstructor NodeFilter; + attribute RangeConstructor Range; + attribute RangeExceptionConstructor RangeException; + + // 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 XMLHttpRequestUploadConstructor XMLHttpRequestUpload; + attribute XMLHttpRequestExceptionConstructor XMLHttpRequestException; + + attribute PluginConstructor Plugin; + attribute PluginArrayConstructor PluginArray; + + attribute MimeTypeConstructor MimeType; + attribute MimeTypeArrayConstructor MimeTypeArray; + +#if ENABLE_DOM_STORAGE + attribute StorageConstructor Storage; + attribute StorageEventConstructor StorageEvent; +#endif + + attribute [Conditional=VIDEO] HTMLAudioElementConstructor HTMLAudioElement; + attribute [Conditional=VIDEO] HTMLMediaElementConstructor HTMLMediaElement; + attribute [Conditional=VIDEO] HTMLVideoElementConstructor HTMLVideoElement; + attribute [Conditional=VIDEO] MediaErrorConstructor MediaError; + +#if ENABLE_XPATH + attribute XPathEvaluatorConstructor XPathEvaluator; + attribute XPathResultConstructor XPathResult; + attribute XPathExceptionConstructor XPathException; +#endif + +#if ENABLE_SVG + attribute SVGAngleConstructor SVGAngle; + attribute SVGColorConstructor SVGColor; +// attribute SVGCSSRuleConstructor SVGCSSRule; + attribute SVGExceptionConstructor SVGException; + attribute SVGGradientElementConstructor SVGGradientElement; + attribute SVGLengthConstructor SVGLength; + attribute SVGMarkerElementConstructor SVGMarkerElement; + attribute SVGPaintConstructor SVGPaint; + attribute SVGPathSegConstructor SVGPathSeg; + attribute SVGPreserveAspectRatioConstructor SVGPreserveAspectRatio; + attribute SVGRenderingIntentConstructor SVGRenderingIntent; + attribute SVGTextContentElementConstructor SVGTextContentElement; + attribute SVGTextPathElementConstructor SVGTextPathElement; + attribute SVGTransformConstructor SVGTransform; + attribute SVGUnitTypesConstructor SVGUnitTypes; +// attribute SVGZoomAndPanConstructor SVGZoomAndPan; +#endif + +#if ENABLE_SVG_FILTERS + attribute SVGComponentTransferFunctionElementConstructor SVGComponentTransferFunctionElement; + attribute SVGFEBlendElementConstructor SVGFEBlendElement; + attribute SVGFEColorMatrixElementConstructor SVGFEColorMatrixElement; + attribute SVGFECompositeElementConstructor SVGFECompositeElement; +// attribute SVGFEConvolveMatrixElementConstructor SVGFEConvolveMatrixElement; + attribute SVGFEDisplacementMapElementConstructor SVGFEDisplacementMapElement; +// attribute SVGFEMorphologyElementConstructor SVGFEMorphologyElement; + attribute SVGFETurbulenceElementConstructor SVGFETurbulenceElement; +#endif + +#endif // defined(LANGUAGE_JAVASCRIPT) + }; + +} diff --git a/src/3rdparty/webkit/WebCore/page/DragActions.h b/src/3rdparty/webkit/WebCore/page/DragActions.h new file mode 100644 index 0000000..37b783b --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/DragActions.h @@ -0,0 +1,66 @@ +/* + * 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. + */ + +#ifndef DragActions_h +#define DragActions_h + +#include <limits.h> + +namespace WebCore { + + // WebCoreDragDestinationAction should be kept in sync with WebDragDestinationAction + typedef enum { + DragDestinationActionNone = 0, + DragDestinationActionDHTML = 1, + DragDestinationActionEdit = 2, + DragDestinationActionLoad = 4, + DragDestinationActionAny = UINT_MAX + } DragDestinationAction; + + // WebCoreDragSourceAction should be kept in sync with WebDragSourceAction + typedef enum { + DragSourceActionNone = 0, + DragSourceActionDHTML = 1, + DragSourceActionImage = 2, + DragSourceActionLink = 4, + DragSourceActionSelection = 8, + DragSourceActionAny = UINT_MAX + } DragSourceAction; + + //matches NSDragOperation + typedef enum { + DragOperationNone = 0, + DragOperationCopy = 1, + DragOperationLink = 2, + DragOperationGeneric = 4, + DragOperationPrivate = 8, + DragOperationMove = 16, + DragOperationDelete = 32, + DragOperationEvery = UINT_MAX + } DragOperation; + +} + +#endif // !DragActions_h diff --git a/src/3rdparty/webkit/WebCore/page/DragClient.h b/src/3rdparty/webkit/WebCore/page/DragClient.h new file mode 100644 index 0000000..4f343a0 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/DragClient.h @@ -0,0 +1,81 @@ +/* + * 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. + */ + + +#ifndef DragClient_h +#define DragClient_h + +#include "DragActions.h" +#include "DragImage.h" +#include "IntPoint.h" + +#if PLATFORM(MAC) +#ifdef __OBJC__ +@class DOMElement; +@class NSURL; +@class NSString; +@class NSPasteboard; +#else +class DOMElement; +class NSURL; +class NSString; +class NSPasteboard; +#endif +#endif + +namespace WebCore { + + class Clipboard; + class DragData; + class Frame; + class Image; + class HTMLImageElement; + + class DragClient { + public: + virtual void willPerformDragDestinationAction(DragDestinationAction, DragData*) = 0; + virtual void willPerformDragSourceAction(DragSourceAction, const IntPoint&, Clipboard*) = 0; + virtual DragDestinationAction actionMaskForDrag(DragData*) = 0; + //We work in window rather than view coordinates here + virtual DragSourceAction dragSourceActionMaskForPoint(const IntPoint& windowPoint) = 0; + + virtual void startDrag(DragImageRef dragImage, const IntPoint& dragImageOrigin, const IntPoint& eventPos, Clipboard*, Frame*, bool linkDrag = false) = 0; + virtual DragImageRef createDragImageForLink(KURL&, const String& label, Frame*) = 0; + + virtual void dragControllerDestroyed() = 0; +#if PLATFORM(MAC) + //Mac specific helper functions to allow access to functionality in webkit -- such as + //web archives and NSPasteboard extras + //not abstract as that would require another #if PLATFORM(MAC) for the SVGImage client empty impl + virtual void declareAndWriteDragImage(NSPasteboard*, DOMElement*, NSURL*, NSString*, Frame*) {}; +#endif + + virtual ~DragClient() {}; + }; + +} + +#endif // !DragClient_h + diff --git a/src/3rdparty/webkit/WebCore/page/DragController.cpp b/src/3rdparty/webkit/WebCore/page/DragController.cpp new file mode 100644 index 0000000..8490f2d --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/DragController.cpp @@ -0,0 +1,781 @@ +/* + * 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 "CSSStyleDeclaration.h" +#include "Clipboard.h" +#include "ClipboardAccessPolicy.h" +#include "DocLoader.h" +#include "Document.h" +#include "DocumentFragment.h" +#include "DragActions.h" +#include "DragClient.h" +#include "DragData.h" +#include "Editor.h" +#include "EditorClient.h" +#include "Element.h" +#include "EventHandler.h" +#include "FloatRect.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameView.h" +#include "HTMLAnchorElement.h" +#include "HTMLInputElement.h" +#include "HTMLNames.h" +#include "HitTestResult.h" +#include "Image.h" +#include "MoveSelectionCommand.h" +#include "Node.h" +#include "Page.h" +#include "RenderFileUploadControl.h" +#include "RenderImage.h" +#include "ReplaceSelectionCommand.h" +#include "ResourceRequest.h" +#include "SelectionController.h" +#include "Settings.h" +#include "SystemTime.h" +#include "Text.h" +#include "htmlediting.h" +#include "markup.h" +#include <wtf/RefPtr.h> + +namespace WebCore { + +static PlatformMouseEvent createMouseEvent(DragData* dragData) +{ + // FIXME: We should fake modifier keys here. + return PlatformMouseEvent(dragData->clientPosition(), dragData->globalPosition(), + LeftButton, MouseEventMoved, 0, false, false, false, false, currentTime()); + +} + +DragController::DragController(Page* page, DragClient* client) + : m_page(page) + , m_client(client) + , m_document(0) + , m_dragInitiator(0) + , m_dragDestinationAction(DragDestinationActionNone) + , m_dragSourceAction(DragSourceActionNone) + , m_didInitiateDrag(false) + , m_isHandlingDrag(false) + , m_dragOperation(DragOperationNone) +{ +} + +DragController::~DragController() +{ + m_client->dragControllerDestroyed(); +} + +static PassRefPtr<DocumentFragment> documentFragmentFromDragData(DragData* dragData, RefPtr<Range> context, + bool allowPlainText, bool& chosePlainText) +{ + ASSERT(dragData); + chosePlainText = false; + + Document* document = context->ownerDocument(); + ASSERT(document); + if (document && dragData->containsCompatibleContent()) { + if (PassRefPtr<DocumentFragment> fragment = dragData->asFragment(document)) + return fragment; + + if (dragData->containsURL()) { + String title; + String url = dragData->asURL(&title); + if (!url.isEmpty()) { + ExceptionCode ec; + RefPtr<HTMLAnchorElement> anchor = static_cast<HTMLAnchorElement*>(document->createElement("a", ec).get()); + anchor->setHref(url); + RefPtr<Node> anchorText = document->createTextNode(title); + anchor->appendChild(anchorText, ec); + RefPtr<DocumentFragment> fragment = document->createDocumentFragment(); + fragment->appendChild(anchor, ec); + return fragment.get(); + } + } + } + if (allowPlainText && dragData->containsPlainText()) { + chosePlainText = true; + return createFragmentFromText(context.get(), dragData->asPlainText()).get(); + } + + return 0; +} + +bool DragController::dragIsMove(SelectionController* selection, DragData* dragData) +{ + return m_document == m_dragInitiator + && selection->isContentEditable() + && !isCopyKeyDown(); +} + +void DragController::cancelDrag() +{ + m_page->dragCaretController()->clear(); +} + +void DragController::dragEnded() +{ + m_dragInitiator = 0; + m_didInitiateDrag = false; + m_page->dragCaretController()->clear(); +} + +DragOperation DragController::dragEntered(DragData* dragData) +{ + return dragEnteredOrUpdated(dragData); +} + +void DragController::dragExited(DragData* dragData) +{ + ASSERT(dragData); + Frame* mainFrame = m_page->mainFrame(); + + if (RefPtr<FrameView> v = mainFrame->view()) { + ClipboardAccessPolicy policy = mainFrame->loader()->baseURL().isLocalFile() ? ClipboardReadable : ClipboardTypesReadable; + RefPtr<Clipboard> clipboard = dragData->createClipboard(policy); + clipboard->setSourceOperation(dragData->draggingSourceOperationMask()); + mainFrame->eventHandler()->cancelDragAndDrop(createMouseEvent(dragData), clipboard.get()); + clipboard->setAccessPolicy(ClipboardNumb); // invalidate clipboard here for security + } + + cancelDrag(); + m_document = 0; +} + +DragOperation DragController::dragUpdated(DragData* dragData) +{ + return dragEnteredOrUpdated(dragData); +} + +bool DragController::performDrag(DragData* dragData) +{ + ASSERT(dragData); + m_document = m_page->mainFrame()->documentAtPoint(dragData->clientPosition()); + if (m_isHandlingDrag) { + ASSERT(m_dragDestinationAction & DragDestinationActionDHTML); + m_client->willPerformDragDestinationAction(DragDestinationActionDHTML, dragData); + RefPtr<Frame> mainFrame = m_page->mainFrame(); + if (mainFrame->view()) { + // Sending an event can result in the destruction of the view and part. + RefPtr<Clipboard> clipboard = dragData->createClipboard(ClipboardReadable); + clipboard->setSourceOperation(dragData->draggingSourceOperationMask()); + mainFrame->eventHandler()->performDragAndDrop(createMouseEvent(dragData), clipboard.get()); + clipboard->setAccessPolicy(ClipboardNumb); // invalidate clipboard here for security + } + m_document = 0; + return true; + } + + if ((m_dragDestinationAction & DragDestinationActionEdit) && concludeDrag(dragData, m_dragDestinationAction)) { + m_document = 0; + return true; + } + + m_document = 0; + + if (operationForLoad(dragData) == DragOperationNone) + return false; + + m_client->willPerformDragDestinationAction(DragDestinationActionLoad, dragData); + m_page->mainFrame()->loader()->load(ResourceRequest(dragData->asURL())); + return true; +} + +DragOperation DragController::dragEnteredOrUpdated(DragData* dragData) +{ + ASSERT(dragData); + IntPoint windowPoint = dragData->clientPosition(); + + Document* newDraggingDoc = 0; + if (Frame* frame = m_page->mainFrame()) + newDraggingDoc = frame->documentAtPoint(windowPoint); + if (m_document != newDraggingDoc) { + if (m_document) + cancelDrag(); + m_document = newDraggingDoc; + } + + m_dragDestinationAction = m_client->actionMaskForDrag(dragData); + + DragOperation operation = DragOperationNone; + + if (m_dragDestinationAction == DragDestinationActionNone) + cancelDrag(); + else { + operation = tryDocumentDrag(dragData, m_dragDestinationAction); + if (operation == DragOperationNone && (m_dragDestinationAction & DragDestinationActionLoad)) + return operationForLoad(dragData); + } + + return operation; +} + +static HTMLInputElement* asFileInput(Node* node) +{ + ASSERT(node); + + // The button for a FILE input is a sub element with no set input type + // In order to get around this problem we assume any non-FILE input element + // is this internal button, and try querying the shadow parent node. + if (node->hasTagName(HTMLNames::inputTag) && node->isShadowNode() && static_cast<HTMLInputElement*>(node)->inputType() != HTMLInputElement::FILE) + node = node->shadowParentNode(); + + if (!node || !node->hasTagName(HTMLNames::inputTag)) + return 0; + + HTMLInputElement* inputElem = static_cast<HTMLInputElement*>(node); + if (inputElem->inputType() == HTMLInputElement::FILE) + return inputElem; + + return 0; +} + +DragOperation DragController::tryDocumentDrag(DragData* dragData, DragDestinationAction actionMask) +{ + ASSERT(dragData); + + if (!m_document) + return DragOperationNone; + + DragOperation operation = DragOperationNone; + if (actionMask & DragDestinationActionDHTML) + operation = tryDHTMLDrag(dragData); + m_isHandlingDrag = operation != DragOperationNone; + + RefPtr<FrameView> frameView = m_document->view(); + if (!frameView) + return operation; + + if ((actionMask & DragDestinationActionEdit) && !m_isHandlingDrag && canProcessDrag(dragData)) { + if (dragData->containsColor()) + return DragOperationGeneric; + + IntPoint dragPos = dragData->clientPosition(); + IntPoint point = frameView->windowToContents(dragPos); + Element* element = m_document->elementFromPoint(point.x(), point.y()); + ASSERT(element); + Frame* innerFrame = element->document()->frame(); + ASSERT(innerFrame); + if (!asFileInput(element)) { + Selection dragCaret; + if (Frame* frame = m_document->frame()) + dragCaret = frame->visiblePositionForPoint(point); + m_page->dragCaretController()->setSelection(dragCaret); + } + + return dragIsMove(innerFrame->selection(), dragData) ? DragOperationMove : DragOperationCopy; + } + + m_page->dragCaretController()->clear(); + return operation; +} + +DragSourceAction DragController::delegateDragSourceAction(const IntPoint& windowPoint) +{ + m_dragSourceAction = m_client->dragSourceActionMaskForPoint(windowPoint); + return m_dragSourceAction; +} + +DragOperation DragController::operationForLoad(DragData* dragData) +{ + ASSERT(dragData); + Document* doc = 0; + doc = m_page->mainFrame()->documentAtPoint(dragData->clientPosition()); + if (doc && (m_didInitiateDrag || doc->isPluginDocument() || (doc->frame() && doc->frame()->editor()->clientIsEditable()))) + return DragOperationNone; + return dragOperation(dragData); +} + +static bool setSelectionToDragCaret(Frame* frame, Selection& dragCaret, RefPtr<Range>& range, const IntPoint& point) +{ + frame->selection()->setSelection(dragCaret); + if (frame->selection()->isNone()) { + dragCaret = frame->visiblePositionForPoint(point); + frame->selection()->setSelection(dragCaret); + range = dragCaret.toRange(); + } + return !frame->selection()->isNone() && frame->selection()->isContentEditable(); +} + +bool DragController::concludeDrag(DragData* dragData, DragDestinationAction actionMask) +{ + ASSERT(dragData); + ASSERT(!m_isHandlingDrag); + ASSERT(actionMask & DragDestinationActionEdit); + + if (!m_document) + return false; + + IntPoint point = m_document->view()->windowToContents(dragData->clientPosition()); + Element* element = m_document->elementFromPoint(point.x(), point.y()); + ASSERT(element); + Frame* innerFrame = element->ownerDocument()->frame(); + ASSERT(innerFrame); + + if (dragData->containsColor()) { + Color color = dragData->asColor(); + if (!color.isValid()) + return false; + if (!innerFrame) + return false; + RefPtr<Range> innerRange = innerFrame->selection()->toRange(); + RefPtr<CSSStyleDeclaration> style = m_document->createCSSStyleDeclaration(); + ExceptionCode ec; + style->setProperty("color", color.name(), ec); + if (!innerFrame->editor()->shouldApplyStyle(style.get(), innerRange.get())) + return false; + m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dragData); + innerFrame->editor()->applyStyle(style.get(), EditActionSetColor); + return true; + } + + if (!m_page->dragController()->canProcessDrag(dragData)) { + m_page->dragCaretController()->clear(); + return false; + } + + if (HTMLInputElement* fileInput = asFileInput(element)) { + + if (!fileInput->isEnabled()) + return false; + + if (!dragData->containsFiles()) + return false; + + Vector<String> filenames; + dragData->asFilenames(filenames); + if (filenames.isEmpty()) + return false; + + // Ugly. For security none of the API's available to us to set the input value + // on file inputs. Even forcing a change in HTMLInputElement doesn't work as + // RenderFileUploadControl clears the file when doing updateFromElement() + RenderFileUploadControl* renderer = static_cast<RenderFileUploadControl*>(fileInput->renderer()); + + if (!renderer) + return false; + + renderer->receiveDroppedFiles(filenames); + return true; + } + + Selection dragCaret(m_page->dragCaretController()->selection()); + m_page->dragCaretController()->clear(); + RefPtr<Range> range = dragCaret.toRange(); + + // For range to be null a WebKit client must have done something bad while + // manually controlling drag behaviour + if (!range) + return false; + DocLoader* loader = range->ownerDocument()->docLoader(); + loader->setAllowStaleResources(true); + if (dragIsMove(innerFrame->selection(), dragData) || dragCaret.isContentRichlyEditable()) { + bool chosePlainText = false; + RefPtr<DocumentFragment> fragment = documentFragmentFromDragData(dragData, range, true, chosePlainText); + if (!fragment || !innerFrame->editor()->shouldInsertFragment(fragment, range, EditorInsertActionDropped)) { + loader->setAllowStaleResources(false); + return false; + } + + m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dragData); + if (dragIsMove(innerFrame->selection(), dragData)) { + bool smartMove = innerFrame->selectionGranularity() == WordGranularity + && innerFrame->editor()->smartInsertDeleteEnabled() + && dragData->canSmartReplace(); + applyCommand(MoveSelectionCommand::create(fragment, dragCaret.base(), smartMove)); + } else { + if (setSelectionToDragCaret(innerFrame, dragCaret, range, point)) + applyCommand(ReplaceSelectionCommand::create(m_document, fragment, true, dragData->canSmartReplace(), chosePlainText)); + } + } else { + String text = dragData->asPlainText(); + if (text.isEmpty() || !innerFrame->editor()->shouldInsertText(text, range.get(), EditorInsertActionDropped)) { + loader->setAllowStaleResources(false); + return false; + } + + m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dragData); + if (setSelectionToDragCaret(innerFrame, dragCaret, range, point)) + applyCommand(ReplaceSelectionCommand::create(m_document, createFragmentFromText(range.get(), text), true, false, true)); + } + loader->setAllowStaleResources(false); + + return true; +} + + +bool DragController::canProcessDrag(DragData* dragData) +{ + ASSERT(dragData); + + if (!dragData->containsCompatibleContent()) + return false; + + IntPoint point = m_page->mainFrame()->view()->windowToContents(dragData->clientPosition()); + HitTestResult result = HitTestResult(point); + if (!m_page->mainFrame()->contentRenderer()) + return false; + + result = m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(point, true); + + if (!result.innerNonSharedNode()) + return false; + + if (dragData->containsFiles() && asFileInput(result.innerNonSharedNode())) + return true; + + if (!result.innerNonSharedNode()->isContentEditable()) + return false; + + if (m_didInitiateDrag && m_document == m_dragInitiator && result.isSelected()) + return false; + + return true; +} + +DragOperation DragController::tryDHTMLDrag(DragData* dragData) +{ + ASSERT(dragData); + ASSERT(m_document); + DragOperation op = DragOperationNone; + RefPtr<Frame> frame = m_page->mainFrame(); + RefPtr<FrameView> viewProtector = frame->view(); + if (!viewProtector) + return DragOperationNone; + + ClipboardAccessPolicy policy = frame->loader()->baseURL().isLocalFile() ? ClipboardReadable : ClipboardTypesReadable; + RefPtr<Clipboard> clipboard = dragData->createClipboard(policy); + DragOperation srcOp = dragData->draggingSourceOperationMask(); + clipboard->setSourceOperation(srcOp); + + PlatformMouseEvent event = createMouseEvent(dragData); + if (frame->eventHandler()->updateDragAndDrop(event, clipboard.get())) { + // *op unchanged if no source op was set + if (!clipboard->destinationOperation(op)) { + // The element accepted but they didn't pick an operation, so we pick one for them + // (as does WinIE). + if (srcOp & DragOperationCopy) + op = DragOperationCopy; + else if (srcOp & DragOperationMove || srcOp & DragOperationGeneric) + op = DragOperationMove; + else if (srcOp & DragOperationLink) + op = DragOperationLink; + else + op = DragOperationGeneric; + } else if (!(op & srcOp)) { + op = DragOperationNone; + } + + clipboard->setAccessPolicy(ClipboardNumb); // invalidate clipboard here for security + return op; + } + return op; +} + +bool DragController::mayStartDragAtEventLocation(const Frame* frame, const IntPoint& framePos) +{ + ASSERT(frame); + ASSERT(frame->settings()); + + if (!frame->view() || !frame->contentRenderer()) + return false; + + HitTestResult mouseDownTarget = HitTestResult(framePos); + + mouseDownTarget = frame->eventHandler()->hitTestResultAtPoint(framePos, true); + + if (mouseDownTarget.image() + && !mouseDownTarget.absoluteImageURL().isEmpty() + && frame->settings()->loadsImagesAutomatically() + && m_dragSourceAction & DragSourceActionImage) + return true; + + if (!mouseDownTarget.absoluteLinkURL().isEmpty() + && m_dragSourceAction & DragSourceActionLink + && mouseDownTarget.isLiveLink()) + return true; + + if (mouseDownTarget.isSelected() + && m_dragSourceAction & DragSourceActionSelection) + return true; + + return false; + +} + +static CachedImage* getCachedImage(Element* element) +{ + ASSERT(element); + RenderObject* renderer = element->renderer(); + if (!renderer || !renderer->isImage()) + return 0; + RenderImage* image = static_cast<RenderImage*>(renderer); + return image->cachedImage(); +} + +static Image* getImage(Element* element) +{ + ASSERT(element); + RenderObject* renderer = element->renderer(); + if (!renderer || !renderer->isImage()) + return 0; + + RenderImage* image = static_cast<RenderImage*>(renderer); + if (image->cachedImage() && !image->cachedImage()->errorOccurred()) + return image->cachedImage()->image(); + return 0; +} + +static void prepareClipboardForImageDrag(Frame* src, Clipboard* clipboard, Element* node, const KURL& linkURL, const KURL& imageURL, const String& label) +{ + RefPtr<Range> range = src->document()->createRange(); + ExceptionCode ec = 0; + range->selectNode(node, ec); + ASSERT(ec == 0); + src->selection()->setSelection(Selection(range.get(), DOWNSTREAM)); + clipboard->declareAndWriteDragImage(node, !linkURL.isEmpty() ? linkURL : imageURL, label, src); +} + +static IntPoint dragLocForDHTMLDrag(const IntPoint& mouseDraggedPoint, const IntPoint& dragOrigin, const IntPoint& dragImageOffset, bool isLinkImage) +{ + // dragImageOffset is the cursor position relative to the lower-left corner of the image. +#if PLATFORM(MAC) + // We add in the Y dimension because we are a flipped view, so adding moves the image down. + const int yOffset = dragImageOffset.y(); +#else + const int yOffset = -dragImageOffset.y(); +#endif + + if (isLinkImage) + return IntPoint(mouseDraggedPoint.x() - dragImageOffset.x(), mouseDraggedPoint.y() + yOffset); + + return IntPoint(dragOrigin.x() - dragImageOffset.x(), dragOrigin.y() + yOffset); +} + +static IntPoint dragLocForSelectionDrag(Frame* src) +{ + IntRect draggingRect = enclosingIntRect(src->selectionBounds()); + int xpos = draggingRect.right(); + xpos = draggingRect.x() < xpos ? draggingRect.x() : xpos; + int ypos = draggingRect.bottom(); +#if PLATFORM(MAC) + // Deal with flipped coordinates on Mac + ypos = draggingRect.y() > ypos ? draggingRect.y() : ypos; +#else + ypos = draggingRect.y() < ypos ? draggingRect.y() : ypos; +#endif + return IntPoint(xpos, ypos); +} + +bool DragController::startDrag(Frame* src, Clipboard* clipboard, DragOperation srcOp, const PlatformMouseEvent& dragEvent, const IntPoint& dragOrigin, bool isDHTMLDrag) +{ + ASSERT(src); + ASSERT(clipboard); + + if (!src->view() || !src->contentRenderer()) + return false; + + HitTestResult dragSource = HitTestResult(dragOrigin); + dragSource = src->eventHandler()->hitTestResultAtPoint(dragOrigin, true); + KURL linkURL = dragSource.absoluteLinkURL(); + KURL imageURL = dragSource.absoluteImageURL(); + bool isSelected = dragSource.isSelected(); + + IntPoint mouseDraggedPoint = src->view()->windowToContents(dragEvent.pos()); + + m_draggingImageURL = KURL(); + m_dragOperation = srcOp; + + DragImageRef dragImage = 0; + IntPoint dragLoc(0, 0); + IntPoint dragImageOffset(0, 0); + + if (isDHTMLDrag) + dragImage = clipboard->createDragImage(dragImageOffset); + + // We allow DHTML/JS to set the drag image, even if its a link, image or text we're dragging. + // This is in the spirit of the IE API, which allows overriding of pasteboard data and DragOp. + if (dragImage) { + dragLoc = dragLocForDHTMLDrag(mouseDraggedPoint, dragOrigin, dragImageOffset, !linkURL.isEmpty()); + m_dragOffset = dragImageOffset; + } + + bool startedDrag = true; // optimism - we almost always manage to start the drag + + Node* node = dragSource.innerNonSharedNode(); + + Image* image = getImage(static_cast<Element*>(node)); + if (!imageURL.isEmpty() && node && node->isElementNode() && image + && (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, dragSource.altDisplayString()); + } + + m_client->willPerformDragSourceAction(DragSourceActionImage, dragOrigin, clipboard); + + if (!dragImage) { + IntRect imageRect = dragSource.imageRect(); + imageRect.setLocation(m_page->mainFrame()->view()->windowToContents(src->view()->contentsToWindow(imageRect.location()))); + doImageDrag(element, dragOrigin, dragSource.imageRect(), clipboard, src, m_dragOffset); + } else + // DHTML defined drag image + doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false); + + } else if (!linkURL.isEmpty() && (m_dragSourceAction & DragSourceActionLink)) { + if (!clipboard->hasData()) + // Simplify whitespace so the title put on the clipboard resembles what the user sees + // on the web page. This includes replacing newlines with spaces. + clipboard->writeURL(linkURL, dragSource.textContent().simplifyWhiteSpace(), src); + + if (src->selection()->isCaret() && src->selection()->isContentEditable()) { + // a user can initiate a drag on a link without having any text + // selected. In this case, we should expand the selection to + // the enclosing anchor element + Position pos = src->selection()->base(); + Node* node = enclosingAnchorElement(pos); + if (node) + src->selection()->setSelection(Selection::selectionFromContentsOfNode(node)); + } + + m_client->willPerformDragSourceAction(DragSourceActionLink, dragOrigin, clipboard); + if (!dragImage) { + dragImage = m_client->createDragImageForLink(linkURL, dragSource.textContent(), src); + 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 (isSelected && (m_dragSourceAction & DragSourceActionSelection)) { + RefPtr<Range> selectionRange = src->selection()->toRange(); + ASSERT(selectionRange); + if (!clipboard->hasData()) + clipboard->writeRange(selectionRange.get(), src); + m_client->willPerformDragSourceAction(DragSourceActionSelection, dragOrigin, clipboard); + if (!dragImage) { + dragImage = createDragImageForSelection(src); + dragLoc = dragLocForSelectionDrag(src); + m_dragOffset = IntPoint((int)(dragOrigin.x() - dragLoc.x()), (int)(dragOrigin.y() - dragLoc.y())); + } + doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false); + } else if (isDHTMLDrag) { + ASSERT(m_dragSourceAction & DragSourceActionDHTML); + m_client->willPerformDragSourceAction(DragSourceActionDHTML, dragOrigin, clipboard); + doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false); + } else { + // Only way I know to get here is if to get here is if the original element clicked on in the mousedown is no longer + // under the mousedown point, so linkURL, imageURL and isSelected are all false/empty. + startedDrag = false; + } + + if (dragImage) + deleteDragImage(dragImage); + return startedDrag; +} + +void DragController::doImageDrag(Element* element, const IntPoint& dragOrigin, const IntRect& rect, Clipboard* clipboard, Frame* frame, IntPoint& dragImageOffset) +{ + IntPoint mouseDownPoint = dragOrigin; + DragImageRef dragImage; + IntPoint origin; + + Image* image = getImage(element); + if (image && image->size().height() * image->size().width() <= MaxOriginalImageArea + && (dragImage = createDragImageFromImage(image))) { + IntSize originalSize = rect.size(); + origin = rect.location(); + + dragImage = fitDragImageToMaxSize(dragImage, rect.size(), maxDragImageSize()); + dragImage = dissolveDragImageToFraction(dragImage, DragImageAlpha); + IntSize newSize = dragImageSize(dragImage); + + // Properly orient the drag image and orient it differently if it's smaller than the original + float scale = newSize.width() / (float)originalSize.width(); + float dx = origin.x() - mouseDownPoint.x(); + dx *= scale; + origin.setX((int)(dx + 0.5)); +#if PLATFORM(MAC) + //Compensate for accursed flipped coordinates in cocoa + origin.setY(origin.y() + originalSize.height()); +#endif + float dy = origin.y() - mouseDownPoint.y(); + dy *= scale; + origin.setY((int)(dy + 0.5)); + } else { + dragImage = createDragImageIconForCachedImage(getCachedImage(element)); + if (dragImage) + origin = IntPoint(DragIconRightInset - dragImageSize(dragImage).width(), DragIconBottomInset); + } + + dragImageOffset.setX(mouseDownPoint.x() + origin.x()); + dragImageOffset.setY(mouseDownPoint.y() + origin.y()); + doSystemDrag(dragImage, dragImageOffset, dragOrigin, clipboard, frame, false); + + deleteDragImage(dragImage); +} + +void DragController::doSystemDrag(DragImageRef image, const IntPoint& dragLoc, const IntPoint& eventPos, Clipboard* clipboard, Frame* frame, bool forLink) +{ + m_didInitiateDrag = true; + m_dragInitiator = frame->document(); + // Protect this frame and view, as a load may occur mid drag and attempt to unload this frame + RefPtr<Frame> frameProtector = m_page->mainFrame(); + RefPtr<FrameView> viewProtector = frameProtector->view(); + m_client->startDrag(image, viewProtector->windowToContents(frame->view()->contentsToWindow(dragLoc)), + viewProtector->windowToContents(frame->view()->contentsToWindow(eventPos)), clipboard, frameProtector.get(), forLink); + + cleanupAfterSystemDrag(); +} + +// Manual drag caret manipulation +void DragController::placeDragCaret(const IntPoint& windowPoint) +{ + Frame* mainFrame = m_page->mainFrame(); + Document* newDraggingDoc = mainFrame->documentAtPoint(windowPoint); + if (m_document != newDraggingDoc) { + if (m_document) + cancelDrag(); + m_document = newDraggingDoc; + } + if (!m_document) + return; + Frame* frame = m_document->frame(); + ASSERT(frame); + FrameView* frameView = frame->view(); + if (!frameView) + return; + IntPoint framePoint = frameView->windowToContents(windowPoint); + Selection dragCaret(frame->visiblePositionForPoint(framePoint)); + m_page->dragCaretController()->setSelection(dragCaret); +} + +} diff --git a/src/3rdparty/webkit/WebCore/page/DragController.h b/src/3rdparty/webkit/WebCore/page/DragController.h new file mode 100644 index 0000000..0c2504e --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/DragController.h @@ -0,0 +1,132 @@ +/* + * 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. + */ + +#ifndef DragController_h +#define DragController_h + +#include "DragActions.h" +#include "DragImage.h" +#include "IntPoint.h" +#include "IntRect.h" +#include "KURL.h" + +namespace WebCore { + + class Clipboard; + class Document; + class DragClient; + class DragData; + class Element; + class Frame; + class Image; + class Node; + class Page; + class PlatformMouseEvent; + class Range; + class SelectionController; + + class DragController { + public: + DragController(Page*, DragClient*); + ~DragController(); + DragClient* client() const { return m_client; } + + DragOperation dragEntered(DragData*); + void dragExited(DragData*); + DragOperation dragUpdated(DragData*); + bool performDrag(DragData*); + + //FIXME: It should be possible to remove a number of these accessors once all + //drag logic is in WebCore + void setDidInitiateDrag(bool initiated) { m_didInitiateDrag = initiated; } + bool didInitiateDrag() const { return m_didInitiateDrag; } + void setIsHandlingDrag(bool handling) { m_isHandlingDrag = handling; } + bool isHandlingDrag() const { return m_isHandlingDrag; } + void setDragOperation(DragOperation dragOp) { m_dragOperation = dragOp; } + DragOperation dragOperation() const { return m_dragOperation; } + void setDraggingImageURL(const KURL& url) { m_draggingImageURL = url; } + const KURL& draggingImageURL() const { return m_draggingImageURL; } + void setDragInitiator(Document* initiator) { m_dragInitiator = initiator; m_didInitiateDrag = true; } + Document* dragInitiator() const { return m_dragInitiator; } + void setDragOffset(const IntPoint& offset) { m_dragOffset = offset; } + const IntPoint& dragOffset() const { return m_dragOffset; } + DragSourceAction dragSourceAction() const { return m_dragSourceAction; } + + Document* document() const { return m_document; } + DragDestinationAction dragDestinationAction() const { return m_dragDestinationAction; } + DragSourceAction delegateDragSourceAction(const IntPoint& pagePoint); + + bool mayStartDragAtEventLocation(const Frame*, const IntPoint& framePos); + void dragEnded(); + + void placeDragCaret(const IntPoint&); + + bool startDrag(Frame* src, Clipboard*, DragOperation srcOp, const PlatformMouseEvent& dragEvent, const IntPoint& dragOrigin, bool isDHTMLDrag); + static const IntSize& maxDragImageSize(); + + static const int LinkDragBorderInset; + static const int MaxOriginalImageArea; + static const int DragIconRightInset; + static const int DragIconBottomInset; + static const float DragImageAlpha; + private: + bool canProcessDrag(DragData*); + bool concludeDrag(DragData*, DragDestinationAction); + DragOperation dragEnteredOrUpdated(DragData*); + DragOperation operationForLoad(DragData*); + DragOperation tryDocumentDrag(DragData*, DragDestinationAction); + DragOperation tryDHTMLDrag(DragData*); + DragOperation dragOperation(DragData*); + void cancelDrag(); + bool dragIsMove(SelectionController*, DragData*); + bool isCopyKeyDown(); + + 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(); + Page* m_page; + DragClient* m_client; + + //The Document the mouse was last dragged over + Document* m_document; + + //The Document (if any) that initiated the drag + Document* m_dragInitiator; + + DragDestinationAction m_dragDestinationAction; + DragSourceAction m_dragSourceAction; + bool m_didInitiateDrag; + bool m_isHandlingDrag; + DragOperation m_dragOperation; + IntPoint m_dragOffset; + KURL m_draggingImageURL; + + }; + +} + +#endif diff --git a/src/3rdparty/webkit/WebCore/page/EditorClient.h b/src/3rdparty/webkit/WebCore/page/EditorClient.h new file mode 100644 index 0000000..56d0435 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/EditorClient.h @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * 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. + */ + +#ifndef EditorClient_h +#define EditorClient_h + +#include "EditorInsertAction.h" +#include "PlatformString.h" +#include "TextAffinity.h" +#include <wtf/Forward.h> +#include <wtf/Vector.h> + +#if PLATFORM(MAC) +class NSArray; +class NSData; +class NSString; +class NSURL; +#endif + +namespace WebCore { + +class CSSStyleDeclaration; +class EditCommand; +class Element; +class Frame; +class HTMLElement; +class KeyboardEvent; +class Node; +class Range; +class Selection; +class String; +class VisiblePosition; + +struct GrammarDetail { + int location; + int length; + Vector<String> guesses; + String userDescription; +}; + +class EditorClient { +public: + virtual ~EditorClient() { } + virtual void pageDestroyed() = 0; + + virtual bool shouldDeleteRange(Range*) = 0; + virtual bool shouldShowDeleteInterface(HTMLElement*) = 0; + virtual bool smartInsertDeleteEnabled() = 0; + virtual bool isSelectTrailingWhitespaceEnabled() = 0; + virtual bool isContinuousSpellCheckingEnabled() = 0; + virtual void toggleContinuousSpellChecking() = 0; + virtual bool isGrammarCheckingEnabled() = 0; + virtual void toggleGrammarChecking() = 0; + virtual int spellCheckerDocumentTag() = 0; + + virtual bool isEditable() = 0; + + virtual bool shouldBeginEditing(Range*) = 0; + virtual bool shouldEndEditing(Range*) = 0; + virtual bool shouldInsertNode(Node*, Range*, EditorInsertAction) = 0; + virtual bool shouldInsertText(const String&, Range*, EditorInsertAction) = 0; + virtual bool shouldChangeSelectedRange(Range* fromRange, Range* toRange, EAffinity, bool stillSelecting) = 0; + + virtual bool shouldApplyStyle(CSSStyleDeclaration*, Range*) = 0; +// virtual bool shouldChangeTypingStyle(CSSStyleDeclaration* fromStyle, CSSStyleDeclaration* toStyle) = 0; +// virtual bool doCommandBySelector(SEL selector) = 0; + virtual bool shouldMoveRangeAfterDelete(Range*, Range*) = 0; + + virtual void didBeginEditing() = 0; + virtual void respondToChangedContents() = 0; + virtual void respondToChangedSelection() = 0; + virtual void didEndEditing() = 0; + virtual void didWriteSelectionToPasteboard() = 0; + virtual void didSetSelectionTypesForPasteboard() = 0; +// virtual void didChangeTypingStyle:(NSNotification *)notification = 0; +// virtual void didChangeSelection:(NSNotification *)notification = 0; +// virtual NSUndoManager* undoManager:(WebView *)webView = 0; + + virtual void registerCommandForUndo(PassRefPtr<EditCommand>) = 0; + virtual void registerCommandForRedo(PassRefPtr<EditCommand>) = 0; + virtual void clearUndoRedoOperations() = 0; + + virtual bool canUndo() const = 0; + virtual bool canRedo() const = 0; + + virtual void undo() = 0; + virtual void redo() = 0; + + virtual void handleKeyboardEvent(KeyboardEvent*) = 0; + virtual void handleInputMethodKeydown(KeyboardEvent*) = 0; + + virtual void textFieldDidBeginEditing(Element*) = 0; + virtual void textFieldDidEndEditing(Element*) = 0; + virtual void textDidChangeInTextField(Element*) = 0; + virtual bool doTextFieldCommandFromEvent(Element*, KeyboardEvent*) = 0; + virtual void textWillBeDeletedInTextField(Element*) = 0; + virtual void textDidChangeInTextArea(Element*) = 0; + +#if PLATFORM(MAC) + virtual NSString* userVisibleString(NSURL*) = 0; +#ifdef BUILDING_ON_TIGER + virtual NSArray* pasteboardTypesForSelection(Frame*) = 0; +#endif +#endif + + virtual void ignoreWordInSpellDocument(const String&) = 0; + virtual void learnWord(const String&) = 0; + virtual void checkSpellingOfString(const UChar*, int length, int* misspellingLocation, int* misspellingLength) = 0; + virtual void checkGrammarOfString(const UChar*, int length, Vector<GrammarDetail>&, int* badGrammarLocation, int* badGrammarLength) = 0; + virtual void updateSpellingUIWithGrammarString(const String&, const GrammarDetail& detail) = 0; + virtual void updateSpellingUIWithMisspelledWord(const String&) = 0; + virtual void showSpellingUI(bool show) = 0; + virtual bool spellingUIIsShowing() = 0; + virtual void getGuessesForWord(const String&, Vector<String>& guesses) = 0; + virtual void setInputMethodState(bool enabled) = 0; +}; + +} + +#endif // EditorClient_h diff --git a/src/3rdparty/webkit/WebCore/page/EventHandler.cpp b/src/3rdparty/webkit/WebCore/page/EventHandler.cpp new file mode 100644 index 0000000..cc0e358 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/EventHandler.cpp @@ -0,0 +1,2275 @@ +/* + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) + * + * 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 "AXObjectCache.h" +#include "CachedImage.h" +#include "ChromeClient.h" +#include "Cursor.h" +#include "Document.h" +#include "DragController.h" +#include "Editor.h" +#include "EventNames.h" +#include "FloatPoint.h" +#include "FloatRect.h" +#include "FocusController.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameTree.h" +#include "FrameView.h" +#include "HitTestRequest.h" +#include "HitTestResult.h" +#include "HTMLFrameSetElement.h" +#include "HTMLFrameElementBase.h" +#include "HTMLInputElement.h" +#include "HTMLNames.h" +#include "Image.h" +#include "InspectorController.h" +#include "KeyboardEvent.h" +#include "MouseEvent.h" +#include "MouseEventWithHitTestResults.h" +#include "Page.h" +#include "PlatformKeyboardEvent.h" +#include "PlatformWheelEvent.h" +#include "RenderFrameSet.h" +#include "RenderWidget.h" +#include "RenderView.h" +#include "Scrollbar.h" +#include "SelectionController.h" +#include "Settings.h" +#include "TextEvent.h" +#include <wtf/StdLibExtras.h> + +#if ENABLE(SVG) +#include "SVGDocument.h" +#include "SVGElementInstance.h" +#include "SVGNames.h" +#include "SVGUseElement.h" +#endif + +namespace WebCore { + +using namespace HTMLNames; + +// The link drag hysteresis is much larger than the others because there +// needs to be enough space to cancel the link press without starting a link drag, +// and because dragging links is rare. +const int LinkDragHysteresis = 40; +const int ImageDragHysteresis = 5; +const int TextDragHysteresis = 3; +const int GeneralDragHysteresis = 3; + +// Match key code of composition keydown event on windows. +// IE sends VK_PROCESSKEY which has value 229; +const int CompositionEventKeyCode = 229; + +#if ENABLE(SVG) +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; + +static Frame* subframeForTargetNode(Node*); +static Frame* subframeForHitTestResult(const MouseEventWithHitTestResults&); + +static inline void scrollAndAcceptEvent(float delta, ScrollDirection positiveDirection, ScrollDirection negativeDirection, PlatformWheelEvent& e, Node* node) +{ + if (!delta) + return; + if (e.granularity() == ScrollByPageWheelEvent) { + if (node->renderer()->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPage, 1)) + e.accept(); + return; + } + float pixelsToScroll = delta > 0 ? delta : -delta; + if (e.granularity() == ScrollByLineWheelEvent) + pixelsToScroll *= cMouseWheelPixelsPerLineStep; + if (node->renderer()->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPixel, pixelsToScroll)) + e.accept(); +} + +EventHandler::EventHandler(Frame* frame) + : m_frame(frame) + , m_mousePressed(false) + , m_mouseDownMayStartSelect(false) + , m_mouseDownMayStartDrag(false) + , m_mouseDownWasSingleClickInSelection(false) + , m_beganSelectingText(false) + , m_panScrollInProgress(false) + , m_hoverTimer(this, &EventHandler::hoverTimerFired) + , m_autoscrollTimer(this, &EventHandler::autoscrollTimerFired) + , m_autoscrollRenderer(0) + , m_autoscrollInProgress(false) + , m_mouseDownMayStartAutoscroll(false) + , m_mouseDownWasInSubframe(false) +#if ENABLE(SVG) + , m_svgPan(false) +#endif + , m_resizeLayer(0) + , m_capturingMouseEventsNode(0) + , m_clickCount(0) + , m_mouseDownTimestamp(0) + , m_pendingFrameUnloadEventCount(0) + , m_pendingFrameBeforeUnloadEventCount(0) +#if PLATFORM(MAC) + , m_mouseDownView(nil) + , m_sendingEventToSubview(false) + , m_activationEventNumber(0) +#endif +{ +} + +EventHandler::~EventHandler() +{ +} + +EventHandler::EventHandlerDragState& EventHandler::dragState() +{ + DEFINE_STATIC_LOCAL(EventHandlerDragState, state, ()); + return state; +} + +void EventHandler::clear() +{ + m_hoverTimer.stop(); + m_resizeLayer = 0; + m_nodeUnderMouse = 0; + m_lastNodeUnderMouse = 0; +#if ENABLE(SVG) + m_instanceUnderMouse = 0; + m_lastInstanceUnderMouse = 0; +#endif + m_lastMouseMoveEventSubframe = 0; + m_lastScrollbarUnderMouse = 0; + m_clickCount = 0; + m_clickNode = 0; + m_frameSetBeingResized = 0; + m_dragTarget = 0; + m_currentMousePosition = IntPoint(); + m_mousePressNode = 0; + m_mousePressed = false; + m_capturingMouseEventsNode = 0; +} + +void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& result) +{ + Node* innerNode = result.targetNode(); + Selection newSelection; + + if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) { + VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint())); + if (pos.isNotNull()) { + newSelection = Selection(pos); + newSelection.expandUsingGranularity(WordGranularity); + } + + if (newSelection.isRange()) { + m_frame->setSelectionGranularity(WordGranularity); + m_beganSelectingText = true; + if (result.event().clickCount() == 2 && m_frame->editor()->isSelectTrailingWhitespaceEnabled()) + newSelection.appendTrailingWhitespace(); + } + + if (m_frame->shouldChangeSelection(newSelection)) + m_frame->selection()->setSelection(newSelection); + } +} + +void EventHandler::selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults& result) +{ + if (!result.hitTestResult().isLiveLink()) + return selectClosestWordFromMouseEvent(result); + + Node* innerNode = result.targetNode(); + + if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) { + Selection newSelection; + Element* URLElement = result.hitTestResult().URLElement(); + VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint())); + if (pos.isNotNull() && pos.deepEquivalent().node()->isDescendantOf(URLElement)) + newSelection = Selection::selectionFromContentsOfNode(URLElement); + + if (newSelection.isRange()) { + m_frame->setSelectionGranularity(WordGranularity); + m_beganSelectingText = true; + } + + if (m_frame->shouldChangeSelection(newSelection)) + m_frame->selection()->setSelection(newSelection); + } +} + +bool EventHandler::handleMousePressEventDoubleClick(const MouseEventWithHitTestResults& event) +{ + if (event.event().button() != LeftButton) + return false; + + if (m_frame->selection()->isRange()) + // A double-click when range is already selected + // should not change the selection. So, do not call + // selectClosestWordFromMouseEvent, but do set + // m_beganSelectingText to prevent handleMouseReleaseEvent + // from setting caret selection. + m_beganSelectingText = true; + else + selectClosestWordFromMouseEvent(event); + + return true; +} + +bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event) +{ + if (event.event().button() != LeftButton) + return false; + + Node* innerNode = event.targetNode(); + if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect)) + return false; + + Selection newSelection; + VisiblePosition pos(innerNode->renderer()->positionForPoint(event.localPoint())); + if (pos.isNotNull()) { + newSelection = Selection(pos); + newSelection.expandUsingGranularity(ParagraphGranularity); + } + if (newSelection.isRange()) { + m_frame->setSelectionGranularity(ParagraphGranularity); + m_beganSelectingText = true; + } + + if (m_frame->shouldChangeSelection(newSelection)) + m_frame->selection()->setSelection(newSelection); + + return true; +} + +bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event) +{ + if (event.event().button() != LeftButton) + return false; + + Node* innerNode = event.targetNode(); + if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect)) + return false; + + // Extend the selection if the Shift key is down, unless the click is in a link. + bool extendSelection = event.event().shiftKey() && !event.isOverLink(); + + // Don't restart the selection when the mouse is pressed on an + // existing selection so we can allow for text dragging. + IntPoint vPoint = m_frame->view()->windowToContents(event.event().pos()); + if (!extendSelection && m_frame->selection()->contains(vPoint)) { + m_mouseDownWasSingleClickInSelection = true; + return false; + } + + VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(event.localPoint())); + if (visiblePos.isNull()) + visiblePos = VisiblePosition(innerNode, 0, DOWNSTREAM); + Position pos = visiblePos.deepEquivalent(); + + Selection newSelection = m_frame->selection()->selection(); + if (extendSelection && newSelection.isCaretOrRange()) { + m_frame->selection()->setLastChangeWasHorizontalExtension(false); + + // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection + // was created right-to-left + Position start = newSelection.start(); + Position end = newSelection.end(); + short before = Range::compareBoundaryPoints(pos.node(), pos.offset(), start.node(), start.offset()); + if (before <= 0) + newSelection = Selection(pos, end); + else + newSelection = Selection(start, pos); + + if (m_frame->selectionGranularity() != CharacterGranularity) + newSelection.expandUsingGranularity(m_frame->selectionGranularity()); + m_beganSelectingText = true; + } else { + newSelection = Selection(visiblePos); + m_frame->setSelectionGranularity(CharacterGranularity); + } + + if (m_frame->shouldChangeSelection(newSelection)) + m_frame->selection()->setSelection(newSelection); + + return true; +} + +bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& event) +{ + // Reset drag state. + dragState().m_dragSrc = 0; + + 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()); + + // Careful that the drag starting logic stays in sync with eventMayStartDrag() + m_mouseDownMayStartDrag = singleClick; + + m_mouseDownWasSingleClickInSelection = false; + + if (event.isOverWidget() && passWidgetMouseDownEventToWidget(event)) + return true; + +#if ENABLE(SVG) + if (m_frame->document()->isSVGDocument() && + static_cast<SVGDocument*>(m_frame->document())->zoomAndPanEnabled()) { + if (event.event().shiftKey() && singleClick) { + m_svgPan = true; + static_cast<SVGDocument*>(m_frame->document())->startPan(event.event().pos()); + return true; + } + } +#endif + + // We don't do this at the start of mouse down handling, + // because we don't want to do it until we know we didn't hit a widget. + if (singleClick) + focusDocumentView(); + + Node* innerNode = event.targetNode(); + + m_mousePressNode = innerNode; + m_dragStartPos = event.event().pos(); + + bool swallowEvent = false; + if (event.event().button() == LeftButton || event.event().button() == MiddleButton) { + m_frame->selection()->setCaretBlinkingSuspended(true); + m_mousePressed = true; + m_beganSelectingText = false; + + if (event.event().clickCount() == 2) + swallowEvent = handleMousePressEventDoubleClick(event); + else if (event.event().clickCount() >= 3) + swallowEvent = handleMousePressEventTripleClick(event); + else + swallowEvent = handleMousePressEventSingleClick(event); + } + + m_mouseDownMayStartAutoscroll = m_mouseDownMayStartSelect || + (m_mousePressNode && m_mousePressNode->renderer() && m_mousePressNode->renderer()->canBeProgramaticallyScrolled(true)); + + return swallowEvent; +} + +bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& event) +{ + if (handleDrag(event)) + return true; + + if (!m_mousePressed) + return false; + + Node* targetNode = event.targetNode(); + if (event.event().button() != LeftButton || !targetNode || !targetNode->renderer()) + return false; + +#if PLATFORM(MAC) // FIXME: Why does this assertion fire on other platforms? + ASSERT(m_mouseDownMayStartSelect || m_mouseDownMayStartAutoscroll); +#endif + + m_mouseDownMayStartDrag = false; + + if (m_mouseDownMayStartAutoscroll && !m_panScrollInProgress) { + // If the selection is contained in a layer that can scroll, that layer should handle the autoscroll + // Otherwise, let the bridge handle it so the view can scroll itself. + RenderObject* renderer = targetNode->renderer(); + while (renderer && !renderer->canBeProgramaticallyScrolled(false)) { + 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); + } + + m_mouseDownMayStartAutoscroll = false; + } + + updateSelectionForMouseDrag(targetNode, event.localPoint()); + return true; +} + +bool EventHandler::eventMayStartDrag(const PlatformMouseEvent& event) const +{ + // This is a pre-flight check of whether the event might lead to a drag being started. Be careful + // that its logic needs to stay in sync with handleMouseMoveEvent() and the way we setMouseDownMayStartDrag + // in handleMousePressEvent + + if (!m_frame->contentRenderer() || !m_frame->contentRenderer()->hasLayer() + || event.button() != LeftButton || event.clickCount() != 1) + return false; + + bool DHTMLFlag; + bool UAFlag; + allowDHTMLDrag(DHTMLFlag, UAFlag); + if (!DHTMLFlag && !UAFlag) + return false; + + HitTestRequest request(true, false); + HitTestResult result(m_frame->view()->windowToContents(event.pos())); + m_frame->contentRenderer()->layer()->hitTest(request, result); + bool srcIsDHTML; + return result.innerNode() && result.innerNode()->renderer()->draggableNode(DHTMLFlag, UAFlag, result.point().x(), result.point().y(), srcIsDHTML); +} + +void EventHandler::updateSelectionForMouseDrag() +{ + FrameView* view = m_frame->view(); + if (!view) + return; + RenderObject* renderer = m_frame->contentRenderer(); + if (!renderer) + return; + RenderLayer* layer = renderer->layer(); + if (!layer) + return; + + HitTestResult result(view->windowToContents(m_currentMousePosition)); + layer->hitTest(HitTestRequest(true, true, true), result); + updateSelectionForMouseDrag(result.innerNode(), result.localPoint()); +} + +void EventHandler::updateSelectionForMouseDrag(Node* targetNode, const IntPoint& localPoint) +{ + if (!m_mouseDownMayStartSelect) + return; + + if (!targetNode) + return; + + RenderObject* targetRenderer = targetNode->renderer(); + if (!targetRenderer) + return; + + if (!canMouseDragExtendSelect(targetNode)) + return; + + VisiblePosition targetPosition(targetRenderer->positionForPoint(localPoint)); + + // Don't modify the selection if we're not on a node. + if (targetPosition.isNull()) + return; + + // Restart the selection if this is the first mouse move. This work is usually + // done in handleMousePressEvent, but not if the mouse press was on an existing selection. + Selection newSelection = m_frame->selection()->selection(); + +#if ENABLE(SVG) + // Special case to limit selection to the containing block for SVG text. + // FIXME: Isn't there a better non-SVG-specific way to do this? + if (Node* selectionBaseNode = newSelection.base().node()) + if (RenderObject* selectionBaseRenderer = selectionBaseNode->renderer()) + if (selectionBaseRenderer->isSVGText()) + if (targetNode->renderer()->containingBlock() != selectionBaseRenderer->containingBlock()) + return; +#endif + + if (!m_beganSelectingText) { + m_beganSelectingText = true; + newSelection = Selection(targetPosition); + } + + newSelection.setExtent(targetPosition); + if (m_frame->selectionGranularity() != CharacterGranularity) + newSelection.expandUsingGranularity(m_frame->selectionGranularity()); + + if (m_frame->shouldChangeSelection(newSelection)) { + m_frame->selection()->setLastChangeWasHorizontalExtension(false); + m_frame->selection()->setSelection(newSelection); + } +} + +bool EventHandler::handleMouseUp(const MouseEventWithHitTestResults& event) +{ + if (eventLoopHandleMouseUp(event)) + return true; + + // If this was the first click in the window, we don't even want to clear the selection. + // This case occurs when the user clicks on a draggable element, since we have to process + // the mouse down and drag events to see if we might start a drag. For other first clicks + // in a window, we just don't acceptFirstMouse, and the whole down-drag-up sequence gets + // ignored upstream of this layer. + return eventActivatedView(event.event()); +} + +bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event) +{ + if (m_autoscrollInProgress) + stopAutoscrollTimer(); + + if (handleMouseUp(event)) + return true; + + // Used to prevent mouseMoveEvent from initiating a drag before + // the mouse is pressed again. + m_frame->selection()->setCaretBlinkingSuspended(false); + m_mousePressed = false; + m_mouseDownMayStartDrag = false; + m_mouseDownMayStartSelect = false; + m_mouseDownMayStartAutoscroll = false; + m_mouseDownWasInSubframe = false; + + bool handled = false; + + // Clear the selection if the mouse didn't move after the last mouse press. + // We do this so when clicking on the selection, the selection goes away. + // However, if we are editing, place the caret. + if (m_mouseDownWasSingleClickInSelection && !m_beganSelectingText + && m_dragStartPos == event.event().pos() + && m_frame->selection()->isRange()) { + Selection newSelection; + Node *node = event.targetNode(); + if (node && node->isContentEditable() && node->renderer()) { + VisiblePosition pos = node->renderer()->positionForPoint(event.localPoint()); + newSelection = Selection(pos); + } + if (m_frame->shouldChangeSelection(newSelection)) + m_frame->selection()->setSelection(newSelection); + + handled = true; + } + + m_frame->notifyRendererOfSelectionChange(true); + + m_frame->selection()->selectFrameElementInParentIfFullySelected(); + + 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(); + m_frame->view()->addPanScrollIcon(m_panScrollStartPos); + // If we're not in the top frame we notify it that we are using the panScroll + if (m_frame != m_frame->page()->mainFrame()) + m_frame->page()->mainFrame()->eventHandler()->setPanScrollInProgress(true); + } +#endif + + startAutoscrollTimer(); +} + +void EventHandler::autoscrollTimerFired(Timer<EventHandler>*) +{ + RenderObject* r = autoscrollRenderer(); + if (!r) { + stopAutoscrollTimer(); + return; + } + + if (m_autoscrollInProgress) { + if (!m_mousePressed) { + stopAutoscrollTimer(); + return; + } + r->autoscroll(); + } else { + // we verify that the main frame hasn't received the order to stop the panScroll + if (!m_frame->page()->mainFrame()->eventHandler()->panScrollInProgress()) { + stopAutoscrollTimer(); + return; + } +#if ENABLE(PAN_SCROLLING) + setPanScrollCursor(); + r->panScroll(m_panScrollStartPos); +#endif + } +} + +void EventHandler::setPanScrollCursor() +{ + // 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 + const int noScrollRadius = 9; + bool east = m_panScrollStartPos.x() < (m_currentMousePosition.x() - noScrollRadius); + bool west = m_panScrollStartPos.x() > (m_currentMousePosition.x() + noScrollRadius); + bool north = m_panScrollStartPos.y() > (m_currentMousePosition.y() + noScrollRadius); + bool south = m_panScrollStartPos.y() < (m_currentMousePosition.y() - noScrollRadius); + + if (north) { + if (east) + m_frame->view()->setCursor(northEastPanningCursor()); + else if (west) + m_frame->view()->setCursor(northWestPanningCursor()); + else + m_frame->view()->setCursor(northPanningCursor()); + } else if (south) { + if (east) + m_frame->view()->setCursor(southEastPanningCursor()); + else if (west) + m_frame->view()->setCursor(southWestPanningCursor()); + else + m_frame->view()->setCursor(southPanningCursor()); + } else if (east) + m_frame->view()->setCursor(eastPanningCursor()); + else if (west) + m_frame->view()->setCursor(westPanningCursor()); + else + m_frame->view()->setCursor(middlePanningCursor()); +} + +RenderObject* EventHandler::autoscrollRenderer() const +{ + return m_autoscrollRenderer; +} + +void EventHandler::updateAutoscrollRenderer() +{ + if (!m_autoscrollRenderer) + return; + + HitTestResult hitTest = hitTestResultAtPoint(m_panScrollStartPos, true); + + if (Node* nodeAtPoint = hitTest.innerNode()) + m_autoscrollRenderer = nodeAtPoint->renderer(); + + while (m_autoscrollRenderer && !m_autoscrollRenderer->canBeProgramaticallyScrolled(false)) + m_autoscrollRenderer = m_autoscrollRenderer->parent(); +} + +void EventHandler::setAutoscrollRenderer(RenderObject* renderer) +{ + m_autoscrollRenderer = renderer; +} + +void EventHandler::allowDHTMLDrag(bool& flagDHTML, bool& flagUA) const +{ + if (!m_frame || !m_frame->document()) { + flagDHTML = false; + flagUA = false; + return; + } + + unsigned mask = m_frame->page()->dragController()->delegateDragSourceAction(m_frame->view()->contentsToWindow(m_mouseDownPos)); + flagDHTML = (mask & DragSourceActionDHTML) != DragSourceActionNone; + flagUA = ((mask & DragSourceActionImage) || (mask & DragSourceActionLink) || (mask & DragSourceActionSelection)); +} + +HitTestResult EventHandler::hitTestResultAtPoint(const IntPoint& point, bool allowShadowContent) +{ + HitTestResult result(point); + if (!m_frame->contentRenderer()) + return result; + m_frame->contentRenderer()->layer()->hitTest(HitTestRequest(true, true), result); + + while (true) { + Node* n = result.innerNode(); + if (!result.isOverWidget() || !n || !n->renderer() || !n->renderer()->isWidget()) + break; + Widget* widget = static_cast<RenderWidget*>(n->renderer())->widget(); + if (!widget || !widget->isFrameView()) + break; + Frame* frame = static_cast<HTMLFrameElementBase*>(n)->contentFrame(); + if (!frame || !frame->contentRenderer()) + break; + FrameView* view = static_cast<FrameView*>(widget); + IntPoint widgetPoint(result.localPoint().x() + view->scrollX() - n->renderer()->borderLeft() - n->renderer()->paddingLeft(), + result.localPoint().y() + view->scrollY() - n->renderer()->borderTop() - n->renderer()->paddingTop()); + HitTestResult widgetHitTestResult(widgetPoint); + frame->contentRenderer()->layer()->hitTest(HitTestRequest(true, true), widgetHitTestResult); + result = widgetHitTestResult; + } + + // If our HitTestResult is not visible, then we started hit testing too far down the frame chain. + // Another hit test at the main frame level should get us the correct visible result. + Frame* resultFrame = result.innerNonSharedNode() ? result.innerNonSharedNode()->document()->frame() : 0; + Frame* mainFrame = m_frame->page()->mainFrame(); + if (m_frame != mainFrame && resultFrame && resultFrame != mainFrame && !resultFrame->editor()->insideVisibleArea(result.point())) { + IntPoint windowPoint = resultFrame->view()->contentsToWindow(result.point()); + IntPoint mainFramePoint = mainFrame->view()->windowToContents(windowPoint); + result = mainFrame->eventHandler()->hitTestResultAtPoint(mainFramePoint, allowShadowContent); + } + + if (!allowShadowContent) + 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)) + autoscrollRenderer()->stopAutoscroll(); +#if ENABLE(PAN_SCROLLING) + if (m_panScrollInProgress) { + m_frame->view()->removePanScrollIcon(); + m_frame->view()->setCursor(pointerCursor()); + } +#endif + + setAutoscrollRenderer(0); + } + + m_autoscrollTimer.stop(); + + m_panScrollInProgress = false; + // If we're not in the top frame we notify it that we are not using the panScroll anymore + if (m_frame->page() && m_frame != m_frame->page()->mainFrame()) + m_frame->page()->mainFrame()->eventHandler()->setPanScrollInProgress(false); + m_autoscrollInProgress = false; +} + +Node* EventHandler::mousePressNode() const +{ + return m_mousePressNode.get(); +} + +void EventHandler::setMousePressNode(PassRefPtr<Node> node) +{ + m_mousePressNode = node; +} + +bool EventHandler::scrollOverflow(ScrollDirection direction, ScrollGranularity granularity) +{ + if (!m_frame->document()) + return false; + + Node* node = m_frame->document()->focusedNode(); + if (!node) + node = m_mousePressNode.get(); + + if (node) { + RenderObject *r = node->renderer(); + if (r && !r->isListBox()) + return r->scroll(direction, granularity); + } + + return false; +} + +IntPoint EventHandler::currentMousePosition() const +{ + return m_currentMousePosition; +} + +Frame* subframeForHitTestResult(const MouseEventWithHitTestResults& hitTestResult) +{ + if (!hitTestResult.isOverWidget()) + return 0; + return subframeForTargetNode(hitTestResult.targetNode()); +} + +Frame* subframeForTargetNode(Node* node) +{ + if (!node) + return 0; + + RenderObject* renderer = node->renderer(); + if (!renderer || !renderer->isWidget()) + return 0; + + Widget* widget = static_cast<RenderWidget*>(renderer)->widget(); + if (!widget || !widget->isFrameView()) + return 0; + + return static_cast<FrameView*>(widget)->frame(); +} + +static bool isSubmitImage(Node* node) +{ + return node && node->hasTagName(inputTag) + && static_cast<HTMLInputElement*>(node)->inputType() == HTMLInputElement::IMAGE; +} + +// Returns true if the node's editable block is not current focused for editing +static bool nodeIsNotBeingEdited(Node* node, Frame* frame) +{ + return frame->selection()->rootEditableElement() != node->rootEditableElement(); +} + +Cursor EventHandler::selectCursor(const MouseEventWithHitTestResults& event, Scrollbar* scrollbar) +{ + // During selection, use an I-beam no matter what we're over. + // If you're capturing mouse events for a particular node, don't treat this as a selection. + if (m_mousePressed && m_mouseDownMayStartSelect && m_frame->selection()->isCaretOrRange() && !m_capturingMouseEventsNode) + return iBeamCursor(); + + Node* node = event.targetNode(); + RenderObject* renderer = node ? node->renderer() : 0; + RenderStyle* style = renderer ? renderer->style() : 0; + + if (renderer && renderer->isFrameSet()) { + RenderFrameSet* fs = static_cast<RenderFrameSet*>(renderer); + if (fs->canResizeRow(event.localPoint())) + return rowResizeCursor(); + if (fs->canResizeColumn(event.localPoint())) + return columnResizeCursor(); + } + + if (style && style->cursors()) { + const CursorList* cursors = style->cursors(); + for (unsigned i = 0; i < cursors->size(); ++i) { + CachedImage* cimage = (*cursors)[i].cursorImage.get(); + IntPoint hotSpot = (*cursors)[i].hotSpot; + if (!cimage) + continue; + // Limit the size of cursors so that they cannot be used to cover UI elements in chrome. + IntSize size = cimage->image()->size(); + if (size.width() > 128 || size.height() > 128) + continue; + // Do not let the hotspot be outside the bounds of the image. + if (hotSpot.x() < 0 || hotSpot.y() < 0 || hotSpot.x() > size.width() || hotSpot.y() > size.height()) + continue; + if (cimage->image()->isNull()) + break; + if (!cimage->errorOccurred()) + return Cursor(cimage->image(), hotSpot); + } + } + + switch (style ? style->cursor() : CURSOR_AUTO) { + case CURSOR_AUTO: { + bool editable = (node && node->isContentEditable()); + bool editableLinkEnabled = false; + + // If the link is editable, then we need to check the settings to see whether or not the link should be followed + if (editable) { + ASSERT(m_frame->settings()); + switch(m_frame->settings()->editableLinkBehavior()) { + default: + case EditableLinkDefaultBehavior: + case EditableLinkAlwaysLive: + editableLinkEnabled = true; + break; + + case EditableLinkNeverLive: + editableLinkEnabled = false; + break; + + case EditableLinkLiveWhenNotFocused: + editableLinkEnabled = nodeIsNotBeingEdited(node, m_frame) || event.event().shiftKey(); + break; + + case EditableLinkOnlyLiveWithShiftKey: + editableLinkEnabled = event.event().shiftKey(); + break; + } + } + + if ((event.isOverLink() || isSubmitImage(node)) && (!editable || editableLinkEnabled)) + return handCursor(); + RenderLayer* layer = renderer ? renderer->enclosingLayer() : 0; + bool inResizer = false; + if (m_frame->view() && layer && layer->isPointInResizeControl(m_frame->view()->windowToContents(event.event().pos()))) + inResizer = true; + if ((editable || (renderer && renderer->isText() && node->canStartSelection())) && !inResizer && !scrollbar) + return iBeamCursor(); + return pointerCursor(); + } + case CURSOR_CROSS: + return crossCursor(); + case CURSOR_POINTER: + return handCursor(); + case CURSOR_MOVE: + return moveCursor(); + case CURSOR_ALL_SCROLL: + return moveCursor(); + case CURSOR_E_RESIZE: + return eastResizeCursor(); + case CURSOR_W_RESIZE: + return westResizeCursor(); + case CURSOR_N_RESIZE: + return northResizeCursor(); + case CURSOR_S_RESIZE: + return southResizeCursor(); + case CURSOR_NE_RESIZE: + return northEastResizeCursor(); + case CURSOR_SW_RESIZE: + return southWestResizeCursor(); + case CURSOR_NW_RESIZE: + return northWestResizeCursor(); + case CURSOR_SE_RESIZE: + return southEastResizeCursor(); + case CURSOR_NS_RESIZE: + return northSouthResizeCursor(); + case CURSOR_EW_RESIZE: + return eastWestResizeCursor(); + case CURSOR_NESW_RESIZE: + return northEastSouthWestResizeCursor(); + case CURSOR_NWSE_RESIZE: + return northWestSouthEastResizeCursor(); + case CURSOR_COL_RESIZE: + return columnResizeCursor(); + case CURSOR_ROW_RESIZE: + return rowResizeCursor(); + case CURSOR_TEXT: + return iBeamCursor(); + case CURSOR_WAIT: + return waitCursor(); + case CURSOR_HELP: + return helpCursor(); + case CURSOR_VERTICAL_TEXT: + return verticalTextCursor(); + case CURSOR_CELL: + return cellCursor(); + case CURSOR_CONTEXT_MENU: + return contextMenuCursor(); + case CURSOR_PROGRESS: + return progressCursor(); + case CURSOR_NO_DROP: + return noDropCursor(); + case CURSOR_ALIAS: + return aliasCursor(); + case CURSOR_COPY: + return copyCursor(); + case CURSOR_NONE: + return noneCursor(); + case CURSOR_NOT_ALLOWED: + return notAllowedCursor(); + case CURSOR_DEFAULT: + return pointerCursor(); + case CURSOR_WEBKIT_ZOOM_IN: + return zoomInCursor(); + case CURSOR_WEBKIT_ZOOM_OUT: + return zoomOutCursor(); + case CURSOR_WEBKIT_GRAB: + return grabCursor(); + case CURSOR_WEBKIT_GRABBING: + return grabbingCursor(); + } + return pointerCursor(); +} + +bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent) +{ + if (!m_frame->document()) + return false; + + RefPtr<FrameView> protector(m_frame->view()); + + m_mousePressed = true; + m_currentMousePosition = mouseEvent.pos(); + m_mouseDownTimestamp = mouseEvent.timestamp(); + m_mouseDownMayStartDrag = false; + m_mouseDownMayStartSelect = false; + m_mouseDownMayStartAutoscroll = false; + m_mouseDownPos = m_frame->view()->windowToContents(mouseEvent.pos()); + m_mouseDownWasInSubframe = false; + + MouseEventWithHitTestResults mev = prepareMouseEvent(HitTestRequest(false, true), mouseEvent); + + if (!mev.targetNode()) { + invalidateClick(); + return false; + } + + m_mousePressNode = mev.targetNode(); + + InspectorController* inspector = m_frame->page()->inspectorController(); + if (inspector && inspector->enabled() && inspector->searchingForNodeInPage()) { + inspector->handleMousePressOnNode(m_mousePressNode.get()); + invalidateClick(); + return true; + } + + Frame* subframe = subframeForHitTestResult(mev); + if (subframe && passMousePressEventToSubframe(mev, subframe)) { + // Start capturing future events for this frame. We only do this if we didn't clear + // the m_mousePressed flag, which may happen if an AppKit widget entered a modal event loop. + if (m_mousePressed) + m_capturingMouseEventsNode = mev.targetNode(); + invalidateClick(); + return true; + } + +#if ENABLE(PAN_SCROLLING) + if (m_frame->page()->mainFrame()->eventHandler()->panScrollInProgress() || m_autoscrollInProgress) { + stopAutoscrollTimer(); + invalidateClick(); + return true; + } + + if (mouseEvent.button() == MiddleButton && !mev.isOverLink()) { + RenderObject* renderer = mev.targetNode()->renderer(); + + while (renderer && !renderer->canBeProgramaticallyScrolled(false)) { + if (!renderer->parent() && renderer->node() == renderer->document() && renderer->document()->ownerElement()) + renderer = renderer->document()->ownerElement()->renderer(); + else + renderer = renderer->parent(); + } + + if (renderer) { + m_panScrollInProgress = true; + handleAutoscroll(renderer); + invalidateClick(); + return true; + } + } +#endif + + m_clickCount = mouseEvent.clickCount(); + m_clickNode = mev.targetNode(); + + RenderLayer* layer = m_clickNode->renderer() ? m_clickNode->renderer()->enclosingLayer() : 0; + IntPoint p = m_frame->view()->windowToContents(mouseEvent.pos()); + if (layer && layer->isPointInResizeControl(p)) { + layer->setInResizeMode(true); + m_resizeLayer = layer; + m_offsetFromResizeCorner = layer->offsetFromResizeCorner(p); + invalidateClick(); + return true; + } + + bool swallowEvent = dispatchMouseEvent(eventNames().mousedownEvent, mev.targetNode(), true, m_clickCount, mouseEvent, true); + + // If the hit testing originally determined the event was in a scrollbar, refetch the MouseEventWithHitTestResults + // in case the scrollbar widget was destroyed when the mouse event was handled. + if (mev.scrollbar()) { + const bool wasLastScrollBar = mev.scrollbar() == m_lastScrollbarUnderMouse.get(); + mev = prepareMouseEvent(HitTestRequest(true, true), mouseEvent); + + if (wasLastScrollBar && mev.scrollbar() != m_lastScrollbarUnderMouse.get()) + m_lastScrollbarUnderMouse = 0; + } + + if (swallowEvent) { + // scrollbars should get events anyway, even disabled controls might be scrollable + if (mev.scrollbar()) + passMousePressEventToScrollbar(mev, mev.scrollbar()); + } else { + // Refetch the event target node if it currently is the shadow node inside an <input> element. + // 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()->isShadowNode() && mev.targetNode()->shadowParentNode()->hasTagName(inputTag)) + mev = prepareMouseEvent(HitTestRequest(true, true), mouseEvent); + + Scrollbar* scrollbar = m_frame->view()->scrollbarUnderMouse(mouseEvent); + if (!scrollbar) + scrollbar = mev.scrollbar(); + if (scrollbar && passMousePressEventToScrollbar(mev, scrollbar)) + swallowEvent = true; + else + swallowEvent = handleMousePressEvent(mev); + } + + return swallowEvent; +} + +// This method only exists for platforms that don't know how to deliver +bool EventHandler::handleMouseDoubleClickEvent(const PlatformMouseEvent& mouseEvent) +{ + if (!m_frame->document()) + return false; + + RefPtr<FrameView> protector(m_frame->view()); + + // We get this instead of a second mouse-up + m_mousePressed = false; + m_currentMousePosition = mouseEvent.pos(); + + MouseEventWithHitTestResults mev = prepareMouseEvent(HitTestRequest(false, true), mouseEvent); + Frame* subframe = subframeForHitTestResult(mev); + if (subframe && passMousePressEventToSubframe(mev, subframe)) { + m_capturingMouseEventsNode = 0; + return true; + } + + m_clickCount = mouseEvent.clickCount(); + bool swallowMouseUpEvent = dispatchMouseEvent(eventNames().mouseupEvent, mev.targetNode(), true, m_clickCount, mouseEvent, false); + + bool swallowClickEvent = false; + // Don't ever dispatch click events for right clicks + if (mouseEvent.button() != RightButton && mev.targetNode() == m_clickNode) + swallowClickEvent = dispatchMouseEvent(eventNames().clickEvent, mev.targetNode(), true, m_clickCount, mouseEvent, true); + + if (m_lastScrollbarUnderMouse) + swallowMouseUpEvent = m_lastScrollbarUnderMouse->mouseUp(); + + bool swallowMouseReleaseEvent = false; + if (!swallowMouseUpEvent) + swallowMouseReleaseEvent = handleMouseReleaseEvent(mev); + + invalidateClick(); + + return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent; +} + +bool EventHandler::mouseMoved(const PlatformMouseEvent& event) +{ + HitTestResult hoveredNode = HitTestResult(IntPoint()); + bool result = handleMouseMoveEvent(event, &hoveredNode); + + Page* page = m_frame->page(); + if (!page) + return result; + + hoveredNode.setToNonShadowAncestor(); + page->chrome()->mouseDidMoveOverElement(hoveredNode, event.modifierFlags()); + page->chrome()->setToolTip(hoveredNode); + return result; +} + +bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent, HitTestResult* hoveredNode) +{ + // in Radar 3703768 we saw frequent crashes apparently due to the + // part being null here, which seems impossible, so check for nil + // but also assert so that we can try to figure this out in debug + // builds, if it happens. + ASSERT(m_frame); + if (!m_frame || !m_frame->document()) + return false; + + RefPtr<FrameView> protector(m_frame->view()); + m_currentMousePosition = mouseEvent.pos(); + + if (m_hoverTimer.isActive()) + m_hoverTimer.stop(); + +#if ENABLE(SVG) + if (m_svgPan) { + static_cast<SVGDocument*>(m_frame->document())->updatePan(m_currentMousePosition); + return true; + } +#endif + + if (m_frameSetBeingResized) + return dispatchMouseEvent(eventNames().mousemoveEvent, m_frameSetBeingResized.get(), false, 0, mouseEvent, false); + + // Send events right to a scrollbar if the mouse is pressed. + if (m_lastScrollbarUnderMouse && m_mousePressed) + return m_lastScrollbarUnderMouse->mouseMoved(m_lastScrollbarUnderMouse->transformEvent(mouseEvent)); + + // Treat mouse move events while the mouse is pressed as "read-only" in prepareMouseEvent + // if we are allowed to select. + // This means that :hover and :active freeze in the state they were in when the mouse + // was pressed, rather than updating for nodes the mouse moves over as you hold the mouse down. + HitTestRequest request(m_mousePressed && m_mouseDownMayStartSelect, m_mousePressed, true); + MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent); + if (hoveredNode) + *hoveredNode = mev.hitTestResult(); + + Scrollbar* scrollbar = 0; + + if (m_resizeLayer && m_resizeLayer->inResizeMode()) + m_resizeLayer->resize(mouseEvent, m_offsetFromResizeCorner); + else { + if (m_frame->view()) + scrollbar = m_frame->view()->scrollbarUnderMouse(mouseEvent); + + if (!scrollbar) + scrollbar = mev.scrollbar(); + + if (m_lastScrollbarUnderMouse != scrollbar) { + // Send mouse exited to the old scrollbar. + if (m_lastScrollbarUnderMouse) + m_lastScrollbarUnderMouse->mouseExited(); + m_lastScrollbarUnderMouse = m_mousePressed ? 0 : scrollbar; + } + } + + bool swallowEvent = false; + RefPtr<Frame> newSubframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev); + + // We want mouseouts to happen first, from the inside out. First send a move event to the last subframe so that it will fire mouseouts. + if (m_lastMouseMoveEventSubframe && m_lastMouseMoveEventSubframe->tree()->isDescendantOf(m_frame) && m_lastMouseMoveEventSubframe != newSubframe) + passMouseMoveEventToSubframe(mev, m_lastMouseMoveEventSubframe.get()); + + if (newSubframe) { + // Update over/out state before passing the event to the subframe. + updateMouseEventTargetNode(mev.targetNode(), mouseEvent, true); + + // Event dispatch in updateMouseEventTargetNode may have caused the subframe of the target + // node to be detached from its FrameView, in which case the event should not be passed. + if (newSubframe->view()) + swallowEvent |= passMouseMoveEventToSubframe(mev, newSubframe.get(), hoveredNode); + } else { + if (scrollbar && !m_mousePressed) + scrollbar->mouseMoved(scrollbar->transformEvent(mouseEvent)); // Handle hover effects on platforms that support visual feedback on scrollbar hovering. + if ((!m_resizeLayer || !m_resizeLayer->inResizeMode()) && !m_frame->page()->mainFrame()->eventHandler()->panScrollInProgress() && m_frame->view()) + m_frame->view()->setCursor(selectCursor(mev, scrollbar)); + } + + m_lastMouseMoveEventSubframe = newSubframe; + + if (swallowEvent) + return true; + + swallowEvent = dispatchMouseEvent(eventNames().mousemoveEvent, mev.targetNode(), false, 0, mouseEvent, true); + if (!swallowEvent) + swallowEvent = handleMouseDraggedEvent(mev); + + return swallowEvent; +} + +void EventHandler::invalidateClick() +{ + m_clickCount = 0; + m_clickNode = 0; +} + +bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent) +{ + if (!m_frame->document()) + return false; + + RefPtr<FrameView> protector(m_frame->view()); + + m_mousePressed = false; + m_currentMousePosition = mouseEvent.pos(); + +#if ENABLE(SVG) + if (m_svgPan) { + m_svgPan = false; + static_cast<SVGDocument*>(m_frame->document())->updatePan(m_currentMousePosition); + return true; + } +#endif + + if (m_frameSetBeingResized) + return dispatchMouseEvent(eventNames().mouseupEvent, m_frameSetBeingResized.get(), true, m_clickCount, mouseEvent, false); + + if (m_lastScrollbarUnderMouse) { + invalidateClick(); + return m_lastScrollbarUnderMouse->mouseUp(); + } + + MouseEventWithHitTestResults mev = prepareMouseEvent(HitTestRequest(false, false, false, true), mouseEvent); + Frame* subframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev); + if (subframe && passMouseReleaseEventToSubframe(mev, subframe)) { + m_capturingMouseEventsNode = 0; + return true; + } + + bool swallowMouseUpEvent = dispatchMouseEvent(eventNames().mouseupEvent, mev.targetNode(), true, m_clickCount, mouseEvent, false); + + // Don't ever dispatch click events for right clicks + bool swallowClickEvent = false; + if (m_clickCount > 0 && mouseEvent.button() != RightButton && mev.targetNode() == m_clickNode) + swallowClickEvent = dispatchMouseEvent(eventNames().clickEvent, mev.targetNode(), true, m_clickCount, mouseEvent, true); + + if (m_resizeLayer) { + m_resizeLayer->setInResizeMode(false); + m_resizeLayer = 0; + } + + bool swallowMouseReleaseEvent = false; + if (!swallowMouseUpEvent) + swallowMouseReleaseEvent = handleMouseReleaseEvent(mev); + + invalidateClick(); + + return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent; +} + +bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Node* dragTarget, const PlatformMouseEvent& event, Clipboard* clipboard) +{ + IntPoint contentsPos = m_frame->view()->windowToContents(event.pos()); + + RefPtr<MouseEvent> me = MouseEvent::create(eventType, + true, true, m_frame->document()->defaultView(), + 0, event.globalX(), event.globalY(), contentsPos.x(), contentsPos.y(), + event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(), + 0, 0, clipboard); + + ExceptionCode ec = 0; + EventTargetNodeCast(dragTarget)->dispatchEvent(me.get(), ec); + return me->defaultPrevented(); +} + +bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard) +{ + bool accept = false; + + if (!m_frame->document()) + return false; + + if (!m_frame->view()) + return false; + + MouseEventWithHitTestResults mev = prepareMouseEvent(HitTestRequest(true, false), event); + + // Drag events should never go to text nodes (following IE, and proper mouseover/out dispatch) + Node* newTarget = mev.targetNode(); + if (newTarget && newTarget->isTextNode()) + newTarget = newTarget->parentNode(); + if (newTarget) + newTarget = newTarget->shadowAncestorNode(); + + if (m_dragTarget != newTarget) { + // FIXME: this ordering was explicitly chosen to match WinIE. However, + // it is sometimes incorrect when dragging within subframes, as seen with + // LayoutTests/fast/events/drag-in-frames.html. + if (newTarget) + if (newTarget->hasTagName(frameTag) || newTarget->hasTagName(iframeTag)) + accept = static_cast<HTMLFrameElementBase*>(newTarget)->contentFrame()->eventHandler()->updateDragAndDrop(event, clipboard); + else + accept = dispatchDragEvent(eventNames().dragenterEvent, newTarget, event, clipboard); + + if (m_dragTarget) { + Frame* frame = (m_dragTarget->hasTagName(frameTag) || m_dragTarget->hasTagName(iframeTag)) + ? static_cast<HTMLFrameElementBase*>(m_dragTarget.get())->contentFrame() : 0; + if (frame) + accept = frame->eventHandler()->updateDragAndDrop(event, clipboard); + else + dispatchDragEvent(eventNames().dragleaveEvent, m_dragTarget.get(), event, clipboard); + } + } else { + if (newTarget) + if (newTarget->hasTagName(frameTag) || newTarget->hasTagName(iframeTag)) + accept = static_cast<HTMLFrameElementBase*>(newTarget)->contentFrame()->eventHandler()->updateDragAndDrop(event, clipboard); + else + accept = dispatchDragEvent(eventNames().dragoverEvent, newTarget, event, clipboard); + } + m_dragTarget = newTarget; + + return accept; +} + +void EventHandler::cancelDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard) +{ + if (m_dragTarget) { + Frame* frame = (m_dragTarget->hasTagName(frameTag) || m_dragTarget->hasTagName(iframeTag)) + ? static_cast<HTMLFrameElementBase*>(m_dragTarget.get())->contentFrame() : 0; + if (frame) + frame->eventHandler()->cancelDragAndDrop(event, clipboard); + else + dispatchDragEvent(eventNames().dragleaveEvent, m_dragTarget.get(), event, clipboard); + } + clearDragState(); +} + +bool EventHandler::performDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard) +{ + bool accept = false; + if (m_dragTarget) { + Frame* frame = (m_dragTarget->hasTagName(frameTag) || m_dragTarget->hasTagName(iframeTag)) + ? static_cast<HTMLFrameElementBase*>(m_dragTarget.get())->contentFrame() : 0; + if (frame) + accept = frame->eventHandler()->performDragAndDrop(event, clipboard); + else + accept = dispatchDragEvent(eventNames().dropEvent, m_dragTarget.get(), event, clipboard); + } + clearDragState(); + return accept; +} + +void EventHandler::clearDragState() +{ + m_dragTarget = 0; + m_capturingMouseEventsNode = 0; +#if PLATFORM(MAC) + m_sendingEventToSubview = false; +#endif +} + +void EventHandler::setCapturingMouseEventsNode(PassRefPtr<Node> n) +{ + m_capturingMouseEventsNode = n; +} + +MouseEventWithHitTestResults EventHandler::prepareMouseEvent(const HitTestRequest& request, const PlatformMouseEvent& mev) +{ + ASSERT(m_frame); + ASSERT(m_frame->document()); + + IntPoint documentPoint = m_frame->view()->windowToContents(mev.pos()); + return m_frame->document()->prepareMouseEvent(request, documentPoint, mev); +} + +#if ENABLE(SVG) +static inline SVGElementInstance* instanceAssociatedWithShadowTreeElement(Node* referenceNode) +{ + if (!referenceNode || !referenceNode->isSVGElement()) + return 0; + + Node* shadowTreeElement = referenceNode->shadowTreeRootNode(); + if (!shadowTreeElement) + return 0; + + Node* shadowTreeParentElement = shadowTreeElement->shadowParentNode(); + if (!shadowTreeParentElement) + return 0; + + ASSERT(shadowTreeParentElement->hasTagName(useTag)); + return static_cast<SVGUseElement*>(shadowTreeParentElement)->instanceForShadowTreeElement(referenceNode); +} +#endif + +void EventHandler::updateMouseEventTargetNode(Node* targetNode, const PlatformMouseEvent& mouseEvent, bool fireMouseOverOut) +{ + Node* result = targetNode; + + // If we're capturing, we always go right to that node. + if (m_capturingMouseEventsNode) + result = m_capturingMouseEventsNode.get(); + else { + // If the target node is a text node, dispatch on the parent node - rdar://4196646 + if (result && result->isTextNode()) + result = result->parentNode(); + if (result) + result = result->shadowAncestorNode(); + } + m_nodeUnderMouse = result; +#if ENABLE(SVG) + m_instanceUnderMouse = instanceAssociatedWithShadowTreeElement(result); + + // <use> shadow tree elements may have been recloned, update node under mouse in any case + if (m_lastInstanceUnderMouse) { + SVGElement* lastCorrespondingElement = m_lastInstanceUnderMouse->correspondingElement(); + SVGElement* lastCorrespondingUseElement = m_lastInstanceUnderMouse->correspondingUseElement(); + + if (lastCorrespondingElement && lastCorrespondingUseElement) { + HashSet<SVGElementInstance*> instances = lastCorrespondingElement->instancesForElement(); + + // Locate the recloned shadow tree element for our corresponding instance + HashSet<SVGElementInstance*>::iterator end = instances.end(); + for (HashSet<SVGElementInstance*>::iterator it = instances.begin(); it != end; ++it) { + SVGElementInstance* instance = (*it); + ASSERT(instance->correspondingElement() == lastCorrespondingElement); + + if (instance == m_lastInstanceUnderMouse) + continue; + + if (instance->correspondingUseElement() != lastCorrespondingUseElement) + continue; + + SVGElement* shadowTreeElement = instance->shadowTreeElement(); + if (!shadowTreeElement->inDocument() || m_lastNodeUnderMouse == shadowTreeElement) + continue; + + m_lastNodeUnderMouse = shadowTreeElement; + m_lastInstanceUnderMouse = instance; + break; + } + } + } +#endif + + // Fire mouseout/mouseover if the mouse has shifted to a different node. + if (fireMouseOverOut) { + if (m_lastNodeUnderMouse && m_lastNodeUnderMouse->document() != m_frame->document()) { + m_lastNodeUnderMouse = 0; + m_lastScrollbarUnderMouse = 0; +#if ENABLE(SVG) + m_lastInstanceUnderMouse = 0; +#endif + } + + if (m_lastNodeUnderMouse != m_nodeUnderMouse) { + // send mouseout event to the old node + if (m_lastNodeUnderMouse) + EventTargetNodeCast(m_lastNodeUnderMouse.get())->dispatchMouseEvent(mouseEvent, eventNames().mouseoutEvent, 0, m_nodeUnderMouse.get()); + // send mouseover event to the new node + if (m_nodeUnderMouse) + EventTargetNodeCast(m_nodeUnderMouse.get())->dispatchMouseEvent(mouseEvent, eventNames().mouseoverEvent, 0, m_lastNodeUnderMouse.get()); + } + m_lastNodeUnderMouse = m_nodeUnderMouse; +#if ENABLE(SVG) + m_lastInstanceUnderMouse = instanceAssociatedWithShadowTreeElement(m_nodeUnderMouse.get()); +#endif + } +} + +bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targetNode, bool /*cancelable*/, int clickCount, const PlatformMouseEvent& mouseEvent, bool setUnder) +{ + updateMouseEventTargetNode(targetNode, mouseEvent, setUnder); + + bool swallowEvent = false; + + if (m_nodeUnderMouse) + swallowEvent = EventTargetNodeCast(m_nodeUnderMouse.get())->dispatchMouseEvent(mouseEvent, eventType, clickCount); + + if (!swallowEvent && eventType == eventNames().mousedownEvent) { + // 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(); + RenderObject* renderer = node ? node->renderer() : 0; + + // Walk up the render tree to search for a node to focus. + // Walking up the DOM tree wouldn't work for shadow trees, like those behind the engine-based text fields. + while (renderer) { + node = renderer->element(); + if (node && node->isFocusable()) { + // 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->isShadowNode() ? node->shadowParentNode() : node; + if (m_frame->selection()->isRange() && + m_frame->selection()->toRange()->compareNode(n, ec) == Range::NODE_INSIDE && + n->isDescendantOf(m_frame->document()->focusedNode())) + return false; + + break; + } + + renderer = renderer->parent(); + } + // 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 (node && node->isMouseFocusable()) { + if (!m_frame->page()->focusController()->setFocusedNode(node, m_frame)) + swallowEvent = true; + } else if (!node || !node->focused()) { + if (!m_frame->page()->focusController()->setFocusedNode(0, m_frame)) + swallowEvent = true; + } + } + + return swallowEvent; +} + +bool EventHandler::handleWheelEvent(PlatformWheelEvent& e) +{ + Document* doc = m_frame->document(); + if (!doc) + return false; + + RenderObject* docRenderer = doc->renderer(); + if (!docRenderer) + return false; + + IntPoint vPoint = m_frame->view()->windowToContents(e.pos()); + + HitTestRequest request(true, false); + HitTestResult result(vPoint); + doc->renderer()->layer()->hitTest(request, result); + Node* node = result.innerNode(); + + if (node) { + // Figure out which view to send the event to. + RenderObject* target = node->renderer(); + + if (result.isOverWidget() && target && target->isWidget()) { + Widget* widget = static_cast<RenderWidget*>(target)->widget(); + + if (widget && passWheelEventToWidget(e, widget)) { + e.accept(); + return true; + } + } + + node = node->shadowAncestorNode(); + EventTargetNodeCast(node)->dispatchWheelEvent(e); + if (e.isAccepted()) + return true; + + if (node->renderer()) { + // Just 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). + scrollAndAcceptEvent(e.deltaX(), ScrollLeft, ScrollRight, e, node); + scrollAndAcceptEvent(e.deltaY(), ScrollUp, ScrollDown, e, node); + } + } + + if (!e.isAccepted()) + m_frame->view()->wheelEvent(e); + + return e.isAccepted(); +} + +bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event) +{ + Document* doc = m_frame->document(); + FrameView* v = m_frame->view(); + if (!doc || !v) + return false; + + bool swallowEvent; + IntPoint viewportPos = v->windowToContents(event.pos()); + MouseEventWithHitTestResults mev = doc->prepareMouseEvent(HitTestRequest(false, true), viewportPos, event); + + // Context menu events shouldn't select text in GTK+ applications. +#if !PLATFORM(GTK) + if (!m_frame->selection()->contains(viewportPos) && + // 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. + (m_frame->selection()->isContentEditable() || mev.targetNode() && mev.targetNode()->isTextNode())) { + m_mouseDownMayStartSelect = true; // context menu events are always allowed to perform a selection + selectClosestWordOrLinkFromMouseEvent(mev); + } +#endif + + swallowEvent = dispatchMouseEvent(eventNames().contextmenuEvent, mev.targetNode(), true, 0, event, true); + + return swallowEvent; +} + +void EventHandler::scheduleHoverStateUpdate() +{ + if (!m_hoverTimer.isActive()) + m_hoverTimer.startOneShot(0); +} + +// Whether or not a mouse down can begin the creation of a selection. Fires the selectStart event. +bool EventHandler::canMouseDownStartSelect(Node* node) +{ + if (!node || !node->renderer()) + return true; + + // Some controls and images can't start a select on a mouse down. + if (!node->canStartSelection()) + return false; + + for (RenderObject* curr = node->renderer(); curr; curr = curr->parent()) + if (Node* node = curr->element()) + return EventTargetNodeCast(node)->dispatchEventForType(eventNames().selectstartEvent, true, true); + + return true; +} + +bool EventHandler::canMouseDragExtendSelect(Node* node) +{ + if (!node || !node->renderer()) + return true; + + for (RenderObject* curr = node->renderer(); curr; curr = curr->parent()) + if (Node* node = curr->element()) + return EventTargetNodeCast(node)->dispatchEventForType(eventNames().selectstartEvent, true, true); + + return true; +} + +void EventHandler::setResizingFrameSet(HTMLFrameSetElement* frameSet) +{ + m_frameSetBeingResized = frameSet; +} + +void EventHandler::resizeLayerDestroyed() +{ + ASSERT(m_resizeLayer); + m_resizeLayer = 0; +} + +void EventHandler::hoverTimerFired(Timer<EventHandler>*) +{ + m_hoverTimer.stop(); + + ASSERT(m_frame); + ASSERT(m_frame->document()); + + if (RenderObject* renderer = m_frame->contentRenderer()) { + HitTestResult result(m_frame->view()->windowToContents(m_currentMousePosition)); + renderer->layer()->hitTest(HitTestRequest(false, false, true), result); + m_frame->document()->updateRendering(); + } +} + +static EventTargetNode* eventTargetNodeForDocument(Document* doc) +{ + if (!doc) + return 0; + Node* node = doc->focusedNode(); + if (!node) { + if (doc->isHTMLDocument()) + node = doc->body(); + else + node = doc->documentElement(); + if (!node) + return 0; + } + return EventTargetNodeCast(node); +} + +bool EventHandler::handleAccessKey(const PlatformKeyboardEvent& evt) +{ + // FIXME: Ignoring the state of Shift key is what neither IE nor Firefox do. + // IE matches lower and upper case access keys regardless of Shift key state - but if both upper and + // lower case variants are present in a document, the correct element is matched based on Shift key state. + // Firefox only matches an access key if Shift is not pressed, and does that case-insensitively. + ASSERT(!(accessKeyModifiers() & PlatformKeyboardEvent::ShiftKey)); + if ((evt.modifiers() & ~PlatformKeyboardEvent::ShiftKey) != accessKeyModifiers()) + return false; + String key = evt.unmodifiedText(); + Element* elem = m_frame->document()->getElementByAccessKey(key.lower()); + if (!elem) + return false; + elem->accessKeyAction(false); + return true; +} + +#if !PLATFORM(MAC) +bool EventHandler::needsKeyboardEventDisambiguationQuirks() const +{ + return false; +} +#endif + +bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent) +{ +#if ENABLE(PAN_SCROLLING) + if (m_frame->page()->mainFrame()->eventHandler()->panScrollInProgress() || m_autoscrollInProgress) { + String escKeyId = "U+001B"; + // If a key is pressed while the autoscroll/panScroll is in progress then we want to stop + if (initialKeyEvent.keyIdentifier() == escKeyId && initialKeyEvent.type() == PlatformKeyboardEvent::KeyUp) + stopAutoscrollTimer(); + + // If we were in autoscroll/panscroll mode, we swallow the key event + return true; + } +#endif + + // Check for cases where we are too early for events -- possible unmatched key up + // from pressing return in the location bar. + RefPtr<EventTargetNode> node = eventTargetNodeForDocument(m_frame->document()); + if (!node) + return false; + + // FIXME: what is this doing here, in keyboard event handler? + m_frame->loader()->resetMultipleFormSubmissionProtection(); + + // In IE, access keys are special, they are handled after default keydown processing, but cannot be canceled - this is hard to match. + // On Mac OS X, we process them before dispatching keydown, as the default keydown handler implements Emacs key bindings, which may conflict + // with access keys. Then we dispatch keydown, but suppress its default handling. + // On Windows, WebKit explicitly calls handleAccessKey() instead of dispatching a keypress event for WM_SYSCHAR messages. + // Other platforms currently match either Mac or Windows behavior, depending on whether they send combined KeyDown events. + bool matchedAnAccessKey = false; + if (initialKeyEvent.type() == PlatformKeyboardEvent::KeyDown) + matchedAnAccessKey = handleAccessKey(initialKeyEvent); + + // FIXME: it would be fair to let an input method handle KeyUp events before DOM dispatch. + if (initialKeyEvent.type() == PlatformKeyboardEvent::KeyUp || initialKeyEvent.type() == PlatformKeyboardEvent::Char) + return !node->dispatchKeyEvent(initialKeyEvent); + + bool backwardCompatibilityMode = needsKeyboardEventDisambiguationQuirks(); + + ExceptionCode ec; + PlatformKeyboardEvent keyDownEvent = initialKeyEvent; + if (keyDownEvent.type() != PlatformKeyboardEvent::RawKeyDown) + keyDownEvent.disambiguateKeyDownEvent(PlatformKeyboardEvent::RawKeyDown, backwardCompatibilityMode); + RefPtr<KeyboardEvent> keydown = KeyboardEvent::create(keyDownEvent, m_frame->document()->defaultView()); + if (matchedAnAccessKey) + keydown->setDefaultPrevented(true); + keydown->setTarget(node); + + if (initialKeyEvent.type() == PlatformKeyboardEvent::RawKeyDown) { + node->dispatchEvent(keydown, ec); + return keydown->defaultHandled() || keydown->defaultPrevented(); + } + + // Run input method in advance of DOM event handling. This may result in the IM + // modifying the page prior the keydown event, but this behaviour is necessary + // 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()); + + bool handledByInputMethod = keydown->defaultHandled(); + + if (handledByInputMethod) { + keyDownEvent.setWindowsVirtualKeyCode(CompositionEventKeyCode); + keydown = KeyboardEvent::create(keyDownEvent, m_frame->document()->defaultView()); + keydown->setTarget(node); + keydown->setDefaultHandled(); + } + + node->dispatchEvent(keydown, ec); + bool keydownResult = keydown->defaultHandled() || keydown->defaultPrevented(); + if (handledByInputMethod || (keydownResult && !backwardCompatibilityMode)) + return keydownResult; + + // Focus may have changed during keydown handling, so refetch node. + // But if we are dispatching a fake backward compatibility keypress, then we pretend that the keypress happened on the original node. + if (!keydownResult) { + node = eventTargetNodeForDocument(m_frame->document()); + if (!node) + return false; + } + + PlatformKeyboardEvent keyPressEvent = initialKeyEvent; + keyPressEvent.disambiguateKeyDownEvent(PlatformKeyboardEvent::Char, backwardCompatibilityMode); + if (keyPressEvent.text().isEmpty()) + return keydownResult; + RefPtr<KeyboardEvent> keypress = KeyboardEvent::create(keyPressEvent, m_frame->document()->defaultView()); + keypress->setTarget(node); + if (keydownResult) + keypress->setDefaultPrevented(true); +#if PLATFORM(MAC) + keypress->keypressCommands() = keydown->keypressCommands(); +#endif + node->dispatchEvent(keypress, ec); + + return keydownResult || keypress->defaultPrevented() || keypress->defaultHandled(); +} + +void EventHandler::handleKeyboardSelectionMovement(KeyboardEvent* event) +{ + if (!event) + return; + + String key = event->keyIdentifier(); + bool isShifted = event->getModifierState("Shift"); + bool isOptioned = event->getModifierState("Alt"); + + if (key == "Up") { + m_frame->selection()->modify((isShifted) ? SelectionController::EXTEND : SelectionController::MOVE, SelectionController::BACKWARD, LineGranularity, true); + event->setDefaultHandled(); + } + else if (key == "Down") { + m_frame->selection()->modify((isShifted) ? SelectionController::EXTEND : SelectionController::MOVE, SelectionController::FORWARD, LineGranularity, true); + event->setDefaultHandled(); + } + else if (key == "Left") { + m_frame->selection()->modify((isShifted) ? SelectionController::EXTEND : SelectionController::MOVE, SelectionController::LEFT, (isOptioned) ? WordGranularity : CharacterGranularity, true); + event->setDefaultHandled(); + } + else if (key == "Right") { + m_frame->selection()->modify((isShifted) ? SelectionController::EXTEND : SelectionController::MOVE, SelectionController::RIGHT, (isOptioned) ? WordGranularity : CharacterGranularity, true); + event->setDefaultHandled(); + } +} + +void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event) +{ + if (event->type() == eventNames().keydownEvent) { + m_frame->editor()->handleKeyboardEvent(event); + if (event->defaultHandled()) + return; + const String& keyIdentifier = event->keyIdentifier(); + if (keyIdentifier == "U+0009") + defaultTabEventHandler(event); + else if (keyIdentifier == "U+0020") + defaultSpaceEventHandler(event); + + // provides KB navigation and selection for enhanced accessibility users + if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled()) + handleKeyboardSelectionMovement(event); + } + if (event->type() == eventNames().keypressEvent) { + m_frame->editor()->handleKeyboardEvent(event); + if (event->defaultHandled()) + return; + if (event->charCode() == ' ') + defaultSpaceEventHandler(event); + } +} + +bool EventHandler::dragHysteresisExceeded(const FloatPoint& floatDragViewportLocation) const +{ + IntPoint dragViewportLocation((int)floatDragViewportLocation.x(), (int)floatDragViewportLocation.y()); + return dragHysteresisExceeded(dragViewportLocation); +} + +bool EventHandler::dragHysteresisExceeded(const IntPoint& dragViewportLocation) const +{ + IntPoint dragLocation = m_frame->view()->windowToContents(dragViewportLocation); + IntSize delta = dragLocation - m_mouseDownPos; + + int threshold = GeneralDragHysteresis; + if (dragState().m_dragSrcIsImage) + threshold = ImageDragHysteresis; + else if (dragState().m_dragSrcIsLink) + threshold = LinkDragHysteresis; + else if (dragState().m_dragSrcInSelection) + threshold = TextDragHysteresis; + + return abs(delta.width()) >= threshold || abs(delta.height()) >= threshold; +} + +void EventHandler::freeClipboard() +{ + if (dragState().m_dragClipboard) + dragState().m_dragClipboard->setAccessPolicy(ClipboardNumb); +} + +bool EventHandler::shouldDragAutoNode(Node* node, const IntPoint& point) const +{ + ASSERT(node); + if (node->hasChildNodes() || !m_frame->view()) + return false; + return m_frame->page() && m_frame->page()->dragController()->mayStartDragAtEventLocation(m_frame, point); +} + +void EventHandler::dragSourceMovedTo(const PlatformMouseEvent& event) +{ + if (dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML) + // for now we don't care if event handler cancels default behavior, since there is none + dispatchDragSrcEvent(eventNames().dragEvent, event); +} + +void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperation operation) +{ + if (dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML) { + dragState().m_dragClipboard->setDestinationOperation(operation); + // for now we don't care if event handler cancels default behavior, since there is none + dispatchDragSrcEvent(eventNames().dragendEvent, event); + } + freeClipboard(); + dragState().m_dragSrc = 0; +} + +// returns if we should continue "default processing", i.e., whether eventhandler canceled +bool EventHandler::dispatchDragSrcEvent(const AtomicString& eventType, const PlatformMouseEvent& event) +{ + return !dispatchDragEvent(eventType, dragState().m_dragSrc.get(), event, dragState().m_dragClipboard.get()); +} + +bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event) +{ + if (event.event().button() != LeftButton || event.event().eventType() != MouseEventMoved) { + // If we allowed the other side of the bridge to handle a drag + // last time, then m_mousePressed might still be set. So we + // clear it now to make sure the next move after a drag + // doesn't look like a drag. + m_mousePressed = false; + return false; + } + + if (eventLoopHandleMouseDragged(event)) + return true; + + // Careful that the drag starting logic stays in sync with eventMayStartDrag() + + if (m_mouseDownMayStartDrag && !dragState().m_dragSrc) { + allowDHTMLDrag(dragState().m_dragSrcMayBeDHTML, dragState().m_dragSrcMayBeUA); + if (!dragState().m_dragSrcMayBeDHTML && !dragState().m_dragSrcMayBeUA) + m_mouseDownMayStartDrag = false; // no element is draggable + } + + if (m_mouseDownMayStartDrag && !dragState().m_dragSrc) { + // try to find an element that wants to be dragged + HitTestRequest request(true, false); + HitTestResult result(m_mouseDownPos); + m_frame->contentRenderer()->layer()->hitTest(request, result); + Node* node = result.innerNode(); + if (node && node->renderer()) + dragState().m_dragSrc = node->renderer()->draggableNode(dragState().m_dragSrcMayBeDHTML, dragState().m_dragSrcMayBeUA, + m_mouseDownPos.x(), m_mouseDownPos.y(), dragState().m_dragSrcIsDHTML); + else + dragState().m_dragSrc = 0; + + if (!dragState().m_dragSrc) + m_mouseDownMayStartDrag = false; // no element is draggable + else { + // remember some facts about this source, while we have a HitTestResult handy + node = result.URLElement(); + dragState().m_dragSrcIsLink = node && node->isLink(); + + node = result.innerNonSharedNode(); + dragState().m_dragSrcIsImage = node && node->renderer() && node->renderer()->isImage(); + + dragState().m_dragSrcInSelection = m_frame->selection()->contains(m_mouseDownPos); + } + } + + // 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 && !dragState().m_dragSrcIsImage && dragState().m_dragSrcInSelection && event.event().timestamp() - m_mouseDownTimestamp < TextDragDelay) { + m_mouseDownMayStartDrag = false; + dragState().m_dragSrc = 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; + } + + if (!m_mouseDownMayStartDrag) + return !mouseDownMayStartSelect() && !m_mouseDownMayStartAutoscroll; + + // We are starting a text/image/url drag, so the cursor should be an arrow + m_frame->view()->setCursor(pointerCursor()); + + if (!dragHysteresisExceeded(event.event().pos())) + return true; + + // Once we're past the hysteresis point, we don't want to treat this gesture as a click + invalidateClick(); + + 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(); + + if (dragState().m_dragSrcMayBeDHTML) { + // Check to see if the is a DOM based drag, if it is get the DOM specified drag + // image and offset + if (dragState().m_dragSrcIsDHTML) { + if (RenderObject* renderer = dragState().m_dragSrc->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(), IntPoint() + delta); + } 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. + m_mouseDownMayStartDrag = false; + goto cleanupDrag; + } + } + + m_mouseDownMayStartDrag = dispatchDragSrcEvent(eventNames().dragstartEvent, m_mouseDown) + && !m_frame->selection()->isInPasswordField(); + + // 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); + + if (m_mouseDownMayStartDrag) { + // gather values from DHTML element, if it set any + dragState().m_dragClipboard->sourceOperation(srcOp); + + // Yuck, dragSourceMovedTo() can be called 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(); + } + } + + if (m_mouseDownMayStartDrag) { + DragController* dragController = m_frame->page() ? m_frame->page()->dragController() : 0; + bool startedDrag = dragController && dragController->startDrag(m_frame, dragState().m_dragClipboard.get(), srcOp, event.event(), m_mouseDownPos, dragState().m_dragSrcIsDHTML); + if (!startedDrag && dragState().m_dragSrcMayBeDHTML) { + // Drag was canned at the last minute - we owe m_dragSrc a DRAGEND event + dispatchDragSrcEvent(eventNames().dragendEvent, event.event()); + m_mouseDownMayStartDrag = false; + } + } + +cleanupDrag: + if (!m_mouseDownMayStartDrag) { + // something failed to start the drag, cleanup + freeClipboard(); + dragState().m_dragSrc = 0; + } + + // No more default handling (like selection), whether we're past the hysteresis bounds or not + return true; +} + +bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEvent, bool isLineBreak, bool isBackTab) +{ + // Platforms should differentiate real commands like selectAll from text input in disguise (like insertNewline), + // and avoid dispatching text input events from keydown default handlers. + ASSERT(!underlyingEvent || !underlyingEvent->isKeyboardEvent() || static_cast<KeyboardEvent*>(underlyingEvent)->type() == eventNames().keypressEvent); + + if (!m_frame) + return false; + + EventTarget* target; + if (underlyingEvent) + target = underlyingEvent->target(); + else + target = eventTargetNodeForDocument(m_frame->document()); + if (!target) + return false; + + RefPtr<TextEvent> event = TextEvent::create(m_frame->domWindow(), text); + event->setUnderlyingEvent(underlyingEvent); + event->setIsLineBreak(isLineBreak); + event->setIsBackTab(isBackTab); + ExceptionCode ec; + target->dispatchEvent(event, ec); + return event->defaultHandled(); +} + + +#if !PLATFORM(MAC) && !PLATFORM(QT) +bool EventHandler::invertSenseOfTabsToLinks(KeyboardEvent*) const +{ + return false; +} +#endif + +bool EventHandler::tabsToLinks(KeyboardEvent* event) const +{ + Page* page = m_frame->page(); + if (!page) + return false; + + if (page->chrome()->client()->tabsToLinks()) + return !invertSenseOfTabsToLinks(event); + + return invertSenseOfTabsToLinks(event); +} + +void EventHandler::defaultTextInputEventHandler(TextEvent* event) +{ + String data = event->data(); + if (data == "\n") { + if (event->isLineBreak()) { + if (m_frame->editor()->insertLineBreak()) + event->setDefaultHandled(); + } else { + if (m_frame->editor()->insertParagraphSeparator()) + event->setDefaultHandled(); + } + } else { + if (m_frame->editor()->insertTextWithoutSendingTextEvent(data, false, event)) + event->setDefaultHandled(); + } +} + +#if PLATFORM(QT) || PLATFORM(MAC) + +// These two platforms handle the space event in the platform-specific WebKit code. +// Eventually it would be good to eliminate that and use the code here instead, but +// the Qt version is inside an ifdef and the Mac version has some extra behavior +// so we can't unify everything yet. +void EventHandler::defaultSpaceEventHandler(KeyboardEvent*) +{ +} + +#else + +void EventHandler::defaultSpaceEventHandler(KeyboardEvent* event) +{ + ScrollDirection direction = event->shiftKey() ? ScrollUp : ScrollDown; + if (scrollOverflow(direction, ScrollByPage)) { + event->setDefaultHandled(); + return; + } + + FrameView* view = m_frame->view(); + if (!view) + return; + + if (view->scroll(direction, ScrollByPage)) + event->setDefaultHandled(); +} + +#endif + +void EventHandler::defaultTabEventHandler(KeyboardEvent* event) +{ + // We should only advance focus on tabs if no special modifier keys are held down. + if (event->ctrlKey() || event->metaKey() || event->altGraphKey()) + return; + + Page* page = m_frame->page(); + if (!page) + return; + if (!page->tabKeyCyclesThroughElements()) + return; + + FocusDirection focusDirection = event->shiftKey() ? FocusDirectionBackward : FocusDirectionForward; + + // Tabs can be used in design mode editing. + if (m_frame->document()->inDesignMode()) + return; + + if (page->focusController()->advanceFocus(focusDirection, event)) + event->setDefaultHandled(); +} + +void EventHandler::capsLockStateMayHaveChanged() +{ + if (Document* d = m_frame->document()) + if (Node* node = d->focusedNode()) + if (RenderObject* r = node->renderer()) + r->capsLockStateMayHaveChanged(); +} + +unsigned EventHandler::pendingFrameUnloadEventCount() +{ + return m_pendingFrameUnloadEventCount; +} + +void EventHandler::addPendingFrameUnloadEventCount() +{ + m_pendingFrameUnloadEventCount += 1; + m_frame->page()->changePendingUnloadEventCount(1); + return; +} + +void EventHandler::removePendingFrameUnloadEventCount() +{ + ASSERT( (-1 + (int)m_pendingFrameUnloadEventCount) >= 0 ); + m_pendingFrameUnloadEventCount -= 1; + m_frame->page()->changePendingUnloadEventCount(-1); + return; +} + +void EventHandler::clearPendingFrameUnloadEventCount() +{ + m_frame->page()->changePendingUnloadEventCount(-((int)m_pendingFrameUnloadEventCount)); + m_pendingFrameUnloadEventCount = 0; + return; +} + +unsigned EventHandler::pendingFrameBeforeUnloadEventCount() +{ + return m_pendingFrameBeforeUnloadEventCount; +} + +void EventHandler::addPendingFrameBeforeUnloadEventCount() +{ + m_pendingFrameBeforeUnloadEventCount += 1; + m_frame->page()->changePendingBeforeUnloadEventCount(1); + return; +} + +void EventHandler::removePendingFrameBeforeUnloadEventCount() +{ + ASSERT( (-1 + (int)m_pendingFrameBeforeUnloadEventCount) >= 0 ); + m_pendingFrameBeforeUnloadEventCount -= 1; + m_frame->page()->changePendingBeforeUnloadEventCount(-1); + return; +} + + void EventHandler::clearPendingFrameBeforeUnloadEventCount() +{ + m_frame->page()->changePendingBeforeUnloadEventCount(-((int)m_pendingFrameBeforeUnloadEventCount)); + m_pendingFrameBeforeUnloadEventCount = 0; + return; +} + +bool EventHandler::passMousePressEventToScrollbar(MouseEventWithHitTestResults& mev, Scrollbar* scrollbar) +{ + if (!scrollbar || !scrollbar->enabled()) + return false; + return scrollbar->mouseDown(mev.event()); +} + +} diff --git a/src/3rdparty/webkit/WebCore/page/EventHandler.h b/src/3rdparty/webkit/WebCore/page/EventHandler.h new file mode 100644 index 0000000..5d51cb6 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/EventHandler.h @@ -0,0 +1,352 @@ +/* + * Copyright (C) 2006, 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. + */ + +#ifndef EventHandler_h +#define EventHandler_h + +#include "DragActions.h" +#include "FocusDirection.h" +#include "PlatformMouseEvent.h" +#include "ScrollTypes.h" +#include "Timer.h" +#include <wtf/Forward.h> +#include <wtf/Noncopyable.h> +#include <wtf/Platform.h> +#include <wtf/RefPtr.h> + +#if PLATFORM(MAC) +#include "WebCoreKeyboardUIMode.h" +#ifndef __OBJC__ +class NSEvent; +class NSView; +#endif +#endif + +namespace WebCore { + +class AtomicString; +class Clipboard; +class Cursor; +class EventTargetNode; +class Event; +class FloatPoint; +class FloatRect; +class Frame; +class HitTestResult; +class HTMLFrameSetElement; +class KeyboardEvent; +class MouseEventWithHitTestResults; +class Node; +class PlatformKeyboardEvent; +class PlatformWheelEvent; +class RenderLayer; +class RenderObject; +class RenderWidget; +class Scrollbar; +class String; +class SVGElementInstance; +class TextEvent; +class VisiblePosition; +class Widget; + +struct HitTestRequest; + +extern const int LinkDragHysteresis; +extern const int ImageDragHysteresis; +extern const int TextDragHysteresis; +extern const int GeneralDragHysteresis; + +class EventHandler : Noncopyable { +public: + EventHandler(Frame*); + ~EventHandler(); + + void clear(); + + void updateSelectionForMouseDrag(); + + Node* mousePressNode() const; + void setMousePressNode(PassRefPtr<Node>); + + bool panScrollInProgress() { return m_panScrollInProgress; } + void setPanScrollInProgress(bool inProgress) { m_panScrollInProgress = inProgress; } + + void stopAutoscrollTimer(bool rendererIsBeingDestroyed = false); + RenderObject* autoscrollRenderer() const; + void updateAutoscrollRenderer(); + + HitTestResult hitTestResultAtPoint(const IntPoint&, bool allowShadowContent); + + bool mousePressed() const { return m_mousePressed; } + void setMousePressed(bool pressed) { m_mousePressed = pressed; } + + void setCapturingMouseEventsNode(PassRefPtr<Node>); + + bool updateDragAndDrop(const PlatformMouseEvent&, Clipboard*); + void cancelDragAndDrop(const PlatformMouseEvent&, Clipboard*); + bool performDragAndDrop(const PlatformMouseEvent&, Clipboard*); + + void scheduleHoverStateUpdate(); + + void setResizingFrameSet(HTMLFrameSetElement*); + + void resizeLayerDestroyed(); + + IntPoint currentMousePosition() const; + + void setIgnoreWheelEvents(bool); + + bool scrollOverflow(ScrollDirection, ScrollGranularity); + + bool shouldDragAutoNode(Node*, const IntPoint&) const; // -webkit-user-drag == auto + + bool tabsToLinks(KeyboardEvent*) const; + bool tabsToAllControls(KeyboardEvent*) const; + + bool mouseDownMayStartSelect() const { return m_mouseDownMayStartSelect; } + + bool mouseMoved(const PlatformMouseEvent&); + + bool handleMousePressEvent(const PlatformMouseEvent&); + bool handleMouseMoveEvent(const PlatformMouseEvent&, HitTestResult* hoveredNode = 0); + bool handleMouseReleaseEvent(const PlatformMouseEvent&); + bool handleWheelEvent(PlatformWheelEvent&); + + bool sendContextMenuEvent(const PlatformMouseEvent&); + + void setMouseDownMayStartAutoscroll() { m_mouseDownMayStartAutoscroll = true; } + + bool needsKeyboardEventDisambiguationQuirks() const; + + static unsigned accessKeyModifiers(); + bool handleAccessKey(const PlatformKeyboardEvent&); + bool keyEvent(const PlatformKeyboardEvent&); + void defaultKeyboardEventHandler(KeyboardEvent*); + + bool handleTextInputEvent(const String& text, Event* underlyingEvent = 0, + bool isLineBreak = false, bool isBackTab = false); + void defaultTextInputEventHandler(TextEvent*); + + bool eventMayStartDrag(const PlatformMouseEvent&) const; + + void dragSourceMovedTo(const PlatformMouseEvent&); + void dragSourceEndedAt(const PlatformMouseEvent&, DragOperation); + + void focusDocumentView(); + + void capsLockStateMayHaveChanged(); + + unsigned pendingFrameUnloadEventCount(); + void addPendingFrameUnloadEventCount(); + void removePendingFrameUnloadEventCount(); + void clearPendingFrameUnloadEventCount(); + unsigned pendingFrameBeforeUnloadEventCount(); + void addPendingFrameBeforeUnloadEventCount(); + void removePendingFrameBeforeUnloadEventCount(); + void clearPendingFrameBeforeUnloadEventCount(); + +#if PLATFORM(MAC) + PassRefPtr<KeyboardEvent> currentKeyboardEvent() const; + + void mouseDown(NSEvent*); + void mouseDragged(NSEvent*); + void mouseUp(NSEvent*); + void mouseMoved(NSEvent*); + bool keyEvent(NSEvent*); + bool wheelEvent(NSEvent*); + + void sendFakeEventsAfterWidgetTracking(NSEvent* initiatingEvent); + + void setActivationEventNumber(int num) { m_activationEventNumber = num; } + + NSEvent *currentNSEvent(); +#endif + +private: + struct EventHandlerDragState { + RefPtr<Node> m_dragSrc; // element that may be a drag source, for the current mouse gesture + bool m_dragSrcIsLink; + bool m_dragSrcIsImage; + bool m_dragSrcInSelection; + bool m_dragSrcMayBeDHTML; + bool m_dragSrcMayBeUA; // Are DHTML and/or the UserAgent allowed to drag out? + bool m_dragSrcIsDHTML; + RefPtr<Clipboard> m_dragClipboard; // used on only the source side of dragging + }; + static EventHandlerDragState& dragState(); + static const double TextDragDelay; + + PassRefPtr<Clipboard> createDraggingClipboard() const; + + bool eventActivatedView(const PlatformMouseEvent&) const; + void selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& event); + void selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults& event); + + bool handleMouseDoubleClickEvent(const PlatformMouseEvent&); + + bool handleMousePressEvent(const MouseEventWithHitTestResults&); + bool handleMousePressEventSingleClick(const MouseEventWithHitTestResults&); + bool handleMousePressEventDoubleClick(const MouseEventWithHitTestResults&); + bool handleMousePressEventTripleClick(const MouseEventWithHitTestResults&); + bool handleMouseDraggedEvent(const MouseEventWithHitTestResults&); + bool handleMouseReleaseEvent(const MouseEventWithHitTestResults&); + + void handleKeyboardSelectionMovement(KeyboardEvent*); + + Cursor selectCursor(const MouseEventWithHitTestResults&, Scrollbar*); + void setPanScrollCursor(); + + void hoverTimerFired(Timer<EventHandler>*); + + static bool canMouseDownStartSelect(Node*); + static bool canMouseDragExtendSelect(Node*); + + void handleAutoscroll(RenderObject*); + void startAutoscrollTimer(); + void setAutoscrollRenderer(RenderObject*); + void autoscrollTimerFired(Timer<EventHandler>*); + + void invalidateClick(); + + Node* nodeUnderMouse() const; + + void updateMouseEventTargetNode(Node*, const PlatformMouseEvent&, bool fireMouseOverOut); + void fireMouseOverOut(bool fireMouseOver = true, bool fireMouseOut = true, bool updateLastNodeUnderMouse = true); + + MouseEventWithHitTestResults prepareMouseEvent(const HitTestRequest&, const PlatformMouseEvent&); + + bool dispatchMouseEvent(const AtomicString& eventType, Node* target, bool cancelable, int clickCount, const PlatformMouseEvent&, bool setUnder); + bool dispatchDragEvent(const AtomicString& eventType, Node* target, const PlatformMouseEvent&, Clipboard*); + + void freeClipboard(); + + bool handleDrag(const MouseEventWithHitTestResults&); + bool handleMouseUp(const MouseEventWithHitTestResults&); + void clearDragState(); + + bool dispatchDragSrcEvent(const AtomicString& eventType, const PlatformMouseEvent&); + + bool dragHysteresisExceeded(const FloatPoint&) const; + bool dragHysteresisExceeded(const IntPoint&) const; + + bool passMousePressEventToSubframe(MouseEventWithHitTestResults&, Frame* subframe); + bool passMouseMoveEventToSubframe(MouseEventWithHitTestResults&, Frame* subframe, HitTestResult* hoveredNode = 0); + bool passMouseReleaseEventToSubframe(MouseEventWithHitTestResults&, Frame* subframe); + + bool passSubframeEventToSubframe(MouseEventWithHitTestResults&, Frame* subframe, HitTestResult* hoveredNode = 0); + + bool passMousePressEventToScrollbar(MouseEventWithHitTestResults&, Scrollbar*); + + bool passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults&); + bool passWidgetMouseDownEventToWidget(RenderWidget*); + + bool passMouseDownEventToWidget(Widget*); + bool passWheelEventToWidget(PlatformWheelEvent&, Widget*); + + void defaultSpaceEventHandler(KeyboardEvent*); + void defaultTabEventHandler(KeyboardEvent*); + + void allowDHTMLDrag(bool& flagDHTML, bool& flagUA) const; + + // The following are called at the beginning of handleMouseUp and handleDrag. + // If they return true it indicates that they have consumed the event. +#if PLATFORM(MAC) + bool eventLoopHandleMouseUp(const MouseEventWithHitTestResults&); + bool eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&); + NSView *mouseDownViewIfStillGood(); +#else + bool eventLoopHandleMouseUp(const MouseEventWithHitTestResults&) { return false; } + bool eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&) { return false; } +#endif + + bool invertSenseOfTabsToLinks(KeyboardEvent*) const; + + void updateSelectionForMouseDrag(Node* targetNode, const IntPoint& localPoint); + + Frame* m_frame; + + bool m_mousePressed; + RefPtr<Node> m_mousePressNode; + + bool m_mouseDownMayStartSelect; + bool m_mouseDownMayStartDrag; + bool m_mouseDownWasSingleClickInSelection; + bool m_beganSelectingText; + + IntPoint m_dragStartPos; + + IntPoint m_panScrollStartPos; + bool m_panScrollInProgress; + + Timer<EventHandler> m_hoverTimer; + + Timer<EventHandler> m_autoscrollTimer; + RenderObject* m_autoscrollRenderer; + bool m_autoscrollInProgress; + bool m_mouseDownMayStartAutoscroll; + bool m_mouseDownWasInSubframe; +#if ENABLE(SVG) + bool m_svgPan; + RefPtr<SVGElementInstance> m_instanceUnderMouse; + RefPtr<SVGElementInstance> m_lastInstanceUnderMouse; +#endif + + RenderLayer* m_resizeLayer; + + RefPtr<Node> m_capturingMouseEventsNode; + + RefPtr<Node> m_nodeUnderMouse; + RefPtr<Node> m_lastNodeUnderMouse; + RefPtr<Frame> m_lastMouseMoveEventSubframe; + RefPtr<Scrollbar> m_lastScrollbarUnderMouse; + + int m_clickCount; + RefPtr<Node> m_clickNode; + + RefPtr<Node> m_dragTarget; + + RefPtr<HTMLFrameSetElement> m_frameSetBeingResized; + + IntSize m_offsetFromResizeCorner; // in the coords of m_resizeLayer + + IntPoint m_currentMousePosition; + IntPoint m_mouseDownPos; // in our view's coords + double m_mouseDownTimestamp; + PlatformMouseEvent m_mouseDown; + + unsigned m_pendingFrameUnloadEventCount; + unsigned m_pendingFrameBeforeUnloadEventCount; + +#if PLATFORM(MAC) + NSView *m_mouseDownView; + bool m_sendingEventToSubview; + int m_activationEventNumber; +#endif + +}; + +} // namespace WebCore + +#endif // EventHandler_h diff --git a/src/3rdparty/webkit/WebCore/page/FocusController.cpp b/src/3rdparty/webkit/WebCore/page/FocusController.cpp new file mode 100644 index 0000000..9b30362 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/FocusController.cpp @@ -0,0 +1,307 @@ +/* + * Copyright (C) 2006, 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 "FocusController.h" + +#include "AXObjectCache.h" +#include "Chrome.h" +#include "Document.h" +#include "Editor.h" +#include "EditorClient.h" +#include "Element.h" +#include "Event.h" +#include "EventHandler.h" +#include "Frame.h" +#include "FrameView.h" +#include "FrameTree.h" +#include "HTMLFrameOwnerElement.h" +#include "HTMLNames.h" +#include "KeyboardEvent.h" +#include "Page.h" +#include "Range.h" +#include "RenderObject.h" +#include "RenderWidget.h" +#include "SelectionController.h" +#include "Widget.h" +#include <wtf/Platform.h> + +namespace WebCore { + +using namespace HTMLNames; + +FocusController::FocusController(Page* page) + : m_page(page) + , m_isActive(false) +{ +} + +void FocusController::setFocusedFrame(PassRefPtr<Frame> frame) +{ + if (m_focusedFrame == frame) + return; + + if (m_focusedFrame && m_focusedFrame->view()) + m_focusedFrame->selection()->setFocused(false); + + m_focusedFrame = frame; + + if (m_focusedFrame && m_focusedFrame->view()) + m_focusedFrame->selection()->setFocused(true); +} + +Frame* FocusController::focusedOrMainFrame() +{ + if (Frame* frame = focusedFrame()) + return frame; + return m_page->mainFrame(); +} + +static Node* deepFocusableNode(FocusDirection direction, Node* node, KeyboardEvent* event) +{ + // The node we found might be a HTMLFrameOwnerElement, so descend down the frame 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); + if (!owner->contentFrame()) + break; + + Document* document = owner->contentFrame()->document(); + if (!document) + break; + + node = (direction == FocusDirectionForward) + ? document->nextFocusableNode(0, event) + : document->previousFocusableNode(0, event); + if (!node) { + node = owner; + break; + } + } + + return node; +} + +bool FocusController::setInitialFocus(FocusDirection direction, KeyboardEvent* event) +{ + return advanceFocus(direction, event, true); +} + +bool FocusController::advanceFocus(FocusDirection direction, KeyboardEvent* event, bool initialFocus) +{ + Frame* frame = focusedOrMainFrame(); + ASSERT(frame); + Document* document = frame->document(); + if (!document) + return false; + + Node* node = (direction == FocusDirectionForward) + ? document->nextFocusableNode(document->focusedNode(), event) + : document->previousFocusableNode(document->focusedNode(), event); + + // If there's no focusable node to advance to, move up the frame tree until we find one. + while (!node && frame) { + Frame* parentFrame = frame->tree()->parent(); + if (!parentFrame) + break; + + Document* parentDocument = parentFrame->document(); + if (!parentDocument) + break; + + HTMLFrameOwnerElement* owner = frame->ownerElement(); + if (!owner) + break; + + node = (direction == FocusDirectionForward) + ? parentDocument->nextFocusableNode(owner, event) + : parentDocument->previousFocusableNode(owner, event); + + frame = parentFrame; + } + + node = deepFocusableNode(direction, node, event); + + if (!node) { + // 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); + setFocusedFrame(0); + m_page->chrome()->takeFocus(direction); + return true; + } + + // Chrome doesn't want focus, so we should wrap focus. + if (Document* d = m_page->mainFrame()->document()) + node = (direction == FocusDirectionForward) + ? d->nextFocusableNode(0, event) + : d->previousFocusableNode(0, event); + + node = deepFocusableNode(direction, node, event); + + if (!node) + return false; + } + + ASSERT(node); + + if (node == document->focusedNode()) + // Focus wrapped around to the same node. + return true; + + if (!node->isElementNode()) + // FIXME: May need a way to focus a document here. + return false; + + if (node->isFrameOwnerElement()) { + // 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); + if (!owner->contentFrame()) + return false; + + document->setFocusedNode(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 + // that because some elements (e.g. HTMLInputElement and HTMLTextAreaElement) do extra work in + // their focus() methods. + + Document* newDocument = node->document(); + + if (newDocument != document) + // Focus is going away from this document, so clear the focused node. + document->setFocusedNode(0); + + if (newDocument) + setFocusedFrame(newDocument->frame()); + + static_cast<Element*>(node)->focus(false); + return true; +} + +static bool relinquishesEditingFocus(Node *node) +{ + ASSERT(node); + ASSERT(node->isContentEditable()); + + Node* root = node->rootEditableElement(); + Frame* frame = node->document()->frame(); + if (!frame || !root) + return false; + + return frame->editor()->shouldEndEditing(rangeOfContents(root).get()); +} + +static void clearSelectionIfNeeded(Frame* oldFocusedFrame, Frame* newFocusedFrame, Node* newFocusedNode) +{ + if (!oldFocusedFrame || !newFocusedFrame) + return; + + if (oldFocusedFrame->document() != newFocusedFrame->document()) + return; + + SelectionController* s = oldFocusedFrame->selection(); + if (s->isNone()) + return; + + Node* selectionStartNode = s->selection().start().node(); + if (selectionStartNode == newFocusedNode || selectionStartNode->isDescendantOf(newFocusedNode) || selectionStartNode->shadowAncestorNode() == newFocusedNode) + return; + + if (Node* mousePressNode = newFocusedFrame->eventHandler()->mousePressNode()) + if (mousePressNode->renderer() && !mousePressNode->canStartSelection()) + if (Node* root = s->rootEditableElement()) + if (Node* shadowAncestorNode = root->shadowAncestorNode()) + // Don't do this for textareas and text fields, when they lose focus their selections should be cleared + // and then restored when they regain focus, to match other browsers. + if (!shadowAncestorNode->hasTagName(inputTag) && !shadowAncestorNode->hasTagName(textareaTag)) + return; + + s->clear(); +} + +bool FocusController::setFocusedNode(Node* node, PassRefPtr<Frame> newFocusedFrame) +{ + RefPtr<Frame> oldFocusedFrame = focusedFrame(); + RefPtr<Document> oldDocument = oldFocusedFrame ? oldFocusedFrame->document() : 0; + + Node* oldFocusedNode = oldDocument ? oldDocument->focusedNode() : 0; + if (oldFocusedNode == node) + return true; + + if (oldFocusedNode && oldFocusedNode->rootEditableElement() == oldFocusedNode && !relinquishesEditingFocus(oldFocusedNode)) + return false; + + clearSelectionIfNeeded(oldFocusedFrame.get(), newFocusedFrame.get(), node); + + if (!node) { + if (oldDocument) + oldDocument->setFocusedNode(0); + m_page->editorClient()->setInputMethodState(false); + return true; + } + + RefPtr<Document> newDocument = node ? node->document() : 0; + + if (newDocument && newDocument->focusedNode() == node) { + m_page->editorClient()->setInputMethodState(node->shouldUseInputMethod()); + return true; + } + + if (oldDocument && oldDocument != newDocument) + oldDocument->setFocusedNode(0); + + setFocusedFrame(newFocusedFrame); + + if (newDocument) + newDocument->setFocusedNode(node); + + m_page->editorClient()->setInputMethodState(node->shouldUseInputMethod()); + + return true; +} + +void FocusController::setActive(bool active) +{ + if (m_isActive == active) + return; + + m_isActive = active; + + if (FrameView* view = m_page->mainFrame()->view()) { + if (!view->platformWidget()) { + view->layoutIfNeededRecursive(); + view->updateControlTints(); + } + } + + focusedOrMainFrame()->selection()->pageActivationChanged(); +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/FocusController.h b/src/3rdparty/webkit/WebCore/page/FocusController.h new file mode 100644 index 0000000..f4a6632 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/FocusController.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2006, 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. + */ + +#ifndef FocusController_h +#define FocusController_h + +#include "FocusDirection.h" +#include <wtf/Forward.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + + class Frame; + class KeyboardEvent; + class Node; + class Page; + + class FocusController { + public: + FocusController(Page*); + + void setFocusedFrame(PassRefPtr<Frame>); + Frame* focusedFrame() const { return m_focusedFrame.get(); } + Frame* focusedOrMainFrame(); + + bool setInitialFocus(FocusDirection, KeyboardEvent*); + bool advanceFocus(FocusDirection, KeyboardEvent*, bool initialFocus = false); + + bool setFocusedNode(Node*, PassRefPtr<Frame>); + + void setActive(bool); + bool isActive() const { return m_isActive; } + + private: + Page* m_page; + RefPtr<Frame> m_focusedFrame; + bool m_isActive; + }; + +} // namespace WebCore + +#endif // FocusController_h diff --git a/src/3rdparty/webkit/WebCore/page/FocusDirection.h b/src/3rdparty/webkit/WebCore/page/FocusDirection.h new file mode 100644 index 0000000..261c745 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/FocusDirection.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2006 Apple Computer, 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 FocusDirection_h +#define FocusDirection_h + +namespace WebCore { + enum FocusDirection { + FocusDirectionForward = 0, + FocusDirectionBackward + }; +} + +#endif // FocusDirection_h diff --git a/src/3rdparty/webkit/WebCore/page/Frame.cpp b/src/3rdparty/webkit/WebCore/page/Frame.cpp new file mode 100644 index 0000000..a4c0b57 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/Frame.cpp @@ -0,0 +1,1880 @@ +/* + * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org> + * 1999 Lars Knoll <knoll@kde.org> + * 1999 Antti Koivisto <koivisto@kde.org> + * 2000 Simon Hausmann <hausmann@kde.org> + * 2000 Stefan Schimanski <1Stein@gmx.de> + * 2001 George Staikos <staikos@kde.org> + * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2005 Alexey Proskuryakov <ap@nypop.com> + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2008 Eric Seidel <eric@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "Frame.h" +#include "FramePrivate.h" + +#include "ApplyStyleCommand.h" +#include "BeforeUnloadEvent.h" +#include "CSSComputedStyleDeclaration.h" +#include "CSSProperty.h" +#include "CSSPropertyNames.h" +#include "CachedCSSStyleSheet.h" +#include "DOMWindow.h" +#include "DocLoader.h" +#include "DocumentType.h" +#include "EditingText.h" +#include "EditorClient.h" +#include "EventNames.h" +#include "FocusController.h" +#include "FrameLoader.h" +#include "FrameView.h" +#include "GraphicsContext.h" +#include "HTMLDocument.h" +#include "HTMLFormElement.h" +#include "HTMLFrameElementBase.h" +#include "HTMLFormControlElement.h" +#include "HTMLNames.h" +#include "HTMLTableCellElement.h" +#include "HitTestResult.h" +#include "JSDOMWindowShell.h" +#include "Logging.h" +#include "markup.h" +#include "MediaFeatureNames.h" +#include "Navigator.h" +#include "NodeList.h" +#include "Page.h" +#include "RegularExpression.h" +#include "RenderPart.h" +#include "RenderTableCell.h" +#include "RenderTextControl.h" +#include "RenderTheme.h" +#include "RenderView.h" +#include "Settings.h" +#include "SystemTime.h" +#include "TextIterator.h" +#include "TextResourceDecoder.h" +#include "XMLNames.h" +#include "ScriptController.h" +#include "npruntime_impl.h" +#include "runtime_root.h" +#include "visible_units.h" +#include <wtf/RefCountedLeakCounter.h> +#include <wtf/StdLibExtras.h> + +#if FRAME_LOADS_USER_STYLESHEET +#include "UserStyleSheetLoader.h" +#endif + +#if ENABLE(SVG) +#include "SVGDocument.h" +#include "SVGDocumentExtensions.h" +#include "SVGNames.h" +#include "XLinkNames.h" +#endif + +#if ENABLE(WML) +#include "WMLNames.h" +#endif + +using namespace std; + +namespace WebCore { + +using namespace HTMLNames; + +#ifndef NDEBUG +static WTF::RefCountedLeakCounter frameCounter("Frame"); +#endif + +static inline Frame* parentFromOwnerElement(HTMLFrameOwnerElement* ownerElement) +{ + if (!ownerElement) + return 0; + return ownerElement->document()->frame(); +} + +Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* frameLoaderClient) + : d(new FramePrivate(page, parentFromOwnerElement(ownerElement), this, ownerElement, frameLoaderClient)) +{ + AtomicString::init(); + HTMLNames::init(); + QualifiedName::init(); + MediaFeatureNames::init(); + +#if ENABLE(SVG) + SVGNames::init(); + XLinkNames::init(); +#endif + +#if ENABLE(WML) + WMLNames::init(); +#endif + + XMLNames::init(); + + if (!ownerElement) + page->setMainFrame(this); + else { + page->incrementFrameCount(); + // Make sure we will not end up with two frames referencing the same owner element. + ASSERT((!(ownerElement->m_contentFrame)) || (ownerElement->m_contentFrame->ownerElement() != ownerElement)); + ownerElement->m_contentFrame = this; + } + +#ifndef NDEBUG + frameCounter.increment(); +#endif +} + +Frame::~Frame() +{ + setView(0); + loader()->clearRecordedFormValues(); + loader()->cancelAndClear(); + + // FIXME: We should not be doing all this work inside the destructor + + ASSERT(!d->m_lifeSupportTimer.isActive()); + +#ifndef NDEBUG + frameCounter.decrement(); +#endif + + if (d->m_script.haveWindowShell()) + d->m_script.windowShell()->disconnectFrame(); + + disconnectOwnerElement(); + + if (d->m_domWindow) + d->m_domWindow->disconnectFrame(); + + HashSet<DOMWindow*>::iterator end = d->m_liveFormerWindows.end(); + for (HashSet<DOMWindow*>::iterator it = d->m_liveFormerWindows.begin(); it != end; ++it) + (*it)->disconnectFrame(); + + if (d->m_view) { + d->m_view->hide(); + d->m_view->clearFrame(); + } + + ASSERT(!d->m_lifeSupportTimer.isActive()); + +#if FRAME_LOADS_USER_STYLESHEET + delete d->m_userStyleSheetLoader; +#endif + + delete d; + d = 0; +} + +void Frame::init() +{ + d->m_loader.init(); +} + +FrameLoader* Frame::loader() const +{ + return &d->m_loader; +} + +FrameView* Frame::view() const +{ + return d->m_view.get(); +} + +void Frame::setView(FrameView* view) +{ + // Detach the document now, so any onUnload handlers get run - if + // we wait until the view is destroyed, then things won't be + // hooked up enough for some JavaScript calls to work. + if (!view && d->m_doc && d->m_doc->attached() && !d->m_doc->inPageCache()) { + // FIXME: We don't call willRemove here. Why is that OK? + d->m_doc->detach(); + if (d->m_view) + d->m_view->unscheduleRelayout(); + } + eventHandler()->clear(); + + d->m_view = view; + + // Only one form submission is allowed per view of a part. + // Since this part may be getting reused as a result of being + // pulled from the back/forward cache, reset this flag. + loader()->resetMultipleFormSubmissionProtection(); +} + +ScriptController* Frame::script() +{ + return &d->m_script; +} + +Document* Frame::document() const +{ + return d->m_doc.get(); +} + +void Frame::setDocument(PassRefPtr<Document> newDoc) +{ + if (d->m_doc && d->m_doc->attached() && !d->m_doc->inPageCache()) { + // FIXME: We don't call willRemove here. Why is that OK? + d->m_doc->detach(); + } + + d->m_doc = newDoc; + if (d->m_doc && selection()->isFocusedAndActive()) + setUseSecureKeyboardEntry(d->m_doc->useSecureKeyboardEntryWhenActive()); + + if (d->m_doc && !d->m_doc->attached()) + d->m_doc->attach(); + + // Update the cached 'document' property, which is now stale. + d->m_script.updateDocument(); +} + +Settings* Frame::settings() const +{ + return d->m_page ? d->m_page->settings() : 0; +} + +String Frame::selectedText() const +{ + return plainText(selection()->toRange().get()); +} + +IntRect Frame::firstRectForRange(Range* range) const +{ + int extraWidthToEndOfLine = 0; + ExceptionCode ec = 0; + ASSERT(range->startContainer(ec)); + ASSERT(range->endContainer(ec)); + + InlineBox* startInlineBox; + int startCaretOffset; + range->startPosition().getInlineBoxAndOffset(DOWNSTREAM, startInlineBox, startCaretOffset); + + RenderObject* startRenderer = range->startContainer(ec)->renderer(); + IntRect startCaretRect = startRenderer->localCaretRect(startInlineBox, startCaretOffset, &extraWidthToEndOfLine); + if (startCaretRect != IntRect()) + startCaretRect = startRenderer->localToAbsoluteQuad(FloatRect(startCaretRect)).enclosingBoundingBox(); + + InlineBox* endInlineBox; + int endCaretOffset; + range->endPosition().getInlineBoxAndOffset(UPSTREAM, endInlineBox, endCaretOffset); + + RenderObject* endRenderer = range->endContainer(ec)->renderer(); + IntRect endCaretRect = endRenderer->localCaretRect(endInlineBox, endCaretOffset); + if (endCaretRect != IntRect()) + endCaretRect = endRenderer->localToAbsoluteQuad(FloatRect(endCaretRect)).enclosingBoundingBox(); + + if (startCaretRect.y() == endCaretRect.y()) { + // start and end are on the same line + return IntRect(min(startCaretRect.x(), endCaretRect.x()), + startCaretRect.y(), + abs(endCaretRect.x() - startCaretRect.x()), + max(startCaretRect.height(), endCaretRect.height())); + } + + // start and end aren't on the same line, so go from start to the end of its line + return IntRect(startCaretRect.x(), + startCaretRect.y(), + startCaretRect.width() + extraWidthToEndOfLine, + startCaretRect.height()); +} + +SelectionController* Frame::selection() const +{ + return &d->m_selectionController; +} + +Editor* Frame::editor() const +{ + return &d->m_editor; +} + +TextGranularity Frame::selectionGranularity() const +{ + return d->m_selectionGranularity; +} + +void Frame::setSelectionGranularity(TextGranularity granularity) const +{ + d->m_selectionGranularity = granularity; +} + +SelectionController* Frame::dragCaretController() const +{ + return d->m_page->dragCaretController(); +} + + +AnimationController* Frame::animation() const +{ + return &d->m_animationController; +} + +static RegularExpression* createRegExpForLabels(const Vector<String>& labels) +{ + // REVIEW- version of this call in FrameMac.mm caches based on the NSArray ptrs being + // the same across calls. We can't do that. + + DEFINE_STATIC_LOCAL(RegularExpression, wordRegExp, ("\\w")); + String pattern("("); + unsigned int numLabels = labels.size(); + unsigned int i; + for (i = 0; i < numLabels; i++) { + String label = labels[i]; + + bool startsWithWordChar = false; + bool endsWithWordChar = false; + if (label.length() != 0) { + startsWithWordChar = wordRegExp.search(label.substring(0, 1)) >= 0; + endsWithWordChar = wordRegExp.search(label.substring(label.length() - 1, 1)) >= 0; + } + + if (i != 0) + pattern.append("|"); + // Search for word boundaries only if label starts/ends with "word characters". + // If we always searched for word boundaries, this wouldn't work for languages + // such as Japanese. + if (startsWithWordChar) { + pattern.append("\\b"); + } + pattern.append(label); + if (endsWithWordChar) { + pattern.append("\\b"); + } + } + pattern.append(")"); + return new RegularExpression(pattern, false); +} + +String Frame::searchForLabelsAboveCell(RegularExpression* regExp, HTMLTableCellElement* cell) +{ + RenderTableCell* cellRenderer = static_cast<RenderTableCell*>(cell->renderer()); + + if (cellRenderer && cellRenderer->isTableCell()) { + RenderTableCell* cellAboveRenderer = cellRenderer->table()->cellAbove(cellRenderer); + + if (cellAboveRenderer) { + HTMLTableCellElement* aboveCell = + static_cast<HTMLTableCellElement*>(cellAboveRenderer->element()); + + if (aboveCell) { + // search within the above cell we found for a match + for (Node* n = aboveCell->firstChild(); n; n = n->traverseNextNode(aboveCell)) { + if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) { + // For each text chunk, run the regexp + String nodeString = n->nodeValue(); + int pos = regExp->searchRev(nodeString); + if (pos >= 0) + return nodeString.substring(pos, regExp->matchedLength()); + } + } + } + } + } + // Any reason in practice to search all cells in that are above cell? + return String(); +} + +String Frame::searchForLabelsBeforeElement(const Vector<String>& labels, Element* element) +{ + OwnPtr<RegularExpression> regExp(createRegExpForLabels(labels)); + // We stop searching after we've seen this many chars + const unsigned int charsSearchedThreshold = 500; + // This is the absolute max we search. We allow a little more slop than + // charsSearchedThreshold, to make it more likely that we'll search whole nodes. + const unsigned int maxCharsSearched = 600; + // If the starting element is within a table, the cell that contains it + HTMLTableCellElement* startingTableCell = 0; + bool searchedCellAbove = false; + + // 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<HTMLElement*>(n)->isGenericFormElement())) + { + // We hit another form element or the start of the form - bail out + break; + } else if (n->hasTagName(tdTag) && !startingTableCell) { + startingTableCell = static_cast<HTMLTableCellElement*>(n); + } else if (n->hasTagName(trTag) && startingTableCell) { + String result = searchForLabelsAboveCell(regExp.get(), startingTableCell); + if (!result.isEmpty()) + return result; + searchedCellAbove = true; + } else if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) { + // For each text chunk, run the regexp + String nodeString = n->nodeValue(); + // add 100 for slop, to make it more likely that we'll search whole nodes + if (lengthSearched + nodeString.length() > maxCharsSearched) + nodeString = nodeString.right(charsSearchedThreshold - lengthSearched); + int pos = regExp->searchRev(nodeString); + if (pos >= 0) + return nodeString.substring(pos, regExp->matchedLength()); + lengthSearched += nodeString.length(); + } + } + + // If we started in a cell, but bailed because we found the start of the form or the + // previous element, we still might need to search the row above us for a label. + if (startingTableCell && !searchedCellAbove) { + return searchForLabelsAboveCell(regExp.get(), startingTableCell); + } + return String(); +} + +String Frame::matchLabelsAgainstElement(const Vector<String>& labels, Element* element) +{ + String name = element->getAttribute(nameAttr); + if (name.isEmpty()) + return String(); + + // Make numbers and _'s in field names behave like word boundaries, e.g., "address2" + replace(name, RegularExpression("\\d"), " "); + name.replace('_', ' '); + + OwnPtr<RegularExpression> regExp(createRegExpForLabels(labels)); + // Use the largest match we can find in the whole name string + int pos; + int length; + int bestPos = -1; + int bestLength = -1; + int start = 0; + do { + pos = regExp->search(name, start); + if (pos != -1) { + length = regExp->matchedLength(); + if (length >= bestLength) { + bestPos = pos; + bestLength = length; + } + start = pos + 1; + } + } while (pos != -1); + + if (bestPos != -1) + return name.substring(bestPos, bestLength); + return String(); +} + +const Selection& Frame::mark() const +{ + return d->m_mark; +} + +void Frame::setMark(const Selection& s) +{ + ASSERT(!s.base().node() || s.base().node()->document() == document()); + ASSERT(!s.extent().node() || s.extent().node()->document() == document()); + ASSERT(!s.start().node() || s.start().node()->document() == document()); + ASSERT(!s.end().node() || s.end().node()->document() == document()); + + d->m_mark = s; +} + +void Frame::notifyRendererOfSelectionChange(bool userTriggered) +{ + RenderObject* renderer = 0; + if (selection()->rootEditableElement()) + renderer = selection()->rootEditableElement()->shadowAncestorNode()->renderer(); + + // If the current selection is in a textfield or textarea, notify the renderer that the selection has changed + if (renderer && (renderer->isTextArea() || renderer->isTextField())) + static_cast<RenderTextControl*>(renderer)->selectionChanged(userTriggered); +} + +void Frame::invalidateSelection() +{ + selection()->setNeedsLayout(); + selectionLayoutChanged(); +} + +void Frame::setCaretVisible(bool flag) +{ + if (d->m_caretVisible == flag) + return; + clearCaretRectIfNeeded(); + d->m_caretVisible = flag; + selectionLayoutChanged(); +} + +void Frame::clearCaretRectIfNeeded() +{ +#if ENABLE(TEXT_CARET) + if (d->m_caretPaint) { + d->m_caretPaint = false; + selection()->invalidateCaretRect(); + } +#endif +} + +// Helper function that tells whether a particular node is an element that has an entire +// Frame and FrameView, a <frame>, <iframe>, or <object>. +static bool isFrameElement(const Node *n) +{ + if (!n) + return false; + RenderObject *renderer = n->renderer(); + if (!renderer || !renderer->isWidget()) + return false; + Widget* widget = static_cast<RenderWidget*>(renderer)->widget(); + return widget && widget->isFrameView(); +} + +void Frame::setFocusedNodeIfNeeded() +{ + if (!document() || selection()->isNone() || !selection()->isFocusedAndActive()) + return; + + Node* target = selection()->rootEditableElement(); + if (target) { + RenderObject* renderer = target->renderer(); + + // Walk up the render tree to search for a node to focus. + // Walking up the DOM tree wouldn't work for shadow trees, like those behind the engine-based text fields. + while (renderer) { + // We don't want to set focus on a subframe when selecting in a parent frame, + // so add the !isFrameElement check here. There's probably a better way to make this + // work in the long term, but this is the safest fix at this time. + if (target && target->isMouseFocusable() && !isFrameElement(target)) { + page()->focusController()->setFocusedNode(target, this); + return; + } + renderer = renderer->parent(); + if (renderer) + target = renderer->element(); + } + document()->setFocusedNode(0); + } +} + +void Frame::selectionLayoutChanged() +{ + bool caretRectChanged = selection()->recomputeCaretRect(); + +#if ENABLE(TEXT_CARET) + bool shouldBlink = d->m_caretVisible + && selection()->isCaret() && selection()->isContentEditable(); + + // If the caret moved, stop the blink timer so we can restart with a + // black caret in the new location. + if (caretRectChanged || !shouldBlink) + d->m_caretBlinkTimer.stop(); + + // Start blinking with a black caret. Be sure not to restart if we're + // already blinking in the right location. + if (shouldBlink && !d->m_caretBlinkTimer.isActive()) { + if (double blinkInterval = theme()->caretBlinkInterval()) + d->m_caretBlinkTimer.startRepeating(blinkInterval); + + if (!d->m_caretPaint) { + d->m_caretPaint = true; + selection()->invalidateCaretRect(); + } + } +#else + if (!caretRectChanged) + return; +#endif + + RenderView* view = contentRenderer(); + if (!view) + return; + + Selection selection = this->selection()->selection(); + + if (!selection.isRange()) + view->clearSelection(); + else { + // Use the rightmost candidate for the start of the selection, and the leftmost candidate for the end of the selection. + // Example: foo <a>bar</a>. Imagine that a line wrap occurs after 'foo', and that 'bar' is selected. If we pass [foo, 3] + // as the start of the selection, the selection painting code will think that content on the line containing 'foo' is selected + // and will fill the gap before 'bar'. + Position startPos = selection.start(); + if (startPos.downstream().isCandidate()) + startPos = startPos.downstream(); + Position endPos = selection.end(); + if (endPos.upstream().isCandidate()) + endPos = endPos.upstream(); + + // We can get into a state where the selection endpoints map to the same VisiblePosition when a selection is deleted + // because we don't yet notify the SelectionController of text removal. + if (startPos.isNotNull() && endPos.isNotNull() && selection.visibleStart() != selection.visibleEnd()) { + RenderObject *startRenderer = startPos.node()->renderer(); + RenderObject *endRenderer = endPos.node()->renderer(); + view->setSelection(startRenderer, startPos.offset(), endRenderer, endPos.offset()); + } + } +} + +void Frame::caretBlinkTimerFired(Timer<Frame>*) +{ +#if ENABLE(TEXT_CARET) + ASSERT(d->m_caretVisible); + ASSERT(selection()->isCaret()); + bool caretPaint = d->m_caretPaint; + if (selection()->isCaretBlinkingSuspended() && caretPaint) + return; + d->m_caretPaint = !caretPaint; + selection()->invalidateCaretRect(); +#endif +} + +void Frame::paintCaret(GraphicsContext* p, int tx, int ty, const IntRect& clipRect) const +{ +#if ENABLE(TEXT_CARET) + if (d->m_caretPaint && d->m_caretVisible) + selection()->paintCaret(p, tx, ty, clipRect); +#endif +} + +void Frame::paintDragCaret(GraphicsContext* p, int tx, int ty, const IntRect& clipRect) const +{ +#if ENABLE(TEXT_CARET) + SelectionController* dragCaretController = d->m_page->dragCaretController(); + ASSERT(dragCaretController->selection().isCaret()); + if (dragCaretController->selection().start().node()->document()->frame() == this) + dragCaretController->paintCaret(p, tx, ty, clipRect); +#endif +} + +float Frame::zoomFactor() const +{ + return d->m_zoomFactor; +} + +bool Frame::isZoomFactorTextOnly() const +{ + return d->m_page->settings()->zoomsTextOnly(); +} + +bool Frame::shouldApplyTextZoom() const +{ + if (d->m_zoomFactor == 1.0f || !isZoomFactorTextOnly()) + return false; +#if ENABLE(SVG) + if (d->m_doc && d->m_doc->isSVGDocument()) + return false; +#endif + return true; +} + +bool Frame::shouldApplyPageZoom() const +{ + if (d->m_zoomFactor == 1.0f || isZoomFactorTextOnly()) + return false; +#if ENABLE(SVG) + if (d->m_doc && d->m_doc->isSVGDocument()) + return false; +#endif + return true; +} + +void Frame::setZoomFactor(float percent, bool isTextOnly) +{ + if (d->m_zoomFactor == percent && isZoomFactorTextOnly()) + return; + +#if ENABLE(SVG) + // SVG doesn't care if the zoom factor is text only. It will always apply a + // zoom to the whole SVG. + if (d->m_doc && d->m_doc->isSVGDocument()) { + if (!static_cast<SVGDocument*>(d->m_doc.get())->zoomAndPanEnabled()) + return; + d->m_zoomFactor = percent; + d->m_page->settings()->setZoomsTextOnly(true); // We do this to avoid doing any scaling of CSS pixels, since the SVG has its own notion of zoom. + if (d->m_doc->renderer()) + d->m_doc->renderer()->repaint(); + return; + } +#endif + + d->m_zoomFactor = percent; + d->m_page->settings()->setZoomsTextOnly(isTextOnly); + + if (d->m_doc) + d->m_doc->recalcStyle(Node::Force); + + for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling()) + child->setZoomFactor(d->m_zoomFactor, isTextOnly); + + if (d->m_doc && d->m_doc->renderer() && d->m_doc->renderer()->needsLayout() && view()->didFirstLayout()) + view()->layout(); +} + +void Frame::setPrinting(bool printing, float minPageWidth, float maxPageWidth, bool adjustViewSize) +{ + if (!d->m_doc) + return; + + d->m_doc->setPrinting(printing); + view()->setMediaType(printing ? "print" : "screen"); + d->m_doc->updateStyleSelector(); + forceLayoutWithPageWidthRange(minPageWidth, maxPageWidth, adjustViewSize); + + for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling()) + child->setPrinting(printing, minPageWidth, maxPageWidth, adjustViewSize); +} + +void Frame::setJSStatusBarText(const String& text) +{ + d->m_kjsStatusBarText = text; + if (d->m_page) + d->m_page->chrome()->setStatusbarText(this, d->m_kjsStatusBarText); +} + +void Frame::setJSDefaultStatusBarText(const String& text) +{ + d->m_kjsDefaultStatusBarText = text; + if (d->m_page) + d->m_page->chrome()->setStatusbarText(this, d->m_kjsDefaultStatusBarText); +} + +String Frame::jsStatusBarText() const +{ + return d->m_kjsStatusBarText; +} + +String Frame::jsDefaultStatusBarText() const +{ + return d->m_kjsDefaultStatusBarText; +} + +void Frame::setNeedsReapplyStyles() +{ + if (d->m_needsReapplyStyles) + return; + + d->m_needsReapplyStyles = true; + + // FrameView's "layout" timer includes reapplyStyles, so despite its + // name, it's what we want to call here. + if (view()) + view()->scheduleRelayout(); +} + +bool Frame::needsReapplyStyles() const +{ + return d->m_needsReapplyStyles; +} + +void Frame::reapplyStyles() +{ + d->m_needsReapplyStyles = false; + + // FIXME: This call doesn't really make sense in a method called + // "reapplyStyles". We should probably eventually move it into its own + // method. + if (d->m_doc) + d->m_doc->docLoader()->setAutoLoadImages(d->m_page && d->m_page->settings()->loadsImagesAutomatically()); + +#if FRAME_LOADS_USER_STYLESHEET + const KURL userStyleSheetLocation = d->m_page ? d->m_page->settings()->userStyleSheetLocation() : KURL(); + if (!userStyleSheetLocation.isEmpty()) + setUserStyleSheetLocation(userStyleSheetLocation); + else + setUserStyleSheet(String()); +#endif + + // FIXME: It's not entirely clear why the following is needed. + // The document automatically does this as required when you set the style sheet. + // But we had problems when this code was removed. Details are in + // <http://bugs.webkit.org/show_bug.cgi?id=8079>. + if (d->m_doc) + d->m_doc->updateStyleSelector(); +} + +bool Frame::shouldChangeSelection(const Selection& newSelection) const +{ + return shouldChangeSelection(selection()->selection(), newSelection, newSelection.affinity(), false); +} + +bool Frame::shouldChangeSelection(const Selection& oldSelection, const Selection& newSelection, EAffinity affinity, bool stillSelecting) const +{ + return editor()->client()->shouldChangeSelectedRange(oldSelection.toRange().get(), newSelection.toRange().get(), + affinity, stillSelecting); +} + +bool Frame::shouldDeleteSelection(const Selection& selection) const +{ + return editor()->client()->shouldDeleteRange(selection.toRange().get()); +} + +bool Frame::isContentEditable() const +{ + if (d->m_editor.clientIsEditable()) + return true; + if (!d->m_doc) + return false; + return d->m_doc->inDesignMode(); +} + +#if !PLATFORM(MAC) + +void Frame::setUseSecureKeyboardEntry(bool) +{ +} + +#endif + +void Frame::updateSecureKeyboardEntryIfActive() +{ + if (selection()->isFocusedAndActive()) + setUseSecureKeyboardEntry(d->m_doc->useSecureKeyboardEntryWhenActive()); +} + +CSSMutableStyleDeclaration *Frame::typingStyle() const +{ + return d->m_typingStyle.get(); +} + +void Frame::setTypingStyle(CSSMutableStyleDeclaration *style) +{ + d->m_typingStyle = style; +} + +void Frame::clearTypingStyle() +{ + d->m_typingStyle = 0; +} + +void Frame::computeAndSetTypingStyle(CSSStyleDeclaration *style, EditAction editingAction) +{ + if (!style || style->length() == 0) { + clearTypingStyle(); + return; + } + + // Calculate the current typing style. + RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable(); + if (typingStyle()) { + typingStyle()->merge(mutableStyle.get()); + mutableStyle = typingStyle(); + } + + RefPtr<CSSValue> unicodeBidi; + RefPtr<CSSValue> direction; + if (editingAction == EditActionSetWritingDirection) { + unicodeBidi = mutableStyle->getPropertyCSSValue(CSSPropertyUnicodeBidi); + direction = mutableStyle->getPropertyCSSValue(CSSPropertyDirection); + } + + Node* node = selection()->selection().visibleStart().deepEquivalent().node(); + computedStyle(node)->diff(mutableStyle.get()); + + if (editingAction == EditActionSetWritingDirection && unicodeBidi) { + ASSERT(unicodeBidi->isPrimitiveValue()); + mutableStyle->setProperty(CSSPropertyUnicodeBidi, static_cast<CSSPrimitiveValue*>(unicodeBidi.get())->getIdent()); + if (direction) { + ASSERT(direction->isPrimitiveValue()); + mutableStyle->setProperty(CSSPropertyDirection, static_cast<CSSPrimitiveValue*>(direction.get())->getIdent()); + } + } + + // Handle block styles, substracting these from the typing style. + RefPtr<CSSMutableStyleDeclaration> blockStyle = mutableStyle->copyBlockProperties(); + blockStyle->diff(mutableStyle.get()); + if (document() && blockStyle->length() > 0) + applyCommand(ApplyStyleCommand::create(document(), blockStyle.get(), editingAction)); + + // Set the remaining style as the typing style. + d->m_typingStyle = mutableStyle.release(); +} + +String Frame::selectionStartStylePropertyValue(int stylePropertyID) const +{ + Node *nodeToRemove; + RefPtr<CSSStyleDeclaration> selectionStyle = selectionComputedStyle(nodeToRemove); + if (!selectionStyle) + return String(); + + String value = selectionStyle->getPropertyValue(stylePropertyID); + + if (nodeToRemove) { + ExceptionCode ec = 0; + nodeToRemove->remove(ec); + ASSERT(ec == 0); + } + + return value; +} + +PassRefPtr<CSSComputedStyleDeclaration> Frame::selectionComputedStyle(Node*& nodeToRemove) const +{ + nodeToRemove = 0; + + if (!document()) + return 0; + + if (selection()->isNone()) + return 0; + + RefPtr<Range> range(selection()->toRange()); + Position pos = range->editingStartPosition(); + + Element *elem = pos.element(); + if (!elem) + return 0; + + RefPtr<Element> styleElement = elem; + ExceptionCode ec = 0; + + if (d->m_typingStyle) { + styleElement = document()->createElementNS(xhtmlNamespaceURI, "span", ec); + ASSERT(ec == 0); + + styleElement->setAttribute(styleAttr, d->m_typingStyle->cssText().impl(), ec); + ASSERT(ec == 0); + + styleElement->appendChild(document()->createEditingTextNode(""), ec); + ASSERT(ec == 0); + + if (elem->renderer() && elem->renderer()->canHaveChildren()) { + elem->appendChild(styleElement, ec); + } else { + Node *parent = elem->parent(); + Node *next = elem->nextSibling(); + + if (next) { + parent->insertBefore(styleElement, next, ec); + } else { + parent->appendChild(styleElement, ec); + } + } + ASSERT(ec == 0); + + nodeToRemove = styleElement.get(); + } + + return computedStyle(styleElement.release()); +} + +void Frame::textFieldDidBeginEditing(Element* e) +{ + if (editor()->client()) + editor()->client()->textFieldDidBeginEditing(e); +} + +void Frame::textFieldDidEndEditing(Element* e) +{ + if (editor()->client()) + editor()->client()->textFieldDidEndEditing(e); +} + +void Frame::textDidChangeInTextField(Element* e) +{ + if (editor()->client()) + editor()->client()->textDidChangeInTextField(e); +} + +bool Frame::doTextFieldCommandFromEvent(Element* e, KeyboardEvent* ke) +{ + if (editor()->client()) + return editor()->client()->doTextFieldCommandFromEvent(e, ke); + + return false; +} + +void Frame::textWillBeDeletedInTextField(Element* input) +{ + if (editor()->client()) + editor()->client()->textWillBeDeletedInTextField(input); +} + +void Frame::textDidChangeInTextArea(Element* e) +{ + if (editor()->client()) + editor()->client()->textDidChangeInTextArea(e); +} + +void Frame::applyEditingStyleToBodyElement() const +{ + if (!d->m_doc) + return; + + RefPtr<NodeList> list = d->m_doc->getElementsByTagName("body"); + unsigned len = list->length(); + for (unsigned i = 0; i < len; i++) { + applyEditingStyleToElement(static_cast<Element*>(list->item(i))); + } +} + +void Frame::removeEditingStyleFromBodyElement() const +{ + if (!d->m_doc) + return; + + RefPtr<NodeList> list = d->m_doc->getElementsByTagName("body"); + unsigned len = list->length(); + for (unsigned i = 0; i < len; i++) { + removeEditingStyleFromElement(static_cast<Element*>(list->item(i))); + } +} + +void Frame::applyEditingStyleToElement(Element* element) const +{ + if (!element) + return; + + CSSStyleDeclaration* style = element->style(); + ASSERT(style); + + ExceptionCode ec = 0; + style->setProperty(CSSPropertyWordWrap, "break-word", false, ec); + ASSERT(ec == 0); + style->setProperty(CSSPropertyWebkitNbspMode, "space", false, ec); + ASSERT(ec == 0); + style->setProperty(CSSPropertyWebkitLineBreak, "after-white-space", false, ec); + ASSERT(ec == 0); +} + +void Frame::removeEditingStyleFromElement(Element*) const +{ +} + +#ifndef NDEBUG +static HashSet<Frame*>& keepAliveSet() +{ + DEFINE_STATIC_LOCAL(HashSet<Frame*>, staticKeepAliveSet, ()); + return staticKeepAliveSet; +} +#endif + +void Frame::keepAlive() +{ + if (d->m_lifeSupportTimer.isActive()) + return; +#ifndef NDEBUG + keepAliveSet().add(this); +#endif + ref(); + d->m_lifeSupportTimer.startOneShot(0); +} + +#ifndef NDEBUG +void Frame::cancelAllKeepAlive() +{ + HashSet<Frame*>::iterator end = keepAliveSet().end(); + for (HashSet<Frame*>::iterator it = keepAliveSet().begin(); it != end; ++it) { + Frame* frame = *it; + frame->d->m_lifeSupportTimer.stop(); + frame->deref(); + } + keepAliveSet().clear(); +} +#endif + +void Frame::lifeSupportTimerFired(Timer<Frame>*) +{ +#ifndef NDEBUG + keepAliveSet().remove(this); +#endif + deref(); +} + +void Frame::clearDOMWindow() +{ + if (d->m_domWindow) { + d->m_liveFormerWindows.add(d->m_domWindow.get()); + d->m_domWindow->clear(); + } + d->m_domWindow = 0; +} + +RenderView* Frame::contentRenderer() const +{ + Document* doc = document(); + if (!doc) + return 0; + RenderObject* object = doc->renderer(); + if (!object) + return 0; + ASSERT(object->isRenderView()); + return static_cast<RenderView*>(object); +} + +HTMLFrameOwnerElement* Frame::ownerElement() const +{ + return d->m_ownerElement; +} + +RenderPart* Frame::ownerRenderer() const +{ + HTMLFrameOwnerElement* ownerElement = d->m_ownerElement; + if (!ownerElement) + return 0; + RenderObject* object = ownerElement->renderer(); + if (!object) + return 0; + // FIXME: If <object> is ever fixed to disassociate itself from frames + // that it has started but canceled, then this can turn into an ASSERT + // since d->m_ownerElement would be 0 when the load is canceled. + // https://bugs.webkit.org/show_bug.cgi?id=18585 + if (!object->isRenderPart()) + return 0; + return static_cast<RenderPart*>(object); +} + +bool Frame::isDisconnected() const +{ + return d->m_isDisconnected; +} + +void Frame::setIsDisconnected(bool isDisconnected) +{ + d->m_isDisconnected = isDisconnected; +} + +bool Frame::excludeFromTextSearch() const +{ + return d->m_excludeFromTextSearch; +} + +void Frame::setExcludeFromTextSearch(bool exclude) +{ + d->m_excludeFromTextSearch = exclude; +} + +// returns FloatRect because going through IntRect would truncate any floats +FloatRect Frame::selectionBounds(bool clipToVisibleContent) const +{ + RenderView* root = contentRenderer(); + FrameView* view = d->m_view.get(); + if (!root || !view) + return IntRect(); + + IntRect selectionRect = root->selectionBounds(clipToVisibleContent); + return clipToVisibleContent ? intersection(selectionRect, view->visibleContentRect()) : selectionRect; +} + +void Frame::selectionTextRects(Vector<FloatRect>& rects, bool clipToVisibleContent) const +{ + RenderView* root = contentRenderer(); + if (!root) + return; + + RefPtr<Range> selectedRange = selection()->toRange(); + + Vector<IntRect> intRects; + selectedRange->addLineBoxRects(intRects, true); + + unsigned size = intRects.size(); + FloatRect visibleContentRect = d->m_view->visibleContentRect(); + for (unsigned i = 0; i < size; ++i) + if (clipToVisibleContent) + rects.append(intersection(intRects[i], visibleContentRect)); + else + rects.append(intRects[i]); +} + + +bool Frame::isFrameSet() const +{ + Document* document = d->m_doc.get(); + if (!document || !document->isHTMLDocument()) + return false; + Node *body = static_cast<HTMLDocument*>(document)->body(); + return body && body->renderer() && body->hasTagName(framesetTag); +} + +// Scans logically forward from "start", including any child frames +static HTMLFormElement *scanForForm(Node *start) +{ + Node *n; + for (n = start; n; n = n->traverseNextNode()) { + if (n->hasTagName(formTag)) + return static_cast<HTMLFormElement*>(n); + else if (n->isHTMLElement() && static_cast<HTMLElement*>(n)->isGenericFormElement()) + return static_cast<HTMLFormControlElement*>(n)->form(); + else if (n->hasTagName(frameTag) || n->hasTagName(iframeTag)) { + Node *childDoc = static_cast<HTMLFrameElementBase*>(n)->contentDocument(); + if (HTMLFormElement *frameResult = scanForForm(childDoc)) + return frameResult; + } + } + return 0; +} + +// We look for either the form containing the current focus, or for one immediately after it +HTMLFormElement *Frame::currentForm() const +{ + // start looking either at the active (first responder) node, or where the selection is + Node *start = d->m_doc ? d->m_doc->focusedNode() : 0; + if (!start) + start = selection()->start().node(); + + // try walking up the node tree to find a form element + Node *n; + for (n = start; n; n = n->parentNode()) { + if (n->hasTagName(formTag)) + return static_cast<HTMLFormElement*>(n); + else if (n->isHTMLElement() + && static_cast<HTMLElement*>(n)->isGenericFormElement()) + return static_cast<HTMLFormControlElement*>(n)->form(); + } + + // try walking forward in the node tree to find a form element + return start ? scanForForm(start) : 0; +} + +// FIXME: should this go in SelectionController? +void Frame::revealSelection(const RenderLayer::ScrollAlignment& alignment) const +{ + IntRect rect; + + switch (selection()->state()) { + case Selection::NONE: + return; + + case Selection::CARET: + rect = selection()->absoluteCaretBounds(); + break; + + case Selection::RANGE: + rect = enclosingIntRect(selectionBounds(false)); + break; + } + + Position start = selection()->start(); + + ASSERT(start.node()); + if (start.node() && start.node()->renderer()) { + // FIXME: This code only handles scrolling the startContainer's layer, but + // the selection rect could intersect more than just that. + // See <rdar://problem/4799899>. + if (RenderLayer *layer = start.node()->renderer()->enclosingLayer()) + layer->scrollRectToVisible(rect, false, alignment, alignment); + } +} + +void Frame::revealCaret(const RenderLayer::ScrollAlignment& alignment) const +{ + if (selection()->isNone()) + return; + + Position extent = selection()->extent(); + if (extent.node() && extent.node()->renderer()) { + IntRect extentRect = VisiblePosition(extent).absoluteCaretBounds(); + RenderLayer* layer = extent.node()->renderer()->enclosingLayer(); + if (layer) + layer->scrollRectToVisible(extentRect, false, alignment, alignment); + } +} + +void Frame::adjustPageHeight(float* newBottom, float oldTop, float oldBottom, float /*bottomLimit*/) +{ + RenderView* root = contentRenderer(); + if (root) { + // Use a context with painting disabled. + GraphicsContext context((PlatformGraphicsContext*)0); + root->setTruncatedAt((int)floorf(oldBottom)); + IntRect dirtyRect(0, (int)floorf(oldTop), root->docWidth(), (int)ceilf(oldBottom - oldTop)); + root->layer()->paint(&context, dirtyRect); + *newBottom = root->bestTruncatedAt(); + if (*newBottom == 0) + *newBottom = oldBottom; + } else + *newBottom = oldBottom; +} + +Frame* Frame::frameForWidget(const Widget* widget) +{ + ASSERT_ARG(widget, widget); + + if (RenderWidget* renderer = RenderWidget::find(widget)) + if (Node* node = renderer->node()) + return node->document()->frame(); + + // 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(); +} + +void Frame::forceLayout(bool allowSubtree) +{ + FrameView *v = d->m_view.get(); + if (v) { + v->layout(allowSubtree); + // We cannot unschedule a pending relayout, since the force can be called with + // a tiny rectangle from a drawRect update. By unscheduling we in effect + // "validate" and stop the necessary full repaint from occurring. Basically any basic + // append/remove DHTML is broken by this call. For now, I have removed the optimization + // until we have a better invalidation stategy. -dwh + //v->unscheduleRelayout(); + } +} + +void Frame::forceLayoutWithPageWidthRange(float minPageWidth, float maxPageWidth, bool adjustViewSize) +{ + // Dumping externalRepresentation(m_frame->renderer()).ascii() is a good trick to see + // the state of things before and after the layout + RenderView *root = static_cast<RenderView*>(document()->renderer()); + if (root) { + // This magic is basically copied from khtmlview::print + int pageW = (int)ceilf(minPageWidth); + root->setWidth(pageW); + root->setNeedsLayoutAndPrefWidthsRecalc(); + forceLayout(); + + // If we don't fit in the minimum page width, we'll lay out again. If we don't fit in the + // maximum page width, we will lay out to the maximum page width and clip extra content. + // FIXME: We are assuming a shrink-to-fit printing implementation. A cropping + // implementation should not do this! + int rightmostPos = root->rightmostPosition(); + if (rightmostPos > minPageWidth) { + pageW = min(rightmostPos, (int)ceilf(maxPageWidth)); + root->setWidth(pageW); + root->setNeedsLayoutAndPrefWidthsRecalc(); + forceLayout(); + } + } + + if (adjustViewSize && view()) + view()->adjustViewSize(); +} + +void Frame::sendResizeEvent() +{ + if (Document* doc = document()) + doc->dispatchWindowEvent(eventNames().resizeEvent, false, false); +} + +void Frame::sendScrollEvent() +{ + FrameView* v = d->m_view.get(); + if (!v) + return; + v->setWasScrolledByUser(true); + Document* doc = document(); + if (!doc) + return; + doc->dispatchEventForType(eventNames().scrollEvent, true, false); +} + +void Frame::clearTimers(FrameView *view, Document *document) +{ + if (view) { + view->unscheduleRelayout(); + if (view->frame()) { + if (document && document->renderer() && document->renderer()->hasLayer()) + document->renderer()->layer()->suspendMarquees(); + view->frame()->animation()->suspendAnimations(document); + view->frame()->eventHandler()->stopAutoscrollTimer(); + } + } +} + +void Frame::clearTimers() +{ + clearTimers(d->m_view.get(), document()); +} + +RenderStyle *Frame::styleForSelectionStart(Node *&nodeToRemove) const +{ + nodeToRemove = 0; + + if (!document()) + return 0; + if (selection()->isNone()) + return 0; + + Position pos = selection()->selection().visibleStart().deepEquivalent(); + if (!pos.isCandidate()) + return 0; + Node *node = pos.node(); + if (!node) + return 0; + + if (!d->m_typingStyle) + return node->renderer()->style(); + + ExceptionCode ec = 0; + RefPtr<Element> styleElement = document()->createElementNS(xhtmlNamespaceURI, "span", ec); + ASSERT(ec == 0); + + String styleText = d->m_typingStyle->cssText() + " display: inline"; + styleElement->setAttribute(styleAttr, styleText.impl(), ec); + ASSERT(ec == 0); + + styleElement->appendChild(document()->createEditingTextNode(""), ec); + ASSERT(ec == 0); + + node->parentNode()->appendChild(styleElement, ec); + ASSERT(ec == 0); + + nodeToRemove = styleElement.get(); + return styleElement->renderer() ? styleElement->renderer()->style() : 0; +} + +void Frame::setSelectionFromNone() +{ + // Put a caret inside the body if the entire frame is editable (either the + // entire WebView is editable or designMode is on for this document). + Document *doc = document(); + if (!doc || !selection()->isNone() || !isContentEditable()) + return; + + Node* node = doc->documentElement(); + while (node && !node->hasTagName(bodyTag)) + node = node->traverseNextNode(); + if (node) + selection()->setSelection(Selection(Position(node, 0), DOWNSTREAM)); +} + +bool Frame::inViewSourceMode() const +{ + return d->m_inViewSourceMode; +} + +void Frame::setInViewSourceMode(bool mode) const +{ + d->m_inViewSourceMode = mode; +} + +UChar Frame::backslashAsCurrencySymbol() const +{ + Document *doc = document(); + if (!doc) + return '\\'; + TextResourceDecoder *decoder = doc->decoder(); + if (!decoder) + return '\\'; + + return decoder->encoding().backslashAsCurrencySymbol(); +} + +// Searches from the beginning of the document if nothing is selected. +bool Frame::findString(const String& target, bool forward, bool caseFlag, bool wrapFlag, bool startInSelection) +{ + if (target.isEmpty() || !document()) + return false; + + if (excludeFromTextSearch()) + return false; + + // Start from an edge of the selection, if there's a selection that's not in shadow content. Which edge + // is used depends on whether we're searching forward or backward, and whether startInSelection is set. + RefPtr<Range> searchRange(rangeOfContents(document())); + Selection selection = this->selection()->selection(); + + if (forward) + setStart(searchRange.get(), startInSelection ? selection.visibleStart() : selection.visibleEnd()); + else + setEnd(searchRange.get(), startInSelection ? selection.visibleEnd() : selection.visibleStart()); + + Node* shadowTreeRoot = selection.shadowTreeRootNode(); + if (shadowTreeRoot) { + ExceptionCode ec = 0; + if (forward) + searchRange->setEnd(shadowTreeRoot, shadowTreeRoot->childNodeCount(), ec); + else + searchRange->setStart(shadowTreeRoot, 0, ec); + } + + RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, forward, caseFlag)); + // If we started in the selection and the found range exactly matches the existing selection, find again. + // Build a selection with the found range to remove collapsed whitespace. + // Compare ranges instead of selection objects to ignore the way that the current selection was made. + if (startInSelection && *Selection(resultRange.get()).toRange() == *selection.toRange()) { + searchRange = rangeOfContents(document()); + if (forward) + setStart(searchRange.get(), selection.visibleEnd()); + else + setEnd(searchRange.get(), selection.visibleStart()); + + if (shadowTreeRoot) { + ExceptionCode ec = 0; + if (forward) + searchRange->setEnd(shadowTreeRoot, shadowTreeRoot->childNodeCount(), ec); + else + searchRange->setStart(shadowTreeRoot, 0, ec); + } + + resultRange = findPlainText(searchRange.get(), target, forward, caseFlag); + } + + ExceptionCode exception = 0; + + // If nothing was found in the shadow tree, search in main content following the shadow tree. + if (resultRange->collapsed(exception) && shadowTreeRoot) { + searchRange = rangeOfContents(document()); + if (forward) + searchRange->setStartAfter(shadowTreeRoot->shadowParentNode(), exception); + else + searchRange->setEndBefore(shadowTreeRoot->shadowParentNode(), exception); + + resultRange = findPlainText(searchRange.get(), target, forward, caseFlag); + } + + if (!editor()->insideVisibleArea(resultRange.get())) { + resultRange = editor()->nextVisibleRange(resultRange.get(), target, forward, caseFlag, wrapFlag); + if (!resultRange) + return false; + } + + // If we didn't find anything and we're wrapping, search again in the entire document (this will + // redundantly re-search the area already searched in some cases). + if (resultRange->collapsed(exception) && wrapFlag) { + searchRange = rangeOfContents(document()); + resultRange = findPlainText(searchRange.get(), target, forward, caseFlag); + // We used to return false here if we ended up with the same range that we started with + // (e.g., the selection was already the only instance of this text). But we decided that + // this should be a success case instead, so we'll just fall through in that case. + } + + if (resultRange->collapsed(exception)) + return false; + + this->selection()->setSelection(Selection(resultRange.get(), DOWNSTREAM)); + revealSelection(); + return true; +} + +unsigned Frame::markAllMatchesForText(const String& target, bool caseFlag, unsigned limit) +{ + if (target.isEmpty() || !document()) + return 0; + + RefPtr<Range> searchRange(rangeOfContents(document())); + + ExceptionCode exception = 0; + unsigned matchCount = 0; + do { + RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, true, caseFlag)); + if (resultRange->collapsed(exception)) { + if (!resultRange->startContainer()->isInShadowTree()) + break; + + searchRange = rangeOfContents(document()); + searchRange->setStartAfter(resultRange->startContainer()->shadowAncestorNode(), exception); + continue; + } + + // A non-collapsed result range can in some funky whitespace cases still not + // advance the range's start position (4509328). Break to avoid infinite loop. + VisiblePosition newStart = endVisiblePosition(resultRange.get(), DOWNSTREAM); + if (newStart == startVisiblePosition(searchRange.get(), DOWNSTREAM)) + break; + + // Only treat the result as a match if it is visible + if (editor()->insideVisibleArea(resultRange.get())) { + ++matchCount; + document()->addMarker(resultRange.get(), DocumentMarker::TextMatch); + } + + // Stop looking if we hit the specified limit. A limit of 0 means no limit. + if (limit > 0 && matchCount >= limit) + break; + + setStart(searchRange.get(), newStart); + Node* shadowTreeRoot = searchRange->shadowTreeRootNode(); + if (searchRange->collapsed(exception) && shadowTreeRoot) + searchRange->setEnd(shadowTreeRoot, shadowTreeRoot->childNodeCount(), exception); + } while (true); + + // Do a "fake" paint in order to execute the code that computes the rendered rect for + // each text match. + Document* doc = document(); + if (doc && d->m_view && contentRenderer()) { + doc->updateLayout(); // Ensure layout is up to date. + IntRect visibleRect = d->m_view->visibleContentRect(); + if (!visibleRect.isEmpty()) { + GraphicsContext context((PlatformGraphicsContext*)0); + context.setPaintingDisabled(true); + d->m_view->paintContents(&context, visibleRect); + } + } + + return matchCount; +} + +bool Frame::markedTextMatchesAreHighlighted() const +{ + return d->m_highlightTextMatches; +} + +void Frame::setMarkedTextMatchesAreHighlighted(bool flag) +{ + if (flag == d->m_highlightTextMatches || !document()) + return; + + d->m_highlightTextMatches = flag; + document()->repaintMarkers(DocumentMarker::TextMatch); +} + +FrameTree* Frame::tree() const +{ + return &d->m_treeNode; +} + +void Frame::setDOMWindow(DOMWindow* domWindow) +{ + if (d->m_domWindow) { + d->m_liveFormerWindows.add(d->m_domWindow.get()); + d->m_domWindow->clear(); + } + d->m_domWindow = domWindow; +} + +DOMWindow* Frame::domWindow() const +{ + if (!d->m_domWindow) + d->m_domWindow = DOMWindow::create(const_cast<Frame*>(this)); + + return d->m_domWindow.get(); +} + +void Frame::clearFormerDOMWindow(DOMWindow* window) +{ + d->m_liveFormerWindows.remove(window); +} + +Page* Frame::page() const +{ + return d->m_page; +} + +EventHandler* Frame::eventHandler() const +{ + return &d->m_eventHandler; +} + +void Frame::pageDestroyed() +{ + if (Frame* parent = tree()->parent()) + parent->loader()->checkLoadComplete(); + + // FIXME: It's unclear as to why this is called more than once, but it is, + // so page() could be NULL. + if (page() && page()->focusController()->focusedFrame() == this) + page()->focusController()->setFocusedFrame(0); + + script()->clearWindowShell(); + + // This will stop any JS timers + if (script()->haveWindowShell()) + script()->windowShell()->disconnectFrame(); + + script()->clearScriptObjects(); + script()->updatePlatformScriptObjects(); + + d->m_page = 0; +} + +void Frame::disconnectOwnerElement() +{ + if (d->m_ownerElement) { + if (Document* doc = document()) + doc->clearAXObjectCache(); + d->m_ownerElement->m_contentFrame = 0; + if (d->m_page) + d->m_page->decrementFrameCount(); + } + d->m_ownerElement = 0; +} + +String Frame::documentTypeString() const +{ + if (Document* doc = document()) { + if (DocumentType* doctype = doc->doctype()) + return createMarkup(doctype); + } + + return String(); +} + +void Frame::focusWindow() +{ + if (!page()) + return; + + // If we're a top level window, bring the window to the front. + if (!tree()->parent()) + page()->chrome()->focus(); + + eventHandler()->focusDocumentView(); +} + +void Frame::unfocusWindow() +{ + if (!page()) + return; + + // If we're a top level window, deactivate the window. + if (!tree()->parent()) + page()->chrome()->unfocus(); +} + +bool Frame::shouldClose() +{ + Chrome* chrome = page() ? page()->chrome() : 0; + if (!chrome || !chrome->canRunBeforeUnloadConfirmPanel()) + return true; + + RefPtr<Document> doc = document(); + if (!doc) + return true; + HTMLElement* body = doc->body(); + if (!body) + return true; + + RefPtr<BeforeUnloadEvent> beforeUnloadEvent = BeforeUnloadEvent::create(); + beforeUnloadEvent->setTarget(doc); + doc->handleWindowEvent(beforeUnloadEvent.get(), false); + + if (!beforeUnloadEvent->defaultPrevented() && doc) + doc->defaultEventHandler(beforeUnloadEvent.get()); + if (beforeUnloadEvent->result().isNull()) + return true; + + String text = beforeUnloadEvent->result(); + text.replace('\\', backslashAsCurrencySymbol()); + + return chrome->runBeforeUnloadConfirmPanel(text, this); +} + +void Frame::scheduleClose() +{ + if (!shouldClose()) + return; + + Chrome* chrome = page() ? page()->chrome() : 0; + if (chrome) + chrome->closeWindowSoon(); +} + +void Frame::respondToChangedSelection(const Selection& oldSelection, bool closeTyping) +{ + if (document()) { + bool isContinuousSpellCheckingEnabled = editor()->isContinuousSpellCheckingEnabled(); + bool isContinuousGrammarCheckingEnabled = isContinuousSpellCheckingEnabled && editor()->isGrammarCheckingEnabled(); + if (isContinuousSpellCheckingEnabled) { + Selection newAdjacentWords; + Selection newSelectedSentence; + if (selection()->selection().isContentEditable()) { + VisiblePosition newStart(selection()->selection().visibleStart()); + newAdjacentWords = Selection(startOfWord(newStart, LeftWordIfOnBoundary), endOfWord(newStart, RightWordIfOnBoundary)); + if (isContinuousGrammarCheckingEnabled) + newSelectedSentence = Selection(startOfSentence(newStart), endOfSentence(newStart)); + } + + // When typing we check spelling elsewhere, so don't redo it here. + // If this is a change in selection resulting from a delete operation, + // oldSelection may no longer be in the document. + if (closeTyping && oldSelection.isContentEditable() && oldSelection.start().node() && oldSelection.start().node()->inDocument()) { + VisiblePosition oldStart(oldSelection.visibleStart()); + Selection oldAdjacentWords = Selection(startOfWord(oldStart, LeftWordIfOnBoundary), endOfWord(oldStart, RightWordIfOnBoundary)); + if (oldAdjacentWords != newAdjacentWords) { + editor()->markMisspellings(oldAdjacentWords); + if (isContinuousGrammarCheckingEnabled) { + Selection oldSelectedSentence = Selection(startOfSentence(oldStart), endOfSentence(oldStart)); + if (oldSelectedSentence != newSelectedSentence) + editor()->markBadGrammar(oldSelectedSentence); + } + } + } + + // This only erases markers that are in the first unit (word or sentence) of the selection. + // Perhaps peculiar, but it matches AppKit. + if (RefPtr<Range> wordRange = newAdjacentWords.toRange()) + document()->removeMarkers(wordRange.get(), DocumentMarker::Spelling); + if (RefPtr<Range> sentenceRange = newSelectedSentence.toRange()) + document()->removeMarkers(sentenceRange.get(), DocumentMarker::Grammar); + } + + // When continuous spell checking is off, existing markers disappear after the selection changes. + if (!isContinuousSpellCheckingEnabled) + document()->removeMarkers(DocumentMarker::Spelling); + if (!isContinuousGrammarCheckingEnabled) + document()->removeMarkers(DocumentMarker::Grammar); + } + + editor()->respondToChangedSelection(oldSelection); +} + +VisiblePosition Frame::visiblePositionForPoint(const IntPoint& framePoint) +{ + HitTestResult result = eventHandler()->hitTestResultAtPoint(framePoint, true); + Node* node = result.innerNode(); + if (!node) + return VisiblePosition(); + RenderObject* renderer = node->renderer(); + if (!renderer) + return VisiblePosition(); + VisiblePosition visiblePos = renderer->positionForCoordinates(result.localPoint().x(), result.localPoint().y()); + if (visiblePos.isNull()) + visiblePos = VisiblePosition(Position(node, 0)); + return visiblePos; +} + +Document* Frame::documentAtPoint(const IntPoint& point) +{ + if (!view()) + return 0; + + IntPoint pt = view()->windowToContents(point); + HitTestResult result = HitTestResult(pt); + + if (contentRenderer()) + result = eventHandler()->hitTestResultAtPoint(pt, false); + return result.innerNode() ? result.innerNode()->document() : 0; +} + +FramePrivate::FramePrivate(Page* page, Frame* parent, Frame* thisFrame, HTMLFrameOwnerElement* ownerElement, + FrameLoaderClient* frameLoaderClient) + : m_page(page) + , m_treeNode(thisFrame, parent) + , m_loader(thisFrame, frameLoaderClient) + , m_ownerElement(ownerElement) + , m_script(thisFrame) + , m_zoomFactor(parent ? parent->d->m_zoomFactor : 1.0f) + , m_selectionGranularity(CharacterGranularity) + , m_selectionController(thisFrame) + , m_caretBlinkTimer(thisFrame, &Frame::caretBlinkTimerFired) + , m_editor(thisFrame) + , m_eventHandler(thisFrame) + , m_animationController(thisFrame) + , m_lifeSupportTimer(thisFrame, &Frame::lifeSupportTimerFired) + , m_caretVisible(false) + , m_caretPaint(true) + , m_highlightTextMatches(false) + , m_inViewSourceMode(false) + , m_needsReapplyStyles(false) + , m_isDisconnected(false) + , m_excludeFromTextSearch(false) +#if FRAME_LOADS_USER_STYLESHEET + , m_userStyleSheetLoader(0) +#endif +{ +} + +FramePrivate::~FramePrivate() +{ +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/Frame.h b/src/3rdparty/webkit/WebCore/page/Frame.h new file mode 100644 index 0000000..874d90d --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/Frame.h @@ -0,0 +1,328 @@ +/* + * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org> + * 1999-2001 Lars Knoll <knoll@kde.org> + * 1999-2001 Antti Koivisto <koivisto@kde.org> + * 2000-2001 Simon Hausmann <hausmann@kde.org> + * 2000-2001 Dirk Mueller <mueller@kde.org> + * 2000 Stefan Schimanski <1Stein@gmx.de> + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2008 Eric Seidel <eric@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef Frame_h +#define Frame_h + +#include "DragImage.h" +#include "EditAction.h" +#include "RenderLayer.h" +#include "TextGranularity.h" + +#if PLATFORM(MAC) +#ifndef __OBJC__ +class NSArray; +class NSDictionary; +class NSMutableDictionary; +class NSString; +typedef int NSWritingDirection; +#endif +#endif + +#if PLATFORM(WIN) +typedef struct HBITMAP__* HBITMAP; +#endif + +namespace WebCore { + +class Editor; +class EventHandler; +class FrameLoader; +class FrameLoaderClient; +class FramePrivate; +class FrameTree; +class HTMLFrameOwnerElement; +class HTMLTableCellElement; +class ScriptController; +class RegularExpression; +class RenderPart; +class Selection; +class SelectionController; +class Widget; + +template <typename T> class Timer; + +class Frame : public RefCounted<Frame> { +public: + static PassRefPtr<Frame> create(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* client) + { + return adoptRef(new Frame(page, ownerElement, client)); + } + void setView(FrameView*); + ~Frame(); + + void init(); + + Page* page() const; + HTMLFrameOwnerElement* ownerElement() const; + + void pageDestroyed(); + void disconnectOwnerElement(); + + Document* document() const; + FrameView* view() const; + + void setDOMWindow(DOMWindow*); + DOMWindow* domWindow() const; + void clearFormerDOMWindow(DOMWindow*); + + Editor* editor() const; + EventHandler* eventHandler() const; + FrameLoader* loader() const; + SelectionController* selection() const; + FrameTree* tree() const; + AnimationController* animation() const; + ScriptController* script(); + + RenderView* contentRenderer() const; // root renderer for the document contained in this frame + RenderPart* ownerRenderer() const; // renderer for the element that contains this frame + + bool isDisconnected() const; + void setIsDisconnected(bool); + bool excludeFromTextSearch() const; + void setExcludeFromTextSearch(bool); + + friend class FramePrivate; + +private: + Frame(Page*, HTMLFrameOwnerElement*, FrameLoaderClient*); + + FramePrivate* d; + +// === undecided, would like to consider moving to another class + +public: + static Frame* frameForWidget(const Widget*); + + Settings* settings() const; // can be NULL + +#if FRAME_LOADS_USER_STYLESHEET + void setUserStyleSheetLocation(const KURL&); + void setUserStyleSheet(const String& styleSheetData); +#endif + + void setPrinting(bool printing, float minPageWidth, float maxPageWidth, bool adjustViewSize); + + bool inViewSourceMode() const; + void setInViewSourceMode(bool = true) const; + + void keepAlive(); // Used to keep the frame alive when running a script that might destroy it. +#ifndef NDEBUG + static void cancelAllKeepAlive(); +#endif + + void setDocument(PassRefPtr<Document>); + + void clearTimers(); + static void clearTimers(FrameView*, Document*); + + // Convenience, to avoid repeating the code to dig down to get this. + UChar backslashAsCurrencySymbol() const; + + void setNeedsReapplyStyles(); + bool needsReapplyStyles() const; + void reapplyStyles(); + + String documentTypeString() const; + + // This method -- and the corresponding list of former DOM windows -- + // should move onto ScriptController + void clearDOMWindow(); + +private: + void lifeSupportTimerFired(Timer<Frame>*); + +// === to be moved into Document + +public: + bool isFrameSet() const; + +// === to be moved into EventHandler + +public: + void sendResizeEvent(); + void sendScrollEvent(); + +// === to be moved into FrameView + +public: + void forceLayout(bool allowSubtree = false); + void forceLayoutWithPageWidthRange(float minPageWidth, float maxPageWidth, bool adjustViewSize); + + void adjustPageHeight(float* newBottom, float oldTop, float oldBottom, float bottomLimit); + + void setZoomFactor(float scale, bool isTextOnly); + float zoomFactor() const; + bool isZoomFactorTextOnly() const; + bool shouldApplyTextZoom() const; + bool shouldApplyPageZoom() const; + float pageZoomFactor() const { return shouldApplyPageZoom() ? zoomFactor() : 1.0f; } + float textZoomFactor() const { return shouldApplyTextZoom() ? zoomFactor() : 1.0f; } + +// === to be moved into Chrome + +public: + void focusWindow(); + void unfocusWindow(); + bool shouldClose(); + void scheduleClose(); + + void setJSStatusBarText(const String&); + void setJSDefaultStatusBarText(const String&); + String jsStatusBarText() const; + String jsDefaultStatusBarText() const; + +// === to be moved into Editor + +public: + String selectedText() const; + bool findString(const String&, bool forward, bool caseFlag, bool wrapFlag, bool startInSelection); + + const Selection& mark() const; // Mark, to be used as emacs uses it. + void setMark(const Selection&); + + void computeAndSetTypingStyle(CSSStyleDeclaration* , EditAction = EditActionUnspecified); + String selectionStartStylePropertyValue(int stylePropertyID) const; + void applyEditingStyleToBodyElement() const; + void removeEditingStyleFromBodyElement() const; + void applyEditingStyleToElement(Element*) const; + void removeEditingStyleFromElement(Element*) const; + + IntRect firstRectForRange(Range*) const; + + void respondToChangedSelection(const Selection& oldSelection, bool closeTyping); + bool shouldChangeSelection(const Selection& oldSelection, const Selection& newSelection, EAffinity, bool stillSelecting) const; + + RenderStyle* styleForSelectionStart(Node*& nodeToRemove) const; + + unsigned markAllMatchesForText(const String&, bool caseFlag, unsigned limit); + bool markedTextMatchesAreHighlighted() const; + void setMarkedTextMatchesAreHighlighted(bool flag); + + PassRefPtr<CSSComputedStyleDeclaration> selectionComputedStyle(Node*& nodeToRemove) const; + + void textFieldDidBeginEditing(Element*); + void textFieldDidEndEditing(Element*); + void textDidChangeInTextField(Element*); + bool doTextFieldCommandFromEvent(Element*, KeyboardEvent*); + void textWillBeDeletedInTextField(Element* input); + void textDidChangeInTextArea(Element*); + + DragImageRef dragImageForSelection(); + +// === to be moved into SelectionController + +public: + TextGranularity selectionGranularity() const; + void setSelectionGranularity(TextGranularity) const; + + bool shouldChangeSelection(const Selection&) const; + bool shouldDeleteSelection(const Selection&) const; + void clearCaretRectIfNeeded(); + void setFocusedNodeIfNeeded(); + void selectionLayoutChanged(); + void notifyRendererOfSelectionChange(bool userTriggered); + + void invalidateSelection(); + + void setCaretVisible(bool = true); + void paintCaret(GraphicsContext*, int tx, int ty, const IntRect& clipRect) const; + void paintDragCaret(GraphicsContext*, int tx, int ty, const IntRect& clipRect) const; + + bool isContentEditable() const; // if true, everything in frame is editable + + void updateSecureKeyboardEntryIfActive(); + + CSSMutableStyleDeclaration* typingStyle() const; + void setTypingStyle(CSSMutableStyleDeclaration*); + void clearTypingStyle(); + + FloatRect selectionBounds(bool clipToVisibleContent = true) const; + void selectionTextRects(Vector<FloatRect>&, bool clipToVisibleContent = true) const; + + HTMLFormElement* currentForm() const; + + void revealSelection(const RenderLayer::ScrollAlignment& = RenderLayer::gAlignCenterIfNeeded) const; + void revealCaret(const RenderLayer::ScrollAlignment& = RenderLayer::gAlignCenterIfNeeded) const; + void setSelectionFromNone(); + + void setUseSecureKeyboardEntry(bool); + +private: + void caretBlinkTimerFired(Timer<Frame>*); + +public: + SelectionController* dragCaretController() const; + + String searchForLabelsAboveCell(RegularExpression*, HTMLTableCellElement*); + String searchForLabelsBeforeElement(const Vector<String>& labels, Element*); + String matchLabelsAgainstElement(const Vector<String>& labels, Element*); + + VisiblePosition visiblePositionForPoint(const IntPoint& framePoint); + Document* documentAtPoint(const IntPoint& windowPoint); + +#if PLATFORM(MAC) + +// === undecided, would like to consider moving to another class + +public: + NSString* searchForNSLabelsAboveCell(RegularExpression*, HTMLTableCellElement*); + NSString* searchForLabelsBeforeElement(NSArray* labels, Element*); + NSString* matchLabelsAgainstElement(NSArray* labels, Element*); + +#if ENABLE(DASHBOARD_SUPPORT) + NSMutableDictionary* dashboardRegionsDictionary(); +#endif + + NSImage* selectionImage(bool forceBlackText = false) const; + NSImage* snapshotDragImage(Node*, NSRect* imageRect, NSRect* elementRect) const; + NSImage* nodeImage(Node*) const; + +private: + NSImage* imageFromRect(NSRect) const; + +// === to be moved into Editor + +public: + NSDictionary* fontAttributesForSelectionStart() const; + NSWritingDirection baseWritingDirectionForSelectionStart() const; + +#endif + +#if PLATFORM(WIN) + +public: + // FIXME - We should have a single version of nodeImage instead of using platform types. + HBITMAP nodeImage(Node*) const; + +#endif + +}; + +} // namespace WebCore + +#endif // Frame_h diff --git a/src/3rdparty/webkit/WebCore/page/FrameLoadRequest.h b/src/3rdparty/webkit/WebCore/page/FrameLoadRequest.h new file mode 100644 index 0000000..99f415f --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/FrameLoadRequest.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2003, 2006 Apple Computer, 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 FrameLoadRequest_h +#define FrameLoadRequest_h + +#include "ResourceRequest.h" + +namespace WebCore { + + struct FrameLoadRequest { + public: + FrameLoadRequest() + : m_lockHistory(false) + { + } + + FrameLoadRequest(const ResourceRequest& resourceRequest) + : m_resourceRequest(resourceRequest) + , m_lockHistory(false) + { + } + + FrameLoadRequest(const ResourceRequest& resourceRequest, const String& frameName) + : m_resourceRequest(resourceRequest) + , m_frameName(frameName) + , m_lockHistory(false) + { + } + + bool isEmpty() const { return m_resourceRequest.isEmpty(); } + + ResourceRequest& resourceRequest() { return m_resourceRequest; } + const ResourceRequest& resourceRequest() const { return m_resourceRequest; } + + const String& frameName() const { return m_frameName; } + void setFrameName(const String& frameName) { m_frameName = frameName; } + + bool lockHistory() const { return m_lockHistory; } + void setLockHistory(bool lock) { m_lockHistory = lock; } + + private: + ResourceRequest m_resourceRequest; + String m_frameName; + bool m_lockHistory; + }; + +} + +#endif // FrameLoadRequest_h + diff --git a/src/3rdparty/webkit/WebCore/page/FramePrivate.h b/src/3rdparty/webkit/WebCore/page/FramePrivate.h new file mode 100644 index 0000000..2f7c59a --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/FramePrivate.h @@ -0,0 +1,99 @@ +/* Copyright (C) 1998, 1999 Torben Weis <weis@kde.org> + * 1999-2001 Lars Knoll <knoll@kde.org> + * 1999-2001 Antti Koivisto <koivisto@kde.org> + * 2000-2001 Simon Hausmann <hausmann@kde.org> + * 2000-2001 Dirk Mueller <mueller@kde.org> + * 2000 Stefan Schimanski <1Stein@gmx.de> + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef FramePrivate_h +#define FramePrivate_h + +#include "AnimationController.h" +#include "Editor.h" +#include "EventHandler.h" +#include "FrameLoader.h" +#include "FrameTree.h" +#include "Range.h" +#include "SelectionController.h" +#include "StringHash.h" +#include "ScriptController.h" + +#if PLATFORM(WIN) +#include "FrameWin.h" +#endif + +namespace WebCore { + +#if FRAME_LOADS_USER_STYLESHEET + class UserStyleSheetLoader; +#endif + + class FramePrivate { + public: + FramePrivate(Page*, Frame* parent, Frame* thisFrame, HTMLFrameOwnerElement*, FrameLoaderClient*); + ~FramePrivate(); + + Page* m_page; + FrameTree m_treeNode; + FrameLoader m_loader; + RefPtr<DOMWindow> m_domWindow; + HashSet<DOMWindow*> m_liveFormerWindows; + + HTMLFrameOwnerElement* m_ownerElement; + RefPtr<FrameView> m_view; + RefPtr<Document> m_doc; + + ScriptController m_script; + + String m_kjsStatusBarText; + String m_kjsDefaultStatusBarText; + + float m_zoomFactor; + + TextGranularity m_selectionGranularity; + + SelectionController m_selectionController; + Selection m_mark; + Timer<Frame> m_caretBlinkTimer; + Editor m_editor; + EventHandler m_eventHandler; + AnimationController m_animationController; + + RefPtr<CSSMutableStyleDeclaration> m_typingStyle; + + Timer<Frame> m_lifeSupportTimer; + + bool m_caretVisible; + bool m_caretPaint; + + bool m_highlightTextMatches; + bool m_inViewSourceMode; + bool m_needsReapplyStyles; + bool m_isDisconnected; + bool m_excludeFromTextSearch; + +#if FRAME_LOADS_USER_STYLESHEET + UserStyleSheetLoader* m_userStyleSheetLoader; +#endif + }; +} + +#endif diff --git a/src/3rdparty/webkit/WebCore/page/FrameTree.cpp b/src/3rdparty/webkit/WebCore/page/FrameTree.cpp new file mode 100644 index 0000000..c9b4172 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/FrameTree.cpp @@ -0,0 +1,314 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "FrameTree.h" + +#include "Frame.h" +#include "Page.h" +#include "PageGroup.h" +#include <stdarg.h> +#include <wtf/Platform.h> +#include <wtf/StringExtras.h> +#include <wtf/Vector.h> + +using std::swap; + +namespace WebCore { + +FrameTree::~FrameTree() +{ + for (Frame* child = firstChild(); child; child = child->tree()->nextSibling()) + child->setView(0); +} + +void FrameTree::setName(const AtomicString& name) +{ + if (!parent()) { + m_name = name; + return; + } + m_name = AtomicString(); // Remove our old frame name so it's not considered in uniqueChildName. + m_name = parent()->tree()->uniqueChildName(name); +} + +void FrameTree::clearName() +{ + m_name = AtomicString(); +} + +Frame* FrameTree::parent(bool checkForDisconnectedFrame) const +{ + if (checkForDisconnectedFrame && m_thisFrame->isDisconnected()) + return 0; + return m_parent; +} + +void FrameTree::appendChild(PassRefPtr<Frame> child) +{ + ASSERT(child->page() == m_thisFrame->page()); + child->tree()->m_parent = m_thisFrame; + + Frame* oldLast = m_lastChild; + m_lastChild = child.get(); + + if (oldLast) { + child->tree()->m_previousSibling = oldLast; + oldLast->tree()->m_nextSibling = child; + } else + m_firstChild = child; + + m_childCount++; + + ASSERT(!m_lastChild->tree()->m_nextSibling); +} + +void FrameTree::removeChild(Frame* child) +{ + child->tree()->m_parent = 0; + child->setView(0); + if (child->ownerElement()) + child->page()->decrementFrameCount(); + child->pageDestroyed(); + + // Slightly tricky way to prevent deleting the child until we are done with it, w/o + // extra refs. These swaps leave the child in a circular list by itself. Clearing its + // previous and next will then finally deref it. + + RefPtr<Frame>& newLocationForNext = m_firstChild == child ? m_firstChild : child->tree()->m_previousSibling->tree()->m_nextSibling; + Frame*& newLocationForPrevious = m_lastChild == child ? m_lastChild : child->tree()->m_nextSibling->tree()->m_previousSibling; + swap(newLocationForNext, child->tree()->m_nextSibling); + // For some inexplicable reason, the following line does not compile without the explicit std:: namepsace + std::swap(newLocationForPrevious, child->tree()->m_previousSibling); + + child->tree()->m_previousSibling = 0; + child->tree()->m_nextSibling = 0; + + m_childCount--; +} + +AtomicString FrameTree::uniqueChildName(const AtomicString& requestedName) const +{ + if (!requestedName.isEmpty() && !child(requestedName) && requestedName != "_blank") + return requestedName; + + // Create a repeatable name for a child about to be added to us. The name must be + // unique within the frame tree. The string we generate includes a "path" of names + // from the root frame down to us. For this path to be unique, each set of siblings must + // contribute a unique name to the path, which can't collide with any HTML-assigned names. + // We generate this path component by index in the child list along with an unlikely + // frame name that can't be set in HTML because it collides with comment syntax. + + const char framePathPrefix[] = "<!--framePath "; + const int framePathPrefixLength = 14; + const int framePathSuffixLength = 3; + + // Find the nearest parent that has a frame with a path in it. + Vector<Frame*, 16> chain; + Frame* frame; + for (frame = m_thisFrame; frame; frame = frame->tree()->parent()) { + if (frame->tree()->name().startsWith(framePathPrefix)) + break; + chain.append(frame); + } + String name; + name += framePathPrefix; + if (frame) + name += frame->tree()->name().string().substring(framePathPrefixLength, + frame->tree()->name().length() - framePathPrefixLength - framePathSuffixLength); + for (int i = chain.size() - 1; i >= 0; --i) { + frame = chain[i]; + name += "/"; + name += frame->tree()->name(); + } + + // Suffix buffer has more than enough space for: + // 10 characters before the number + // a number (3 digits for the highest this gets in practice, 20 digits for the largest 64-bit integer) + // 6 characters after the number + // trailing null byte + // But we still use snprintf just to be extra-safe. + char suffix[40]; + snprintf(suffix, sizeof(suffix), "/<!--frame%u-->-->", childCount()); + + name += suffix; + + return AtomicString(name); +} + +Frame* FrameTree::child(unsigned index) const +{ + Frame* result = firstChild(); + for (unsigned i = 0; result && i != index; ++i) + result = result->tree()->nextSibling(); + return result; +} + +Frame* FrameTree::child(const AtomicString& name) const +{ + for (Frame* child = firstChild(); child; child = child->tree()->nextSibling()) + if (child->tree()->name() == name) + return child; + return 0; +} + +Frame* FrameTree::find(const AtomicString& name) const +{ + if (name == "_self" || name == "_current" || name.isEmpty()) + return m_thisFrame; + + if (name == "_top") + return top(); + + if (name == "_parent") + return parent() ? parent() : m_thisFrame; + + // Since "_blank" should never be any frame's name, the following just amounts to an optimization. + if (name == "_blank") + return 0; + + // Search subtree starting with this frame first. + for (Frame* frame = m_thisFrame; frame; frame = frame->tree()->traverseNext(m_thisFrame)) + if (frame->tree()->name() == name) + return frame; + + // Search the entire tree for this page next. + Page* page = m_thisFrame->page(); + + // The frame could have been detached from the page, so check it. + if (!page) + return 0; + + for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext()) + if (frame->tree()->name() == name) + return frame; + + // Search the entire tree of each of the other pages in this namespace. + // FIXME: Is random order OK? + const HashSet<Page*>& pages = page->group().pages(); + HashSet<Page*>::const_iterator end = pages.end(); + for (HashSet<Page*>::const_iterator it = pages.begin(); it != end; ++it) { + Page* otherPage = *it; + if (otherPage != page) { + for (Frame* frame = otherPage->mainFrame(); frame; frame = frame->tree()->traverseNext()) { + if (frame->tree()->name() == name) + return frame; + } + } + } + + return 0; +} + +bool FrameTree::isDescendantOf(const Frame* ancestor) const +{ + if (!ancestor) + return false; + + if (m_thisFrame->page() != ancestor->page()) + return false; + + for (Frame* frame = m_thisFrame; frame; frame = frame->tree()->parent()) + if (frame == ancestor) + return true; + return false; +} + +Frame* FrameTree::traverseNext(const Frame* stayWithin) const +{ + Frame* child = firstChild(); + if (child) { + ASSERT(!stayWithin || child->tree()->isDescendantOf(stayWithin)); + return child; + } + + if (m_thisFrame == stayWithin) + return 0; + + Frame* sibling = nextSibling(); + if (sibling) { + ASSERT(!stayWithin || sibling->tree()->isDescendantOf(stayWithin)); + return sibling; + } + + Frame* frame = m_thisFrame; + while (!sibling && (!stayWithin || frame->tree()->parent() != stayWithin)) { + frame = frame->tree()->parent(); + if (!frame) + return 0; + sibling = frame->tree()->nextSibling(); + } + + if (frame) { + ASSERT(!stayWithin || !sibling || sibling->tree()->isDescendantOf(stayWithin)); + return sibling; + } + + return 0; +} + +Frame* FrameTree::traverseNextWithWrap(bool wrap) const +{ + if (Frame* result = traverseNext()) + return result; + + if (wrap) + return m_thisFrame->page()->mainFrame(); + + return 0; +} + +Frame* FrameTree::traversePreviousWithWrap(bool wrap) const +{ + // FIXME: besides the wrap feature, this is just the traversePreviousNode algorithm + + if (Frame* prevSibling = previousSibling()) + return prevSibling->tree()->deepLastChild(); + if (Frame* parentFrame = parent()) + return parentFrame; + + // no siblings, no parent, self==top + if (wrap) + return deepLastChild(); + + // top view is always the last one in this ordering, so prev is nil without wrap + return 0; +} + +Frame* FrameTree::deepLastChild() const +{ + Frame* result = m_thisFrame; + for (Frame* last = lastChild(); last; last = last->tree()->lastChild()) + result = last; + + return result; +} + +Frame* FrameTree::top(bool checkForDisconnectedFrame) const +{ + Frame* frame = m_thisFrame; + for (Frame* parent = m_thisFrame; parent; parent = parent->tree()->parent()) { + frame = parent; + if (checkForDisconnectedFrame && frame->isDisconnected()) + return frame; + } + return frame; +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/FrameTree.h b/src/3rdparty/webkit/WebCore/page/FrameTree.h new file mode 100644 index 0000000..0952dcd --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/FrameTree.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef FrameTree_h +#define FrameTree_h + +#include "AtomicString.h" +#include "Frame.h" + +namespace WebCore { + + class FrameTree : Noncopyable { + public: + FrameTree(Frame* thisFrame, Frame* parentFrame) + : m_thisFrame(thisFrame) + , m_parent(parentFrame) + , m_previousSibling(0) + , m_lastChild(0) + , m_childCount(0) + { + } + ~FrameTree(); + + const AtomicString& name() const { return m_name; } + void setName(const AtomicString&); + void clearName(); + Frame* parent(bool checkForDisconnectedFrame = false) const; + void setParent(Frame* parent) { m_parent = parent; } + + Frame* nextSibling() const { return m_nextSibling.get(); } + Frame* previousSibling() const { return m_previousSibling; } + Frame* firstChild() const { return m_firstChild.get(); } + Frame* lastChild() const { return m_lastChild; } + unsigned childCount() const { return m_childCount; } + + bool isDescendantOf(const Frame* ancestor) const; + Frame* traverseNext(const Frame* stayWithin = 0) const; + Frame* traverseNextWithWrap(bool) const; + Frame* traversePreviousWithWrap(bool) const; + + void appendChild(PassRefPtr<Frame>); + void removeChild(Frame*); + + Frame* child(unsigned index) const; + Frame* child(const AtomicString& name) const; + Frame* find(const AtomicString& name) const; + + AtomicString uniqueChildName(const AtomicString& requestedName) const; + + Frame* top(bool checkForDisconnectedFrame = false) const; + + private: + Frame* deepLastChild() const; + + Frame* m_thisFrame; + + Frame* m_parent; + AtomicString m_name; + + // FIXME: use ListRefPtr? + RefPtr<Frame> m_nextSibling; + Frame* m_previousSibling; + RefPtr<Frame> m_firstChild; + Frame* m_lastChild; + unsigned m_childCount; + }; + +} // namespace WebCore + +#endif // FrameTree_h diff --git a/src/3rdparty/webkit/WebCore/page/FrameView.cpp b/src/3rdparty/webkit/WebCore/page/FrameView.cpp new file mode 100644 index 0000000..4d765ac --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/FrameView.cpp @@ -0,0 +1,1303 @@ +/* + * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org> + * 1999 Lars Knoll <knoll@kde.org> + * 1999 Antti Koivisto <koivisto@kde.org> + * 2000 Dirk Mueller <mueller@kde.org> + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * (C) 2006 Graham Dennis (graham.dennis@gmail.com) + * (C) 2006 Alexey Proskuryakov (ap@nypop.com) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "FrameView.h" + +#include "AXObjectCache.h" +#include "CSSStyleSelector.h" +#include "ChromeClient.h" +#include "EventHandler.h" +#include "FloatRect.h" +#include "FocusController.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameLoaderClient.h" +#include "FrameTree.h" +#include "GraphicsContext.h" +#include "HTMLDocument.h" +#include "HTMLFrameElement.h" +#include "HTMLFrameSetElement.h" +#include "HTMLNames.h" +#include "OverflowEvent.h" +#include "Page.h" +#include "RenderPart.h" +#include "RenderPartObject.h" +#include "RenderScrollbar.h" +#include "RenderTheme.h" +#include "RenderView.h" +#include "Settings.h" +#include "SystemTime.h" + +namespace WebCore { + +using namespace HTMLNames; + +double FrameView::sCurrentPaintTimeStamp = 0.0; + +struct ScheduledEvent { + RefPtr<Event> m_event; + RefPtr<EventTargetNode> m_eventTarget; +}; + +class FrameViewPrivate { +public: + FrameViewPrivate(FrameView* view) + : m_slowRepaintObjectCount(0) + , m_layoutTimer(view, &FrameView::layoutTimerFired) + , m_layoutRoot(0) + , m_postLayoutTasksTimer(view, &FrameView::postLayoutTimerFired) + , m_mediaType("screen") + , m_enqueueEvents(0) + , m_overflowStatusDirty(true) + , m_viewportRenderer(0) + , m_wasScrolledByUser(false) + , m_inProgrammaticScroll(false) + , m_shouldUpdateWhileOffscreen(true) + { + m_isTransparent = false; + m_baseBackgroundColor = Color::white; + m_vmode = m_hmode = ScrollbarAuto; + m_needToInitScrollbars = true; + reset(); + } + void reset() + { + m_useSlowRepaints = false; + m_borderX = 30; + m_borderY = 30; + m_layoutTimer.stop(); + m_layoutRoot = 0; + m_delayedLayout = false; + m_doFullRepaint = true; + m_layoutSchedulingEnabled = true; + m_midLayout = false; + m_layoutCount = 0; + m_nestedLayoutCount = 0; + m_postLayoutTasksTimer.stop(); + m_firstLayout = true; + m_firstLayoutCallbackPending = false; + m_wasScrolledByUser = false; + m_lastLayoutSize = IntSize(); + m_lastZoomFactor = 1.0f; + m_deferringRepaints = 0; + m_repaintCount = 0; + m_repaintRect = IntRect(); + m_repaintRects.clear(); + m_paintRestriction = PaintRestrictionNone; + m_isPainting = false; + m_isVisuallyNonEmpty = false; + m_firstVisuallyNonEmptyLayoutCallbackPending = true; + } + + bool m_doFullRepaint; + + ScrollbarMode m_vmode; + ScrollbarMode m_hmode; + bool m_useSlowRepaints; + unsigned m_slowRepaintObjectCount; + + int m_borderX, m_borderY; + + Timer<FrameView> m_layoutTimer; + bool m_delayedLayout; + RenderObject* m_layoutRoot; + + bool m_layoutSchedulingEnabled; + bool m_midLayout; + int m_layoutCount; + unsigned m_nestedLayoutCount; + Timer<FrameView> m_postLayoutTasksTimer; + bool m_firstLayoutCallbackPending; + + bool m_firstLayout; + bool m_needToInitScrollbars; + bool m_isTransparent; + Color m_baseBackgroundColor; + IntSize m_lastLayoutSize; + float m_lastZoomFactor; + + String m_mediaType; + + unsigned m_enqueueEvents; + Vector<ScheduledEvent*> m_scheduledEvents; + + bool m_overflowStatusDirty; + bool m_horizontalOverflow; + bool m_verticalOverflow; + RenderObject* m_viewportRenderer; + + bool m_wasScrolledByUser; + bool m_inProgrammaticScroll; + + unsigned m_deferringRepaints; + unsigned m_repaintCount; + IntRect m_repaintRect; + Vector<IntRect> m_repaintRects; + + bool m_shouldUpdateWhileOffscreen; + + RefPtr<Node> m_nodeToDraw; + PaintRestriction m_paintRestriction; + bool m_isPainting; + + bool m_isVisuallyNonEmpty; + bool m_firstVisuallyNonEmptyLayoutCallbackPending; +}; + +FrameView::FrameView(Frame* frame) + : m_refCount(1) + , m_frame(frame) + , d(new FrameViewPrivate(this)) +{ + init(); + show(); +} + +FrameView::FrameView(Frame* frame, const IntSize& initialSize) + : m_refCount(1) + , m_frame(frame) + , d(new FrameViewPrivate(this)) +{ + init(); + Widget::setFrameRect(IntRect(x(), y(), initialSize.width(), initialSize.height())); + show(); +} + +FrameView::~FrameView() +{ + if (d->m_postLayoutTasksTimer.isActive()) { + d->m_postLayoutTasksTimer.stop(); + d->m_scheduledEvents.clear(); + d->m_enqueueEvents = 0; + } + + resetScrollbars(); + setHasHorizontalScrollbar(false); // Remove native scrollbars now before we lose the connection to the HostWindow. + setHasVerticalScrollbar(false); + + ASSERT(m_refCount == 0); + ASSERT(d->m_scheduledEvents.isEmpty()); + ASSERT(!d->m_enqueueEvents); + + if (m_frame) { + ASSERT(m_frame->view() != this || !m_frame->document() || !m_frame->contentRenderer()); + RenderPart* renderer = m_frame->ownerRenderer(); + if (renderer && renderer->widget() == this) + renderer->setWidget(0); + } + + delete d; + d = 0; +} + +bool FrameView::isFrameView() const +{ + return true; +} + +void FrameView::clearFrame() +{ + m_frame = 0; +} + +void FrameView::resetScrollbars() +{ + // Reset the document's scrollbars back to our defaults before we yield the floor. + d->m_firstLayout = true; + setScrollbarsSuppressed(true); + setScrollbarModes(d->m_hmode, d->m_vmode); + setScrollbarsSuppressed(false); +} + +void FrameView::init() +{ + m_margins = IntSize(-1, -1); // undefined + m_size = IntSize(); + + // Propagate the marginwidth/height and scrolling modes to the view. + Element* ownerElement = m_frame && m_frame->document() ? m_frame->document()->ownerElement() : 0; + if (ownerElement && (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag))) { + HTMLFrameElement* frameElt = static_cast<HTMLFrameElement*>(ownerElement); + if (frameElt->scrollingMode() == ScrollbarAlwaysOff) + setCanHaveScrollbars(false); + int marginWidth = frameElt->getMarginWidth(); + int marginHeight = frameElt->getMarginHeight(); + if (marginWidth != -1) + setMarginWidth(marginWidth); + if (marginHeight != -1) + setMarginHeight(marginHeight); + } +} + +void FrameView::clear() +{ + setCanBlitOnScroll(true); + + d->reset(); + + if (m_frame) + if (RenderPart* renderer = m_frame->ownerRenderer()) + renderer->viewCleared(); + + setScrollbarsSuppressed(true); +} + +bool FrameView::didFirstLayout() const +{ + return !d->m_firstLayout; +} + +void FrameView::initScrollbars() +{ + if (!d->m_needToInitScrollbars) + return; + d->m_needToInitScrollbars = false; + updateDefaultScrollbarState(); +} + +void FrameView::updateDefaultScrollbarState() +{ + d->m_hmode = horizontalScrollbarMode(); + d->m_vmode = verticalScrollbarMode(); + setScrollbarModes(d->m_hmode, d->m_vmode); +} + +void FrameView::invalidateRect(const IntRect& rect) +{ + if (!parent()) { + if (hostWindow()) + hostWindow()->repaint(rect, true); + return; + } + + if (!m_frame) + return; + + RenderPart* renderer = m_frame->ownerRenderer(); + if (!renderer) + return; + + IntRect repaintRect = rect; + repaintRect.move(renderer->borderLeft() + renderer->paddingLeft(), + renderer->borderTop() + renderer->paddingTop()); + renderer->repaintRectangle(repaintRect); +} + +void FrameView::setMarginWidth(int w) +{ + // make it update the rendering area when set + m_margins.setWidth(w); +} + +void FrameView::setMarginHeight(int h) +{ + // make it update the rendering area when set + m_margins.setHeight(h); +} + +void FrameView::setCanHaveScrollbars(bool canScroll) +{ + ScrollView::setCanHaveScrollbars(canScroll); + scrollbarModes(d->m_hmode, d->m_vmode); +} + +PassRefPtr<Scrollbar> FrameView::createScrollbar(ScrollbarOrientation orientation) +{ + // FIXME: We need to update the scrollbar dynamically as documents change (or as doc elements and bodies get discovered that have custom styles). + Document* doc = m_frame->document(); + if (!doc) + return ScrollView::createScrollbar(orientation); + + // Try the <body> element first as a scrollbar source. + Element* body = doc->body(); + if (body && body->renderer() && body->renderer()->style()->hasPseudoStyle(RenderStyle::SCROLLBAR)) + return RenderScrollbar::createCustomScrollbar(this, orientation, body->renderer()); + + // If the <body> didn't have a custom style, then the root element might. + Element* docElement = doc->documentElement(); + if (docElement && docElement->renderer() && docElement->renderer()->style()->hasPseudoStyle(RenderStyle::SCROLLBAR)) + return RenderScrollbar::createCustomScrollbar(this, orientation, docElement->renderer()); + + // If we have an owning iframe/frame element, then it can set the custom scrollbar also. + RenderPart* frameRenderer = m_frame->ownerRenderer(); + if (frameRenderer && frameRenderer->style()->hasPseudoStyle(RenderStyle::SCROLLBAR)) + return RenderScrollbar::createCustomScrollbar(this, orientation, frameRenderer); + + // Nobody set a custom style, so we just use a native scrollbar. + return ScrollView::createScrollbar(orientation); +} + +void FrameView::setContentsSize(const IntSize& size) +{ + ScrollView::setContentsSize(size); + + Page* page = frame() ? frame()->page() : 0; + if (!page) + return; + + page->chrome()->contentsSizeChanged(frame(), size); //notify only +} + +void FrameView::adjustViewSize() +{ + ASSERT(m_frame->view() == this); + RenderView* root = m_frame->contentRenderer(); + if (!root) + return; + setContentsSize(IntSize(root->overflowWidth(), root->overflowHeight())); +} + +void FrameView::applyOverflowToViewport(RenderObject* o, ScrollbarMode& hMode, ScrollbarMode& vMode) +{ + // Handle the overflow:hidden/scroll case for the body/html elements. WinIE treats + // overflow:hidden and overflow:scroll on <body> as applying to the document's + // scrollbars. The CSS2.1 draft states that HTML UAs should use the <html> or <body> element and XML/XHTML UAs should + // use the root element. + switch (o->style()->overflowX()) { + case OHIDDEN: + hMode = ScrollbarAlwaysOff; + break; + case OSCROLL: + hMode = ScrollbarAlwaysOn; + break; + case OAUTO: + hMode = ScrollbarAuto; + break; + default: + // Don't set it at all. + ; + } + + switch (o->style()->overflowY()) { + case OHIDDEN: + vMode = ScrollbarAlwaysOff; + break; + case OSCROLL: + vMode = ScrollbarAlwaysOn; + break; + case OAUTO: + vMode = ScrollbarAuto; + break; + default: + // Don't set it at all. + ; + } + + d->m_viewportRenderer = o; +} + +int FrameView::layoutCount() const +{ + return d->m_layoutCount; +} + +bool FrameView::needsFullRepaint() const +{ + return d->m_doFullRepaint; +} + +RenderObject* FrameView::layoutRoot(bool onlyDuringLayout) const +{ + return onlyDuringLayout && layoutPending() ? 0 : d->m_layoutRoot; +} + +void FrameView::layout(bool allowSubtree) +{ + if (d->m_midLayout) + return; + + d->m_layoutTimer.stop(); + d->m_delayedLayout = false; + + // Protect the view from being deleted during layout (in recalcStyle) + RefPtr<FrameView> protector(this); + + if (!m_frame) { + // FIXME: Do we need to set m_size.width here? + // FIXME: Should we set m_size.height here too? + m_size.setWidth(layoutWidth()); + return; + } + + // we shouldn't enter layout() while painting + ASSERT(!isPainting()); + if (isPainting()) + return; + + if (!allowSubtree && d->m_layoutRoot) { + d->m_layoutRoot->markContainingBlocksForLayout(false); + d->m_layoutRoot = 0; + } + + ASSERT(m_frame->view() == this); + // This early return should be removed when rdar://5598072 is resolved. In the meantime, there is a + // gigantic CrashTracer because of this issue, and the early return will hopefully cause graceful + // failure instead. + if (m_frame->view() != this) + return; + + Document* document = m_frame->document(); + if (!document) { + // FIXME: Should we set m_size.height here too? + m_size.setWidth(layoutWidth()); + return; + } + + d->m_layoutSchedulingEnabled = false; + + if (!d->m_nestedLayoutCount && d->m_postLayoutTasksTimer.isActive()) { + // This is a new top-level layout. If there are any remaining tasks from the previous + // layout, finish them now. + d->m_postLayoutTasksTimer.stop(); + performPostLayoutTasks(); + } + + // Viewport-dependent media queries may cause us to need completely different style information. + // Check that here. + if (document->styleSelector()->affectedByViewportChange()) + document->updateStyleSelector(); + + // Always ensure our style info is up-to-date. This can happen in situations where + // the layout beats any sort of style recalc update that needs to occur. + if (m_frame->needsReapplyStyles()) + m_frame->reapplyStyles(); + else if (document->hasChangedChild()) + document->recalcStyle(); + + bool subtree = d->m_layoutRoot; + + // If there is only one ref to this view left, then its going to be destroyed as soon as we exit, + // so there's no point to continuing to layout + if (protector->hasOneRef()) + return; + + RenderObject* root = subtree ? d->m_layoutRoot : document->renderer(); + if (!root) { + // FIXME: Do we need to set m_size here? + d->m_layoutSchedulingEnabled = true; + return; + } + + d->m_nestedLayoutCount++; + + ScrollbarMode hMode = d->m_hmode; + ScrollbarMode vMode = d->m_vmode; + + if (!subtree) { + RenderObject* rootRenderer = document->documentElement() ? document->documentElement()->renderer() : 0; + Node* body = document->body(); + if (body && body->renderer()) { + if (body->hasTagName(framesetTag)) { + body->renderer()->setChildNeedsLayout(true); + vMode = ScrollbarAlwaysOff; + hMode = ScrollbarAlwaysOff; + } else if (body->hasTagName(bodyTag)) { + if (!d->m_firstLayout && m_size.height() != layoutHeight() + && static_cast<RenderBox*>(body->renderer())->stretchesToViewHeight()) + body->renderer()->setChildNeedsLayout(true); + // It's sufficient to just check the X overflow, + // since it's illegal to have visible in only one direction. + RenderObject* o = rootRenderer->style()->overflowX() == OVISIBLE && document->documentElement()->hasTagName(htmlTag) ? body->renderer() : rootRenderer; + applyOverflowToViewport(o, hMode, vMode); + } + } else if (rootRenderer) + applyOverflowToViewport(rootRenderer, hMode, vMode); +#ifdef INSTRUMENT_LAYOUT_SCHEDULING + if (d->m_firstLayout && !document->ownerElement()) + printf("Elapsed time before first layout: %d\n", document->elapsedTime()); +#endif + } + + d->m_doFullRepaint = !subtree && (d->m_firstLayout || static_cast<RenderView*>(root)->printing()); + + if (!subtree) { + // Now set our scrollbar state for the layout. + ScrollbarMode currentHMode = horizontalScrollbarMode(); + ScrollbarMode currentVMode = verticalScrollbarMode(); + + if (d->m_firstLayout || (hMode != currentHMode || vMode != currentVMode)) { + setScrollbarsSuppressed(true); + if (d->m_firstLayout) { + d->m_firstLayout = false; + d->m_firstLayoutCallbackPending = true; + d->m_lastLayoutSize = IntSize(width(), height()); + d->m_lastZoomFactor = root->style()->zoom(); + + // Set the initial vMode to AlwaysOn if we're auto. + if (vMode == ScrollbarAuto) + setVerticalScrollbarMode(ScrollbarAlwaysOn); // This causes a vertical scrollbar to appear. + // Set the initial hMode to AlwaysOff if we're auto. + if (hMode == ScrollbarAuto) + setHorizontalScrollbarMode(ScrollbarAlwaysOff); // This causes a horizontal scrollbar to disappear. + } + setScrollbarModes(hMode, vMode); + setScrollbarsSuppressed(false, true); + } + + IntSize oldSize = m_size; + + m_size = IntSize(layoutWidth(), layoutHeight()); + + if (oldSize != m_size) + d->m_doFullRepaint = true; + } + + RenderLayer* layer = root->enclosingLayer(); + + pauseScheduledEvents(); + + if (subtree) + root->view()->pushLayoutState(root); + + d->m_midLayout = true; + beginDeferredRepaints(); + root->layout(); + endDeferredRepaints(); + d->m_midLayout = false; + + if (subtree) + root->view()->popLayoutState(); + d->m_layoutRoot = 0; + + m_frame->invalidateSelection(); + + d->m_layoutSchedulingEnabled = true; + + if (!subtree && !static_cast<RenderView*>(root)->printing()) + adjustViewSize(); + + // Now update the positions of all layers. + beginDeferredRepaints(); + layer->updateLayerPositions(d->m_doFullRepaint); + endDeferredRepaints(); + + d->m_layoutCount++; + +#if PLATFORM(MAC) + if (AXObjectCache::accessibilityEnabled()) + root->document()->axObjectCache()->postNotificationToElement(root, "AXLayoutComplete"); +#endif +#if ENABLE(DASHBOARD_SUPPORT) + updateDashboardRegions(); +#endif + + ASSERT(!root->needsLayout()); + + setCanBlitOnScroll(!useSlowRepaints()); + + if (document->hasListenerType(Document::OVERFLOWCHANGED_LISTENER)) + updateOverflowStatus(layoutWidth() < contentsWidth(), + layoutHeight() < contentsHeight()); + + if (!d->m_postLayoutTasksTimer.isActive()) { + // Calls resumeScheduledEvents() + performPostLayoutTasks(); + + if (needsLayout()) { + // Post-layout widget updates or an event handler made us need layout again. + // Lay out again, but this time defer widget updates and event dispatch until after + // we return. + d->m_postLayoutTasksTimer.startOneShot(0); + pauseScheduledEvents(); + layout(); + } + } else { + resumeScheduledEvents(); + ASSERT(d->m_enqueueEvents); + } + + d->m_nestedLayoutCount--; +} + +void FrameView::addWidgetToUpdate(RenderPartObject* object) +{ + if (!m_widgetUpdateSet) + m_widgetUpdateSet.set(new HashSet<RenderPartObject*>); + + m_widgetUpdateSet->add(object); +} + +void FrameView::removeWidgetToUpdate(RenderPartObject* object) +{ + if (!m_widgetUpdateSet) + return; + + m_widgetUpdateSet->remove(object); +} + +void FrameView::setMediaType(const String& mediaType) +{ + d->m_mediaType = mediaType; +} + +String FrameView::mediaType() const +{ + // See if we have an override type. + String overrideType = m_frame->loader()->client()->overrideMediaType(); + if (!overrideType.isNull()) + return overrideType; + return d->m_mediaType; +} + +bool FrameView::useSlowRepaints() const +{ + return d->m_useSlowRepaints || d->m_slowRepaintObjectCount > 0; +} + +void FrameView::setUseSlowRepaints() +{ + d->m_useSlowRepaints = true; + setCanBlitOnScroll(false); +} + +void FrameView::addSlowRepaintObject() +{ + if (!d->m_slowRepaintObjectCount) + setCanBlitOnScroll(false); + d->m_slowRepaintObjectCount++; +} + +void FrameView::removeSlowRepaintObject() +{ + ASSERT(d->m_slowRepaintObjectCount > 0); + d->m_slowRepaintObjectCount--; + if (!d->m_slowRepaintObjectCount) + setCanBlitOnScroll(!d->m_useSlowRepaints); +} + +void FrameView::restoreScrollbar() +{ + setScrollbarsSuppressed(false); +} + +void FrameView::scrollRectIntoViewRecursively(const IntRect& r) +{ + bool wasInProgrammaticScroll = d->m_inProgrammaticScroll; + d->m_inProgrammaticScroll = true; + ScrollView::scrollRectIntoViewRecursively(r); + d->m_inProgrammaticScroll = wasInProgrammaticScroll; +} + +void FrameView::setScrollPosition(const IntPoint& scrollPoint) +{ + bool wasInProgrammaticScroll = d->m_inProgrammaticScroll; + d->m_inProgrammaticScroll = true; + ScrollView::setScrollPosition(scrollPoint); + d->m_inProgrammaticScroll = wasInProgrammaticScroll; +} + +HostWindow* FrameView::hostWindow() const +{ + Page* page = frame() ? frame()->page() : 0; + if (!page) + return 0; + return page->chrome(); +} + +const unsigned cRepaintRectUnionThreshold = 25; + +void FrameView::repaintContentRectangle(const IntRect& r, bool immediate) +{ + ASSERT(!m_frame->document()->ownerElement()); + + if (d->m_deferringRepaints && !immediate) { + IntRect visibleContent = visibleContentRect(); + visibleContent.intersect(r); + if (!visibleContent.isEmpty()) { + d->m_repaintCount++; + d->m_repaintRect.unite(r); + if (d->m_repaintCount == cRepaintRectUnionThreshold) + d->m_repaintRects.clear(); + else if (d->m_repaintCount < cRepaintRectUnionThreshold) + d->m_repaintRects.append(r); + } + return; + } + + if (!immediate && isOffscreen() && !shouldUpdateWhileOffscreen()) + return; + + ScrollView::repaintContentRectangle(r, immediate); +} + +void FrameView::beginDeferredRepaints() +{ + Page* page = m_frame->page(); + if (page->mainFrame() != m_frame) + return page->mainFrame()->view()->beginDeferredRepaints(); + + d->m_deferringRepaints++; + d->m_repaintCount = 0; + d->m_repaintRect = IntRect(); + d->m_repaintRects.clear(); +} + + +void FrameView::endDeferredRepaints() +{ + Page* page = m_frame->page(); + if (page->mainFrame() != m_frame) + return page->mainFrame()->view()->endDeferredRepaints(); + + ASSERT(d->m_deferringRepaints > 0); + if (--d->m_deferringRepaints == 0) { + if (d->m_repaintCount >= cRepaintRectUnionThreshold) + repaintContentRectangle(d->m_repaintRect, false); + else { + unsigned size = d->m_repaintRects.size(); + for (unsigned i = 0; i < size; i++) + repaintContentRectangle(d->m_repaintRects[i], false); + d->m_repaintRects.clear(); + } + } +} + +void FrameView::layoutTimerFired(Timer<FrameView>*) +{ +#ifdef INSTRUMENT_LAYOUT_SCHEDULING + if (m_frame->document() && !m_frame->document()->ownerElement()) + printf("Layout timer fired at %d\n", m_frame->document()->elapsedTime()); +#endif + layout(); +} + +void FrameView::scheduleRelayout() +{ + ASSERT(!m_frame->document() || !m_frame->document()->inPageCache()); + ASSERT(m_frame->view() == this); + + if (d->m_layoutRoot) { + d->m_layoutRoot->markContainingBlocksForLayout(false); + d->m_layoutRoot = 0; + } + if (!d->m_layoutSchedulingEnabled) + return; + if (!needsLayout()) + return; + if (!m_frame->document() || !m_frame->document()->shouldScheduleLayout()) + return; + + int delay = m_frame->document()->minimumLayoutDelay(); + if (d->m_layoutTimer.isActive() && d->m_delayedLayout && !delay) + unscheduleRelayout(); + if (d->m_layoutTimer.isActive()) + return; + + d->m_delayedLayout = delay != 0; + +#ifdef INSTRUMENT_LAYOUT_SCHEDULING + if (!m_frame->document()->ownerElement()) + printf("Scheduling layout for %d\n", delay); +#endif + + d->m_layoutTimer.startOneShot(delay * 0.001); +} + +static bool isObjectAncestorContainerOf(RenderObject* ancestor, RenderObject* descendant) +{ + for (RenderObject* r = descendant; r; r = r->container()) { + if (r == ancestor) + return true; + } + return false; +} + +void FrameView::scheduleRelayoutOfSubtree(RenderObject* relayoutRoot) +{ + ASSERT(m_frame->view() == this); + + if (!d->m_layoutSchedulingEnabled || (m_frame->contentRenderer() + && m_frame->contentRenderer()->needsLayout())) { + if (relayoutRoot) + relayoutRoot->markContainingBlocksForLayout(false); + return; + } + + if (layoutPending()) { + if (d->m_layoutRoot != relayoutRoot) { + if (isObjectAncestorContainerOf(d->m_layoutRoot, relayoutRoot)) { + // Keep the current root + relayoutRoot->markContainingBlocksForLayout(false, d->m_layoutRoot); + } else if (d->m_layoutRoot && isObjectAncestorContainerOf(relayoutRoot, d->m_layoutRoot)) { + // Re-root at relayoutRoot + d->m_layoutRoot->markContainingBlocksForLayout(false, relayoutRoot); + d->m_layoutRoot = relayoutRoot; + } else { + // Just do a full relayout + if (d->m_layoutRoot) + d->m_layoutRoot->markContainingBlocksForLayout(false); + d->m_layoutRoot = 0; + relayoutRoot->markContainingBlocksForLayout(false); + } + } + } else { + int delay = m_frame->document()->minimumLayoutDelay(); + d->m_layoutRoot = relayoutRoot; + d->m_delayedLayout = delay != 0; + d->m_layoutTimer.startOneShot(delay * 0.001); + } +} + +bool FrameView::layoutPending() const +{ + return d->m_layoutTimer.isActive(); +} + +bool FrameView::needsLayout() const +{ + // This can return true in cases where the document does not have a body yet. + // Document::shouldScheduleLayout takes care of preventing us from scheduling + // layout in that case. + if (!m_frame) + return false; + RenderView* root = m_frame->contentRenderer(); + Document* document = m_frame->document(); + return layoutPending() + || (root && root->needsLayout()) + || d->m_layoutRoot + || (document && document->hasChangedChild()) // can occur when using WebKit ObjC interface + || m_frame->needsReapplyStyles(); +} + +void FrameView::setNeedsLayout() +{ + RenderView* root = m_frame->contentRenderer(); + if (root) + root->setNeedsLayout(true); +} + +void FrameView::unscheduleRelayout() +{ + if (!d->m_layoutTimer.isActive()) + return; + +#ifdef INSTRUMENT_LAYOUT_SCHEDULING + if (m_frame->document() && !m_frame->document()->ownerElement()) + printf("Layout timer unscheduled at %d\n", m_frame->document()->elapsedTime()); +#endif + + d->m_layoutTimer.stop(); + d->m_delayedLayout = false; +} + +bool FrameView::isTransparent() const +{ + return d->m_isTransparent; +} + +void FrameView::setTransparent(bool isTransparent) +{ + d->m_isTransparent = isTransparent; +} + +Color FrameView::baseBackgroundColor() const +{ + return d->m_baseBackgroundColor; +} + +void FrameView::setBaseBackgroundColor(Color bc) +{ + if (!bc.isValid()) + bc = Color::white; + d->m_baseBackgroundColor = bc; +} + +void FrameView::updateBackgroundRecursively(const Color& backgroundColor, bool transparent) +{ + for (Frame* frame = m_frame.get(); frame; frame = frame->tree()->traverseNext(m_frame.get())) { + FrameView* view = frame->view(); + if (!view) + continue; + + view->setTransparent(transparent); + view->setBaseBackgroundColor(backgroundColor); + } +} + +bool FrameView::shouldUpdateWhileOffscreen() const +{ + return d->m_shouldUpdateWhileOffscreen; +} + +void FrameView::setShouldUpdateWhileOffscreen(bool shouldUpdateWhileOffscreen) +{ + d->m_shouldUpdateWhileOffscreen = shouldUpdateWhileOffscreen; +} + +void FrameView::scheduleEvent(PassRefPtr<Event> event, PassRefPtr<EventTargetNode> eventTarget) +{ + if (!d->m_enqueueEvents) { + ExceptionCode ec = 0; + eventTarget->dispatchEvent(event, ec); + return; + } + + ScheduledEvent* scheduledEvent = new ScheduledEvent; + scheduledEvent->m_event = event; + scheduledEvent->m_eventTarget = eventTarget; + d->m_scheduledEvents.append(scheduledEvent); +} + +void FrameView::pauseScheduledEvents() +{ + ASSERT(d->m_scheduledEvents.isEmpty() || d->m_enqueueEvents); + d->m_enqueueEvents++; +} + +void FrameView::resumeScheduledEvents() +{ + d->m_enqueueEvents--; + if (!d->m_enqueueEvents) + dispatchScheduledEvents(); + ASSERT(d->m_scheduledEvents.isEmpty() || d->m_enqueueEvents); +} + +void FrameView::performPostLayoutTasks() +{ + if (d->m_firstLayoutCallbackPending) { + d->m_firstLayoutCallbackPending = false; + m_frame->loader()->didFirstLayout(); + } + + if (d->m_isVisuallyNonEmpty && d->m_firstVisuallyNonEmptyLayoutCallbackPending) { + d->m_firstVisuallyNonEmptyLayoutCallbackPending = false; + m_frame->loader()->didFirstVisuallyNonEmptyLayout(); + } + + RenderView* root = m_frame->contentRenderer(); + + root->updateWidgetPositions(); + if (m_widgetUpdateSet && d->m_nestedLayoutCount <= 1) { + Vector<RenderPartObject*> objectVector; + copyToVector(*m_widgetUpdateSet, objectVector); + size_t size = objectVector.size(); + for (size_t i = 0; i < size; ++i) { + RenderPartObject* object = objectVector[i]; + object->updateWidget(false); + + // updateWidget() can destroy the RenderPartObject, so we need to make sure it's + // alive by checking if it's still in m_widgetUpdateSet. + if (m_widgetUpdateSet->contains(object)) + object->updateWidgetPosition(); + } + m_widgetUpdateSet->clear(); + } + + resumeScheduledEvents(); + + if (!root->printing()) { + IntSize currentSize = IntSize(width(), height()); + float currentZoomFactor = root->style()->zoom(); + bool resized = !d->m_firstLayout && (currentSize != d->m_lastLayoutSize || currentZoomFactor != d->m_lastZoomFactor); + d->m_lastLayoutSize = currentSize; + d->m_lastZoomFactor = currentZoomFactor; + if (resized) + m_frame->sendResizeEvent(); + } +} + +void FrameView::postLayoutTimerFired(Timer<FrameView>*) +{ + performPostLayoutTasks(); +} + +void FrameView::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow) +{ + if (!d->m_viewportRenderer) + return; + + if (d->m_overflowStatusDirty) { + d->m_horizontalOverflow = horizontalOverflow; + d->m_verticalOverflow = verticalOverflow; + d->m_overflowStatusDirty = false; + return; + } + + bool horizontalOverflowChanged = (d->m_horizontalOverflow != horizontalOverflow); + bool verticalOverflowChanged = (d->m_verticalOverflow != verticalOverflow); + + if (horizontalOverflowChanged || verticalOverflowChanged) { + d->m_horizontalOverflow = horizontalOverflow; + d->m_verticalOverflow = verticalOverflow; + + scheduleEvent(OverflowEvent::create(horizontalOverflowChanged, horizontalOverflow, + verticalOverflowChanged, verticalOverflow), + EventTargetNodeCast(d->m_viewportRenderer->element())); + } + +} + +void FrameView::dispatchScheduledEvents() +{ + if (d->m_scheduledEvents.isEmpty()) + return; + + Vector<ScheduledEvent*> scheduledEventsCopy = d->m_scheduledEvents; + d->m_scheduledEvents.clear(); + + Vector<ScheduledEvent*>::iterator end = scheduledEventsCopy.end(); + for (Vector<ScheduledEvent*>::iterator it = scheduledEventsCopy.begin(); it != end; ++it) { + ScheduledEvent* scheduledEvent = *it; + + ExceptionCode ec = 0; + + // Only dispatch events to nodes that are in the document + if (scheduledEvent->m_eventTarget->inDocument()) + scheduledEvent->m_eventTarget->dispatchEvent(scheduledEvent->m_event, ec); + + delete scheduledEvent; + } +} + +IntRect FrameView::windowClipRect(bool clipToContents) const +{ + ASSERT(m_frame->view() == this); + + // Set our clip rect to be our contents. + IntRect clipRect = contentsToWindow(visibleContentRect(!clipToContents)); + if (!m_frame || !m_frame->document() || !m_frame->document()->ownerElement()) + return clipRect; + + // Take our owner element and get the clip rect from the enclosing layer. + Element* elt = m_frame->document()->ownerElement(); + RenderLayer* layer = elt->renderer()->enclosingLayer(); + // FIXME: layer should never be null, but sometimes seems to be anyway. + if (!layer) + return clipRect; + FrameView* parentView = elt->document()->view(); + clipRect.intersect(parentView->windowClipRectForLayer(layer, true)); + return clipRect; +} + +IntRect FrameView::windowClipRectForLayer(const RenderLayer* layer, bool clipToLayerContents) const +{ + // If we have no layer, just return our window clip rect. + if (!layer) + return windowClipRect(); + + // Apply the clip from the layer. + IntRect clipRect; + if (clipToLayerContents) + clipRect = layer->childrenClipRect(); + else + clipRect = layer->selfClipRect(); + clipRect = contentsToWindow(clipRect); + return intersection(clipRect, windowClipRect()); +} + +bool FrameView::isActive() const +{ + Page* page = frame()->page(); + return page && page->focusController()->isActive(); +} + +void FrameView::valueChanged(Scrollbar* bar) +{ + // Figure out if we really moved. + IntSize offset = scrollOffset(); + ScrollView::valueChanged(bar); + if (offset != scrollOffset()) + frame()->sendScrollEvent(); +} + +void FrameView::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect) +{ + // Add in our offset within the FrameView. + IntRect dirtyRect = rect; + dirtyRect.move(scrollbar->x(), scrollbar->y()); + invalidateRect(dirtyRect); +} + +void FrameView::getTickmarks(Vector<IntRect>& tickmarks) const +{ + tickmarks = frame()->document()->renderedRectsForMarkers(DocumentMarker::TextMatch); +} + +IntRect FrameView::windowResizerRect() const +{ + Page* page = frame() ? frame()->page() : 0; + if (!page) + return IntRect(); + return page->chrome()->windowResizerRect(); +} + +#if ENABLE(DASHBOARD_SUPPORT) +void FrameView::updateDashboardRegions() +{ + Document* document = m_frame->document(); + if (!document->hasDashboardRegions()) + return; + Vector<DashboardRegionValue> newRegions; + document->renderer()->collectDashboardRegions(newRegions); + if (newRegions == document->dashboardRegions()) + return; + document->setDashboardRegions(newRegions); + Page* page = m_frame->page(); + if (!page) + return; + page->chrome()->client()->dashboardRegionsChanged(); +} +#endif + +void FrameView::updateControlTints() +{ + // This is called when control tints are changed from aqua/graphite to clear and vice versa. + // We do a "fake" paint, and when the theme gets a paint call, it can then do an invalidate. + // This is only done if the theme supports control tinting. It's up to the theme and platform + // to define when controls get the tint and to call this function when that changes. + + // Optimize the common case where we bring a window to the front while it's still empty. + if (!m_frame || m_frame->loader()->url().isEmpty()) + return; + + if (theme()->supportsControlTints() && m_frame->contentRenderer()) { + if (needsLayout()) + layout(); + PlatformGraphicsContext* const noContext = 0; + GraphicsContext context(noContext); + context.setUpdatingControlTints(true); + if (platformWidget()) + paintContents(&context, visibleContentRect()); + else + paint(&context, frameRect()); + } +} + +bool FrameView::wasScrolledByUser() const +{ + return d->m_wasScrolledByUser; +} + +void FrameView::setWasScrolledByUser(bool wasScrolledByUser) +{ + if (d->m_inProgrammaticScroll) + return; + d->m_wasScrolledByUser = wasScrolledByUser; +} + +void FrameView::paintContents(GraphicsContext* p, const IntRect& rect) +{ + if (!frame()) + return; + + Document* document = frame()->document(); + if (!document) + return; + +#ifndef NDEBUG + bool fillWithRed; + if (document || document->printing()) + fillWithRed = false; // Printing, don't fill with red (can't remember why). + else if (document->ownerElement()) + fillWithRed = false; // Subframe, don't fill with red. + else if (isTransparent()) + fillWithRed = false; // Transparent, don't fill with red. + else if (d->m_paintRestriction == PaintRestrictionSelectionOnly || d->m_paintRestriction == PaintRestrictionSelectionOnlyBlackText) + fillWithRed = false; // Selections are transparent, don't fill with red. + else if (d->m_nodeToDraw) + fillWithRed = false; // Element images are transparent, don't fill with red. + else + fillWithRed = true; + + if (fillWithRed) + p->fillRect(rect, Color(0xFF, 0, 0)); +#endif + + bool isTopLevelPainter = !sCurrentPaintTimeStamp; + if (isTopLevelPainter) + sCurrentPaintTimeStamp = currentTime(); + + RenderView* contentRenderer = frame()->contentRenderer(); + if (!contentRenderer) { + LOG_ERROR("called Frame::paint with nil renderer"); + return; + } + + ASSERT(!needsLayout()); + ASSERT(!d->m_isPainting); + + d->m_isPainting = true; + + // m_nodeToDraw is used to draw only one element (and its descendants) + RenderObject* eltRenderer = d->m_nodeToDraw ? d->m_nodeToDraw->renderer() : 0; + if (d->m_paintRestriction == PaintRestrictionNone) + document->invalidateRenderedRectsForMarkersInRect(rect); + contentRenderer->layer()->paint(p, rect, d->m_paintRestriction, eltRenderer); + + d->m_isPainting = false; + +#if ENABLE(DASHBOARD_SUPPORT) + // Regions may have changed as a result of the visibility/z-index of element changing. + if (document->dashboardRegionsDirty()) + updateDashboardRegions(); +#endif + + if (isTopLevelPainter) + sCurrentPaintTimeStamp = 0; +} + +void FrameView::setPaintRestriction(PaintRestriction pr) +{ + d->m_paintRestriction = pr; +} + +bool FrameView::isPainting() const +{ + return d->m_isPainting; +} + +void FrameView::setNodeToDraw(Node* node) +{ + d->m_nodeToDraw = node; +} + +void FrameView::layoutIfNeededRecursive() +{ + // We have to crawl our entire tree looking for any FrameViews that need + // layout and make sure they are up to date. + // Mac actually tests for intersection with the dirty region and tries not to + // update layout for frames that are outside the dirty region. Not only does this seem + // pointless (since those frames will have set a zero timer to layout anyway), but + // it is also incorrect, since if two frames overlap, the first could be excluded from the dirty + // region but then become included later by the second frame adding rects to the dirty region + // when it lays out. + + if (needsLayout()) + layout(); + + const HashSet<Widget*>* viewChildren = children(); + HashSet<Widget*>::const_iterator end = viewChildren->end(); + for (HashSet<Widget*>::const_iterator current = viewChildren->begin(); current != end; ++current) + if ((*current)->isFrameView()) + static_cast<FrameView*>(*current)->layoutIfNeededRecursive(); +} + +void FrameView::setIsVisuallyNonEmpty() +{ + d->m_isVisuallyNonEmpty = true; +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/FrameView.h b/src/3rdparty/webkit/WebCore/page/FrameView.h new file mode 100644 index 0000000..03de174 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/FrameView.h @@ -0,0 +1,200 @@ +/* + Copyright (C) 1997 Martin Jones (mjones@kde.org) + (C) 1998 Waldo Bastian (bastian@kde.org) + (C) 1998, 1999 Torben Weis (weis@kde.org) + (C) 1999 Lars Knoll (knoll@kde.org) + (C) 1999 Antti Koivisto (koivisto@kde.org) + Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef FrameView_h +#define FrameView_h + +#include "IntSize.h" +#include "RenderLayer.h" +#include "ScrollView.h" +#include <wtf/Forward.h> +#include <wtf/OwnPtr.h> + +namespace WebCore { + +class Color; +class Event; +class EventTargetNode; +class Frame; +class FrameViewPrivate; +class IntRect; +class PlatformMouseEvent; +class Node; +class RenderLayer; +class RenderObject; +class RenderPartObject; +class String; + +template <typename T> class Timer; + +class FrameView : public ScrollView { +public: + friend class RenderView; + + FrameView(Frame*); + FrameView(Frame*, const IntSize& initialSize); + + virtual ~FrameView(); + + virtual HostWindow* hostWindow() const; + + virtual void invalidateRect(const IntRect&); + + Frame* frame() const { return m_frame.get(); } + void clearFrame(); + + void ref() { ++m_refCount; } + void deref() { if (!--m_refCount) delete this; } + bool hasOneRef() { return m_refCount == 1; } + + int marginWidth() const { return m_margins.width(); } // -1 means default + int marginHeight() const { return m_margins.height(); } // -1 means default + void setMarginWidth(int); + void setMarginHeight(int); + + virtual void setCanHaveScrollbars(bool); + + virtual PassRefPtr<Scrollbar> createScrollbar(ScrollbarOrientation); + + virtual void setContentsSize(const IntSize&); + + void layout(bool allowSubtree = true); + bool didFirstLayout() const; + void layoutTimerFired(Timer<FrameView>*); + void scheduleRelayout(); + void scheduleRelayoutOfSubtree(RenderObject*); + void unscheduleRelayout(); + bool layoutPending() const; + + RenderObject* layoutRoot(bool onlyDuringLayout = false) const; + int layoutCount() const; + + // These two helper functions just pass through to the RenderView. + bool needsLayout() const; + void setNeedsLayout(); + + bool needsFullRepaint() const; + + void resetScrollbars(); + + void clear(); + + bool isTransparent() const; + void setTransparent(bool isTransparent); + + Color baseBackgroundColor() const; + void setBaseBackgroundColor(Color); + void updateBackgroundRecursively(const Color&, bool); + + bool shouldUpdateWhileOffscreen() const; + void setShouldUpdateWhileOffscreen(bool); + + void adjustViewSize(); + void initScrollbars(); + void updateDefaultScrollbarState(); + + virtual IntRect windowClipRect(bool clipToContents = true) const; + IntRect windowClipRectForLayer(const RenderLayer*, bool clipToLayerContents) const; + + virtual bool isActive() const; + virtual void invalidateScrollbarRect(Scrollbar*, const IntRect&); + virtual void valueChanged(Scrollbar*); + virtual void getTickmarks(Vector<IntRect>&) const; + + virtual IntRect windowResizerRect() const; + + virtual void scrollRectIntoViewRecursively(const IntRect&); + virtual void setScrollPosition(const IntPoint&); + + String mediaType() const; + void setMediaType(const String&); + + void setUseSlowRepaints(); + + void addSlowRepaintObject(); + void removeSlowRepaintObject(); + + void beginDeferredRepaints(); + void endDeferredRepaints(); + +#if ENABLE(DASHBOARD_SUPPORT) + void updateDashboardRegions(); +#endif + void updateControlTints(); + + void restoreScrollbar(); + + void scheduleEvent(PassRefPtr<Event>, PassRefPtr<EventTargetNode>); + void pauseScheduledEvents(); + void resumeScheduledEvents(); + void postLayoutTimerFired(Timer<FrameView>*); + + bool wasScrolledByUser() const; + void setWasScrolledByUser(bool); + + void addWidgetToUpdate(RenderPartObject*); + void removeWidgetToUpdate(RenderPartObject*); + + virtual void paintContents(GraphicsContext*, const IntRect& damageRect); + void setPaintRestriction(PaintRestriction); + bool isPainting() const; + void setNodeToDraw(Node*); + + static double currentPaintTimeStamp() { return sCurrentPaintTimeStamp; } // returns 0 if not painting + + void layoutIfNeededRecursive(); + + void setIsVisuallyNonEmpty(); + +private: + void init(); + + virtual bool isFrameView() const; + + bool useSlowRepaints() const; + + void applyOverflowToViewport(RenderObject*, ScrollbarMode& hMode, ScrollbarMode& vMode); + + void updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow); + + void dispatchScheduledEvents(); + void performPostLayoutTasks(); + + virtual void repaintContentRectangle(const IntRect&, bool immediate); + virtual void contentsResized() { setNeedsLayout(); } + virtual void visibleContentsResized() { layout(); } + + static double sCurrentPaintTimeStamp; // used for detecting decoded resource thrash in the cache + + unsigned m_refCount; + IntSize m_size; + IntSize m_margins; + OwnPtr<HashSet<RenderPartObject*> > m_widgetUpdateSet; + RefPtr<Frame> m_frame; + FrameViewPrivate* d; +}; + +} + +#endif diff --git a/src/3rdparty/webkit/WebCore/page/Geolocation.cpp b/src/3rdparty/webkit/WebCore/page/Geolocation.cpp new file mode 100644 index 0000000..f82e95d --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/Geolocation.cpp @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2008 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" +#include "Geolocation.h" + +#include "Document.h" +#include "Frame.h" +#include "PositionError.h" + +namespace WebCore { + +Geolocation::GeoNotifier::GeoNotifier(PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PositionOptions* options) + : m_successCallback(successCallback) + , m_errorCallback(errorCallback) + , m_timer(this, &Geolocation::GeoNotifier::timerFired) +{ + if (m_errorCallback && options) + m_timer.startOneShot(options->timeout() / 1000.0); +} + +void Geolocation::GeoNotifier::timerFired(Timer<GeoNotifier>*) +{ + ASSERT(m_errorCallback); + + m_timer.stop(); + + RefPtr<PositionError> error = PositionError::create(PositionError::TIMEOUT, "Timed out"); + m_errorCallback->handleEvent(error.get()); +} + +Geolocation::Geolocation(Frame* frame) + : m_frame(frame) + , m_service(GeolocationService::create(this)) +{ + ASSERT(m_frame->document()); + m_frame->document()->setUsingGeolocation(true); +} + +void Geolocation::disconnectFrame() +{ + m_service->stopUpdating(); + if (m_frame->document()) + m_frame->document()->setUsingGeolocation(false); + m_frame = 0; +} + +void Geolocation::getCurrentPosition(PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PositionOptions* options) +{ + RefPtr<GeoNotifier> notifier = GeoNotifier::create(successCallback, errorCallback, options); + + if (!m_service->startUpdating(options)) { + if (notifier->m_errorCallback) { + RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, "Unable to Start"); + notifier->m_errorCallback->handleEvent(error.get()); + } + return; + } + + m_oneShots.add(notifier); +} + +int Geolocation::watchPosition(PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PositionOptions* options) +{ + RefPtr<GeoNotifier> notifier = GeoNotifier::create(successCallback, errorCallback, options); + + if (!m_service->startUpdating(options)) { + if (notifier->m_errorCallback) { + RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, "Unable to Start"); + notifier->m_errorCallback->handleEvent(error.get()); + } + return 0; + } + + static int sIdentifier = 0; + + m_watchers.set(++sIdentifier, notifier); + + return sIdentifier; +} + +void Geolocation::clearWatch(int watchId) +{ + m_watchers.remove(watchId); + + if (!hasListeners()) + m_service->stopUpdating(); +} + +void Geolocation::suspend() +{ + if (hasListeners()) + m_service->suspend(); +} + +void Geolocation::resume() +{ + if (hasListeners()) + m_service->resume(); +} + +void Geolocation::sendErrorToOneShots(PositionError* error) +{ + Vector<RefPtr<GeoNotifier> > copy; + copyToVector(m_oneShots, copy); + + Vector<RefPtr<GeoNotifier> >::const_iterator end = copy.end(); + for (Vector<RefPtr<GeoNotifier> >::const_iterator it = copy.begin(); it != end; ++it) { + RefPtr<GeoNotifier> notifier = *it; + + if (notifier->m_errorCallback) + notifier->m_errorCallback->handleEvent(error); + } +} + +void Geolocation::sendErrorToWatchers(PositionError* error) +{ + Vector<RefPtr<GeoNotifier> > copy; + copyValuesToVector(m_watchers, copy); + + Vector<RefPtr<GeoNotifier> >::const_iterator end = copy.end(); + for (Vector<RefPtr<GeoNotifier> >::const_iterator it = copy.begin(); it != end; ++it) { + RefPtr<GeoNotifier> notifier = *it; + + if (notifier->m_errorCallback) + notifier->m_errorCallback->handleEvent(error); + } +} + +void Geolocation::sendPositionToOneShots(Geoposition* position) +{ + Vector<RefPtr<GeoNotifier> > copy; + copyToVector(m_oneShots, copy); + + Vector<RefPtr<GeoNotifier> >::const_iterator end = copy.end(); + for (Vector<RefPtr<GeoNotifier> >::const_iterator it = copy.begin(); it != end; ++it) { + RefPtr<GeoNotifier> notifier = *it; + ASSERT(notifier->m_successCallback); + + notifier->m_timer.stop(); + bool shouldCallErrorCallback = false; + notifier->m_successCallback->handleEvent(position, shouldCallErrorCallback); + if (shouldCallErrorCallback) { + RefPtr<PositionError> error = PositionError::create(PositionError::UNKNOWN_ERROR, "An exception was thrown"); + handleError(error.get()); + } + } +} + +void Geolocation::sendPositionToWatchers(Geoposition* position) +{ + Vector<RefPtr<GeoNotifier> > copy; + copyValuesToVector(m_watchers, copy); + + Vector<RefPtr<GeoNotifier> >::const_iterator end = copy.end(); + for (Vector<RefPtr<GeoNotifier> >::const_iterator it = copy.begin(); it != end; ++it) { + RefPtr<GeoNotifier> notifier = *it; + ASSERT(notifier->m_successCallback); + + notifier->m_timer.stop(); + bool shouldCallErrorCallback = false; + notifier->m_successCallback->handleEvent(position, shouldCallErrorCallback); + if (shouldCallErrorCallback) { + RefPtr<PositionError> error = PositionError::create(PositionError::UNKNOWN_ERROR, "An exception was thrown"); + handleError(error.get()); + } + } +} + +void Geolocation::handleError(PositionError* error) +{ + ASSERT(error); + + sendErrorToOneShots(error); + sendErrorToWatchers(error); + + m_oneShots.clear(); +} + +void Geolocation::geolocationServicePositionChanged(GeolocationService* service) +{ + ASSERT(service->lastPosition()); + + sendPositionToOneShots(service->lastPosition()); + sendPositionToWatchers(service->lastPosition()); + + m_oneShots.clear(); + + if (!hasListeners()) + m_service->stopUpdating(); +} + +void Geolocation::geolocationServiceErrorOccurred(GeolocationService* service) +{ + ASSERT(service->lastError()); + + handleError(service->lastError()); +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/Geolocation.h b/src/3rdparty/webkit/WebCore/page/Geolocation.h new file mode 100644 index 0000000..572cbd8 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/Geolocation.h @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2008 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 Geolocation_h +#define Geolocation_h + +#include "GeolocationService.h" +#include "PositionCallback.h" +#include "PositionErrorCallback.h" +#include "PositionOptions.h" +#include "Timer.h" +#include <wtf/Platform.h> +#include <wtf/HashMap.h> +#include <wtf/HashSet.h> +#include <wtf/OwnPtr.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class Frame; +class Geoposition; + +class Geolocation : public RefCounted<Geolocation>, public GeolocationServiceClient { +public: + static PassRefPtr<Geolocation> create(Frame* frame) { return adoptRef(new Geolocation(frame)); } + + virtual ~Geolocation() {} + + void disconnectFrame(); + + Geoposition* lastPosition() const { return m_service->lastPosition(); } + + void getCurrentPosition(PassRefPtr<PositionCallback>, PassRefPtr<PositionErrorCallback>, PositionOptions*); + int watchPosition(PassRefPtr<PositionCallback>, PassRefPtr<PositionErrorCallback>, PositionOptions*); + void clearWatch(int watchId); + + void suspend(); + void resume(); + +private: + Geolocation(Frame*); + + class GeoNotifier : public RefCounted<GeoNotifier> { + public: + static PassRefPtr<GeoNotifier> create(PassRefPtr<PositionCallback> positionCallback, PassRefPtr<PositionErrorCallback> positionErrorCallback, PositionOptions* options) { return adoptRef(new GeoNotifier(positionCallback, positionErrorCallback, options)); } + + void timerFired(Timer<GeoNotifier>*); + + RefPtr<PositionCallback> m_successCallback; + RefPtr<PositionErrorCallback> m_errorCallback; + Timer<GeoNotifier> m_timer; + + private: + GeoNotifier(PassRefPtr<PositionCallback>, PassRefPtr<PositionErrorCallback>, PositionOptions*); + }; + + bool hasListeners() const { return !m_oneShots.isEmpty() || !m_watchers.isEmpty(); } + + void sendErrorToOneShots(PositionError*); + void sendErrorToWatchers(PositionError*); + void sendPositionToOneShots(Geoposition*); + void sendPositionToWatchers(Geoposition*); + + void handleError(PositionError*); + + virtual void geolocationServicePositionChanged(GeolocationService*); + virtual void geolocationServiceErrorOccurred(GeolocationService*); + + typedef HashSet<RefPtr<GeoNotifier> > GeoNotifierSet; + typedef HashMap<int, RefPtr<GeoNotifier> > GeoNotifierMap; + + GeoNotifierSet m_oneShots; + GeoNotifierMap m_watchers; + Frame* m_frame; + OwnPtr<GeolocationService> m_service; +}; + +} // namespace WebCore + +#endif // Geolocation_h diff --git a/src/3rdparty/webkit/WebCore/page/Geolocation.idl b/src/3rdparty/webkit/WebCore/page/Geolocation.idl new file mode 100644 index 0000000..e125118 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/Geolocation.idl @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2008 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. + */ + +module core { + + interface Geolocation { + readonly attribute Geoposition lastPosition; + + [Custom] void getCurrentPosition(in PositionCallback successCallback, in PositionErrorCallback errorCallback, in PositionOptions options); + + [Custom] long watchPosition(in PositionCallback successCallback, in PositionErrorCallback errorCallback, in PositionOptions options); + + void clearWatch(in long watchId); + }; + +} diff --git a/src/3rdparty/webkit/WebCore/page/Geoposition.cpp b/src/3rdparty/webkit/WebCore/page/Geoposition.cpp new file mode 100644 index 0000000..1792a1f --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/Geoposition.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2008 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" +#include "Geoposition.h" + +namespace WebCore { + +String Geoposition::toString() const +{ + return String::format("position(%.6lg, %.6lg, %.6lg, %.6lg, %.6lg, %.6lg, %.6lg, %.lld)", + m_latitude, m_longitude, m_altitude, m_accuracy, + m_altitudeAccuracy, m_heading, m_speed, m_timestamp); +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/Geoposition.h b/src/3rdparty/webkit/WebCore/page/Geoposition.h new file mode 100644 index 0000000..9ce50e5 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/Geoposition.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2008 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 Geoposition_h +#define Geoposition_h + +#include "Event.h" +#include "PlatformString.h" +#include <wtf/RefCounted.h> + +namespace WebCore { + +typedef int ExceptionCode; + +class Geoposition : public RefCounted<Geoposition> { +public: + static PassRefPtr<Geoposition> create(double latitude, double longitude, double altitude, double accuracy, double altitudeAccuracy, double heading, double speed, DOMTimeStamp timestamp) { return adoptRef(new Geoposition(latitude, longitude, altitude, accuracy, altitudeAccuracy, heading, speed, timestamp)); } + + 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; } + DOMTimeStamp timestamp() const { return m_timestamp; } + + String toString() const; + +private: + Geoposition(double latitude, double longitude, double altitude, double accuracy, double altitudeAccuracy, double heading, double speed, DOMTimeStamp timestamp) + : m_latitude(latitude) + , m_longitude(longitude) + , m_altitude(altitude) + , m_accuracy(accuracy) + , m_altitudeAccuracy(altitudeAccuracy) + , m_heading(heading) + , m_speed(speed) + , m_timestamp(timestamp) + { + } + + double m_latitude; + double m_longitude; + double m_altitude; + double m_accuracy; + double m_altitudeAccuracy; + double m_heading; + double m_speed; + DOMTimeStamp m_timestamp; +}; + +} // namespace WebCore + +#endif // Geoposition_h diff --git a/src/3rdparty/webkit/WebCore/page/Geoposition.idl b/src/3rdparty/webkit/WebCore/page/Geoposition.idl new file mode 100644 index 0000000..554bb30 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/Geoposition.idl @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2008 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. + */ + +module core { + + interface Geoposition { + readonly attribute double latitude; + readonly attribute double longitude; + readonly attribute double altitude; + readonly attribute double accuracy; + readonly attribute double altitudeAccuracy; + readonly attribute double heading; + readonly attribute double speed; + readonly attribute DOMTimeStamp timestamp; + +#if defined(LANGUAGE_JAVASCRIPT) + [DontEnum] DOMString toString(); +#endif + }; +} diff --git a/src/3rdparty/webkit/WebCore/page/History.cpp b/src/3rdparty/webkit/WebCore/page/History.cpp new file mode 100644 index 0000000..2527132 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/History.cpp @@ -0,0 +1,77 @@ +/* + * 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 "History.h" + +#include "Frame.h" +#include "FrameLoader.h" + +namespace WebCore { + +History::History(Frame* frame) + : m_frame(frame) +{ +} + +Frame* History::frame() const +{ + return m_frame; +} + +void History::disconnectFrame() +{ + m_frame = 0; +} + +unsigned History::length() const +{ + if (!m_frame) + return 0; + return m_frame->loader()->getHistoryLength(); +} + +void History::back() +{ + if (!m_frame) + return; + m_frame->loader()->scheduleHistoryNavigation(-1); +} + +void History::forward() +{ + if (!m_frame) + return; + m_frame->loader()->scheduleHistoryNavigation(1); +} + +void History::go(int distance) +{ + if (!m_frame) + return; + m_frame->loader()->scheduleHistoryNavigation(distance); +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/History.h b/src/3rdparty/webkit/WebCore/page/History.h new file mode 100644 index 0000000..f0df2de --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/History.h @@ -0,0 +1,56 @@ +/* + * 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. + */ + +#ifndef History_h +#define History_h + +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + + class Frame; + + class History : public RefCounted<History> { + public: + static PassRefPtr<History> create(Frame* frame) { return adoptRef(new History(frame)); } + + Frame* frame() const; + void disconnectFrame(); + + unsigned length() const; + void back(); + void forward(); + void go(int distance); + + private: + History(Frame*); + + Frame* m_frame; + }; + +} // namespace WebCore + +#endif // History_h diff --git a/src/3rdparty/webkit/WebCore/page/History.idl b/src/3rdparty/webkit/WebCore/page/History.idl new file mode 100644 index 0000000..e86cf92 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/History.idl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2007, 2008 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. + */ + +module window { + + interface [ + CustomGetOwnPropertySlot, + CustomPutFunction, + CustomDeleteProperty, + CustomGetPropertyNames + ] History { + readonly attribute unsigned long length; + + void back(); + void forward(); + void go(in long distance); + }; + +} diff --git a/src/3rdparty/webkit/WebCore/page/Location.cpp b/src/3rdparty/webkit/WebCore/page/Location.cpp new file mode 100644 index 0000000..454aa78 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/Location.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2008 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 "Location.h" + +#include "Frame.h" +#include "FrameLoader.h" +#include "KURL.h" +#include "PlatformString.h" + +namespace WebCore { + +Location::Location(Frame* frame) + : m_frame(frame) +{ +} + +void Location::disconnectFrame() +{ + m_frame = 0; +} + +inline const KURL& Location::url() const +{ + ASSERT(m_frame); + return m_frame->loader()->url(); +} + +String Location::href() const +{ + if (!m_frame) + return String(); + + const KURL& url = this->url(); + return url.hasPath() ? url.prettyURL() : url.prettyURL() + "/"; +} + +String Location::protocol() const +{ + if (!m_frame) + return String(); + + return url().protocol() + ":"; +} + +String Location::host() const +{ + if (!m_frame) + return String(); + + // Note: this is the IE spec. The NS spec swaps the two, it says + // "The hostname property is the concatenation of the host and port properties, separated by a colon." + const KURL& url = this->url(); + return url.port() ? url.host() + ":" + String::number((static_cast<int>(url.port()))) : url.host(); +} + +String Location::hostname() const +{ + if (!m_frame) + return String(); + + return url().host(); +} + +String Location::port() const +{ + if (!m_frame) + return String(); + + const KURL& url = this->url(); + return url.port() ? String::number(static_cast<int>(url.port())) : ""; +} + +String Location::pathname() const +{ + if (!m_frame) + return String(); + + const KURL& url = this->url(); + return url.path().isEmpty() ? "/" : url.path(); +} + +String Location::search() const +{ + if (!m_frame) + return String(); + + return url().query(); +} + +String Location::hash() const +{ + if (!m_frame) + return String(); + + const KURL& url = this->url(); + return url.ref().isNull() ? "" : "#" + url.ref(); +} + +String Location::toString() const +{ + if (!m_frame) + return String(); + + const KURL& url = this->url(); + return url.hasPath() ? url.prettyURL() : url.prettyURL() + "/"; +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/Location.h b/src/3rdparty/webkit/WebCore/page/Location.h new file mode 100644 index 0000000..065bde1 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/Location.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2008 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. + */ + +#ifndef Location_h +#define Location_h + +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + + class Frame; + class KURL; + class String; + + class Location : public RefCounted<Location> { + public: + static PassRefPtr<Location> create(Frame* frame) { return adoptRef(new Location(frame)); } + + Frame* frame() const { return m_frame; } + void disconnectFrame(); + + String href() const; + + // URI decomposition attributes + String protocol() const; + String host() const; + String hostname() const; + String port() const; + String pathname() const; + String search() const; + String hash() const; + + String toString() const; + + private: + Location(Frame*); + + const KURL& url() const; + + Frame* m_frame; + }; + +} // namespace WebCore + +#endif // Location_h diff --git a/src/3rdparty/webkit/WebCore/page/Location.idl b/src/3rdparty/webkit/WebCore/page/Location.idl new file mode 100644 index 0000000..91822ab --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/Location.idl @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2008 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. + */ + +module window { + + interface [ + CustomGetOwnPropertySlot, + CustomPutFunction, + CustomDeleteProperty, + CustomGetPropertyNames + ] Location { + attribute [CustomSetter] DOMString href; + + [Custom] void assign(in DOMString url); + [Custom] void replace(in DOMString url); + [Custom] void reload(); + + // URI decomposition attributes + attribute [CustomSetter] DOMString protocol; + attribute [CustomSetter] DOMString host; + attribute [CustomSetter] DOMString hostname; + attribute [CustomSetter] DOMString port; + attribute [CustomSetter] DOMString pathname; + attribute [CustomSetter] DOMString search; + attribute [CustomSetter] DOMString hash; + +#if defined(LANGUAGE_JAVASCRIPT) + [DontEnum, Custom] DOMString toString(); +#endif + }; + +} diff --git a/src/3rdparty/webkit/WebCore/page/MouseEventWithHitTestResults.cpp b/src/3rdparty/webkit/WebCore/page/MouseEventWithHitTestResults.cpp new file mode 100644 index 0000000..042269c --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/MouseEventWithHitTestResults.cpp @@ -0,0 +1,66 @@ +/* + Copyright (C) 2006 Apple Computer, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config.h" +#include "MouseEventWithHitTestResults.h" + +#include "Element.h" +#include "Node.h" + +// Would TargetedMouseEvent be a better name? + +namespace WebCore { + +MouseEventWithHitTestResults::MouseEventWithHitTestResults(const PlatformMouseEvent& event, const HitTestResult& hitTestResult) + : m_event(event) + , m_hitTestResult(hitTestResult) +{ +} + +Node* MouseEventWithHitTestResults::targetNode() const +{ + Node* node = m_hitTestResult.innerNode(); + if (!node) + return 0; + if (node->inDocument()) + return node; + + Element* element = node->parentElement(); + if (element && element->inDocument()) + return element; + + return node; +} + +const IntPoint MouseEventWithHitTestResults::localPoint() const +{ + return m_hitTestResult.localPoint(); +} + +Scrollbar* MouseEventWithHitTestResults::scrollbar() const +{ + return m_hitTestResult.scrollbar(); +} + +bool MouseEventWithHitTestResults::isOverLink() const +{ + return m_hitTestResult.URLElement() && m_hitTestResult.URLElement()->isLink(); +} + +} diff --git a/src/3rdparty/webkit/WebCore/page/MouseEventWithHitTestResults.h b/src/3rdparty/webkit/WebCore/page/MouseEventWithHitTestResults.h new file mode 100644 index 0000000..c4e419c --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/MouseEventWithHitTestResults.h @@ -0,0 +1,51 @@ +/* This file is part of the KDE project + Copyright (C) 2000 Simon Hausmann <hausmann@kde.org> + Copyright (C) 2006 Apple Computer, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef MouseEventWithHitTestResults_h +#define MouseEventWithHitTestResults_h + +#include "HitTestResult.h" +#include "PlatformMouseEvent.h" + +namespace WebCore { + +class Scrollbar; + +// FIXME: Why doesn't this class just cache a HitTestResult instead of copying all of HitTestResult's fields over? +class MouseEventWithHitTestResults { +public: + MouseEventWithHitTestResults(const PlatformMouseEvent&, const HitTestResult&); + + const PlatformMouseEvent& event() const { return m_event; } + const HitTestResult& hitTestResult() const { return m_hitTestResult; } + Node* targetNode() const; + const IntPoint localPoint() const; + Scrollbar* scrollbar() const; + bool isOverLink() const; + bool isOverWidget() const { return m_hitTestResult.isOverWidget(); } + +private: + PlatformMouseEvent m_event; + HitTestResult m_hitTestResult; +}; + +} + +#endif diff --git a/src/3rdparty/webkit/WebCore/page/Navigator.cpp b/src/3rdparty/webkit/WebCore/page/Navigator.cpp new file mode 100644 index 0000000..429ec00 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/Navigator.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2000 Harri Porten (porten@kde.org) + * Copyright (c) 2000 Daniel Molkentin (molkentin@kde.org) + * Copyright (c) 2000 Stefan Schimanski (schimmi@kde.org) + * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "Navigator.h" + +#include "CookieJar.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameLoaderClient.h" +#include "Geolocation.h" +#include "Language.h" +#include "MimeTypeArray.h" +#include "Page.h" +#include "PlatformString.h" +#include "PluginArray.h" +#include "PluginData.h" +#include "ScriptController.h" +#include "Settings.h" + +namespace WebCore { + +Navigator::Navigator(Frame* frame) + : m_frame(frame) +{ +} + +Navigator::~Navigator() +{ + disconnectFrame(); +} + +void Navigator::disconnectFrame() +{ + if (m_plugins) { + m_plugins->disconnectFrame(); + m_plugins = 0; + } + if (m_mimeTypes) { + m_mimeTypes->disconnectFrame(); + m_mimeTypes = 0; + } + if (m_geolocation) { + m_geolocation->disconnectFrame(); + m_geolocation = 0; + } + m_frame = 0; +} + +// If this function returns true, we need to hide the substring "4." that would otherwise +// appear in the appVersion string. This is to avoid problems with old versions of a +// library called OpenCube QuickMenu, which as of this writing is still being used on +// sites such as nwa.com -- the library thinks Safari is Netscape 4 if we don't do this! +static bool shouldHideFourDot(Frame* frame) +{ + const String* sourceURL = frame->script()->sourceURL(); + if (!sourceURL) + return false; + if (!(sourceURL->endsWith("/dqm_script.js") || sourceURL->endsWith("/dqm_loader.js"))) + return false; + Settings* settings = frame->settings(); + if (!settings) + return false; + return settings->needsSiteSpecificQuirks(); +} + +String Navigator::appVersion() const +{ + if (!m_frame) + return String(); + String appVersion = NavigatorBase::appVersion(); + if (shouldHideFourDot(m_frame)) + appVersion.replace("4.", "4_"); + return appVersion; +} + +String Navigator::language() const +{ + return defaultLanguage(); +} + +String Navigator::userAgent() const +{ + if (!m_frame) + return String(); + return m_frame->loader()->userAgent(m_frame->document() ? m_frame->document()->url() : KURL()); +} + +PluginArray* Navigator::plugins() const +{ + if (!m_plugins) + m_plugins = PluginArray::create(m_frame); + return m_plugins.get(); +} + +MimeTypeArray* Navigator::mimeTypes() const +{ + if (!m_mimeTypes) + m_mimeTypes = MimeTypeArray::create(m_frame); + return m_mimeTypes.get(); +} + +bool Navigator::cookieEnabled() const +{ + if (m_frame->page() && !m_frame->page()->cookieEnabled()) + return false; + + return cookiesEnabled(m_frame->document()); +} + +bool Navigator::javaEnabled() const +{ + if (!m_frame) + return false; + return m_frame->settings()->isJavaEnabled(); +} + +Geolocation* Navigator::geolocation() const +{ + if (!m_geolocation) + m_geolocation = Geolocation::create(m_frame); + return m_geolocation.get(); +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/Navigator.h b/src/3rdparty/webkit/WebCore/page/Navigator.h new file mode 100644 index 0000000..d50721e --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/Navigator.h @@ -0,0 +1,68 @@ +/* + Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef Navigator_h +#define Navigator_h + +#include "NavigatorBase.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + + class Frame; + class Geolocation; + class MimeTypeArray; + class PluginData; + class PluginArray; + class String; + + class Navigator : public NavigatorBase, public RefCounted<Navigator> { + public: + static PassRefPtr<Navigator> create(Frame* frame) { return adoptRef(new Navigator(frame)); } + ~Navigator(); + + void disconnectFrame(); + Frame* frame() const { return m_frame; } + + String appVersion() const; + String language() const; + PluginArray* plugins() const; + MimeTypeArray* mimeTypes() const; + bool cookieEnabled() const; + bool javaEnabled() const; + + virtual String userAgent() const; + + Geolocation* geolocation() const; + // This is used for GC marking. + Geolocation* optionalGeolocation() const { return m_geolocation.get(); } + + private: + Navigator(Frame*); + Frame* m_frame; + mutable RefPtr<PluginArray> m_plugins; + mutable RefPtr<MimeTypeArray> m_mimeTypes; + mutable RefPtr<Geolocation> m_geolocation; + }; + +} + +#endif diff --git a/src/3rdparty/webkit/WebCore/page/Navigator.idl b/src/3rdparty/webkit/WebCore/page/Navigator.idl new file mode 100644 index 0000000..905159c --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/Navigator.idl @@ -0,0 +1,46 @@ +/* + Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +module window { + + interface [ + CustomMarkFunction + ] Navigator { + readonly attribute DOMString appCodeName; + readonly attribute DOMString appName; + readonly attribute [CustomGetter] DOMString appVersion; + readonly attribute DOMString language; + readonly attribute DOMString userAgent; + readonly attribute DOMString platform; + readonly attribute PluginArray plugins; + readonly attribute MimeTypeArray mimeTypes; + readonly attribute DOMString product; + readonly attribute DOMString productSub; + readonly attribute DOMString vendor; + readonly attribute DOMString vendorSub; + readonly attribute boolean cookieEnabled; + boolean javaEnabled(); + + readonly attribute boolean onLine; +#if ENABLE_GEOLOCATION + readonly attribute Geolocation geolocation; +#endif + }; + +} diff --git a/src/3rdparty/webkit/WebCore/page/NavigatorBase.cpp b/src/3rdparty/webkit/WebCore/page/NavigatorBase.cpp new file mode 100644 index 0000000..27c9fdd --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/NavigatorBase.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2008 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 "NavigatorBase.h" + +#include "NetworkStateNotifier.h" +#include "PlatformString.h" + +#ifndef WEBCORE_NAVIGATOR_PLATFORM +#if PLATFORM(MAC) && PLATFORM(PPC) +#define WEBCORE_NAVIGATOR_PLATFORM "MacPPC" +#elif PLATFORM(MAC) && PLATFORM(X86) +#define WEBCORE_NAVIGATOR_PLATFORM "MacIntel" +#elif PLATFORM(WIN_OS) +#define WEBCORE_NAVIGATOR_PLATFORM "Win32" +#else +#define WEBCORE_NAVIGATOR_PLATFORM "" +#endif +#endif // ifndef WEBCORE_NAVIGATOR_PLATFORM + +#ifndef WEBCORE_NAVIGATOR_PRODUCT +#define WEBCORE_NAVIGATOR_PRODUCT "Gecko" +#endif // ifndef WEBCORE_NAVIGATOR_PRODUCT + +#ifndef WEBCORE_NAVIGATOR_PRODUCT_SUB +#define WEBCORE_NAVIGATOR_PRODUCT_SUB "20030107" +#endif // ifndef WEBCORE_NAVIGATOR_PRODUCT_SUB + +#ifndef WEBCORE_NAVIGATOR_VENDOR +#define WEBCORE_NAVIGATOR_VENDOR "Apple Computer, Inc." +#endif // ifndef WEBCORE_NAVIGATOR_VENDOR + +#ifndef WEBCORE_NAVIGATOR_VENDOR_SUB +#define WEBCORE_NAVIGATOR_VENDOR_SUB "" +#endif // ifndef WEBCORE_NAVIGATOR_VENDOR_SUB + + +namespace WebCore { + +NavigatorBase::~NavigatorBase() +{ +} + +String NavigatorBase::appName() const +{ + return "Netscape"; +} + +String NavigatorBase::appVersion() const +{ + // Version is everything in the user agent string past the "Mozilla/" prefix. + const String& agent = userAgent(); + return agent.substring(agent.find('/') + 1); +} + +String NavigatorBase::platform() const +{ + return WEBCORE_NAVIGATOR_PLATFORM; +} + +String NavigatorBase::appCodeName() const +{ + return "Mozilla"; +} + +String NavigatorBase::product() const +{ + return WEBCORE_NAVIGATOR_PRODUCT; +} + +String NavigatorBase::productSub() const +{ + return WEBCORE_NAVIGATOR_PRODUCT_SUB; +} + +String NavigatorBase::vendor() const +{ + return WEBCORE_NAVIGATOR_VENDOR; +} + +String NavigatorBase::vendorSub() const +{ + return WEBCORE_NAVIGATOR_VENDOR_SUB; +} + +bool NavigatorBase::onLine() const +{ + return networkStateNotifier().onLine(); +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/NavigatorBase.h b/src/3rdparty/webkit/WebCore/page/NavigatorBase.h new file mode 100644 index 0000000..4c09f47 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/NavigatorBase.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2008 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 NavigatorBase_h +#define NavigatorBase_h + +namespace WebCore { + + class String; + + class NavigatorBase { + public: + String appName() const; + String appVersion() const; + virtual String userAgent() const = 0; + String platform() const; + + String appCodeName() const; + String product() const; + String productSub() const; + String vendor() const; + String vendorSub() const; + + bool onLine() const; + + protected: + virtual ~NavigatorBase(); + }; + +} // namespace WebCore + +#endif // NavigatorBase_h diff --git a/src/3rdparty/webkit/WebCore/page/Page.cpp b/src/3rdparty/webkit/WebCore/page/Page.cpp new file mode 100644 index 0000000..460183a --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/Page.cpp @@ -0,0 +1,632 @@ +/* + * Copyright (C) 2006, 2007, 2008 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 + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "Page.h" + +#include "Chrome.h" +#include "ChromeClient.h" +#include "ContextMenuClient.h" +#include "ContextMenuController.h" +#include "CSSStyleSelector.h" +#include "EditorClient.h" +#include "DOMWindow.h" +#include "DragController.h" +#include "EventNames.h" +#include "FileSystem.h" +#include "FocusController.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameTree.h" +#include "FrameView.h" +#include "HistoryItem.h" +#include "InspectorController.h" +#include "Logging.h" +#include "NetworkStateNotifier.h" +#include "Navigator.h" +#include "PageGroup.h" +#include "PluginData.h" +#include "ProgressTracker.h" +#include "RenderWidget.h" +#include "SelectionController.h" +#include "Settings.h" +#include "StringHash.h" +#include "TextResourceDecoder.h" +#include "Widget.h" +#include "ScriptController.h" +#include <wtf/HashMap.h> +#include <wtf/RefCountedLeakCounter.h> +#include <wtf/StdLibExtras.h> + +#if ENABLE(DOM_STORAGE) +#include "LocalStorage.h" +#include "SessionStorage.h" +#include "StorageArea.h" +#endif + +#if ENABLE(JAVASCRIPT_DEBUGGER) +#include "JavaScriptDebugServer.h" +#endif + +#if ENABLE(WML) +#include "WMLPageState.h" +#endif + +namespace WebCore { + +static HashSet<Page*>* allPages; + +#ifndef NDEBUG +static WTF::RefCountedLeakCounter pageCounter("Page"); +#endif + +static void networkStateChanged() +{ + Vector<RefPtr<Frame> > frames; + + // Get all the frames of all the pages in all the page groups + 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()) + frames.append(frame); + } + + AtomicString eventName = networkStateNotifier().onLine() ? eventNames().onlineEvent : eventNames().offlineEvent; + + for (unsigned i = 0; i < frames.size(); i++) { + Document* document = frames[i]->document(); + + if (!document) + continue; + + // If the document does not have a body the event should be dispatched to the document + EventTargetNode* eventTarget = document->body(); + if (!eventTarget) + eventTarget = document; + + eventTarget->dispatchEventForType(eventName, false, false); + } +} + +Page::Page(ChromeClient* chromeClient, ContextMenuClient* contextMenuClient, EditorClient* editorClient, DragClient* dragClient, InspectorClient* inspectorClient) + : m_chrome(new Chrome(this, chromeClient)) + , m_dragCaretController(new SelectionController(0, true)) + , m_dragController(new DragController(this, dragClient)) + , m_focusController(new FocusController(this)) + , m_contextMenuController(new ContextMenuController(this, contextMenuClient)) + , m_inspectorController(new InspectorController(this, inspectorClient)) + , m_settings(new Settings(this)) + , m_progress(new ProgressTracker) + , m_backForwardList(BackForwardList::create(this)) + , m_editorClient(editorClient) + , m_frameCount(0) + , m_tabKeyCyclesThroughElements(true) + , m_defersLoading(false) + , m_inLowQualityInterpolationMode(false) + , m_cookieEnabled(true) + , m_areMemoryCacheClientCallsEnabled(true) + , m_mediaVolume(1) + , m_parentInspectorController(0) + , m_didLoadUserStyleSheet(false) + , m_userStyleSheetModificationTime(0) + , m_group(0) + , m_debugger(0) + , m_pendingUnloadEventCount(0) + , m_pendingBeforeUnloadEventCount(0) + , m_customHTMLTokenizerTimeDelay(-1) + , m_customHTMLTokenizerChunkSize(-1) +{ + if (!allPages) { + allPages = new HashSet<Page*>; + + networkStateNotifier().setNetworkStateChangedFunction(networkStateChanged); + } + + ASSERT(!allPages->contains(this)); + allPages->add(this); + +#if ENABLE(JAVASCRIPT_DEBUGGER) + JavaScriptDebugServer::shared().pageCreated(this); +#endif + +#ifndef NDEBUG + pageCounter.increment(); +#endif +} + +Page::~Page() +{ + m_mainFrame->setView(0); + setGroupName(String()); + allPages->remove(this); + + for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) { + if (frame->document()) + frame->document()->documentWillBecomeInactive(); + frame->pageDestroyed(); + } + m_editorClient->pageDestroyed(); + if (m_parentInspectorController) + m_parentInspectorController->pageDestroyed(); + m_inspectorController->inspectedPageDestroyed(); + + m_backForwardList->close(); + +#ifndef NDEBUG + pageCounter.decrement(); + + // Cancel keepAlive timers, to ensure we release all Frames before exiting. + // It's safe to do this because we prohibit closing a Page while JavaScript + // is executing. + Frame::cancelAllKeepAlive(); +#endif +} + +void Page::setMainFrame(PassRefPtr<Frame> mainFrame) +{ + ASSERT(!m_mainFrame); // Should only be called during initialization + m_mainFrame = mainFrame; +} + +BackForwardList* Page::backForwardList() +{ + return m_backForwardList.get(); +} + +bool Page::goBack() +{ + HistoryItem* item = m_backForwardList->backItem(); + + if (item) { + goToItem(item, FrameLoadTypeBack); + return true; + } + return false; +} + +bool Page::goForward() +{ + HistoryItem* item = m_backForwardList->forwardItem(); + + if (item) { + goToItem(item, FrameLoadTypeForward); + return true; + } + return false; +} + +void Page::goToItem(HistoryItem* item, FrameLoadType type) +{ + // Abort any current load if we're going to a history item + m_mainFrame->loader()->stopAllLoaders(); + m_mainFrame->loader()->goToItem(item, type); +} + +void Page::setGlobalHistoryItem(HistoryItem* item) +{ + m_globalHistoryItem = item; +} + +void Page::setGroupName(const String& name) +{ + if (m_group && !m_group->name().isEmpty()) { + ASSERT(m_group != m_singlePageGroup.get()); + ASSERT(!m_singlePageGroup); + m_group->removePage(this); + } + + if (name.isEmpty()) + m_group = 0; + else { + m_singlePageGroup.clear(); + m_group = PageGroup::pageGroup(name); + m_group->addPage(this); + } +} + +const String& Page::groupName() const +{ + DEFINE_STATIC_LOCAL(String, nullString, ()); + return m_group ? m_group->name() : nullString; +} + +void Page::initGroup() +{ + ASSERT(!m_singlePageGroup); + ASSERT(!m_group); + m_singlePageGroup.set(new PageGroup(this)); + m_group = m_singlePageGroup.get(); +} + +void Page::setNeedsReapplyStyles() +{ + 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()) + frame->setNeedsReapplyStyles(); +} + +void Page::refreshPlugins(bool reload) +{ + if (!allPages) + return; + + PluginData::refresh(); + + Vector<RefPtr<Frame> > framesNeedingReload; + + HashSet<Page*>::iterator end = allPages->end(); + for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) { + (*it)->m_pluginData = 0; + + if (reload) { + for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) { + if (frame->loader()->containsPlugins()) + framesNeedingReload.append(frame); + } + } + } + + for (size_t i = 0; i < framesNeedingReload.size(); ++i) + framesNeedingReload[i]->loader()->reload(); +} + +PluginData* Page::pluginData() const +{ + if (!settings()->arePluginsEnabled()) + return 0; + if (!m_pluginData) + m_pluginData = PluginData::create(this); + return m_pluginData.get(); +} + +static Frame* incrementFrame(Frame* curr, bool forward, bool wrapFlag) +{ + return forward + ? curr->tree()->traverseNextWithWrap(wrapFlag) + : curr->tree()->traversePreviousWithWrap(wrapFlag); +} + +bool Page::findString(const String& target, TextCaseSensitivity caseSensitivity, FindDirection direction, bool shouldWrap) +{ + if (target.isEmpty() || !mainFrame()) + return false; + + Frame* frame = focusController()->focusedOrMainFrame(); + Frame* startFrame = frame; + do { + if (frame->findString(target, direction == FindDirectionForward, caseSensitivity == TextCaseSensitive, false, true)) { + if (frame != startFrame) + startFrame->selection()->clear(); + focusController()->setFocusedFrame(frame); + return true; + } + frame = incrementFrame(frame, direction == FindDirectionForward, shouldWrap); + } while (frame && frame != startFrame); + + // 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->findString(target, direction == FindDirectionForward, caseSensitivity == TextCaseSensitive, true, true); + focusController()->setFocusedFrame(frame); + return found; + } + + return false; +} + +unsigned int Page::markAllMatchesForText(const String& target, TextCaseSensitivity caseSensitivity, bool shouldHighlight, unsigned limit) +{ + if (target.isEmpty() || !mainFrame()) + return 0; + + unsigned matches = 0; + + Frame* frame = mainFrame(); + do { + frame->setMarkedTextMatchesAreHighlighted(shouldHighlight); + matches += frame->markAllMatchesForText(target, caseSensitivity == TextCaseSensitive, (limit == 0) ? 0 : (limit - matches)); + frame = incrementFrame(frame, true, false); + } while (frame); + + return matches; +} + +void Page::unmarkAllTextMatches() +{ + if (!mainFrame()) + return; + + Frame* frame = mainFrame(); + do { + if (Document* document = frame->document()) + document->removeMarkers(DocumentMarker::TextMatch); + frame = incrementFrame(frame, true, false); + } while (frame); +} + +const Selection& Page::selection() const +{ + return focusController()->focusedOrMainFrame()->selection()->selection(); +} + +void Page::setDefersLoading(bool defers) +{ + if (defers == m_defersLoading) + return; + + m_defersLoading = defers; + for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) + frame->loader()->setDefersLoading(defers); +} + +void Page::clearUndoRedoOperations() +{ + m_editorClient->clearUndoRedoOperations(); +} + +bool Page::inLowQualityImageInterpolationMode() const +{ + return m_inLowQualityInterpolationMode; +} + +void Page::setInLowQualityImageInterpolationMode(bool mode) +{ + m_inLowQualityInterpolationMode = mode; +} + +void Page::setMediaVolume(float volume) +{ + if (volume < 0 || volume > 1) + return; + + if (m_mediaVolume == volume) + return; + + m_mediaVolume = volume; + for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) { + if (frame->document()) + frame->document()->mediaVolumeDidChange(); + } +} + +void Page::userStyleSheetLocationChanged() +{ +#if !FRAME_LOADS_USER_STYLESHEET + // FIXME: We should provide a way to load other types of URLs than just + // file: (e.g., http:, data:). + if (m_settings->userStyleSheetLocation().isLocalFile()) + m_userStyleSheetPath = m_settings->userStyleSheetLocation().fileSystemPath(); + else + m_userStyleSheetPath = String(); + + m_didLoadUserStyleSheet = false; + m_userStyleSheet = String(); + m_userStyleSheetModificationTime = 0; +#endif +} + +const String& Page::userStyleSheet() const +{ + if (m_userStyleSheetPath.isEmpty()) { + ASSERT(m_userStyleSheet.isEmpty()); + return m_userStyleSheet; + } + + time_t modTime; + if (!getFileModificationTime(m_userStyleSheetPath, modTime)) { + // The stylesheet either doesn't exist, was just deleted, or is + // otherwise unreadable. If we've read the stylesheet before, we should + // throw away that data now as it no longer represents what's on disk. + m_userStyleSheet = String(); + return m_userStyleSheet; + } + + // If the stylesheet hasn't changed since the last time we read it, we can + // just return the old data. + if (m_didLoadUserStyleSheet && modTime <= m_userStyleSheetModificationTime) + return m_userStyleSheet; + + m_didLoadUserStyleSheet = true; + m_userStyleSheet = String(); + m_userStyleSheetModificationTime = modTime; + + // FIXME: It would be better to load this asynchronously to avoid blocking + // the process, but we will first need to create an asynchronous loading + // mechanism that is not tied to a particular Frame. We will also have to + // determine what our behavior should be before the stylesheet is loaded + // and what should happen when it finishes loading, especially with respect + // to when the load event fires, when Document::close is called, and when + // layout/paint are allowed to happen. + RefPtr<SharedBuffer> data = SharedBuffer::createWithContentsOfFile(m_userStyleSheetPath); + if (!data) + return m_userStyleSheet; + + m_userStyleSheet = TextResourceDecoder::create("text/css")->decode(data->data(), data->size()); + + return m_userStyleSheet; +} + +void Page::removeAllVisitedLinks() +{ + if (!allPages) + return; + HashSet<PageGroup*> groups; + HashSet<Page*>::iterator pagesEnd = allPages->end(); + for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) { + if (PageGroup* group = (*it)->groupPtr()) + groups.add(group); + } + HashSet<PageGroup*>::iterator groupsEnd = groups.end(); + for (HashSet<PageGroup*>::iterator it = groups.begin(); it != groupsEnd; ++it) + (*it)->removeVisitedLinks(); +} + +void Page::allVisitedStateChanged(PageGroup* group) +{ + ASSERT(group); + ASSERT(allPages); + HashSet<Page*>::iterator pagesEnd = allPages->end(); + for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) { + Page* page = *it; + if (page->m_group != group) + continue; + for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) { + if (CSSStyleSelector* styleSelector = frame->document()->styleSelector()) + styleSelector->allVisitedStateChanged(); + } + } +} + +void Page::visitedStateChanged(PageGroup* group, LinkHash visitedLinkHash) +{ + ASSERT(group); + ASSERT(allPages); + HashSet<Page*>::iterator pagesEnd = allPages->end(); + for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) { + Page* page = *it; + if (page->m_group != group) + continue; + for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) { + if (CSSStyleSelector* styleSelector = frame->document()->styleSelector()) + styleSelector->visitedStateChanged(visitedLinkHash); + } + } +} + +void Page::setDebuggerForAllPages(JSC::Debugger* debugger) +{ + ASSERT(allPages); + + HashSet<Page*>::iterator end = allPages->end(); + for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) + (*it)->setDebugger(debugger); +} + +void Page::setDebugger(JSC::Debugger* debugger) +{ + if (m_debugger == debugger) + return; + + m_debugger = debugger; + + for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) + frame->script()->attachDebugger(m_debugger); +} + +#if ENABLE(DOM_STORAGE) +SessionStorage* Page::sessionStorage(bool optionalCreate) +{ + if (!m_sessionStorage && optionalCreate) + m_sessionStorage = SessionStorage::create(this); + + return m_sessionStorage.get(); +} + +void Page::setSessionStorage(PassRefPtr<SessionStorage> newStorage) +{ + ASSERT(newStorage->page() == this); + m_sessionStorage = newStorage; +} +#endif + +unsigned Page::pendingUnloadEventCount() +{ + return m_pendingUnloadEventCount; +} + +void Page::changePendingUnloadEventCount(int delta) +{ + if (!delta) + return; + ASSERT( (delta + (int)m_pendingUnloadEventCount) >= 0 ); + + if (m_pendingUnloadEventCount == 0) + m_chrome->disableSuddenTermination(); + else if ((m_pendingUnloadEventCount + delta) == 0) + m_chrome->enableSuddenTermination(); + + m_pendingUnloadEventCount += delta; + return; +} + +unsigned Page::pendingBeforeUnloadEventCount() +{ + return m_pendingBeforeUnloadEventCount; +} + +void Page::changePendingBeforeUnloadEventCount(int delta) +{ + if (!delta) + return; + ASSERT( (delta + (int)m_pendingBeforeUnloadEventCount) >= 0 ); + + if (m_pendingBeforeUnloadEventCount == 0) + m_chrome->disableSuddenTermination(); + else if ((m_pendingBeforeUnloadEventCount + delta) == 0) + m_chrome->enableSuddenTermination(); + + m_pendingBeforeUnloadEventCount += delta; + return; +} + +#if ENABLE(WML) +WMLPageState* Page::wmlPageState() +{ + if (!m_wmlPageState) + m_wmlPageState.set(new WMLPageState(this)); + return m_wmlPageState.get(); +} +#endif + +void Page::setCustomHTMLTokenizerTimeDelay(double customHTMLTokenizerTimeDelay) +{ + if (customHTMLTokenizerTimeDelay < 0) { + m_customHTMLTokenizerTimeDelay = -1; + return; + } + m_customHTMLTokenizerTimeDelay = customHTMLTokenizerTimeDelay; +} + +void Page::setCustomHTMLTokenizerChunkSize(int customHTMLTokenizerChunkSize) +{ + if (customHTMLTokenizerChunkSize < 0) { + m_customHTMLTokenizerChunkSize = -1; + return; + } + m_customHTMLTokenizerChunkSize = customHTMLTokenizerChunkSize; +} + +void Page::setMemoryCacheClientCallsEnabled(bool enabled) +{ + if (m_areMemoryCacheClientCallsEnabled == enabled) + return; + + m_areMemoryCacheClientCallsEnabled = enabled; + if (!enabled) + return; + + for (RefPtr<Frame> frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) + frame->loader()->tellClientAboutPastMemoryCacheLoads(); +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/Page.h b/src/3rdparty/webkit/WebCore/page/Page.h new file mode 100644 index 0000000..de2b3f6 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/Page.h @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2006, 2008 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 + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef Page_h +#define Page_h + +#include "BackForwardList.h" +#include "Chrome.h" +#include "ContextMenuController.h" +#include "FrameLoaderTypes.h" +#include "LinkHash.h" +#include "PlatformString.h" +#include <wtf/HashSet.h> +#include <wtf/OwnPtr.h> + +#if PLATFORM(MAC) +#include "SchedulePair.h" +#endif + +#if PLATFORM(WIN) || (PLATFORM(WX) && PLATFORM(WIN_OS)) || (PLATFORM(QT) && defined(Q_WS_WIN)) +typedef struct HINSTANCE__* HINSTANCE; +#endif + +namespace JSC { + class Debugger; +} + +namespace WebCore { + + class Chrome; + class ChromeClient; + class ContextMenuClient; + class ContextMenuController; + class Document; + class DragClient; + class DragController; + class EditorClient; + class FocusController; + class Frame; + class InspectorClient; + class InspectorController; + class Node; + class PageGroup; + class PluginData; + class ProgressTracker; + class Selection; + class SelectionController; +#if ENABLE(DOM_STORAGE) + class SessionStorage; +#endif + class Settings; +#if ENABLE(WML) + class WMLPageState; +#endif + + enum TextCaseSensitivity { TextCaseSensitive, TextCaseInsensitive }; + enum FindDirection { FindDirectionForward, FindDirectionBackward }; + + class Page : Noncopyable { + public: + static void setNeedsReapplyStyles(); + + Page(ChromeClient*, ContextMenuClient*, EditorClient*, DragClient*, InspectorClient*); + ~Page(); + + static void refreshPlugins(bool reload); + PluginData* pluginData() const; + + EditorClient* editorClient() const { return m_editorClient; } + + void setMainFrame(PassRefPtr<Frame>); + Frame* mainFrame() const { return m_mainFrame.get(); } + + BackForwardList* backForwardList(); + + // FIXME: The following three methods don't fall under the responsibilities of the Page object + // They seem to fit a hypothetical Page-controller object that would be akin to the + // Frame-FrameLoader relationship. They have to live here now, but should move somewhere that + // makes more sense when that class exists. + bool goBack(); + bool goForward(); + void goToItem(HistoryItem*, FrameLoadType); + + HistoryItem* globalHistoryItem() const { return m_globalHistoryItem.get(); } + void setGlobalHistoryItem(HistoryItem*); + + 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 + + void incrementFrameCount() { ++m_frameCount; } + void decrementFrameCount() { --m_frameCount; } + int frameCount() const { return m_frameCount; } + + Chrome* chrome() const { return m_chrome.get(); } + SelectionController* dragCaretController() const { return m_dragCaretController.get(); } + DragController* dragController() const { return m_dragController.get(); } + FocusController* focusController() const { return m_focusController.get(); } + ContextMenuController* contextMenuController() const { return m_contextMenuController.get(); } + InspectorController* inspectorController() const { return m_inspectorController.get(); } + Settings* settings() const { return m_settings.get(); } + ProgressTracker* progress() const { return m_progress.get(); } + + void setParentInspectorController(InspectorController* controller) { m_parentInspectorController = controller; } + InspectorController* parentInspectorController() const { return m_parentInspectorController; } + + void setTabKeyCyclesThroughElements(bool b) { m_tabKeyCyclesThroughElements = b; } + bool tabKeyCyclesThroughElements() const { return m_tabKeyCyclesThroughElements; } + + bool findString(const String&, TextCaseSensitivity, FindDirection, bool shouldWrap); + unsigned int markAllMatchesForText(const String&, TextCaseSensitivity, bool shouldHighlight, unsigned); + void unmarkAllTextMatches(); + +#if PLATFORM(MAC) + void addSchedulePair(PassRefPtr<SchedulePair>); + void removeSchedulePair(PassRefPtr<SchedulePair>); + SchedulePairHashSet* scheduledRunLoopPairs() { return m_scheduledRunLoopPairs.get(); } + + OwnPtr<SchedulePairHashSet> m_scheduledRunLoopPairs; +#endif + + const Selection& selection() const; + + void setDefersLoading(bool); + bool defersLoading() const { return m_defersLoading; } + + void clearUndoRedoOperations(); + + bool inLowQualityImageInterpolationMode() const; + void setInLowQualityImageInterpolationMode(bool = true); + + bool cookieEnabled() const { return m_cookieEnabled; } + void setCookieEnabled(bool enabled) { m_cookieEnabled = enabled; } + + float mediaVolume() const { return m_mediaVolume; } + void setMediaVolume(float volume); + + void userStyleSheetLocationChanged(); + const String& userStyleSheet() const; + + void changePendingUnloadEventCount(int delta); + unsigned pendingUnloadEventCount(); + void changePendingBeforeUnloadEventCount(int delta); + unsigned pendingBeforeUnloadEventCount(); + + static void setDebuggerForAllPages(JSC::Debugger*); + void setDebugger(JSC::Debugger*); + JSC::Debugger* debugger() const { return m_debugger; } + +#if PLATFORM(WIN) || (PLATFORM(WX) && PLATFORM(WIN_OS)) || (PLATFORM(QT) && defined(Q_WS_WIN)) + // The global DLL or application instance used for all windows. + static void setInstanceHandle(HINSTANCE instanceHandle) { s_instanceHandle = instanceHandle; } + static HINSTANCE instanceHandle() { return s_instanceHandle; } +#endif + + static void removeAllVisitedLinks(); + + static void allVisitedStateChanged(PageGroup*); + static void visitedStateChanged(PageGroup*, LinkHash visitedHash); + +#if ENABLE(DOM_STORAGE) + SessionStorage* sessionStorage(bool optionalCreate = true); + void setSessionStorage(PassRefPtr<SessionStorage>); +#endif + +#if ENABLE(WML) + WMLPageState* wmlPageState(); +#endif + + void setCustomHTMLTokenizerTimeDelay(double); + bool hasCustomHTMLTokenizerTimeDelay() const { return m_customHTMLTokenizerTimeDelay != -1; } + double customHTMLTokenizerTimeDelay() const { ASSERT(m_customHTMLTokenizerTimeDelay != -1); return m_customHTMLTokenizerTimeDelay; } + + void setCustomHTMLTokenizerChunkSize(int); + bool hasCustomHTMLTokenizerChunkSize() const { return m_customHTMLTokenizerChunkSize != -1; } + int customHTMLTokenizerChunkSize() const { ASSERT(m_customHTMLTokenizerChunkSize != -1); return m_customHTMLTokenizerChunkSize; } + + void setMemoryCacheClientCallsEnabled(bool); + bool areMemoryCacheClientCallsEnabled() const { return m_areMemoryCacheClientCallsEnabled; } + + private: + void initGroup(); + + OwnPtr<Chrome> m_chrome; + OwnPtr<SelectionController> m_dragCaretController; + OwnPtr<DragController> m_dragController; + OwnPtr<FocusController> m_focusController; + OwnPtr<ContextMenuController> m_contextMenuController; + OwnPtr<InspectorController> m_inspectorController; + OwnPtr<Settings> m_settings; + OwnPtr<ProgressTracker> m_progress; + + RefPtr<BackForwardList> m_backForwardList; + RefPtr<Frame> m_mainFrame; + + RefPtr<HistoryItem> m_globalHistoryItem; + + mutable RefPtr<PluginData> m_pluginData; + + EditorClient* m_editorClient; + + int m_frameCount; + String m_groupName; + + bool m_tabKeyCyclesThroughElements; + bool m_defersLoading; + + bool m_inLowQualityInterpolationMode; + bool m_cookieEnabled; + bool m_areMemoryCacheClientCallsEnabled; + float m_mediaVolume; + + InspectorController* m_parentInspectorController; + + String m_userStyleSheetPath; + mutable String m_userStyleSheet; + mutable bool m_didLoadUserStyleSheet; + mutable time_t m_userStyleSheetModificationTime; + + OwnPtr<PageGroup> m_singlePageGroup; + PageGroup* m_group; + + JSC::Debugger* m_debugger; + + unsigned m_pendingUnloadEventCount; + unsigned m_pendingBeforeUnloadEventCount; + + double m_customHTMLTokenizerTimeDelay; + int m_customHTMLTokenizerChunkSize; + +#if ENABLE(DOM_STORAGE) + RefPtr<SessionStorage> m_sessionStorage; +#endif + +#if PLATFORM(WIN) || (PLATFORM(WX) && defined(__WXMSW__)) || (PLATFORM(QT) && defined(Q_WS_WIN)) + static HINSTANCE s_instanceHandle; +#endif + +#if ENABLE(WML) + OwnPtr<WMLPageState> m_wmlPageState; +#endif + }; + +} // namespace WebCore + +#endif // Page_h diff --git a/src/3rdparty/webkit/WebCore/page/PageGroup.cpp b/src/3rdparty/webkit/WebCore/page/PageGroup.cpp new file mode 100644 index 0000000..f0951eb --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/PageGroup.cpp @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2008 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" +#include "PageGroup.h" + +#include "ChromeClient.h" +#include "Document.h" +#include "Page.h" +#include "Settings.h" + +#if ENABLE(DOM_STORAGE) +#include "LocalStorage.h" +#include "StorageArea.h" +#endif + +#if PLATFORM(CHROMIUM) +#include "ChromiumBridge.h" +#endif + +namespace WebCore { + +static unsigned getUniqueIdentifier() +{ + static unsigned currentIdentifier = 0; + return ++currentIdentifier; +} + +// -------- + +static bool shouldTrackVisitedLinks; + +PageGroup::PageGroup(const String& name) + : m_name(name) + , m_visitedLinksPopulated(false) + , m_identifier(getUniqueIdentifier()) +{ +} + +PageGroup::PageGroup(Page* page) + : m_visitedLinksPopulated(false) + , m_identifier(getUniqueIdentifier()) +{ + ASSERT(page); + addPage(page); +} + +typedef HashMap<String, PageGroup*> PageGroupMap; +static PageGroupMap* pageGroups = 0; + +PageGroup* PageGroup::pageGroup(const String& groupName) +{ + ASSERT(!groupName.isEmpty()); + + if (!pageGroups) + pageGroups = new PageGroupMap; + + pair<PageGroupMap::iterator, bool> result = pageGroups->add(groupName, 0); + + if (result.second) { + ASSERT(!result.first->second); + result.first->second = new PageGroup(groupName); + } + + ASSERT(result.first->second); + return result.first->second; +} + +void PageGroup::closeLocalStorage() +{ +#if ENABLE(DOM_STORAGE) + if (!pageGroups) + return; + + PageGroupMap::iterator end = pageGroups->end(); + + for (PageGroupMap::iterator it = pageGroups->begin(); it != end; ++it) { + if (LocalStorage* localStorage = it->second->localStorage()) + localStorage->close(); + } +#endif +} + +void PageGroup::addPage(Page* page) +{ + ASSERT(page); + ASSERT(!m_pages.contains(page)); + m_pages.add(page); +#if ENABLE(DOM_STORAGE) + if (!m_localStorage) + m_localStorage = LocalStorage::localStorage(page->settings()->localStorageDatabasePath()); +#endif +} + +void PageGroup::removePage(Page* page) +{ + ASSERT(page); + ASSERT(m_pages.contains(page)); + m_pages.remove(page); +} + +bool PageGroup::isLinkVisited(LinkHash visitedLinkHash) +{ +#if PLATFORM(CHROMIUM) + // Use Chromium's built-in visited link database. + return ChromiumBridge::isLinkVisited(visitedLinkHash); +#else + if (!m_visitedLinksPopulated) { + m_visitedLinksPopulated = true; + ASSERT(!m_pages.isEmpty()); + (*m_pages.begin())->chrome()->client()->populateVisitedLinks(); + } + return m_visitedLinkHashes.contains(visitedLinkHash); +#endif +} + +inline void PageGroup::addVisitedLink(LinkHash hash) +{ + ASSERT(shouldTrackVisitedLinks); +#if !PLATFORM(CHROMIUM) + if (!m_visitedLinkHashes.add(hash).second) + return; +#endif + Page::visitedStateChanged(this, hash); +} + +void PageGroup::addVisitedLink(const KURL& url) +{ + if (!shouldTrackVisitedLinks) + return; + ASSERT(!url.isEmpty()); + addVisitedLink(visitedLinkHash(url.string().characters(), url.string().length())); +} + +void PageGroup::addVisitedLink(const UChar* characters, size_t length) +{ + if (!shouldTrackVisitedLinks) + return; + addVisitedLink(visitedLinkHash(characters, length)); +} + +void PageGroup::removeVisitedLinks() +{ + m_visitedLinksPopulated = false; + if (m_visitedLinkHashes.isEmpty()) + return; + m_visitedLinkHashes.clear(); + Page::allVisitedStateChanged(this); +} + +void PageGroup::removeAllVisitedLinks() +{ + Page::removeAllVisitedLinks(); +} + +void PageGroup::setShouldTrackVisitedLinks(bool shouldTrack) +{ + if (shouldTrackVisitedLinks == shouldTrack) + return; + shouldTrackVisitedLinks = shouldTrack; + if (!shouldTrackVisitedLinks) + removeAllVisitedLinks(); +} + +#if ENABLE(DOM_STORAGE) +LocalStorage* PageGroup::localStorage() +{ + return m_localStorage.get(); +} +#endif + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/PageGroup.h b/src/3rdparty/webkit/WebCore/page/PageGroup.h new file mode 100644 index 0000000..097fb87 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/PageGroup.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2008 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 PageGroup_h +#define PageGroup_h + +#include <wtf/HashSet.h> +#include <wtf/Noncopyable.h> +#include "LinkHash.h" +#include "StringHash.h" + +namespace WebCore { + + class KURL; + class LocalStorage; + class Page; + + class PageGroup : Noncopyable { + public: + PageGroup(const String& name); + PageGroup(Page*); + + static PageGroup* pageGroup(const String& groupName); + static void closeLocalStorage(); + + const HashSet<Page*>& pages() const { return m_pages; } + + void addPage(Page*); + void removePage(Page*); + + bool isLinkVisited(LinkHash); + + void addVisitedLink(const KURL&); + void addVisitedLink(const UChar*, size_t); + void removeVisitedLinks(); + + static void setShouldTrackVisitedLinks(bool); + static void removeAllVisitedLinks(); + + const String& name() { return m_name; } + unsigned identifier() { return m_identifier; } + +#if ENABLE(DOM_STORAGE) + LocalStorage* localStorage(); +#endif + + private: + void addVisitedLink(LinkHash stringHash); + + String m_name; + + HashSet<Page*> m_pages; + + HashSet<LinkHash, LinkHashHash> m_visitedLinkHashes; + bool m_visitedLinksPopulated; + + unsigned m_identifier; +#if ENABLE(DOM_STORAGE) + RefPtr<LocalStorage> m_localStorage; +#endif + }; + +} // namespace WebCore + +#endif // PageGroup_h diff --git a/src/3rdparty/webkit/WebCore/page/PositionCallback.h b/src/3rdparty/webkit/WebCore/page/PositionCallback.h new file mode 100644 index 0000000..5f32c75 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/PositionCallback.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2008 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 PositionCallback_h +#define PositionCallback_h + +#include <wtf/Platform.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + + class Geoposition; + + class PositionCallback : public RefCounted<PositionCallback> { + public: + virtual ~PositionCallback() { } + virtual void handleEvent(Geoposition* position, bool& raisedException) = 0; + }; + +} // namespace WebCore + +#endif // PositionCallback_h diff --git a/src/3rdparty/webkit/WebCore/page/PositionCallback.idl b/src/3rdparty/webkit/WebCore/page/PositionCallback.idl new file mode 100644 index 0000000..e862538 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/PositionCallback.idl @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2008 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. + */ + +module core { + + interface [ + GenerateConstructor + ] PositionCallback { + void handleEvent(in Geoposition position); + }; + +} diff --git a/src/3rdparty/webkit/WebCore/page/PositionError.h b/src/3rdparty/webkit/WebCore/page/PositionError.h new file mode 100644 index 0000000..1d31f3b --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/PositionError.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2008 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 PositionError_h +#define PositionError_h + +#include "PlatformString.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + +class PositionError : public RefCounted<PositionError> { +public: + enum ErrorCode { + UNKNOWN_ERROR = 0, + PERMISSION_DENIED = 1, + POSITION_UNAVAILABLE = 2, + TIMEOUT = 3 + }; + + static PassRefPtr<PositionError> create(ErrorCode code, const String& message) { return adoptRef(new PositionError(code, message)); } + + ErrorCode code() const { return m_code; } + const String& message() const { return m_message; } + +private: + PositionError(ErrorCode code, const String& message) + : m_code(code) + , m_message(message) + { + } + + ErrorCode m_code; + String m_message; +}; + +} // namespace WebCore + +#endif // PositionError_h diff --git a/src/3rdparty/webkit/WebCore/page/PositionError.idl b/src/3rdparty/webkit/WebCore/page/PositionError.idl new file mode 100644 index 0000000..cb2ef5e --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/PositionError.idl @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2008 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. + */ + +module core { + + interface [ + GenerateConstructor + ] PositionError { + readonly attribute unsigned short code; + readonly attribute DOMString message; + + const unsigned short UNKNOWN_ERROR = 0; + const unsigned short PERMISSION_DENIED = 1; + const unsigned short POSITION_UNAVAILABLE = 2; + const unsigned short TIMEOUT = 3; + }; + +} diff --git a/src/3rdparty/webkit/WebCore/page/PositionErrorCallback.h b/src/3rdparty/webkit/WebCore/page/PositionErrorCallback.h new file mode 100644 index 0000000..c23e883 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/PositionErrorCallback.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2008 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 PositionErrorCallback_h +#define PositionErrorCallback_h + +#include <wtf/Platform.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + + class PositionError; + + class PositionErrorCallback : public RefCounted<PositionErrorCallback> { + public: + virtual ~PositionErrorCallback() { } + virtual void handleEvent(PositionError*) = 0; + }; + +} // namespace WebCore + +#endif // PositionErrorCallback_h diff --git a/src/3rdparty/webkit/WebCore/page/PositionErrorCallback.idl b/src/3rdparty/webkit/WebCore/page/PositionErrorCallback.idl new file mode 100644 index 0000000..07edfa6 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/PositionErrorCallback.idl @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2008 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. + */ + +module core { + + interface [ + GenerateConstructor + ] PositionErrorCallback { + void handleEvent(in PositionError error); + }; + +} diff --git a/src/3rdparty/webkit/WebCore/page/PositionOptions.h b/src/3rdparty/webkit/WebCore/page/PositionOptions.h new file mode 100644 index 0000000..dc9c167 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/PositionOptions.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2008 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 PositionOptions_h +#define PositionOptions_h + +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + +class PositionOptions : public RefCounted<PositionOptions> { +public: + static PassRefPtr<PositionOptions> create(bool highAccuracy, unsigned timeout) { return adoptRef(new PositionOptions(highAccuracy, timeout)); } + + bool enableHighAccuracy() const { return m_highAccuracy; } + void setEnableHighAccuracy(bool enable) { m_highAccuracy = enable; } + unsigned timeout() const { return m_timeout; } + void setTimeout(unsigned t) { m_timeout = t; } + +private: + PositionOptions(bool highAccuracy, unsigned timeout) + : m_highAccuracy(highAccuracy) + , m_timeout(timeout) + { + } + + bool m_highAccuracy; + unsigned m_timeout; +}; + +} // namespace WebCore + +#endif // PositionOptions_h diff --git a/src/3rdparty/webkit/WebCore/page/PrintContext.cpp b/src/3rdparty/webkit/WebCore/page/PrintContext.cpp new file mode 100644 index 0000000..79672a3 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/PrintContext.cpp @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * Copyright (C) 2007 Apple Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "PrintContext.h" + +#include "GraphicsContext.h" +#include "Frame.h" +#include "FrameView.h" +#include "RenderView.h" + +using namespace WebCore; + +namespace WebCore { + +PrintContext::PrintContext(Frame* frame) + : m_frame(frame) +{ +} + +PrintContext::~PrintContext() +{ + m_pageRects.clear(); +} + +int PrintContext::pageCount() const +{ + return m_pageRects.size(); +} + +void PrintContext::computePageRects(const FloatRect& printRect, float headerHeight, float footerHeight, float userScaleFactor, float& outPageHeight) +{ + m_pageRects.clear(); + outPageHeight = 0; + + if (!m_frame->document() || !m_frame->view() || !m_frame->document()->renderer()) + return; + + RenderView* root = static_cast<RenderView*>(m_frame->document()->renderer()); + + if (!root) { + LOG_ERROR("document to be printed has no renderer"); + return; + } + + if (userScaleFactor <= 0) { + LOG_ERROR("userScaleFactor has bad value %.2f", userScaleFactor); + return; + } + + float ratio = printRect.height() / printRect.width(); + + float pageWidth = (float)root->docWidth(); + float pageHeight = pageWidth * ratio; + outPageHeight = pageHeight; // this is the height of the page adjusted by margins + pageHeight -= headerHeight + footerHeight; + + if (pageHeight <= 0) { + LOG_ERROR("pageHeight has bad value %.2f", pageHeight); + return; + } + + float currPageHeight = pageHeight / userScaleFactor; + float docHeight = root->layer()->height(); + float currPageWidth = pageWidth / userScaleFactor; + + // always return at least one page, since empty files should print a blank page + float printedPagesHeight = 0.0; + do { + float proposedBottom = std::min(docHeight, printedPagesHeight + pageHeight); + m_frame->adjustPageHeight(&proposedBottom, printedPagesHeight, proposedBottom, printedPagesHeight); + currPageHeight = max(1.0f, proposedBottom - printedPagesHeight); + + m_pageRects.append(IntRect(0, (int)printedPagesHeight, (int)currPageWidth, (int)currPageHeight)); + printedPagesHeight += currPageHeight; + } while (printedPagesHeight < docHeight); +} + +void PrintContext::begin(float width) +{ + // By imaging to a width a little wider than the available pixels, + // thin pages will be scaled down a little, matching the way they + // print in IE and Camino. This lets them use fewer sheets than they + // would otherwise, which is presumably why other browsers do this. + // Wide pages will be scaled down more than this. + const float PrintingMinimumShrinkFactor = 1.25f; + + // This number determines how small we are willing to reduce the page content + // in order to accommodate the widest line. If the page would have to be + // reduced smaller to make the widest line fit, we just clip instead (this + // behavior matches MacIE and Mozilla, at least) + const float PrintingMaximumShrinkFactor = 2.0f; + + float minLayoutWidth = width * PrintingMinimumShrinkFactor; + float maxLayoutWidth = width * PrintingMaximumShrinkFactor; + + // FIXME: This will modify the rendering of the on-screen frame. + // Could lead to flicker during printing. + m_frame->setPrinting(true, minLayoutWidth, maxLayoutWidth, true); +} + +void PrintContext::spoolPage(GraphicsContext& ctx, int pageNumber, float width) +{ + IntRect pageRect = m_pageRects[pageNumber]; + float scale = width / pageRect.width(); + + ctx.save(); + ctx.scale(FloatSize(scale, scale)); + ctx.translate(-pageRect.x(), -pageRect.y()); + ctx.clip(pageRect); + m_frame->view()->paintContents(&ctx, pageRect); + ctx.restore(); +} + +void PrintContext::end() +{ + m_frame->setPrinting(false, 0, 0, true); +} + +} diff --git a/src/3rdparty/webkit/WebCore/page/PrintContext.h b/src/3rdparty/webkit/WebCore/page/PrintContext.h new file mode 100644 index 0000000..0b3b303 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/PrintContext.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * Copyright (C) 2007 Apple Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef PrintContext_h +#define PrintContext_h + +#include <wtf/Vector.h> + +namespace WebCore { + +class Frame; +class FloatRect; +class GraphicsContext; +class IntRect; + +class PrintContext { +public: + PrintContext(Frame*); + ~PrintContext(); + + int pageCount() const; + + void computePageRects(const FloatRect& printRect, float headerHeight, float footerHeight, float userScaleFactor, float& outPageHeight); + + // TODO: eliminate width param + void begin(float width); + + // TODO: eliminate width param + void spoolPage(GraphicsContext& ctx, int pageNumber, float width); + + void end(); + +protected: + Frame* m_frame; + Vector<IntRect> m_pageRects; +}; + +} + +#endif diff --git a/src/3rdparty/webkit/WebCore/page/Screen.cpp b/src/3rdparty/webkit/WebCore/page/Screen.cpp new file mode 100644 index 0000000..396a6f4 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/Screen.cpp @@ -0,0 +1,107 @@ +/* + * 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. + * 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 "Screen.h" + +#include "FloatRect.h" +#include "Frame.h" +#include "FrameView.h" +#include "PlatformScreen.h" +#include "Widget.h" + +namespace WebCore { + +Screen::Screen(Frame* frame) + : m_frame(frame) +{ +} + +void Screen::disconnectFrame() +{ + m_frame = 0; +} + +unsigned Screen::height() const +{ + if (!m_frame) + return 0; + return static_cast<unsigned>(screenRect(m_frame->view()).height()); +} + +unsigned Screen::width() const +{ + if (!m_frame) + return 0; + return static_cast<unsigned>(screenRect(m_frame->view()).width()); +} + +unsigned Screen::colorDepth() const +{ + if (!m_frame) + return 0; + return static_cast<unsigned>(screenDepth(m_frame->view())); +} + +unsigned Screen::pixelDepth() const +{ + if (!m_frame) + return 0; + return static_cast<unsigned>(screenDepth(m_frame->view())); +} + +unsigned Screen::availLeft() const +{ + if (!m_frame) + return 0; + return static_cast<unsigned>(screenAvailableRect(m_frame->view()).x()); +} + +unsigned Screen::availTop() const +{ + if (!m_frame) + return 0; + return static_cast<unsigned>(screenAvailableRect(m_frame->view()).y()); +} + +unsigned Screen::availHeight() const +{ + if (!m_frame) + return 0; + return static_cast<unsigned>(screenAvailableRect(m_frame->view()).height()); +} + +unsigned Screen::availWidth() const +{ + if (!m_frame) + return 0; + return static_cast<unsigned>(screenAvailableRect(m_frame->view()).width()); +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/Screen.h b/src/3rdparty/webkit/WebCore/page/Screen.h new file mode 100644 index 0000000..288b1ac --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/Screen.h @@ -0,0 +1,62 @@ +/* + * 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. + * 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. + */ + + +#ifndef Screen_h +#define Screen_h + +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + + class Frame; + + class Screen : public RefCounted<Screen> { + public: + static PassRefPtr<Screen> create(Frame *frame) { return adoptRef(new Screen(frame)); } + void disconnectFrame(); + + unsigned height() const; + unsigned width() const; + unsigned colorDepth() const; + unsigned pixelDepth() const; + unsigned availLeft() const; + unsigned availTop() const; + unsigned availHeight() const; + unsigned availWidth() const; + + private: + Screen(Frame*); + + Frame* m_frame; + }; + +} // namespace WebCore + +#endif // Screen_h diff --git a/src/3rdparty/webkit/WebCore/page/Screen.idl b/src/3rdparty/webkit/WebCore/page/Screen.idl new file mode 100644 index 0000000..ca7d20d --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/Screen.idl @@ -0,0 +1,43 @@ +/* + * 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. + * 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. + */ + + +module window { + + interface Screen { + readonly attribute unsigned long height; + readonly attribute unsigned long width; + readonly attribute unsigned long colorDepth; + readonly attribute unsigned long pixelDepth; + readonly attribute unsigned long availLeft; + readonly attribute unsigned long availTop; + readonly attribute unsigned long availHeight; + readonly attribute unsigned long availWidth; + }; + +} diff --git a/src/3rdparty/webkit/WebCore/page/SecurityOrigin.cpp b/src/3rdparty/webkit/WebCore/page/SecurityOrigin.cpp new file mode 100644 index 0000000..792c3bb --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/SecurityOrigin.cpp @@ -0,0 +1,297 @@ +/* + * 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. + * 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 "SecurityOrigin.h" + +#include "CString.h" +#include "FrameLoader.h" +#include "KURL.h" +#include "PlatformString.h" +#include <wtf/StdLibExtras.h> + +namespace WebCore { + +static bool isDefaultPortForProtocol(unsigned short port, const String& protocol) +{ + if (protocol.isEmpty()) + return false; + + typedef HashMap<String, unsigned> DefaultPortsMap; + DEFINE_STATIC_LOCAL(DefaultPortsMap, defaultPorts, ()); + if (defaultPorts.isEmpty()) { + defaultPorts.set("http", 80); + defaultPorts.set("https", 443); + defaultPorts.set("ftp", 21); + defaultPorts.set("ftps", 990); + } + return defaultPorts.get(protocol) == port; +} + +SecurityOrigin::SecurityOrigin(const KURL& url) + : m_protocol(url.protocol().isNull() ? "" : url.protocol().lower()) + , m_host(url.host().isNull() ? "" : url.host().lower()) + , m_port(url.port()) + , m_noAccess(false) + , m_domainWasSetInDOM(false) +{ + // These protocols do not create security origins; the owner frame provides the origin + if (m_protocol == "about" || m_protocol == "javascript") + m_protocol = ""; + + // data: URLs are not allowed access to anything other than themselves. + if (m_protocol == "data") + m_noAccess = true; + + // document.domain starts as m_host, but can be set by the DOM. + m_domain = m_host; + + // By default, only local SecurityOrigins can load local resources. + m_canLoadLocalResources = isLocal(); + + if (isDefaultPortForProtocol(m_port, m_protocol)) + m_port = 0; +} + +SecurityOrigin::SecurityOrigin(const SecurityOrigin* other) + : m_protocol(other->m_protocol.copy()) + , m_host(other->m_host.copy()) + , m_domain(other->m_domain.copy()) + , m_port(other->m_port) + , m_noAccess(other->m_noAccess) + , m_domainWasSetInDOM(other->m_domainWasSetInDOM) + , m_canLoadLocalResources(other->m_canLoadLocalResources) +{ +} + +bool SecurityOrigin::isEmpty() const +{ + return m_protocol.isEmpty(); +} + +PassRefPtr<SecurityOrigin> SecurityOrigin::create(const KURL& url) +{ + return adoptRef(new SecurityOrigin(url)); +} + +PassRefPtr<SecurityOrigin> SecurityOrigin::createEmpty() +{ + return create(KURL()); +} + +PassRefPtr<SecurityOrigin> SecurityOrigin::copy() +{ + return adoptRef(new SecurityOrigin(this)); +} + +void SecurityOrigin::setDomainFromDOM(const String& newDomain) +{ + m_domainWasSetInDOM = true; + m_domain = newDomain.lower(); +} + +bool SecurityOrigin::canAccess(const SecurityOrigin* other) const +{ + if (isLocal()) + return true; + + if (m_noAccess || other->m_noAccess) + return false; + + // Here are two cases where we should permit access: + // + // 1) Neither document has set document.domain. In this case, we insist + // that the scheme, host, and port of the URLs match. + // + // 2) Both documents have set document.domain. In this case, we insist + // that the documents have set document.domain to the same value and + // that the scheme of the URLs match. + // + // This matches the behavior of Firefox 2 and Internet Explorer 6. + // + // Internet Explorer 7 and Opera 9 are more strict in that they require + // the port numbers to match when both pages have document.domain set. + // + // FIXME: Evaluate whether we can tighten this policy to require matched + // port numbers. + // + // Opera 9 allows access when only one page has set document.domain, but + // this is a security vulnerability. + + if (m_protocol == other->m_protocol) { + if (!m_domainWasSetInDOM && !other->m_domainWasSetInDOM) { + if (m_host == other->m_host && m_port == other->m_port) + return true; + } else if (m_domainWasSetInDOM && other->m_domainWasSetInDOM) { + if (m_domain == other->m_domain) + return true; + } + } + + return false; +} + +bool SecurityOrigin::canRequest(const KURL& url) const +{ + if (isLocal()) + return true; + + if (m_noAccess) + return false; + + RefPtr<SecurityOrigin> targetOrigin = SecurityOrigin::create(url); + + // We call isSameSchemeHostPort here instead of canAccess because we want + // to ignore document.domain effects. + return isSameSchemeHostPort(targetOrigin.get()); +} + +void SecurityOrigin::grantLoadLocalResources() +{ + // This method exists only to support backwards compatibility with older + // versions of WebKit. Granting privileges to some, but not all, documents + // in a SecurityOrigin is a security hazard because the documents without + // the privilege can obtain the privilege by injecting script into the + // documents that have been granted the privilege. + ASSERT(FrameLoader::allowSubstituteDataAccessToLocal()); + m_canLoadLocalResources = true; +} + +bool SecurityOrigin::isLocal() const +{ + return FrameLoader::shouldTreatSchemeAsLocal(m_protocol); +} + +bool SecurityOrigin::isSecureTransitionTo(const KURL& url) const +{ + // New window created by the application + if (isEmpty()) + return true; + + RefPtr<SecurityOrigin> other = SecurityOrigin::create(url); + return canAccess(other.get()); +} + +String SecurityOrigin::toString() const +{ + if (isEmpty()) + return "null"; + + if (m_noAccess) + return "null"; + + if (m_protocol == "file") + return String("file://"); + + Vector<UChar> result; + result.reserveCapacity(m_protocol.length() + m_host.length() + 10); + append(result, m_protocol); + append(result, "://"); + append(result, m_host); + + if (m_port) { + append(result, ":"); + append(result, String::number(m_port)); + } + + return String::adopt(result); +} + +PassRefPtr<SecurityOrigin> SecurityOrigin::createFromString(const String& originString) +{ + return SecurityOrigin::create(KURL(originString)); +} + +static const char SeparatorCharacter = '_'; + +PassRefPtr<SecurityOrigin> SecurityOrigin::createFromDatabaseIdentifier(const String& databaseIdentifier) +{ + // Make sure there's a first separator + int separator1 = databaseIdentifier.find(SeparatorCharacter); + if (separator1 == -1) + return create(KURL()); + + // Make sure there's a second separator + int separator2 = databaseIdentifier.find(SeparatorCharacter, separator1 + 1); + if (separator2 == -1) + return create(KURL()); + + // Make sure there's not a third separator + if (databaseIdentifier.reverseFind(SeparatorCharacter) != separator2) + return create(KURL()); + + // Make sure the port section is a valid port number or doesn't exist + bool portOkay; + int port = databaseIdentifier.right(databaseIdentifier.length() - separator2 - 1).toInt(&portOkay); + if (!portOkay && separator2 + 1 == static_cast<int>(databaseIdentifier.length())) + return create(KURL()); + + if (port < 0 || port > 65535) + return create(KURL()); + + // Split out the 3 sections of data + String protocol = databaseIdentifier.substring(0, separator1); + String host = databaseIdentifier.substring(separator1 + 1, separator2 - separator1 - 1); + return create(KURL(protocol + "://" + host + ":" + String::number(port))); +} + +String SecurityOrigin::databaseIdentifier() const +{ + DEFINE_STATIC_LOCAL(String, separatorString, (&SeparatorCharacter, 1)); + return m_protocol + separatorString + m_host + separatorString + String::number(m_port); +} + +bool SecurityOrigin::equal(const SecurityOrigin* other) const +{ + if (!isSameSchemeHostPort(other)) + return false; + + if (m_domainWasSetInDOM != other->m_domainWasSetInDOM) + return false; + + if (m_domainWasSetInDOM && m_domain != other->m_domain) + return false; + + return true; +} + +bool SecurityOrigin::isSameSchemeHostPort(const SecurityOrigin* other) const +{ + if (m_host != other->m_host) + return false; + + if (m_protocol != other->m_protocol) + return false; + + if (m_port != other->m_port) + return false; + + return true; +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/SecurityOrigin.h b/src/3rdparty/webkit/WebCore/page/SecurityOrigin.h new file mode 100644 index 0000000..1f2624e --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/SecurityOrigin.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2007,2008 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. + */ + +#ifndef SecurityOrigin_h +#define SecurityOrigin_h + +#include <wtf/RefCounted.h> +#include <wtf/PassRefPtr.h> +#include <wtf/Threading.h> + +#include "PlatformString.h" + +namespace WebCore { + + class KURL; + + class SecurityOrigin : public ThreadSafeShared<SecurityOrigin> { + public: + static PassRefPtr<SecurityOrigin> createFromDatabaseIdentifier(const String&); + static PassRefPtr<SecurityOrigin> createFromString(const String&); + static PassRefPtr<SecurityOrigin> create(const KURL&); + static PassRefPtr<SecurityOrigin> createEmpty(); + + // Create a deep copy of this SecurityOrigin. This method is useful + // when marshalling a SecurityOrigin to another thread. + PassRefPtr<SecurityOrigin> copy(); + + // Set the domain property of this security origin to newDomain. This + // function does not check whether newDomain is a suffix of the current + // domain. The caller is responsible for validating newDomain. + void setDomainFromDOM(const String& newDomain); + bool domainWasSetInDOM() const { return m_domainWasSetInDOM; } + + String protocol() const { return m_protocol; } + String host() const { return m_host; } + String domain() const { return m_domain; } + unsigned short port() const { return m_port; } + + // Returns true if this SecurityOrigin can script objects in the given + // SecurityOrigin. For example, call this function before allowing + // script from one security origin to read or write objects from + // another SecurityOrigin. + bool canAccess(const SecurityOrigin*) const; + + // Returns true if this SecurityOrigin can read content retrieved from + // the given URL. For example, call this function before issuing + // XMLHttpRequests. + bool canRequest(const KURL&) const; + + // Returns true if this SecurityOrigin can load local resources, such + // as images, iframes, and style sheets, and can link to local URLs. + // For example, call this function before creating an iframe to a + // file:// URL. + // + // Note: A SecurityOrigin might be allowed to load local resources + // without being able to issue an XMLHttpRequest for a local URL. + // To determine whether the SecurityOrigin can issue an + // XMLHttpRequest for a URL, call canRequest(url). + bool canLoadLocalResources() const { return m_canLoadLocalResources; } + + // Explicitly grant the ability to load local resources to this + // SecurityOrigin. + // + // Note: This method exists only to support backwards compatibility + // with older versions of WebKit. + void grantLoadLocalResources(); + + bool isSecureTransitionTo(const KURL&) const; + + // 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. + bool isLocal() const; + + // The empty SecurityOrigin is the least privileged SecurityOrigin. + bool isEmpty() const; + + // Convert this SecurityOrigin into a string. The string + // representation of a SecurityOrigin is similar to a URL, except it + // lacks a path component. The string representation does not encode + // the value of the SecurityOrigin's domain property. The empty + // SecurityOrigin is represented with the string "null". + String toString() const; + + // Serialize the security origin for storage in the database. This format is + // deprecated and should be used only for compatibility with old databases; + // use toString() and createFromString() instead. + String databaseIdentifier() const; + + // This method checks for equality between SecurityOrigins, not whether + // one origin can access another. It is used for hash table keys. + // For access checks, use canAccess(). + // FIXME: If this method is really only useful for hash table keys, it + // should be refactored into SecurityOriginHash. + bool equal(const SecurityOrigin*) const; + + // This method checks for equality, ignoring the value of document.domain + // (and whether it was set) but considering the host. It is used for postMessage. + bool isSameSchemeHostPort(const SecurityOrigin*) const; + + private: + explicit SecurityOrigin(const KURL&); + explicit SecurityOrigin(const SecurityOrigin*); + + String m_protocol; + String m_host; + String m_domain; + unsigned short m_port; + bool m_noAccess; + bool m_domainWasSetInDOM; + bool m_canLoadLocalResources; + }; + +} // namespace WebCore + +#endif // SecurityOrigin_h diff --git a/src/3rdparty/webkit/WebCore/page/SecurityOriginHash.h b/src/3rdparty/webkit/WebCore/page/SecurityOriginHash.h new file mode 100644 index 0000000..1915fc7 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/SecurityOriginHash.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2008 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. + */ + +#ifndef SecurityOriginHash_h +#define SecurityOriginHash_h + +#include "KURL.h" +#include "SecurityOrigin.h" +#include <wtf/RefPtr.h> + +namespace WebCore { + +struct SecurityOriginHash { + static unsigned hash(SecurityOrigin* origin) + { + unsigned hashCodes[3] = { + origin->protocol().impl() ? origin->protocol().impl()->hash() : 0, + origin->host().impl() ? origin->host().impl()->hash() : 0, + origin->port() + }; + return StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), sizeof(hashCodes) / sizeof(UChar)); + } + static unsigned hash(const RefPtr<SecurityOrigin>& origin) + { + return hash(origin.get()); + } + + 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); + } + static bool equal(SecurityOrigin* a, const RefPtr<SecurityOrigin>& b) + { + return equal(a, b.get()); + } + static bool equal(const RefPtr<SecurityOrigin>& a, SecurityOrigin* b) + { + return equal(a.get(), b); + } + static bool equal(const RefPtr<SecurityOrigin>& a, const RefPtr<SecurityOrigin>& b) + { + return equal(a.get(), b.get()); + } + + static const bool safeToCompareToEmptyOrDeleted = false; +}; + +} // namespace WebCore + +#endif diff --git a/src/3rdparty/webkit/WebCore/page/Settings.cpp b/src/3rdparty/webkit/WebCore/page/Settings.cpp new file mode 100644 index 0000000..9e4b7b5 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/Settings.cpp @@ -0,0 +1,408 @@ +/* + * Copyright (C) 2006, 2007, 2008 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 "Settings.h" + +#include "Frame.h" +#include "FrameTree.h" +#include "HistoryItem.h" +#include "Page.h" +#include "PageCache.h" +#include <limits> + +namespace WebCore { + +static void setNeedsReapplyStylesInAllFrames(Page* page) +{ + for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext()) + frame->setNeedsReapplyStyles(); +} + +#if USE(SAFARI_THEME) +bool Settings::gShouldPaintNativeControls = false; +#endif + +Settings::Settings(Page* page) + : m_page(page) + , m_editableLinkBehavior(EditableLinkDefaultBehavior) + , m_textDirectionSubmenuInclusionBehavior(TextDirectionSubmenuAutomaticallyIncluded) + , m_minimumFontSize(0) + , m_minimumLogicalFontSize(0) + , m_defaultFontSize(0) + , m_defaultFixedFontSize(0) + , m_isJavaEnabled(false) + , m_loadsImagesAutomatically(false) + , m_privateBrowsingEnabled(false) + , m_arePluginsEnabled(false) + , m_databasesEnabled(false) + , m_localStorageEnabled(false) + , m_isJavaScriptEnabled(false) + , m_javaScriptCanOpenWindowsAutomatically(false) + , m_shouldPrintBackgrounds(false) + , m_textAreasAreResizable(false) +#if ENABLE(DASHBOARD_SUPPORT) + , m_usesDashboardBackwardCompatibilityMode(false) +#endif + , m_needsAdobeFrameReloadingQuirk(false) + , m_needsKeyboardEventDisambiguationQuirks(false) + , m_isDOMPasteAllowed(false) + , m_shrinksStandaloneImagesToFit(true) + , m_usesPageCache(false) + , m_showsURLsInToolTips(false) + , m_forceFTPDirectoryListings(false) + , m_developerExtrasEnabled(false) + , m_authorAndUserStylesEnabled(true) + , m_needsSiteSpecificQuirks(false) + , m_fontRenderingMode(0) + , m_webArchiveDebugModeEnabled(false) + , m_inApplicationChromeMode(false) + , m_offlineWebApplicationCacheEnabled(false) + , m_rangeMutationDisabledForOldAppleMail(false) + , m_shouldPaintCustomScrollbars(false) + , m_zoomsTextOnly(false) + , m_enforceCSSMIMETypeInStrictMode(true) + , m_maximumDecodedImageSize(std::numeric_limits<size_t>::max()) +{ + // A Frame may not have been created yet, so we initialize the AtomicString + // hash before trying to use it. + AtomicString::init(); +} + +void Settings::setStandardFontFamily(const AtomicString& standardFontFamily) +{ + if (standardFontFamily == m_standardFontFamily) + return; + + m_standardFontFamily = standardFontFamily; + setNeedsReapplyStylesInAllFrames(m_page); +} + +void Settings::setFixedFontFamily(const AtomicString& fixedFontFamily) +{ + if (m_fixedFontFamily == fixedFontFamily) + return; + + m_fixedFontFamily = fixedFontFamily; + setNeedsReapplyStylesInAllFrames(m_page); +} + +void Settings::setSerifFontFamily(const AtomicString& serifFontFamily) +{ + if (m_serifFontFamily == serifFontFamily) + return; + + m_serifFontFamily = serifFontFamily; + setNeedsReapplyStylesInAllFrames(m_page); +} + +void Settings::setSansSerifFontFamily(const AtomicString& sansSerifFontFamily) +{ + if (m_sansSerifFontFamily == sansSerifFontFamily) + return; + + m_sansSerifFontFamily = sansSerifFontFamily; + setNeedsReapplyStylesInAllFrames(m_page); +} + +void Settings::setCursiveFontFamily(const AtomicString& cursiveFontFamily) +{ + if (m_cursiveFontFamily == cursiveFontFamily) + return; + + m_cursiveFontFamily = cursiveFontFamily; + setNeedsReapplyStylesInAllFrames(m_page); +} + +void Settings::setFantasyFontFamily(const AtomicString& fantasyFontFamily) +{ + if (m_fantasyFontFamily == fantasyFontFamily) + return; + + m_fantasyFontFamily = fantasyFontFamily; + setNeedsReapplyStylesInAllFrames(m_page); +} + +void Settings::setMinimumFontSize(int minimumFontSize) +{ + if (m_minimumFontSize == minimumFontSize) + return; + + m_minimumFontSize = minimumFontSize; + setNeedsReapplyStylesInAllFrames(m_page); +} + +void Settings::setMinimumLogicalFontSize(int minimumLogicalFontSize) +{ + if (m_minimumLogicalFontSize == minimumLogicalFontSize) + return; + + m_minimumLogicalFontSize = minimumLogicalFontSize; + setNeedsReapplyStylesInAllFrames(m_page); +} + +void Settings::setDefaultFontSize(int defaultFontSize) +{ + if (m_defaultFontSize == defaultFontSize) + return; + + m_defaultFontSize = defaultFontSize; + setNeedsReapplyStylesInAllFrames(m_page); +} + +void Settings::setDefaultFixedFontSize(int defaultFontSize) +{ + if (m_defaultFixedFontSize == defaultFontSize) + return; + + m_defaultFixedFontSize = defaultFontSize; + setNeedsReapplyStylesInAllFrames(m_page); +} + +void Settings::setLoadsImagesAutomatically(bool loadsImagesAutomatically) +{ + m_loadsImagesAutomatically = loadsImagesAutomatically; +} + +void Settings::setJavaScriptEnabled(bool isJavaScriptEnabled) +{ + m_isJavaScriptEnabled = isJavaScriptEnabled; +} + +void Settings::setJavaEnabled(bool isJavaEnabled) +{ + m_isJavaEnabled = isJavaEnabled; +} + +void Settings::setPluginsEnabled(bool arePluginsEnabled) +{ + m_arePluginsEnabled = arePluginsEnabled; +} + +void Settings::setDatabasesEnabled(bool databasesEnabled) +{ + m_databasesEnabled = databasesEnabled; +} + +void Settings::setLocalStorageEnabled(bool localStorageEnabled) +{ + m_localStorageEnabled = localStorageEnabled; +} + +void Settings::setPrivateBrowsingEnabled(bool privateBrowsingEnabled) +{ + m_privateBrowsingEnabled = privateBrowsingEnabled; +} + +void Settings::setJavaScriptCanOpenWindowsAutomatically(bool javaScriptCanOpenWindowsAutomatically) +{ + m_javaScriptCanOpenWindowsAutomatically = javaScriptCanOpenWindowsAutomatically; +} + +void Settings::setDefaultTextEncodingName(const String& defaultTextEncodingName) +{ + m_defaultTextEncodingName = defaultTextEncodingName; +} + +void Settings::setUserStyleSheetLocation(const KURL& userStyleSheetLocation) +{ + if (m_userStyleSheetLocation == userStyleSheetLocation) + return; + + m_userStyleSheetLocation = userStyleSheetLocation; + + m_page->userStyleSheetLocationChanged(); + setNeedsReapplyStylesInAllFrames(m_page); +} + +void Settings::setShouldPrintBackgrounds(bool shouldPrintBackgrounds) +{ + m_shouldPrintBackgrounds = shouldPrintBackgrounds; +} + +void Settings::setTextAreasAreResizable(bool textAreasAreResizable) +{ + if (m_textAreasAreResizable == textAreasAreResizable) + return; + + m_textAreasAreResizable = textAreasAreResizable; + setNeedsReapplyStylesInAllFrames(m_page); +} + +void Settings::setEditableLinkBehavior(EditableLinkBehavior editableLinkBehavior) +{ + m_editableLinkBehavior = editableLinkBehavior; +} + +void Settings::setTextDirectionSubmenuInclusionBehavior(TextDirectionSubmenuInclusionBehavior behavior) +{ + m_textDirectionSubmenuInclusionBehavior = behavior; +} + +#if ENABLE(DASHBOARD_SUPPORT) +void Settings::setUsesDashboardBackwardCompatibilityMode(bool usesDashboardBackwardCompatibilityMode) +{ + m_usesDashboardBackwardCompatibilityMode = usesDashboardBackwardCompatibilityMode; +} +#endif + +// 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) +{ + m_needsAdobeFrameReloadingQuirk = shouldNotReloadIFramesForUnchangedSRC; +} + +// 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. +void Settings::setNeedsKeyboardEventDisambiguationQuirks(bool needsQuirks) +{ + m_needsKeyboardEventDisambiguationQuirks = needsQuirks; +} + +void Settings::setDOMPasteAllowed(bool DOMPasteAllowed) +{ + m_isDOMPasteAllowed = DOMPasteAllowed; +} + +void Settings::setUsesPageCache(bool usesPageCache) +{ + if (m_usesPageCache == usesPageCache) + return; + + m_usesPageCache = usesPageCache; + if (!m_usesPageCache) { + HistoryItemVector& historyItems = m_page->backForwardList()->entries(); + for (unsigned i = 0; i < historyItems.size(); i++) + pageCache()->remove(historyItems[i].get()); + pageCache()->releaseAutoreleasedPagesNow(); + } +} + +void Settings::setShrinksStandaloneImagesToFit(bool shrinksStandaloneImagesToFit) +{ + m_shrinksStandaloneImagesToFit = shrinksStandaloneImagesToFit; +} + +void Settings::setShowsURLsInToolTips(bool showsURLsInToolTips) +{ + m_showsURLsInToolTips = showsURLsInToolTips; +} + +void Settings::setFTPDirectoryTemplatePath(const String& path) +{ + m_ftpDirectoryTemplatePath = path; +} + +void Settings::setForceFTPDirectoryListings(bool force) +{ + m_forceFTPDirectoryListings = force; +} + +void Settings::setDeveloperExtrasEnabled(bool developerExtrasEnabled) +{ + m_developerExtrasEnabled = developerExtrasEnabled; +} + +void Settings::setAuthorAndUserStylesEnabled(bool authorAndUserStylesEnabled) +{ + if (m_authorAndUserStylesEnabled == authorAndUserStylesEnabled) + return; + + m_authorAndUserStylesEnabled = authorAndUserStylesEnabled; + setNeedsReapplyStylesInAllFrames(m_page); +} + +void Settings::setFontRenderingMode(FontRenderingMode mode) +{ + if (fontRenderingMode() == mode) + return; + m_fontRenderingMode = mode; + setNeedsReapplyStylesInAllFrames(m_page); +} + +FontRenderingMode Settings::fontRenderingMode() const +{ + return static_cast<FontRenderingMode>(m_fontRenderingMode); +} + +void Settings::setNeedsSiteSpecificQuirks(bool needsQuirks) +{ + m_needsSiteSpecificQuirks = needsQuirks; +} + +void Settings::setWebArchiveDebugModeEnabled(bool enabled) +{ + m_webArchiveDebugModeEnabled = enabled; +} + +void Settings::setLocalStorageDatabasePath(const String& path) +{ + m_localStorageDatabasePath = path; +} + +void Settings::disableRangeMutationForOldAppleMail(bool disable) +{ + m_rangeMutationDisabledForOldAppleMail = disable; +} + +void Settings::setApplicationChromeMode(bool mode) +{ + m_inApplicationChromeMode = mode; +} + +void Settings::setOfflineWebApplicationCacheEnabled(bool enabled) +{ + m_offlineWebApplicationCacheEnabled = enabled; +} + +void Settings::setShouldPaintCustomScrollbars(bool shouldPaintCustomScrollbars) +{ + m_shouldPaintCustomScrollbars = shouldPaintCustomScrollbars; +} + +void Settings::setZoomsTextOnly(bool zoomsTextOnly) +{ + if (zoomsTextOnly == m_zoomsTextOnly) + return; + + m_zoomsTextOnly = zoomsTextOnly; + setNeedsReapplyStylesInAllFrames(m_page); +} + +void Settings::setEnforceCSSMIMETypeInStrictMode(bool enforceCSSMIMETypeInStrictMode) +{ + m_enforceCSSMIMETypeInStrictMode = enforceCSSMIMETypeInStrictMode; +} + +#if USE(SAFARI_THEME) +void Settings::setShouldPaintNativeControls(bool shouldPaintNativeControls) +{ + gShouldPaintNativeControls = shouldPaintNativeControls; +} +#endif + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/Settings.h b/src/3rdparty/webkit/WebCore/page/Settings.h new file mode 100644 index 0000000..d46a3c6 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/Settings.h @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2003, 2006, 2007, 2008 Apple Inc. All rights reserved. + * (C) 2006 Graham Dennis (graham.dennis@gmail.com) + * + * 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 Settings_h +#define Settings_h + +#include "AtomicString.h" +#include "FontDescription.h" +#include "KURL.h" + +namespace WebCore { + + class Page; + + enum EditableLinkBehavior { + EditableLinkDefaultBehavior = 0, + EditableLinkAlwaysLive, + EditableLinkOnlyLiveWithShiftKey, + EditableLinkLiveWhenNotFocused, + EditableLinkNeverLive + }; + + enum TextDirectionSubmenuInclusionBehavior { + TextDirectionSubmenuNeverIncluded, + TextDirectionSubmenuAutomaticallyIncluded, + TextDirectionSubmenuAlwaysIncluded + }; + + class Settings { + public: + Settings(Page*); + + void setStandardFontFamily(const AtomicString&); + const AtomicString& standardFontFamily() const { return m_standardFontFamily; } + + void setFixedFontFamily(const AtomicString&); + const AtomicString& fixedFontFamily() const { return m_fixedFontFamily; } + + void setSerifFontFamily(const AtomicString&); + const AtomicString& serifFontFamily() const { return m_serifFontFamily; } + + void setSansSerifFontFamily(const AtomicString&); + const AtomicString& sansSerifFontFamily() const { return m_sansSerifFontFamily; } + + void setCursiveFontFamily(const AtomicString&); + const AtomicString& cursiveFontFamily() const { return m_cursiveFontFamily; } + + void setFantasyFontFamily(const AtomicString&); + const AtomicString& fantasyFontFamily() const { return m_fantasyFontFamily; } + + 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 setLoadsImagesAutomatically(bool); + bool loadsImagesAutomatically() const { return m_loadsImagesAutomatically; } + + void setJavaScriptEnabled(bool); + bool isJavaScriptEnabled() const { return m_isJavaScriptEnabled; } + + void setJavaScriptCanOpenWindowsAutomatically(bool); + bool JavaScriptCanOpenWindowsAutomatically() const { return m_javaScriptCanOpenWindowsAutomatically; } + + void setJavaEnabled(bool); + bool isJavaEnabled() const { return m_isJavaEnabled; } + + void setPluginsEnabled(bool); + bool arePluginsEnabled() const { return m_arePluginsEnabled; } + + void setDatabasesEnabled(bool); + bool databasesEnabled() const { return m_databasesEnabled; } + + void setLocalStorageEnabled(bool); + bool localStorageEnabled() const { return m_localStorageEnabled; } + + void setPrivateBrowsingEnabled(bool); + bool privateBrowsingEnabled() const { return m_privateBrowsingEnabled; } + + void setDefaultTextEncodingName(const String&); + const String& defaultTextEncodingName() const { return m_defaultTextEncodingName; } + + void setUserStyleSheetLocation(const KURL&); + const KURL& userStyleSheetLocation() const { return m_userStyleSheetLocation; } + + void setShouldPrintBackgrounds(bool); + bool shouldPrintBackgrounds() const { return m_shouldPrintBackgrounds; } + + void setTextAreasAreResizable(bool); + bool textAreasAreResizable() const { return m_textAreasAreResizable; } + + void setEditableLinkBehavior(EditableLinkBehavior); + EditableLinkBehavior editableLinkBehavior() const { return m_editableLinkBehavior; } + + void setTextDirectionSubmenuInclusionBehavior(TextDirectionSubmenuInclusionBehavior); + TextDirectionSubmenuInclusionBehavior textDirectionSubmenuInclusionBehavior() const { return m_textDirectionSubmenuInclusionBehavior; } + +#if ENABLE(DASHBOARD_SUPPORT) + void setUsesDashboardBackwardCompatibilityMode(bool); + bool usesDashboardBackwardCompatibilityMode() const { return m_usesDashboardBackwardCompatibilityMode; } +#endif + + void setNeedsAdobeFrameReloadingQuirk(bool); + bool needsAcrobatFrameReloadingQuirk() const { return m_needsAdobeFrameReloadingQuirk; } + + void setNeedsKeyboardEventDisambiguationQuirks(bool); + bool needsKeyboardEventDisambiguationQuirks() const { return m_needsKeyboardEventDisambiguationQuirks; } + + void setDOMPasteAllowed(bool); + bool isDOMPasteAllowed() const { return m_isDOMPasteAllowed; } + + void setUsesPageCache(bool); + bool usesPageCache() const { return m_usesPageCache; } + + void setShrinksStandaloneImagesToFit(bool); + bool shrinksStandaloneImagesToFit() const { return m_shrinksStandaloneImagesToFit; } + + void setShowsURLsInToolTips(bool); + bool showsURLsInToolTips() const { return m_showsURLsInToolTips; } + + void setFTPDirectoryTemplatePath(const String&); + const String& ftpDirectoryTemplatePath() const { return m_ftpDirectoryTemplatePath; } + + void setForceFTPDirectoryListings(bool); + bool forceFTPDirectoryListings() const { return m_forceFTPDirectoryListings; } + + void setDeveloperExtrasEnabled(bool); + bool developerExtrasEnabled() const { return m_developerExtrasEnabled; } + + void setAuthorAndUserStylesEnabled(bool); + bool authorAndUserStylesEnabled() const { return m_authorAndUserStylesEnabled; } + + void setFontRenderingMode(FontRenderingMode mode); + FontRenderingMode fontRenderingMode() const; + + void setNeedsSiteSpecificQuirks(bool); + bool needsSiteSpecificQuirks() const { return m_needsSiteSpecificQuirks; } + + void setWebArchiveDebugModeEnabled(bool); + bool webArchiveDebugModeEnabled() const { return m_webArchiveDebugModeEnabled; } + + void setLocalStorageDatabasePath(const String&); + const String& localStorageDatabasePath() const { return m_localStorageDatabasePath; } + + void disableRangeMutationForOldAppleMail(bool); + bool rangeMutationDisabledForOldAppleMail() const { return m_rangeMutationDisabledForOldAppleMail; } + + void setApplicationChromeMode(bool); + bool inApplicationChromeMode() const { return m_inApplicationChromeMode; } + + void setOfflineWebApplicationCacheEnabled(bool); + bool offlineWebApplicationCacheEnabled() const { return m_offlineWebApplicationCacheEnabled; } + + void setShouldPaintCustomScrollbars(bool); + bool shouldPaintCustomScrollbars() const { return m_shouldPaintCustomScrollbars; } + + void setZoomsTextOnly(bool); + bool zoomsTextOnly() const { return m_zoomsTextOnly; } + + void setEnforceCSSMIMETypeInStrictMode(bool); + bool enforceCSSMIMETypeInStrictMode() { return m_enforceCSSMIMETypeInStrictMode; } + + void setMaximumDecodedImageSize(size_t size) { m_maximumDecodedImageSize = size; } + size_t maximumDecodedImageSize() const { return m_maximumDecodedImageSize; } + +#if USE(SAFARI_THEME) + // Windows debugging pref (global) for switching between the Aqua look and a native windows look. + static void setShouldPaintNativeControls(bool); + static bool shouldPaintNativeControls() { return gShouldPaintNativeControls; } +#endif + + private: + Page* m_page; + + String m_defaultTextEncodingName; + String m_ftpDirectoryTemplatePath; + String m_localStorageDatabasePath; + KURL m_userStyleSheetLocation; + AtomicString m_standardFontFamily; + AtomicString m_fixedFontFamily; + AtomicString m_serifFontFamily; + AtomicString m_sansSerifFontFamily; + AtomicString m_cursiveFontFamily; + AtomicString m_fantasyFontFamily; + EditableLinkBehavior m_editableLinkBehavior; + TextDirectionSubmenuInclusionBehavior m_textDirectionSubmenuInclusionBehavior; + int m_minimumFontSize; + int m_minimumLogicalFontSize; + int m_defaultFontSize; + int m_defaultFixedFontSize; + bool m_isJavaEnabled : 1; + bool m_loadsImagesAutomatically : 1; + bool m_privateBrowsingEnabled : 1; + bool m_arePluginsEnabled : 1; + bool m_databasesEnabled : 1; + bool m_localStorageEnabled : 1; + bool m_isJavaScriptEnabled : 1; + bool m_javaScriptCanOpenWindowsAutomatically : 1; + bool m_shouldPrintBackgrounds : 1; + bool m_textAreasAreResizable : 1; +#if ENABLE(DASHBOARD_SUPPORT) + bool m_usesDashboardBackwardCompatibilityMode : 1; +#endif + bool m_needsAdobeFrameReloadingQuirk : 1; + bool m_needsKeyboardEventDisambiguationQuirks : 1; + bool m_isDOMPasteAllowed : 1; + bool m_shrinksStandaloneImagesToFit : 1; + bool m_usesPageCache: 1; + bool m_showsURLsInToolTips : 1; + bool m_forceFTPDirectoryListings : 1; + bool m_developerExtrasEnabled : 1; + bool m_authorAndUserStylesEnabled : 1; + bool m_needsSiteSpecificQuirks : 1; + unsigned m_fontRenderingMode : 1; + bool m_webArchiveDebugModeEnabled : 1; + bool m_inApplicationChromeMode : 1; + bool m_offlineWebApplicationCacheEnabled : 1; + bool m_rangeMutationDisabledForOldAppleMail : 1; + bool m_shouldPaintCustomScrollbars : 1; + bool m_zoomsTextOnly : 1; + bool m_enforceCSSMIMETypeInStrictMode : 1; + size_t m_maximumDecodedImageSize; + +#if USE(SAFARI_THEME) + static bool gShouldPaintNativeControls; +#endif + }; + +} // namespace WebCore + +#endif // Settings_h diff --git a/src/3rdparty/webkit/WebCore/page/WindowFeatures.cpp b/src/3rdparty/webkit/WebCore/page/WindowFeatures.cpp new file mode 100644 index 0000000..c499a4a --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/WindowFeatures.cpp @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2000 Harri Porten (porten@kde.org) + * Copyright (C) 2006 Jon Shier (jshier@iastate.edu) + * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reseved. + * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#include "config.h" +#include "WindowFeatures.h" + +#include "PlatformString.h" +#include "StringHash.h" +#include <wtf/Assertions.h> +#include <wtf/HashMap.h> +#include <wtf/MathExtras.h> + +namespace WebCore { + +// Though isspace() considers \t and \v to be whitespace, Win IE doesn't. +static bool isSeparator(UChar c) +{ + return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '=' || c == ',' || c == '\0'; +} + +WindowFeatures::WindowFeatures(const String& features) + : xSet(false) + , ySet(false) + , widthSet(false) + , heightSet(false) + , fullscreen(false) + , dialog(false) +{ + /* + The IE rule is: all features except for channelmode and fullscreen default to YES, but + if the user specifies a feature string, all features default to NO. (There is no public + standard that applies to this method.) + + <http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/open_0.asp> + We always allow a window to be resized, which is consistent with Firefox. + */ + + if (features.length() == 0) { + menuBarVisible = true; + statusBarVisible = true; + toolBarVisible = true; + locationBarVisible = true; + scrollbarsVisible = true; + resizable = true; + return; + } + + menuBarVisible = false; + statusBarVisible = false; + toolBarVisible = false; + locationBarVisible = false; + scrollbarsVisible = false; + resizable = true; + + // Tread lightly in this code -- it was specifically designed to mimic Win IE's parsing behavior. + int keyBegin, keyEnd; + int valueBegin, valueEnd; + + int i = 0; + int length = features.length(); + String buffer = features.lower(); + while (i < length) { + // skip to first non-separator, but don't skip past the end of the string + while (isSeparator(buffer[i])) { + if (i >= length) + break; + i++; + } + keyBegin = i; + + // skip to first separator + while (!isSeparator(buffer[i])) + i++; + keyEnd = i; + + // skip to first '=', but don't skip past a ',' or the end of the string + while (buffer[i] != '=') { + if (buffer[i] == ',' || i >= length) + break; + i++; + } + + // skip to first non-separator, but don't skip past a ',' or the end of the string + while (isSeparator(buffer[i])) { + if (buffer[i] == ',' || i >= length) + break; + i++; + } + valueBegin = i; + + // skip to first separator + while (!isSeparator(buffer[i])) + i++; + valueEnd = i; + + ASSERT(i <= length); + + String keyString(buffer.substring(keyBegin, keyEnd - keyBegin)); + String valueString(buffer.substring(valueBegin, valueEnd - valueBegin)); + setWindowFeature(keyString, valueString); + } +} + +void WindowFeatures::setWindowFeature(const String& keyString, const String& valueString) +{ + int value; + + // Listing a key with no value is shorthand for key=yes + if (valueString.length() == 0 || valueString == "yes") + value = 1; + else + value = valueString.toInt(); + + // We ignore a keyString of "resizable", which is consistent with Firefox. + if (keyString == "left" || keyString == "screenx") { + xSet = true; + x = value; + } else if (keyString == "top" || keyString == "screeny") { + ySet = true; + y = value; + } else if (keyString == "width" || keyString == "innerwidth") { + widthSet = true; + width = value; + } else if (keyString == "height" || keyString == "innerheight") { + heightSet = true; + height = value; + } else if (keyString == "menubar") + menuBarVisible = value; + else if (keyString == "toolbar") + toolBarVisible = value; + else if (keyString == "location") + locationBarVisible = value; + else if (keyString == "status") + statusBarVisible = value; + else if (keyString == "fullscreen") + fullscreen = value; + else if (keyString == "scrollbars") + scrollbarsVisible = value; +} + +bool WindowFeatures::boolFeature(const HashMap<String, String>& features, const char* key, bool defaultValue) +{ + HashMap<String, String>::const_iterator it = features.find(key); + if (it == features.end()) + return defaultValue; + const String& value = it->second; + return value.isNull() || value == "1" || value == "yes" || value == "on"; +} + +float WindowFeatures::floatFeature(const HashMap<String, String>& features, const char* key, float min, float max, float defaultValue) +{ + HashMap<String, String>::const_iterator it = features.find(key); + if (it == features.end()) + return defaultValue; + // FIXME: Can't distinguish "0q" from string with no digits in it -- both return d == 0 and ok == false. + // Would be good to tell them apart somehow since string with no digits should be default value and + // "0q" should be minimum value. + bool ok; + double d = it->second.toDouble(&ok); + if ((d == 0 && !ok) || isnan(d)) + return defaultValue; + if (d < min || max <= min) + return min; + if (d > max) + return max; + return static_cast<int>(d); +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/WindowFeatures.h b/src/3rdparty/webkit/WebCore/page/WindowFeatures.h new file mode 100644 index 0000000..a12cf05 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/WindowFeatures.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2003, 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. + * 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. + */ + +#ifndef WindowFeatures_h +#define WindowFeatures_h + +#include "PlatformString.h" +#include <wtf/HashMap.h> + +namespace WebCore { + + 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) + { + } + + WindowFeatures(const String& features); + + void setWindowFeature(const String& keyString, const String& valueString); + + static bool boolFeature(const HashMap<String, String>& features, const char* key, bool defaultValue = false); + static float floatFeature(const HashMap<String, String>& features, const char* key, float min, float max, float defaultValue); + + 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 fullscreen; + bool dialog; + }; + +} // namespace WebCore + +#endif // WindowFeatures_h diff --git a/src/3rdparty/webkit/WebCore/page/WorkerNavigator.cpp b/src/3rdparty/webkit/WebCore/page/WorkerNavigator.cpp new file mode 100644 index 0000000..339f107 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/WorkerNavigator.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2008 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" + +#if ENABLE(WORKERS) + +#include "WorkerNavigator.h" + +namespace WebCore { + +WorkerNavigator::WorkerNavigator(const String& userAgent) + : m_userAgent(userAgent) +{ +} + +WorkerNavigator::~WorkerNavigator() +{ +} + +String WorkerNavigator::userAgent() const +{ + return m_userAgent; +} + +} // namespace WebCore + +#endif // ENABLE(WORKERS) diff --git a/src/3rdparty/webkit/WebCore/page/WorkerNavigator.h b/src/3rdparty/webkit/WebCore/page/WorkerNavigator.h new file mode 100644 index 0000000..8ca2fd9 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/WorkerNavigator.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2008 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 WorkerNavigator_h +#define WorkerNavigator_h + +#if ENABLE(WORKERS) + +#include "NavigatorBase.h" +#include "PlatformString.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + + class WorkerNavigator : public NavigatorBase, public RefCounted<WorkerNavigator> { + public: + static PassRefPtr<WorkerNavigator> create(const String& userAgent) { return adoptRef(new WorkerNavigator(userAgent)); } + virtual ~WorkerNavigator(); + + virtual String userAgent() const; + + private: + WorkerNavigator(const String&); + + String m_userAgent; + }; + +} // namespace WebCore + +#endif // ENABLE(WORKERS) + +#endif // WorkerNavigator_h diff --git a/src/3rdparty/webkit/WebCore/page/WorkerNavigator.idl b/src/3rdparty/webkit/WebCore/page/WorkerNavigator.idl new file mode 100644 index 0000000..195f0bc --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/WorkerNavigator.idl @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2008 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. + */ + +module threads { + + interface [ + Conditional=WORKERS, + NoStaticTables + ] WorkerNavigator { + readonly attribute DOMString appName; + readonly attribute DOMString appVersion; + readonly attribute DOMString platform; + readonly attribute DOMString userAgent; + + readonly attribute boolean onLine; + }; + +} diff --git a/src/3rdparty/webkit/WebCore/page/animation/AnimationBase.cpp b/src/3rdparty/webkit/WebCore/page/animation/AnimationBase.cpp new file mode 100644 index 0000000..60bc774 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/animation/AnimationBase.cpp @@ -0,0 +1,860 @@ +/* + * 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. + * 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 "AnimationBase.h" + +#include "AnimationController.h" +#include "CSSPropertyNames.h" +#include "CString.h" +#include "CompositeAnimation.h" +#include "Document.h" +#include "EventNames.h" +#include "FloatConversion.h" +#include "Frame.h" +#include "IdentityTransformOperation.h" +#include "ImplicitAnimation.h" +#include "KeyframeAnimation.h" +#include "MatrixTransformOperation.h" +#include "RenderObject.h" +#include "RenderStyle.h" +#include "SystemTime.h" +#include "UnitBezier.h" + +namespace WebCore { + +// The epsilon value we pass to UnitBezier::solve given that the animation is going to run over |dur| seconds. The longer the +// animation, the more precision we need in the timing function result to avoid ugly discontinuities. +static inline double solveEpsilon(double duration) +{ + return 1.0 / (200.0 * duration); +} + +static inline double solveCubicBezierFunction(double p1x, double p1y, double p2x, double p2y, double t, double duration) +{ + // Convert from input time to parametric value in curve, then from + // that to output time. + UnitBezier bezier(p1x, p1y, p2x, p2y); + return bezier.solve(t, solveEpsilon(duration)); +} + +static inline int blendFunc(const AnimationBase*, int from, int to, double progress) +{ + return int(from + (to - from) * progress); +} + +static inline double blendFunc(const AnimationBase*, double from, double to, double progress) +{ + return from + (to - from) * progress; +} + +static inline float blendFunc(const AnimationBase*, float from, float to, double progress) +{ + return narrowPrecisionToFloat(from + (to - from) * progress); +} + +static inline Color blendFunc(const AnimationBase* anim, const Color& from, const Color& to, double progress) +{ + return Color(blendFunc(anim, from.red(), to.red(), progress), + blendFunc(anim, from.green(), to.green(), progress), + blendFunc(anim, from.blue(), to.blue(), progress), + blendFunc(anim, from.alpha(), to.alpha(), progress)); +} + +static inline Length blendFunc(const AnimationBase*, const Length& from, const Length& to, double progress) +{ + return to.blend(from, progress); +} + +static inline IntSize blendFunc(const AnimationBase* anim, const IntSize& from, const IntSize& to, double progress) +{ + return IntSize(blendFunc(anim, from.width(), to.width(), progress), + blendFunc(anim, from.height(), to.height(), progress)); +} + +static inline ShadowData* blendFunc(const AnimationBase* anim, const ShadowData* from, const ShadowData* to, double progress) +{ + ASSERT(from && to); + return new ShadowData(blendFunc(anim, from->x, to->x, progress), blendFunc(anim, from->y, to->y, progress), + blendFunc(anim, from->blur, to->blur, progress), blendFunc(anim, from->color, to->color, progress)); +} + +static inline TransformOperations blendFunc(const AnimationBase* anim, const TransformOperations& from, const TransformOperations& to, double progress) +{ + TransformOperations result; + + // If we have a transform function list, use that to do a per-function animation. Otherwise do a Matrix animation + if (anim->isTransformFunctionListValid()) { + unsigned fromSize = from.operations().size(); + unsigned toSize = to.operations().size(); + unsigned size = max(fromSize, toSize); + for (unsigned i = 0; i < size; i++) { + RefPtr<TransformOperation> fromOp = (i < fromSize) ? from.operations()[i].get() : 0; + RefPtr<TransformOperation> toOp = (i < toSize) ? to.operations()[i].get() : 0; + RefPtr<TransformOperation> blendedOp = toOp ? toOp->blend(fromOp.get(), progress) : (fromOp ? fromOp->blend(0, progress, true) : 0); + if (blendedOp) + result.operations().append(blendedOp); + else { + RefPtr<TransformOperation> identityOp = IdentityTransformOperation::create(); + if (progress > 0.5) + result.operations().append(toOp ? toOp : identityOp); + else + result.operations().append(fromOp ? fromOp : identityOp); + } + } + } else { + // Convert the TransformOperations into matrices + IntSize size = anim->renderer()->borderBox().size(); + TransformationMatrix fromT; + TransformationMatrix toT; + from.apply(size, fromT); + to.apply(size, toT); + + toT.blend(fromT, progress); + + // Append the result + result.operations().append(MatrixTransformOperation::create(toT.a(), toT.b(), toT.c(), toT.d(), toT.e(), toT.f())); + } + return result; +} + +static inline EVisibility blendFunc(const AnimationBase* anim, EVisibility from, EVisibility to, double progress) +{ + // Any non-zero result means we consider the object to be visible. Only at 0 do we consider the object to be + // invisible. The invisible value we use (HIDDEN vs. COLLAPSE) depends on the specified from/to values. + double fromVal = from == VISIBLE ? 1. : 0.; + double toVal = to == VISIBLE ? 1. : 0.; + if (fromVal == toVal) + return to; + double result = blendFunc(anim, fromVal, toVal, progress); + return result > 0. ? VISIBLE : (to != VISIBLE ? to : from); +} + +class PropertyWrapperBase { +public: + PropertyWrapperBase(int prop) + : m_prop(prop) + { + } + + virtual ~PropertyWrapperBase() { } + virtual bool equals(const RenderStyle* a, const RenderStyle* b) const = 0; + virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const = 0; + + int property() const { return m_prop; } + +private: + int m_prop; +}; + +template <typename T> +class PropertyWrapperGetter : public PropertyWrapperBase { +public: + PropertyWrapperGetter(int prop, T (RenderStyle::*getter)() const) + : PropertyWrapperBase(prop) + , m_getter(getter) + { + } + + virtual bool equals(const RenderStyle* a, const RenderStyle* b) const + { + // If the style pointers are the same, don't bother doing the test. + // If either is null, return false. If both are null, return true. + if (!a && !b || a == b) + return true; + if (!a || !b) + return false; + return (a->*m_getter)() == (b->*m_getter)(); + } + +protected: + T (RenderStyle::*m_getter)() const; +}; + +template <typename T> +class PropertyWrapper : public PropertyWrapperGetter<T> { +public: + PropertyWrapper(int prop, T (RenderStyle::*getter)() const, void (RenderStyle::*setter)(T)) + : PropertyWrapperGetter<T>(prop, getter) + , m_setter(setter) + { + } + + virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const + { + (dst->*m_setter)(blendFunc(anim, (a->*PropertyWrapperGetter<T>::m_getter)(), (b->*PropertyWrapperGetter<T>::m_getter)(), progress)); + } + +protected: + void (RenderStyle::*m_setter)(T); +}; + +class PropertyWrapperShadow : public PropertyWrapperGetter<ShadowData*> { +public: + PropertyWrapperShadow(int prop, ShadowData* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(ShadowData*, bool)) + : PropertyWrapperGetter<ShadowData*>(prop, getter) + , m_setter(setter) + { + } + + virtual bool equals(const RenderStyle* a, const RenderStyle* b) const + { + ShadowData* shadowA = (a->*m_getter)(); + ShadowData* shadowB = (b->*m_getter)(); + + if (!shadowA && shadowB || shadowA && !shadowB) + return false; + if (shadowA && shadowB && (*shadowA != *shadowB)) + return false; + return true; + } + + virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const + { + ShadowData* shadowA = (a->*m_getter)(); + ShadowData* shadowB = (b->*m_getter)(); + ShadowData defaultShadowData(0, 0, 0, Color::transparent); + + if (!shadowA) + shadowA = &defaultShadowData; + if (!shadowB) + shadowB = &defaultShadowData; + + (dst->*m_setter)(blendFunc(anim, shadowA, shadowB, progress), false); + } + +private: + void (RenderStyle::*m_setter)(ShadowData*, bool); +}; + +class PropertyWrapperMaybeInvalidColor : public PropertyWrapperBase { +public: + PropertyWrapperMaybeInvalidColor(int prop, const Color& (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&)) + : PropertyWrapperBase(prop) + , m_getter(getter) + , m_setter(setter) + { + } + + virtual bool equals(const RenderStyle* a, const RenderStyle* b) const + { + Color fromColor = (a->*m_getter)(); + Color toColor = (b->*m_getter)(); + if (!fromColor.isValid()) + fromColor = a->color(); + if (!toColor.isValid()) + toColor = b->color(); + + return fromColor == toColor; + } + + virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const + { + Color fromColor = (a->*m_getter)(); + Color toColor = (b->*m_getter)(); + if (!fromColor.isValid()) + fromColor = a->color(); + if (!toColor.isValid()) + toColor = b->color(); + (dst->*m_setter)(blendFunc(anim, fromColor, toColor, progress)); + } + +private: + const Color& (RenderStyle::*m_getter)() const; + void (RenderStyle::*m_setter)(const Color&); +}; + +static Vector<PropertyWrapperBase*>* gPropertyWrappers = 0; +static int gPropertyWrapperMap[numCSSProperties]; + +static void ensurePropertyMap() +{ + // FIXME: This data is never destroyed. Maybe we should ref count it and toss it when the last AnimationController is destroyed? + if (gPropertyWrappers == 0) { + gPropertyWrappers = new Vector<PropertyWrapperBase*>(); + + // build the list of property wrappers to do the comparisons and blends + gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyLeft, &RenderStyle::left, &RenderStyle::setLeft)); + gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyRight, &RenderStyle::right, &RenderStyle::setRight)); + gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyTop, &RenderStyle::top, &RenderStyle::setTop)); + gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyBottom, &RenderStyle::bottom, &RenderStyle::setBottom)); + gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWidth, &RenderStyle::width, &RenderStyle::setWidth)); + gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyHeight, &RenderStyle::height, &RenderStyle::setHeight)); + gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyBorderLeftWidth, &RenderStyle::borderLeftWidth, &RenderStyle::setBorderLeftWidth)); + gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyBorderRightWidth, &RenderStyle::borderRightWidth, &RenderStyle::setBorderRightWidth)); + gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyBorderTopWidth, &RenderStyle::borderTopWidth, &RenderStyle::setBorderTopWidth)); + gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyBorderBottomWidth, &RenderStyle::borderBottomWidth, &RenderStyle::setBorderBottomWidth)); + gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginLeft, &RenderStyle::marginLeft, &RenderStyle::setMarginLeft)); + gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginRight, &RenderStyle::marginRight, &RenderStyle::setMarginRight)); + gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginTop, &RenderStyle::marginTop, &RenderStyle::setMarginTop)); + gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginBottom, &RenderStyle::marginBottom, &RenderStyle::setMarginBottom)); + gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingLeft, &RenderStyle::paddingLeft, &RenderStyle::setPaddingLeft)); + gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingRight, &RenderStyle::paddingRight, &RenderStyle::setPaddingRight)); + gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingTop, &RenderStyle::paddingTop, &RenderStyle::setPaddingTop)); + gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingBottom, &RenderStyle::paddingBottom, &RenderStyle::setPaddingBottom)); + gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyOpacity, &RenderStyle::opacity, &RenderStyle::setOpacity)); + gPropertyWrappers->append(new PropertyWrapper<const Color&>(CSSPropertyColor, &RenderStyle::color, &RenderStyle::setColor)); + gPropertyWrappers->append(new PropertyWrapper<const Color&>(CSSPropertyBackgroundColor, &RenderStyle::backgroundColor, &RenderStyle::setBackgroundColor)); + gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyFontSize, &RenderStyle::fontSize, &RenderStyle::setBlendedFontSize)); + gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyWebkitColumnRuleWidth, &RenderStyle::columnRuleWidth, &RenderStyle::setColumnRuleWidth)); + gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitColumnGap, &RenderStyle::columnGap, &RenderStyle::setColumnGap)); + gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyWebkitColumnCount, &RenderStyle::columnCount, &RenderStyle::setColumnCount)); + gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitColumnWidth, &RenderStyle::columnWidth, &RenderStyle::setColumnWidth)); + 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<Length>(CSSPropertyLineHeight, &RenderStyle::lineHeight, &RenderStyle::setLineHeight)); + gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyOutlineOffset, &RenderStyle::outlineOffset, &RenderStyle::setOutlineOffset)); + gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyOutlineWidth, &RenderStyle::outlineWidth, &RenderStyle::setOutlineWidth)); + gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyLetterSpacing, &RenderStyle::letterSpacing, &RenderStyle::setLetterSpacing)); + gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyWordSpacing, &RenderStyle::wordSpacing, &RenderStyle::setWordSpacing)); + gPropertyWrappers->append(new PropertyWrapper<const TransformOperations&>(CSSPropertyWebkitTransform, &RenderStyle::transform, &RenderStyle::setTransform)); + gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitTransformOriginX, &RenderStyle::transformOriginX, &RenderStyle::setTransformOriginX)); + gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitTransformOriginY, &RenderStyle::transformOriginY, &RenderStyle::setTransformOriginY)); + gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyWebkitBorderTopLeftRadius, &RenderStyle::borderTopLeftRadius, &RenderStyle::setBorderTopLeftRadius)); + gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyWebkitBorderTopRightRadius, &RenderStyle::borderTopRightRadius, &RenderStyle::setBorderTopRightRadius)); + gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyWebkitBorderBottomLeftRadius, &RenderStyle::borderBottomLeftRadius, &RenderStyle::setBorderBottomLeftRadius)); + gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyWebkitBorderBottomRightRadius, &RenderStyle::borderBottomRightRadius, &RenderStyle::setBorderBottomRightRadius)); + gPropertyWrappers->append(new PropertyWrapper<EVisibility>(CSSPropertyVisibility, &RenderStyle::visibility, &RenderStyle::setVisibility)); + gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyZoom, &RenderStyle::zoom, &RenderStyle::setZoom)); + gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyWebkitColumnRuleColor, &RenderStyle::columnRuleColor, &RenderStyle::setColumnRuleColor)); + gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyWebkitTextStrokeColor, &RenderStyle::textStrokeColor, &RenderStyle::setTextStrokeColor)); + gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyWebkitTextFillColor, &RenderStyle::textFillColor, &RenderStyle::setTextFillColor)); + gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyBorderLeftColor, &RenderStyle::borderLeftColor, &RenderStyle::setBorderLeftColor)); + gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyBorderRightColor, &RenderStyle::borderRightColor, &RenderStyle::setBorderRightColor)); + gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyBorderTopColor, &RenderStyle::borderTopColor, &RenderStyle::setBorderTopColor)); + gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyBorderBottomColor, &RenderStyle::borderBottomColor, &RenderStyle::setBorderBottomColor)); + gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyOutlineColor, &RenderStyle::outlineColor, &RenderStyle::setOutlineColor)); + + // These are for shadows + gPropertyWrappers->append(new PropertyWrapperShadow(CSSPropertyWebkitBoxShadow, &RenderStyle::boxShadow, &RenderStyle::setBoxShadow)); + gPropertyWrappers->append(new PropertyWrapperShadow(CSSPropertyTextShadow, &RenderStyle::textShadow, &RenderStyle::setTextShadow)); + +#if ENABLE(SVG) + gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyFillOpacity, &RenderStyle::fillOpacity, &RenderStyle::setFillOpacity)); + gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyFloodOpacity, &RenderStyle::floodOpacity, &RenderStyle::setFloodOpacity)); + gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyStrokeOpacity, &RenderStyle::strokeOpacity, &RenderStyle::setStrokeOpacity)); +#endif + + // Make sure unused slots have a value + for (unsigned int i = 0; i < (unsigned int) numCSSProperties; ++i) + gPropertyWrapperMap[i] = CSSPropertyInvalid; + + size_t n = gPropertyWrappers->size(); + for (unsigned int i = 0; i < n; ++i) { + ASSERT((*gPropertyWrappers)[i]->property() - firstCSSProperty < numCSSProperties); + gPropertyWrapperMap[(*gPropertyWrappers)[i]->property() - firstCSSProperty] = i; + } + } +} + +AnimationBase::AnimationBase(const Animation* transition, RenderObject* renderer, CompositeAnimation* compAnim) + : m_animState(AnimationStateNew) + , m_isAnimating(false) + , m_waitedForResponse(false) + , m_startTime(0) + , m_pauseTime(-1) + , m_requestedStartTime(0) + , m_object(renderer) + , m_animation(const_cast<Animation*>(transition)) + , m_compAnim(compAnim) + , m_transformFunctionListValid(false) + , m_nextIterationDuration(-1) +{ + // Compute the total duration + m_totalDuration = -1; + if (m_animation->iterationCount() > 0) + m_totalDuration = m_animation->duration() * m_animation->iterationCount(); +} + +AnimationBase::~AnimationBase() +{ + if (m_animState == AnimationStateStartWaitStyleAvailable) + m_compAnim->setWaitingForStyleAvailable(false); +} + +bool AnimationBase::propertiesEqual(int prop, const RenderStyle* a, const RenderStyle* b) +{ + ensurePropertyMap(); + if (prop == cAnimateAll) { + size_t n = gPropertyWrappers->size(); + for (unsigned int i = 0; i < n; ++i) { + if (!(*gPropertyWrappers)[i]->equals(a, b)) + return false; + } + } else { + int propIndex = prop - firstCSSProperty; + + if (propIndex >= 0 && propIndex < numCSSProperties) { + int i = gPropertyWrapperMap[propIndex]; + return i >= 0 ? (*gPropertyWrappers)[i]->equals(a, b) : true; + } + } + return true; +} + +int AnimationBase::getPropertyAtIndex(int i) +{ + ensurePropertyMap(); + if (i < 0 || i >= static_cast<int>(gPropertyWrappers->size())) + return CSSPropertyInvalid; + + return (*gPropertyWrappers)[i]->property(); +} + +int AnimationBase::getNumProperties() +{ + ensurePropertyMap(); + return gPropertyWrappers->size(); +} + +// Returns true if we need to start animation timers +bool AnimationBase::blendProperties(const AnimationBase* anim, int prop, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) +{ + ASSERT(prop != cAnimateAll); + // FIXME: Why can this happen? + + ensurePropertyMap(); + if (prop == cAnimateAll) { + bool needsTimer = false; + + size_t n = gPropertyWrappers->size(); + for (unsigned int i = 0; i < n; ++i) { + PropertyWrapperBase* wrapper = (*gPropertyWrappers)[i]; + if (!wrapper->equals(a, b)) { + wrapper->blend(anim, dst, a, b, progress); + needsTimer = true; + } + } + return needsTimer; + } + + int propIndex = prop - firstCSSProperty; + if (propIndex >= 0 && propIndex < numCSSProperties) { + int i = gPropertyWrapperMap[propIndex]; + if (i >= 0) { + PropertyWrapperBase* wrapper = (*gPropertyWrappers)[i]; + wrapper->blend(anim, dst, a, b, progress); + return true; + } + } + + return false; +} + +void AnimationBase::setChanged(Node* node) +{ + ASSERT(!node || (node->document() && !node->document()->inPageCache())); + if (node) + node->setChanged(AnimationStyleChange); +} + +double AnimationBase::duration() const +{ + return m_animation->duration(); +} + +bool AnimationBase::playStatePlaying() const +{ + return m_animation->playState() == AnimPlayStatePlaying; +} + +bool AnimationBase::animationsMatch(const Animation* anim) const +{ + return m_animation->animationsMatch(anim); +} + +void AnimationBase::updateStateMachine(AnimStateInput input, double param) +{ + // If we get AnimationStateInputRestartAnimation then we force a new animation, regardless of state. + if (input == AnimationStateInputMakeNew) { + if (m_animState == AnimationStateStartWaitStyleAvailable) + m_compAnim->setWaitingForStyleAvailable(false); + m_animState = AnimationStateNew; + m_startTime = 0; + m_pauseTime = -1; + m_requestedStartTime = 0; + m_nextIterationDuration = -1; + m_waitedForResponse = false; + endAnimation(false); + return; + } + + if (input == AnimationStateInputRestartAnimation) { + if (m_animState == AnimationStateStartWaitStyleAvailable) + m_compAnim->setWaitingForStyleAvailable(false); + m_animState = AnimationStateNew; + m_startTime = 0; + m_pauseTime = -1; + m_requestedStartTime = 0; + m_nextIterationDuration = -1; + endAnimation(false); + + if (!paused()) + updateStateMachine(AnimationStateInputStartAnimation, -1); + return; + } + + if (input == AnimationStateInputEndAnimation) { + if (m_animState == AnimationStateStartWaitStyleAvailable) + m_compAnim->setWaitingForStyleAvailable(false); + m_animState = AnimationStateDone; + endAnimation(true); + return; + } + + if (input == AnimationStateInputPauseOverride) { + if (m_animState == AnimationStateStartWaitResponse) { + // If we are in AnimationStateStartWaitResponse, the animation will get canceled before + // we get a response, so move to the next state. + endAnimation(false); + updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUpdateTime()); + } + return; + } + + if (input == AnimationStateInputResumeOverride) { + if (m_animState == AnimationStateLooping || m_animState == AnimationStateEnding) { + // Start the animation + startAnimation(m_startTime); + } + return; + } + + // Execute state machine + switch(m_animState) { + case AnimationStateNew: + ASSERT(input == AnimationStateInputStartAnimation || input == AnimationStateInputPlayStateRunnning || input == AnimationStateInputPlayStatePaused); + if (input == AnimationStateInputStartAnimation || input == AnimationStateInputPlayStateRunnning) { + m_waitedForResponse = false; + m_requestedStartTime = beginAnimationUpdateTime(); + m_animState = AnimationStateStartWaitTimer; + } + break; + case AnimationStateStartWaitTimer: + ASSERT(input == AnimationStateInputStartTimerFired || input == AnimationStateInputPlayStatePaused); + + if (input == AnimationStateInputStartTimerFired) { + ASSERT(param >= 0); + // Start timer has fired, tell the animation to start and wait for it to respond with start time + m_animState = AnimationStateStartWaitStyleAvailable; + m_compAnim->setWaitingForStyleAvailable(true); + + // Trigger a render so we can start the animation + setChanged(m_object->element()); + m_object->animation()->startUpdateRenderingDispatcher(); + } else { + 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(); + m_animState = AnimationStatePausedWaitTimer; + } + break; + case AnimationStateStartWaitStyleAvailable: + ASSERT(input == AnimationStateInputStyleAvailable || input == AnimationStateInputPlayStatePaused); + + m_compAnim->setWaitingForStyleAvailable(false); + + // Start timer has fired, tell the animation to start and wait for it to respond with start time + m_animState = AnimationStateStartWaitResponse; + + overrideAnimations(); + + // Send start event, if needed + onAnimationStart(0); // The elapsedTime is always 0 here + + // Start the animation + if (overridden() || !startAnimation(0)) { + // We're not going to get a startTime callback, so fire the start time here + m_animState = AnimationStateStartWaitResponse; + updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUpdateTime()); + } else + m_waitedForResponse = true; + break; + case AnimationStateStartWaitResponse: + ASSERT(input == AnimationStateInputStartTimeSet || input == AnimationStateInputPlayStatePaused); + + if (input == AnimationStateInputStartTimeSet) { + ASSERT(param >= 0); + // We have a start time, set it, unless the startTime is already set + if (m_startTime <= 0) + m_startTime = param; + + // Decide whether to go into looping or ending state + goIntoEndingOrLoopingState(); + + // Trigger a render so we can start the animation + if (m_object) { + setChanged(m_object->element()); + m_compAnim->animationController()->startUpdateRenderingDispatcher(); + } + } else { + // We are pausing while waiting for a start response. Cancel the animation and wait. When + // we unpause, we will act as though the start timer just fired + m_pauseTime = -1; + endAnimation(false); + m_animState = AnimationStatePausedWaitResponse; + } + break; + case AnimationStateLooping: + ASSERT(input == AnimationStateInputLoopTimerFired || input == AnimationStateInputPlayStatePaused); + + if (input == AnimationStateInputLoopTimerFired) { + ASSERT(param >= 0); + // Loop timer fired, loop again or end. + onAnimationIteration(param); + + // Decide whether to go into looping or ending state + goIntoEndingOrLoopingState(); + } else { + // We are pausing while running. Cancel the animation and wait + m_pauseTime = beginAnimationUpdateTime(); + endAnimation(false); + m_animState = AnimationStatePausedRun; + } + break; + case AnimationStateEnding: + ASSERT(input == AnimationStateInputEndTimerFired || input == AnimationStateInputPlayStatePaused); + + if (input == AnimationStateInputEndTimerFired) { + ASSERT(param >= 0); + // End timer fired, finish up + onAnimationEnd(param); + + m_animState = AnimationStateDone; + + if (m_object) { + resumeOverriddenAnimations(); + + // Fire off another style change so we can set the final value + setChanged(m_object->element()); + m_object->animation()->startUpdateRenderingDispatcher(); + } + } else { + // We are pausing while running. Cancel the animation and wait + m_pauseTime = beginAnimationUpdateTime(); + endAnimation(false); + m_animState = AnimationStatePausedRun; + } + // |this| may be deleted here + break; + case AnimationStatePausedWaitTimer: + ASSERT(input == AnimationStateInputPlayStateRunnning); + ASSERT(paused()); + // Update the times + m_startTime += beginAnimationUpdateTime() - m_pauseTime; + m_pauseTime = -1; + + // we were waiting for the start timer to fire, go back and wait again + m_animState = AnimationStateNew; + updateStateMachine(AnimationStateInputStartAnimation, 0); + break; + case AnimationStatePausedWaitResponse: + case AnimationStatePausedRun: + // We treat these two cases the same. The only difference is that, when we are in + // 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 == AnimationStateInputPlayStateRunnning); + ASSERT(paused()); + // Update the times + if (m_animState == AnimationStatePausedRun) + m_startTime += beginAnimationUpdateTime() - m_pauseTime; + else + m_startTime = 0; + m_pauseTime = -1; + + // We were waiting for a begin time response from the animation, go back and wait again + m_animState = AnimationStateStartWaitResponse; + + // Start the animation + if (overridden() || !startAnimation(m_startTime)) { + // We're not going to get a startTime callback, so fire the start time here + updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUpdateTime()); + } else + m_waitedForResponse = true; + break; + case AnimationStateDone: + // We're done. Stay in this state until we are deleted + break; + } +} + +void AnimationBase::fireAnimationEventsIfNeeded() +{ + // If we are waiting for the delay time to expire and it has, go to the next state + if (m_animState != AnimationStateStartWaitTimer && m_animState != AnimationStateLooping && m_animState != AnimationStateEnding) + return; + + // We have to make sure to keep a ref to the this pointer, because it could get destroyed + // during an animation callback that might get called. Since the owner is a CompositeAnimation + // and it ref counts this object, we will keep a ref to that instead. That way the AnimationBase + // can still access the resources of its CompositeAnimation as needed. + RefPtr<AnimationBase> protector(this); + RefPtr<CompositeAnimation> compProtector(m_compAnim); + + // Check for start timeout + if (m_animState == AnimationStateStartWaitTimer) { + if (beginAnimationUpdateTime() - m_requestedStartTime >= m_animation->delay()) + updateStateMachine(AnimationStateInputStartTimerFired, 0); + return; + } + + double elapsedDuration = beginAnimationUpdateTime() - m_startTime; + ASSERT(elapsedDuration >= 0); + + // Check for end timeout + if (m_totalDuration >= 0 && elapsedDuration >= m_totalDuration) { + // Fire an end event + updateStateMachine(AnimationStateInputEndTimerFired, m_totalDuration); + } + else { + // Check for iteration timeout + if (m_nextIterationDuration < 0) { + // Hasn't been set yet, set it + double durationLeft = m_animation->duration() - fmod(elapsedDuration, m_animation->duration()); + m_nextIterationDuration = elapsedDuration + durationLeft; + } + + if (elapsedDuration >= m_nextIterationDuration) { + // Set to the next iteration + double previous = m_nextIterationDuration; + double durationLeft = m_animation->duration() - fmod(elapsedDuration, m_animation->duration()); + m_nextIterationDuration = elapsedDuration + durationLeft; + + // Send the event + updateStateMachine(AnimationStateInputLoopTimerFired, previous); + } + } +} + +void AnimationBase::updatePlayState(bool run) +{ + if (paused() == run || isNew()) + updateStateMachine(run ? AnimationStateInputPlayStateRunnning : AnimationStateInputPlayStatePaused, -1); +} + +double AnimationBase::willNeedService() const +{ + // Returns the time at which next service is required. -1 means no service is required. 0 means + // service is required now, and > 0 means service is required that many seconds in the future. + if (paused() || isNew()) + return -1; + + if (m_animState == AnimationStateStartWaitTimer) { + double timeFromNow = m_animation->delay() - (beginAnimationUpdateTime() - m_requestedStartTime); + return (float) ((timeFromNow > 0) ? timeFromNow : 0); + } + + // In all other cases, we need service right away. + return 0; +} + +double AnimationBase::progress(double scale, double offset, const TimingFunction* tf) const +{ + if (preActive()) + return 0; + + double elapsedTime = running() && !paused() ? (beginAnimationUpdateTime() - m_startTime) : (m_pauseTime - m_startTime); + if (running() && elapsedTime < 0) + return 0; + + double dur = m_animation->duration(); + if (m_animation->iterationCount() > 0) + dur *= m_animation->iterationCount(); + + if (postActive() || !m_animation->duration() || (m_animation->iterationCount() > 0 && elapsedTime >= dur)) + return 1.0; + + // Compute the fractional time, taking into account direction. + // There is no need to worry about iterations, we assume that we would have + // short circuited above if we were done. + double fractionalTime = elapsedTime / m_animation->duration(); + int integralTime = static_cast<int>(fractionalTime); + fractionalTime -= integralTime; + + if (m_animation->direction() && (integralTime & 1)) + fractionalTime = 1 - fractionalTime; + + if (scale != 1 || offset) + fractionalTime = (fractionalTime - offset) * scale; + + if (!tf) + tf = &m_animation->timingFunction(); + + if (tf->type() == LinearTimingFunction) + return fractionalTime; + + // Cubic bezier. + double result = solveCubicBezierFunction(tf->x1(), + tf->y1(), + tf->x2(), + tf->y2(), + fractionalTime, m_animation->duration()); + return result; +} + +void AnimationBase::goIntoEndingOrLoopingState() +{ + // Decide when the end or loop event needs to fire + double totalDuration = -1; + if (m_animation->iterationCount() > 0) + totalDuration = m_animation->duration() * m_animation->iterationCount(); + + const double elapsedDuration = beginAnimationUpdateTime() - m_startTime; + ASSERT(elapsedDuration >= 0); + double durationLeft = 0; + double nextIterationTime = totalDuration; + + if (totalDuration < 0 || elapsedDuration < totalDuration) { + durationLeft = m_animation->duration() - fmod(elapsedDuration, m_animation->duration()); + nextIterationTime = elapsedDuration + durationLeft; + } + + if (totalDuration < 0 || nextIterationTime < totalDuration) { + // We are not at the end yet + ASSERT(nextIterationTime > 0); + m_animState = AnimationStateLooping; + } else { + // We are at the end + m_animState = AnimationStateEnding; + } +} + +void AnimationBase::pauseAtTime(double t) +{ + updatePlayState(false); + m_pauseTime = m_startTime + t - m_animation->delay(); +} + +double AnimationBase::beginAnimationUpdateTime() const +{ + return m_compAnim->animationController()->beginAnimationUpdateTime(); +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/animation/AnimationBase.h b/src/3rdparty/webkit/WebCore/page/animation/AnimationBase.h new file mode 100644 index 0000000..3a5cb85 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/animation/AnimationBase.h @@ -0,0 +1,199 @@ +/* + * 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. + * 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. + */ + +#ifndef AnimationBase_h +#define AnimationBase_h + +#include "AtomicString.h" +#include <wtf/HashMap.h> + +namespace WebCore { + +class Animation; +class AnimationBase; +class AnimationController; +class CompositeAnimation; +class Element; +class Node; +class RenderObject; +class RenderStyle; +class TimingFunction; + +class AnimationBase : public RefCounted<AnimationBase> { + friend class CompositeAnimationPrivate; + +public: + AnimationBase(const Animation* transition, RenderObject* renderer, CompositeAnimation* compAnim); + virtual ~AnimationBase(); + + RenderObject* renderer() const { return m_object; } + void clearRenderer() { m_object = 0; } + + double startTime() const { return m_startTime; } + double duration() const; + + // Animations and Transitions go through the states below. When entering the STARTED state + // the animation is started. This may or may not require deferred response from the animator. + // If so, we stay in this state until that response is received (and it returns the start time). + // Otherwise, we use the current time as the start time and go immediately to AnimationStateLooping + // or AnimationStateEnding. + enum AnimState { + AnimationStateNew, // animation just created, animation not running yet + AnimationStateStartWaitTimer, // start timer running, waiting for fire + AnimationStateStartWaitStyleAvailable, // waiting for style setup so we can start animations + 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 + AnimationStatePausedWaitTimer, // in pause mode when animation started + AnimationStatePausedWaitResponse, // animation paused when in STARTING state + AnimationStatePausedRun, // animation paused when in LOOPING or ENDING state + AnimationStateDone // end timer fired, animation finished and removed + }; + + enum AnimStateInput { + AnimationStateInputMakeNew, // reset back to new from any state + AnimationStateInputStartAnimation, // animation requests a start + AnimationStateInputRestartAnimation, // force a restart from any state + AnimationStateInputStartTimerFired, // start timer fired + AnimationStateInputStyleAvailable, // style is setup, ready to start animating + AnimationStateInputStartTimeSet, // m_startTime was set + AnimationStateInputLoopTimerFired, // loop timer fired + AnimationStateInputEndTimerFired, // end timer fired + AnimationStateInputPauseOverride, // pause an animation due to override + AnimationStateInputResumeOverride, // resume an overridden animation + AnimationStateInputPlayStateRunnning, // play state paused -> running + AnimationStateInputPlayStatePaused, // play state running -> paused + AnimationStateInputEndAnimation // force an end from any state + }; + + // Called when animation is in AnimationStateNew to start animation + void updateStateMachine(AnimStateInput, double param); + + // Animation has actually started, at passed time + void onAnimationStartResponse(double startTime); + + // Called to change to or from paused state + void updatePlayState(bool running); + bool playStatePlaying() const; + + bool waitingToStart() const { return m_animState == AnimationStateNew || m_animState == AnimationStateStartWaitTimer; } + bool preActive() const + { + return m_animState == AnimationStateNew || m_animState == AnimationStateStartWaitTimer || m_animState == AnimationStateStartWaitStyleAvailable || m_animState == AnimationStateStartWaitResponse; + } + + 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 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; } + double willNeedService() const; + + double progress(double scale, double offset, const TimingFunction*) const; + + virtual void animate(CompositeAnimation*, RenderObject*, const RenderStyle* /*currentStyle*/, + const RenderStyle* /*targetStyle*/, RefPtr<RenderStyle>& /*animatedStyle*/) { } + + virtual bool shouldFireEvents() const { return false; } + + void fireAnimationEventsIfNeeded(); + + bool animationsMatch(const Animation*) const; + + void setAnimation(const Animation* anim) { m_animation = const_cast<Animation*>(anim); } + + // Return true if this animation is overridden. This will only be the case for + // ImplicitAnimations and is used to determine whether or not we should force + // set the start time. If an animation is overridden, it will probably not get + // back the AnimationStateInputStartTimeSet input. + virtual bool overridden() const { return false; } + + // Does this animation/transition involve the given property? + virtual bool affectsProperty(int /*property*/) const { return false; } + bool isAnimatingProperty(int property, bool isRunningNow) const + { + if (isRunningNow) + return (!waitingToStart() && !postActive()) && affectsProperty(property); + + return !postActive() && affectsProperty(property); + } + + bool isTransformFunctionListValid() const { return m_transformFunctionListValid; } + + void pauseAtTime(double t); + + double beginAnimationUpdateTime() const; + +protected: + virtual void overrideAnimations() { } + virtual void resumeOverriddenAnimations() { } + + CompositeAnimation* compositeAnimation() { return m_compAnim; } + + // These are called when the corresponding timer fires so subclasses can do any extra work + virtual void onAnimationStart(double /*elapsedTime*/) { } + virtual void onAnimationIteration(double /*elapsedTime*/) { } + virtual void onAnimationEnd(double /*elapsedTime*/) { } + virtual bool startAnimation(double /*beginTime*/) { return false; } + virtual void endAnimation(bool /*reset*/) { } + + void goIntoEndingOrLoopingState(); + + static bool propertiesEqual(int prop, const RenderStyle* a, const RenderStyle* b); + static int getPropertyAtIndex(int); + static int getNumProperties(); + + // Return true if we need to start software animation timers + static bool blendProperties(const AnimationBase* anim, int prop, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress); + + static void setChanged(Node*); + + AnimState m_animState; + + bool m_isAnimating; // transition/animation requires continual timer firing + bool m_waitedForResponse; + double m_startTime; + double m_pauseTime; + double m_requestedStartTime; + RenderObject* m_object; + + RefPtr<Animation> m_animation; + CompositeAnimation* m_compAnim; + bool m_transformFunctionListValid; + double m_totalDuration, m_nextIterationDuration; +}; + +} // namespace WebCore + +#endif // AnimationBase_h diff --git a/src/3rdparty/webkit/WebCore/page/animation/AnimationController.cpp b/src/3rdparty/webkit/WebCore/page/animation/AnimationController.cpp new file mode 100644 index 0000000..3b6cfcc --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/animation/AnimationController.cpp @@ -0,0 +1,456 @@ +/* + * 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. + * 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 "AnimationController.h" +#include "CompositeAnimation.h" +#include "CSSParser.h" +#include "EventNames.h" +#include "Frame.h" +#include "SystemTime.h" +#include "Timer.h" + +namespace WebCore { + +static const double cAnimationTimerDelay = 0.025; +static const double cBeginAnimationUpdateTimeNotSet = -1; + +class AnimationControllerPrivate { +public: + AnimationControllerPrivate(Frame*); + ~AnimationControllerPrivate(); + + PassRefPtr<CompositeAnimation> accessCompositeAnimation(RenderObject*); + bool clear(RenderObject*); + + void animationTimerFired(Timer<AnimationControllerPrivate>*); + void updateAnimationTimer(bool callSetChanged = false); + + void updateRenderingDispatcherFired(Timer<AnimationControllerPrivate>*); + void startUpdateRenderingDispatcher(); + void addEventToDispatch(PassRefPtr<Element> element, const AtomicString& eventType, const String& name, double elapsedTime); + + bool hasAnimations() const { return !m_compositeAnimations.isEmpty(); } + + void suspendAnimations(Document*); + void resumeAnimations(Document*); + + void styleAvailable(); + + bool isAnimatingPropertyOnRenderer(RenderObject*, int property, bool isRunningNow) const; + + bool pauseAnimationAtTime(RenderObject*, const String& name, double t); + bool pauseTransitionAtTime(RenderObject*, const String& property, double t); + unsigned numberOfActiveAnimations() const; + + double beginAnimationUpdateTime() + { + if (m_beginAnimationUpdateTime == cBeginAnimationUpdateTimeNotSet) + m_beginAnimationUpdateTime = currentTime(); + return m_beginAnimationUpdateTime; + } + + void setBeginAnimationUpdateTime(double t) { m_beginAnimationUpdateTime = t; } + +private: + typedef HashMap<RenderObject*, RefPtr<CompositeAnimation> > RenderObjectAnimationMap; + + RenderObjectAnimationMap m_compositeAnimations; + Timer<AnimationControllerPrivate> m_animationTimer; + Timer<AnimationControllerPrivate> m_updateRenderingDispatcher; + Frame* m_frame; + + class EventToDispatch { + public: + RefPtr<Element> element; + AtomicString eventType; + String name; + double elapsedTime; + }; + + Vector<EventToDispatch> m_eventsToDispatch; + + double m_beginAnimationUpdateTime; +}; + +AnimationControllerPrivate::AnimationControllerPrivate(Frame* frame) + : m_animationTimer(this, &AnimationControllerPrivate::animationTimerFired) + , m_updateRenderingDispatcher(this, &AnimationControllerPrivate::updateRenderingDispatcherFired) + , m_frame(frame) + , m_beginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet) +{ +} + +AnimationControllerPrivate::~AnimationControllerPrivate() +{ +} + +PassRefPtr<CompositeAnimation> AnimationControllerPrivate::accessCompositeAnimation(RenderObject* renderer) +{ + RefPtr<CompositeAnimation> animation = m_compositeAnimations.get(renderer); + if (!animation) { + animation = CompositeAnimation::create(m_frame->animation()); + m_compositeAnimations.set(renderer, animation); + } + return animation; +} + +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 setChanged() when suspended). + PassRefPtr<CompositeAnimation> animation = m_compositeAnimations.take(renderer); + if (!animation) + return false; + animation->clearRenderer(); + return animation->isSuspended(); +} + +void AnimationControllerPrivate::styleAvailable() +{ + // styleAvailable() can call event handlers which would ultimately delete a CompositeAnimation + // from the m_compositeAnimations table. So we can't iterate it directly. We will instead build + // a list of CompositeAnimations which need the styleAvailable() call iterate over that. + Vector<RefPtr<CompositeAnimation> > list; + + RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end(); + for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) + if (it->second->isWaitingForStyleAvailable()) + list.append(it->second); + + Vector<RefPtr<CompositeAnimation> >::const_iterator listEnd = list.end(); + for (Vector<RefPtr<CompositeAnimation> >::const_iterator it = list.begin(); it != listEnd; ++it) + (*it)->styleAvailable(); +} + +void AnimationControllerPrivate::updateAnimationTimer(bool callSetChanged/* = false*/) +{ + double needsService = -1; + bool calledSetChanged = false; + + RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end(); + for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) { + RefPtr<CompositeAnimation> compAnim = it->second; + if (!compAnim->isSuspended()) { + double t = compAnim->willNeedService(); + if (t != -1 && (t < needsService || needsService == -1)) + needsService = t; + if (needsService == 0) { + if (callSetChanged) { + Node* node = it->first->element(); + ASSERT(!node || (node->document() && !node->document()->inPageCache())); + node->setChanged(AnimationStyleChange); + calledSetChanged = true; + } + else + break; + } + } + } + + if (calledSetChanged) + m_frame->document()->updateRendering(); + + // If we want service immediately, we start a repeating timer to reduce the overhead of starting + if (needsService == 0) { + if (!m_animationTimer.isActive() || m_animationTimer.repeatInterval() == 0) + m_animationTimer.startRepeating(cAnimationTimerDelay); + return; + } + + // If we don't need service, we want to make sure the timer is no longer running + if (needsService < 0) { + if (m_animationTimer.isActive()) + m_animationTimer.stop(); + return; + } + + // Otherwise, we want to start a one-shot timer so we get here again + if (m_animationTimer.isActive()) + m_animationTimer.stop(); + m_animationTimer.startOneShot(needsService); +} + +void AnimationControllerPrivate::updateRenderingDispatcherFired(Timer<AnimationControllerPrivate>*) +{ + // fire all the events + Vector<EventToDispatch>::const_iterator end = m_eventsToDispatch.end(); + for (Vector<EventToDispatch>::const_iterator it = m_eventsToDispatch.begin(); it != end; ++it) { + if (it->eventType == eventNames().webkitTransitionEndEvent) + it->element->dispatchWebKitTransitionEvent(it->eventType,it->name, it->elapsedTime); + else + it->element->dispatchWebKitAnimationEvent(it->eventType,it->name, it->elapsedTime); + } + + m_eventsToDispatch.clear(); + + if (m_frame && m_frame->document()) + m_frame->document()->updateRendering(); +} + +void AnimationControllerPrivate::startUpdateRenderingDispatcher() +{ + if (!m_updateRenderingDispatcher.isActive()) + m_updateRenderingDispatcher.startOneShot(0); +} + +void AnimationControllerPrivate::addEventToDispatch(PassRefPtr<Element> element, const AtomicString& eventType, const String& name, double elapsedTime) +{ + m_eventsToDispatch.grow(m_eventsToDispatch.size()+1); + EventToDispatch& event = m_eventsToDispatch[m_eventsToDispatch.size()-1]; + event.element = element; + event.eventType = eventType; + event.name = name; + event.elapsedTime = elapsedTime; + + startUpdateRenderingDispatcher(); +} + +void AnimationControllerPrivate::animationTimerFired(Timer<AnimationControllerPrivate>*) +{ + // Make sure animationUpdateTime is updated, so that it is current even if no + // styleChange has happened (e.g. hardware animations) + setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet); + + // When the timer fires, all we do is call setChanged on all DOM nodes with running animations and then do an immediate + // updateRendering. It will then call back to us with new information. + updateAnimationTimer(true); +} + +bool AnimationControllerPrivate::isAnimatingPropertyOnRenderer(RenderObject* renderer, int property, bool isRunningNow) const +{ + RefPtr<CompositeAnimation> animation = m_compositeAnimations.get(renderer); + if (!animation) + return false; + + return animation->isAnimatingProperty(property, isRunningNow); +} + +void AnimationControllerPrivate::suspendAnimations(Document* document) +{ + RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end(); + for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) { + RenderObject* renderer = it->first; + RefPtr<CompositeAnimation> compAnim = it->second; + if (renderer->document() == document) + compAnim->suspendAnimations(); + } + + updateAnimationTimer(); +} + +void AnimationControllerPrivate::resumeAnimations(Document* document) +{ + RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end(); + for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) { + RenderObject* renderer = it->first; + RefPtr<CompositeAnimation> compAnim = it->second; + if (renderer->document() == document) + compAnim->resumeAnimations(); + } + + updateAnimationTimer(); +} + +bool AnimationControllerPrivate::pauseAnimationAtTime(RenderObject* renderer, const String& name, double t) +{ + if (!renderer) + return false; + + RefPtr<CompositeAnimation> compAnim = accessCompositeAnimation(renderer); + if (!compAnim) + return false; + + if (compAnim->pauseAnimationAtTime(name, t)) { + renderer->node()->setChanged(AnimationStyleChange); + return true; + } + + return false; +} + +bool AnimationControllerPrivate::pauseTransitionAtTime(RenderObject* renderer, const String& property, double t) +{ + if (!renderer) + return false; + + RefPtr<CompositeAnimation> compAnim = accessCompositeAnimation(renderer); + if (!compAnim) + return false; + + if (compAnim->pauseTransitionAtTime(cssPropertyID(property), t)) { + renderer->node()->setChanged(AnimationStyleChange); + return true; + } + + return false; +} + +unsigned AnimationControllerPrivate::numberOfActiveAnimations() const +{ + unsigned count = 0; + + RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end(); + for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) { + CompositeAnimation* compAnim = it->second.get(); + count += compAnim->numberOfActiveAnimations(); + } + + return count; +} + +AnimationController::AnimationController(Frame* frame) + : m_data(new AnimationControllerPrivate(frame)) + , m_numStyleAvailableWaiters(0) +{ +} + +AnimationController::~AnimationController() +{ + delete m_data; +} + +void AnimationController::cancelAnimations(RenderObject* renderer) +{ + if (!m_data->hasAnimations()) + return; + + if (m_data->clear(renderer)) { + Node* node = renderer->element(); + ASSERT(!node || (node->document() && !node->document()->inPageCache())); + node->setChanged(AnimationStyleChange); + } +} + +PassRefPtr<RenderStyle> AnimationController::updateAnimations(RenderObject* renderer, RenderStyle* newStyle) +{ + // Don't do anything if we're in the cache + if (!renderer->document() || renderer->document()->inPageCache()) + return newStyle; + + RenderStyle* oldStyle = renderer->style(); + + if ((!oldStyle || (!oldStyle->animations() && !oldStyle->transitions())) && (!newStyle->animations() && !newStyle->transitions())) + return newStyle; + + // Fetch our current set of implicit animations from a hashtable. We then compare them + // 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->element()); // FIXME: We do not animate generated content yet. + + RefPtr<CompositeAnimation> rendererAnimations = m_data->accessCompositeAnimation(renderer); + RefPtr<RenderStyle> blendedStyle = rendererAnimations->animate(renderer, oldStyle, newStyle); + + m_data->updateAnimationTimer(); + + if (blendedStyle != newStyle) { + // If the animations/transitions change opacity or transform, we neeed to update + // the style to impose the stacking rules. Note that this is also + // done in CSSStyleSelector::adjustRenderStyle(). + if (blendedStyle->hasAutoZIndex() && (blendedStyle->opacity() < 1.0f || blendedStyle->hasTransform())) + blendedStyle->setZIndex(0); + } + return blendedStyle.release(); +} + +void AnimationController::setAnimationStartTime(RenderObject* renderer, double t) +{ + RefPtr<CompositeAnimation> rendererAnimations = m_data->accessCompositeAnimation(renderer); + rendererAnimations->setAnimationStartTime(t); +} + +void AnimationController::setTransitionStartTime(RenderObject* renderer, int property, double t) +{ + RefPtr<CompositeAnimation> rendererAnimations = m_data->accessCompositeAnimation(renderer); + rendererAnimations->setTransitionStartTime(property, t); +} + +bool AnimationController::pauseAnimationAtTime(RenderObject* renderer, const String& name, double t) +{ + return m_data->pauseAnimationAtTime(renderer, name, t); +} + +unsigned AnimationController::numberOfActiveAnimations() const +{ + return m_data->numberOfActiveAnimations(); +} + +bool AnimationController::pauseTransitionAtTime(RenderObject* renderer, const String& property, double t) +{ + return m_data->pauseTransitionAtTime(renderer, property, t); +} + +bool AnimationController::isAnimatingPropertyOnRenderer(RenderObject* renderer, int property, bool isRunningNow) const +{ + return m_data->isAnimatingPropertyOnRenderer(renderer, property, isRunningNow); +} + +void AnimationController::suspendAnimations(Document* document) +{ + m_data->suspendAnimations(document); +} + +void AnimationController::resumeAnimations(Document* document) +{ + m_data->resumeAnimations(document); +} + +void AnimationController::startUpdateRenderingDispatcher() +{ + m_data->startUpdateRenderingDispatcher(); +} + +void AnimationController::addEventToDispatch(PassRefPtr<Element> element, const AtomicString& eventType, const String& name, double elapsedTime) +{ + m_data->addEventToDispatch(element, eventType, name, elapsedTime); +} + +void AnimationController::styleAvailable() +{ + if (!m_numStyleAvailableWaiters) + return; + + m_data->styleAvailable(); +} + +double AnimationController::beginAnimationUpdateTime() +{ + return m_data->beginAnimationUpdateTime(); +} + +void AnimationController::beginAnimationUpdate() +{ + m_data->setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet); +} + +void AnimationController::endAnimationUpdate() +{ +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/animation/AnimationController.h b/src/3rdparty/webkit/WebCore/page/animation/AnimationController.h new file mode 100644 index 0000000..45d0c7d --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/animation/AnimationController.h @@ -0,0 +1,91 @@ +/* + * 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. + * 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. + */ + +#ifndef AnimationController_h +#define AnimationController_h + +#include <wtf/Forward.h> + +namespace WebCore { + +class AnimationControllerPrivate; +class AtomicString; +class Document; +class Element; +class Frame; +class Node; +class RenderObject; +class RenderStyle; +class String; + +class AnimationController { +public: + AnimationController(Frame*); + ~AnimationController(); + + void cancelAnimations(RenderObject*); + PassRefPtr<RenderStyle> updateAnimations(RenderObject*, RenderStyle* newStyle); + + void setAnimationStartTime(RenderObject*, double t); + void setTransitionStartTime(RenderObject*, int property, double t); + + bool pauseAnimationAtTime(RenderObject*, const String& 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() const; // To be used only for testing + + bool isAnimatingPropertyOnRenderer(RenderObject*, int property, bool isRunningNow) const; + + void suspendAnimations(Document*); + void resumeAnimations(Document*); + + void startUpdateRenderingDispatcher(); + void addEventToDispatch(PassRefPtr<Element>, const AtomicString& eventType, const String& name, double elapsedTime); + + void styleAvailable(); + + void setWaitingForStyleAvailable(bool waiting) + { + if (waiting) + m_numStyleAvailableWaiters++; + else + m_numStyleAvailableWaiters--; + } + + double beginAnimationUpdateTime(); + + void beginAnimationUpdate(); + void endAnimationUpdate(); + +private: + AnimationControllerPrivate* m_data; + unsigned m_numStyleAvailableWaiters; +}; + +} // namespace WebCore + +#endif // AnimationController_h diff --git a/src/3rdparty/webkit/WebCore/page/animation/CompositeAnimation.cpp b/src/3rdparty/webkit/WebCore/page/animation/CompositeAnimation.cpp new file mode 100644 index 0000000..57cb774 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/animation/CompositeAnimation.cpp @@ -0,0 +1,706 @@ +/* + * 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. + * 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 "CompositeAnimation.h" + +#include "AnimationController.h" +#include "CSSPropertyNames.h" +#include "ImplicitAnimation.h" +#include "KeyframeAnimation.h" +#include "RenderObject.h" +#include "RenderStyle.h" + +namespace WebCore { + +class CompositeAnimationPrivate { +public: + CompositeAnimationPrivate(AnimationController* animationController, CompositeAnimation* compositeAnimation) + : m_isSuspended(false) + , m_animationController(animationController) + , m_compositeAnimation(compositeAnimation) + , m_numStyleAvailableWaiters(0) + { + } + + ~CompositeAnimationPrivate(); + + void clearRenderer(); + + PassRefPtr<RenderStyle> animate(RenderObject*, RenderStyle* currentStyle, RenderStyle* targetStyle); + + AnimationController* animationController() { return m_animationController; } + + void setAnimating(bool); + double willNeedService() const; + + PassRefPtr<KeyframeAnimation> getAnimationForProperty(int property); + + void cleanupFinishedAnimations(RenderObject*); + + void setAnimationStartTime(double t); + void setTransitionStartTime(int property, double t); + + void suspendAnimations(); + void resumeAnimations(); + bool isSuspended() const { return m_isSuspended; } + + void overrideImplicitAnimations(int property); + void resumeOverriddenImplicitAnimations(int property); + + void styleAvailable(); + + bool isAnimatingProperty(int property, bool isRunningNow) const; + + void setWaitingForStyleAvailable(bool); + bool isWaitingForStyleAvailable() const { return m_numStyleAvailableWaiters > 0; } + + bool pauseAnimationAtTime(const AtomicString& name, double t); + bool pauseTransitionAtTime(int property, double t); + unsigned numberOfActiveAnimations() const; + +protected: + void updateTransitions(RenderObject*, RenderStyle* currentStyle, RenderStyle* targetStyle); + void updateKeyframeAnimations(RenderObject*, RenderStyle* currentStyle, RenderStyle* targetStyle); + +private: + typedef HashMap<int, RefPtr<ImplicitAnimation> > CSSPropertyTransitionsMap; + typedef HashMap<AtomicStringImpl*, RefPtr<KeyframeAnimation> > AnimationNameMap; + + CSSPropertyTransitionsMap m_transitions; + AnimationNameMap m_keyframeAnimations; + bool m_isSuspended; + AnimationController* m_animationController; + CompositeAnimation* m_compositeAnimation; + unsigned m_numStyleAvailableWaiters; +}; + +CompositeAnimationPrivate::~CompositeAnimationPrivate() +{ + // Toss the refs to all animations + m_transitions.clear(); + m_keyframeAnimations.clear(); +} + +void CompositeAnimationPrivate::clearRenderer() +{ + // Clear the renderers from all running animations, in case we are in the middle of + // an animation callback (see https://bugs.webkit.org/show_bug.cgi?id=22052) + CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end(); + for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) { + ImplicitAnimation* transition = it->second.get(); + transition->clearRenderer(); + } + + AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end(); + for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) { + KeyframeAnimation* anim = it->second.get(); + anim->clearRenderer(); + } + + +} + +void CompositeAnimationPrivate::updateTransitions(RenderObject* renderer, RenderStyle* currentStyle, RenderStyle* targetStyle) +{ + // If currentStyle is null, we don't do transitions + if (!currentStyle || !targetStyle->transitions()) + return; + + // Check to see if we need to update the active 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; + + int prop = anim->property(); + + if (prop == cAnimateNone) + continue; + + bool all = prop == cAnimateAll; + + // Handle both the 'all' and single property cases. For the single prop case, we make only one pass + // through the loop. + for (int propertyIndex = 0; propertyIndex < AnimationBase::getNumProperties(); ++propertyIndex) { + if (all) { + // Get the next property + prop = AnimationBase::getPropertyAtIndex(propertyIndex); + } + + // ImplicitAnimations are always hashed by actual properties, never cAnimateAll + ASSERT(prop > firstCSSProperty && prop < (firstCSSProperty + numCSSProperties)); + + // If there is a running animation for this property, the transition is overridden + // and we have to use the unanimatedStyle from the animation. We do the test + // against the unanimated style here, but we "override" the transition later. + RefPtr<KeyframeAnimation> keyframeAnim = getAnimationForProperty(prop); + RenderStyle* fromStyle = keyframeAnim ? keyframeAnim->unanimatedStyle() : currentStyle; + + // See if there is a current transition for this prop + ImplicitAnimation* implAnim = m_transitions.get(prop).get(); + bool equal = true; + + if (implAnim) { + // This implAnim might not be an already running transition. It might be + // newly added to the list in a previous iteration. This would happen if + // you have both an explicit transition-property and 'all' in the same + // list. In this case, the latter one overrides the earlier one, so we + // behave as though this is a running animation being replaced. + if (!isActiveTransition) + m_transitions.remove(prop); + else if (!implAnim->isTargetPropertyEqual(prop, targetStyle)) { + m_transitions.remove(prop); + equal = false; + } + } else { + // We need to start a transition if it is active and the properties don't match + equal = !isActiveTransition || AnimationBase::propertiesEqual(prop, fromStyle, targetStyle); + } + + if (!equal) { + // Add the new transition + m_transitions.set(prop, ImplicitAnimation::create(const_cast<Animation*>(anim), prop, renderer, m_compositeAnimation, fromStyle)); + } + + // We only need one pass for the single prop case + if (!all) + break; + } + } +} + +void CompositeAnimationPrivate::updateKeyframeAnimations(RenderObject* renderer, RenderStyle* currentStyle, RenderStyle* targetStyle) +{ + // Nothing to do if we don't have any animations, and didn't have any before + if (m_keyframeAnimations.isEmpty() && !targetStyle->hasAnimations()) + return; + + // Nothing to do if the current and target animations are the same + if (currentStyle && currentStyle->hasAnimations() && targetStyle->hasAnimations() && *(currentStyle->animations()) == *(targetStyle->animations())) + return; + + // Mark all existing animations as no longer active + AnimationNameMap::const_iterator kfend = m_keyframeAnimations.end(); + for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != kfend; ++it) + it->second->setIndex(-1); + + // Now mark any still active animations as active and add any new animations + if (targetStyle->animations()) { + int numAnims = targetStyle->animations()->size(); + for (int i = 0; i < numAnims; ++i) { + const Animation* anim = targetStyle->animations()->animation(i); + AtomicString animationName(anim->name()); + + if (!anim->isValidAnimation()) + continue; + + // See if there is a current animation for this name + RefPtr<KeyframeAnimation> keyframeAnim = m_keyframeAnimations.get(animationName.impl()); + + if (keyframeAnim) { + // There is one so it is still active + + // Animations match, but play states may differ. update if needed + keyframeAnim->updatePlayState(anim->playState() == AnimPlayStatePlaying); + + // Set the saved animation to this new one, just in case the play state has changed + keyframeAnim->setAnimation(anim); + keyframeAnim->setIndex(i); + } else if ((anim->duration() || anim->delay()) && anim->iterationCount()) { + keyframeAnim = KeyframeAnimation::create(const_cast<Animation*>(anim), renderer, i, m_compositeAnimation, currentStyle ? currentStyle : targetStyle); + m_keyframeAnimations.set(keyframeAnim->name().impl(), keyframeAnim); + } + } + } + + // Make a list of animations to be removed + Vector<AtomicStringImpl*> animsToBeRemoved; + kfend = m_keyframeAnimations.end(); + for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != kfend; ++it) { + KeyframeAnimation* keyframeAnim = it->second.get(); + if (keyframeAnim->index() < 0) + animsToBeRemoved.append(keyframeAnim->name().impl()); + } + + // Now remove the animations from the list + for (size_t j = 0; j < animsToBeRemoved.size(); ++j) + m_keyframeAnimations.remove(animsToBeRemoved[j]); +} + +PassRefPtr<RenderStyle> CompositeAnimationPrivate::animate(RenderObject* renderer, RenderStyle* currentStyle, RenderStyle* targetStyle) +{ + RefPtr<RenderStyle> resultStyle; + + // Update animations first so we can see if any transitions are overridden + updateKeyframeAnimations(renderer, currentStyle, targetStyle); + + // We don't do any transitions if we don't have a currentStyle (on startup) + updateTransitions(renderer, currentStyle, targetStyle); + + if (currentStyle) { + // Now that we have transition objects ready, let them know about the new goal state. We want them + // to fill in a RenderStyle*& only if needed. + CSSPropertyTransitionsMap::const_iterator end = m_transitions.end(); + for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) { + if (ImplicitAnimation* anim = it->second.get()) + anim->animate(m_compositeAnimation, renderer, currentStyle, targetStyle, resultStyle); + } + } + + // Now that we have animation objects ready, let them know about the new goal state. We want them + // to fill in a RenderStyle*& only if needed. + if (targetStyle->hasAnimations()) { + for (size_t i = 0; i < targetStyle->animations()->size(); ++i) { + const Animation* anim = targetStyle->animations()->animation(i); + + if (anim->isValidAnimation()) { + AtomicString animationName(anim->name()); + RefPtr<KeyframeAnimation> keyframeAnim = m_keyframeAnimations.get(animationName.impl()); + if (keyframeAnim) + keyframeAnim->animate(m_compositeAnimation, renderer, currentStyle, targetStyle, resultStyle); + } + } + } + + cleanupFinishedAnimations(renderer); + + return resultStyle ? resultStyle.release() : targetStyle; +} + +// "animating" means that something is running that requires the timer to keep firing +void CompositeAnimationPrivate::setAnimating(bool animating) +{ + CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end(); + for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) { + ImplicitAnimation* transition = it->second.get(); + transition->setAnimating(animating); + } + + AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end(); + for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) { + KeyframeAnimation* anim = it->second.get(); + anim->setAnimating(animating); + } +} + +double CompositeAnimationPrivate::willNeedService() const +{ + // Returns the time at which next service is required. -1 means no service is required. 0 means + // service is required now, and > 0 means service is required that many seconds in the future. + double minT = -1; + + CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end(); + for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) { + ImplicitAnimation* transition = it->second.get(); + double t = transition ? transition->willNeedService() : -1; + if (t < minT || minT == -1) + minT = t; + if (minT == 0) + return 0; + } + + AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end(); + for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) { + KeyframeAnimation* animation = it->second.get(); + double t = animation ? animation->willNeedService() : -1; + if (t < minT || minT == -1) + minT = t; + if (minT == 0) + return 0; + } + + return minT; +} + +PassRefPtr<KeyframeAnimation> CompositeAnimationPrivate::getAnimationForProperty(int property) +{ + RefPtr<KeyframeAnimation> retval; + + // We want to send back the last animation with the property if there are multiples. + // So we need to iterate through all animations + AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end(); + for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) { + RefPtr<KeyframeAnimation> anim = it->second; + if (anim->hasAnimationForProperty(property)) + retval = anim; + } + + return retval; +} + +void CompositeAnimationPrivate::cleanupFinishedAnimations(RenderObject*) +{ + if (isSuspended()) + return; + + // Make a list of transitions to be deleted + Vector<int> finishedTransitions; + CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end(); + + for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) { + ImplicitAnimation* anim = it->second.get(); + if (!anim) + continue; + if (anim->postActive()) + finishedTransitions.append(anim->animatingProperty()); + } + + // Delete them + size_t finishedTransitionCount = finishedTransitions.size(); + for (size_t i = 0; i < finishedTransitionCount; ++i) + m_transitions.remove(finishedTransitions[i]); + + // Make a list of animations to be deleted + Vector<AtomicStringImpl*> finishedAnimations; + AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end(); + + for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) { + KeyframeAnimation* anim = it->second.get(); + if (!anim) + continue; + if (anim->postActive()) + finishedAnimations.append(anim->name().impl()); + } + + // Delete them + size_t finishedAnimationCount = finishedAnimations.size(); + for (size_t i = 0; i < finishedAnimationCount; ++i) + m_keyframeAnimations.remove(finishedAnimations[i]); +} + +void CompositeAnimationPrivate::setAnimationStartTime(double t) +{ + // Set start time on all animations waiting for it + AnimationNameMap::const_iterator end = m_keyframeAnimations.end(); + for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != end; ++it) { + KeyframeAnimation* anim = it->second.get(); + if (anim && anim->waitingForStartTime()) + anim->updateStateMachine(AnimationBase::AnimationStateInputStartTimeSet, t); + } +} + +void CompositeAnimationPrivate::setTransitionStartTime(int property, double t) +{ + // Set the start time for given property transition + CSSPropertyTransitionsMap::const_iterator end = m_transitions.end(); + for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) { + ImplicitAnimation* anim = it->second.get(); + if (anim && anim->waitingForStartTime() && anim->animatingProperty() == property) + anim->updateStateMachine(AnimationBase::AnimationStateInputStartTimeSet, t); + } +} + +void CompositeAnimationPrivate::suspendAnimations() +{ + if (m_isSuspended) + return; + + m_isSuspended = true; + + AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end(); + for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) { + if (KeyframeAnimation* anim = it->second.get()) + anim->updatePlayState(false); + } + + CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end(); + for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) { + ImplicitAnimation* anim = it->second.get(); + if (anim && anim->hasStyle()) + anim->updatePlayState(false); + } +} + +void CompositeAnimationPrivate::resumeAnimations() +{ + if (!m_isSuspended) + return; + + m_isSuspended = false; + + AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end(); + for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) { + KeyframeAnimation* anim = it->second.get(); + if (anim && anim->playStatePlaying()) + anim->updatePlayState(true); + } + + CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end(); + for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) { + ImplicitAnimation* anim = it->second.get(); + if (anim && anim->hasStyle()) + anim->updatePlayState(true); + } +} + +void CompositeAnimationPrivate::overrideImplicitAnimations(int property) +{ + CSSPropertyTransitionsMap::const_iterator end = m_transitions.end(); + for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) { + ImplicitAnimation* anim = it->second.get(); + if (anim && anim->animatingProperty() == property) + anim->setOverridden(true); + } +} + +void CompositeAnimationPrivate::resumeOverriddenImplicitAnimations(int property) +{ + CSSPropertyTransitionsMap::const_iterator end = m_transitions.end(); + for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) { + ImplicitAnimation* anim = it->second.get(); + if (anim && anim->animatingProperty() == property) + anim->setOverridden(false); + } +} + +static inline bool compareAnimationIndices(RefPtr<KeyframeAnimation> a, const RefPtr<KeyframeAnimation> b) +{ + return a->index() < b->index(); +} + +void CompositeAnimationPrivate::styleAvailable() +{ + if (m_numStyleAvailableWaiters == 0) + return; + + // We have to go through animations in the order in which they appear in + // the style, because order matters for additivity. + Vector<RefPtr<KeyframeAnimation> > animations(m_keyframeAnimations.size()); + copyValuesToVector(m_keyframeAnimations, animations); + + if (animations.size() > 1) + std::stable_sort(animations.begin(), animations.end(), compareAnimationIndices); + + for (size_t i = 0; i < animations.size(); ++i) { + KeyframeAnimation* anim = animations[i].get(); + if (anim && anim->waitingForStyleAvailable()) + anim->updateStateMachine(AnimationBase::AnimationStateInputStyleAvailable, -1); + } + + CSSPropertyTransitionsMap::const_iterator end = m_transitions.end(); + for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) { + ImplicitAnimation* anim = it->second.get(); + if (anim && anim->waitingForStyleAvailable()) + anim->updateStateMachine(AnimationBase::AnimationStateInputStyleAvailable, -1); + } +} + +bool CompositeAnimationPrivate::isAnimatingProperty(int property, bool isRunningNow) const +{ + AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end(); + for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) { + KeyframeAnimation* anim = it->second.get(); + if (anim && anim->isAnimatingProperty(property, isRunningNow)) + return true; + } + + CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end(); + for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) { + ImplicitAnimation* anim = it->second.get(); + if (anim && anim->isAnimatingProperty(property, isRunningNow)) + return true; + } + return false; +} + +void CompositeAnimationPrivate::setWaitingForStyleAvailable(bool waiting) +{ + if (waiting) + m_numStyleAvailableWaiters++; + else + m_numStyleAvailableWaiters--; + m_animationController->setWaitingForStyleAvailable(waiting); +} + +bool CompositeAnimationPrivate::pauseAnimationAtTime(const AtomicString& name, double t) +{ + if (!name) + return false; + + RefPtr<KeyframeAnimation> keyframeAnim = m_keyframeAnimations.get(name.impl()); + if (!keyframeAnim || !keyframeAnim->running()) + return false; + + int count = keyframeAnim->m_animation->iterationCount(); + if ((t >= 0.0) && (!count || (t <= count * keyframeAnim->duration()))) { + keyframeAnim->pauseAtTime(t); + return true; + } + + return false; +} + +bool CompositeAnimationPrivate::pauseTransitionAtTime(int property, double t) +{ + if ((property < firstCSSProperty) || (property >= firstCSSProperty + numCSSProperties)) + return false; + + ImplicitAnimation* implAnim = m_transitions.get(property).get(); + if (!implAnim || !implAnim->running()) + return false; + + if ((t >= 0.0) && (t <= implAnim->duration())) { + implAnim->pauseAtTime(t); + return true; + } + + return false; +} + +unsigned CompositeAnimationPrivate::numberOfActiveAnimations() const +{ + unsigned count = 0; + + AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end(); + for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) { + KeyframeAnimation* anim = it->second.get(); + if (anim->running()) + ++count; + } + + CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end(); + for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) { + ImplicitAnimation* anim = it->second.get(); + if (anim->running()) + ++count; + } + + return count; +} + +CompositeAnimation::CompositeAnimation(AnimationController* animationController) + : m_data(new CompositeAnimationPrivate(animationController, this)) +{ +} + +CompositeAnimation::~CompositeAnimation() +{ + delete m_data; +} + +AnimationController* CompositeAnimation::animationController() +{ + return m_data->animationController(); +} + +void CompositeAnimation::clearRenderer() +{ + m_data->clearRenderer(); +} + +PassRefPtr<RenderStyle> CompositeAnimation::animate(RenderObject* renderer, RenderStyle* currentStyle, RenderStyle* targetStyle) +{ + return m_data->animate(renderer, currentStyle, targetStyle); +} + +double CompositeAnimation::willNeedService() const +{ + return m_data->willNeedService(); +} + +void CompositeAnimation::setWaitingForStyleAvailable(bool b) +{ + m_data->setWaitingForStyleAvailable(b); +} + +bool CompositeAnimation::isWaitingForStyleAvailable() const +{ + return m_data->isWaitingForStyleAvailable(); +} + +void CompositeAnimation::suspendAnimations() +{ + m_data->suspendAnimations(); +} + +void CompositeAnimation::resumeAnimations() +{ + m_data->resumeAnimations(); +} + +bool CompositeAnimation::isSuspended() const +{ + return m_data->isSuspended(); +} + +void CompositeAnimation::styleAvailable() +{ + m_data->styleAvailable(); +} + +void CompositeAnimation::setAnimating(bool b) +{ + m_data->setAnimating(b); +} + +bool CompositeAnimation::isAnimatingProperty(int property, bool isRunningNow) const +{ + return m_data->isAnimatingProperty(property, isRunningNow); +} + +PassRefPtr<KeyframeAnimation> CompositeAnimation::getAnimationForProperty(int property) +{ + return m_data->getAnimationForProperty(property); +} + +void CompositeAnimation::setAnimationStartTime(double t) +{ + m_data->setAnimationStartTime(t); +} + +void CompositeAnimation::setTransitionStartTime(int property, double t) +{ + m_data->setTransitionStartTime(property, t); +} + +void CompositeAnimation::overrideImplicitAnimations(int property) +{ + m_data->overrideImplicitAnimations(property); +} + +void CompositeAnimation::resumeOverriddenImplicitAnimations(int property) +{ + m_data->resumeOverriddenImplicitAnimations(property); +} + +bool CompositeAnimation::pauseAnimationAtTime(const AtomicString& name, double t) +{ + return m_data->pauseAnimationAtTime(name, t); +} + +bool CompositeAnimation::pauseTransitionAtTime(int property, double t) +{ + return m_data->pauseTransitionAtTime(property, t); +} + +unsigned CompositeAnimation::numberOfActiveAnimations() const +{ + return m_data->numberOfActiveAnimations(); +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/animation/CompositeAnimation.h b/src/3rdparty/webkit/WebCore/page/animation/CompositeAnimation.h new file mode 100644 index 0000000..d51718f --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/animation/CompositeAnimation.h @@ -0,0 +1,95 @@ +/* + * 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. + * 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. + */ + +#ifndef CompositeAnimation_h +#define CompositeAnimation_h + +#include "AtomicString.h" + +#include <wtf/HashMap.h> +#include <wtf/Noncopyable.h> + +namespace WebCore { + +class CompositeAnimationPrivate; +class AnimationController; +class KeyframeAnimation; +class RenderObject; +class RenderStyle; + +// A CompositeAnimation represents a collection of animations that are running +// on a single RenderObject, such as a number of properties transitioning at once. +class CompositeAnimation : public RefCounted<CompositeAnimation> { +public: + static PassRefPtr<CompositeAnimation> create(AnimationController* animationController) + { + return adoptRef(new CompositeAnimation(animationController)); + }; + + ~CompositeAnimation(); + + void clearRenderer(); + + PassRefPtr<RenderStyle> animate(RenderObject*, RenderStyle* currentStyle, RenderStyle* targetStyle); + double willNeedService() const; + + AnimationController* animationController(); + + void setWaitingForStyleAvailable(bool); + bool isWaitingForStyleAvailable() const; + + void suspendAnimations(); + void resumeAnimations(); + bool isSuspended() const; + + void styleAvailable(); + void setAnimating(bool); + bool isAnimatingProperty(int property, bool isRunningNow) const; + + PassRefPtr<KeyframeAnimation> getAnimationForProperty(int property); + + + void setAnimationStartTime(double t); + void setTransitionStartTime(int property, double t); + + void overrideImplicitAnimations(int property); + void resumeOverriddenImplicitAnimations(int property); + + bool pauseAnimationAtTime(const AtomicString& name, double t); + bool pauseTransitionAtTime(int property, double t); + unsigned numberOfActiveAnimations() const; + +private: + CompositeAnimation(AnimationController* animationController); + + CompositeAnimationPrivate* m_data; +}; + +} // namespace WebCore + +#endif // CompositeAnimation_h diff --git a/src/3rdparty/webkit/WebCore/page/animation/ImplicitAnimation.cpp b/src/3rdparty/webkit/WebCore/page/animation/ImplicitAnimation.cpp new file mode 100644 index 0000000..f984909 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/animation/ImplicitAnimation.cpp @@ -0,0 +1,212 @@ +/* + * 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. + * 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 "AnimationController.h" +#include "CompositeAnimation.h" +#include "CSSPropertyNames.h" +#include "EventNames.h" +#include "ImplicitAnimation.h" +#include "KeyframeAnimation.h" +#include "RenderObject.h" + +namespace WebCore { + +ImplicitAnimation::ImplicitAnimation(const Animation* transition, int animatingProperty, RenderObject* renderer, CompositeAnimation* compAnim, RenderStyle* fromStyle) + : AnimationBase(transition, renderer, compAnim) + , m_transitionProperty(transition->property()) + , m_animatingProperty(animatingProperty) + , m_overridden(false) + , m_fromStyle(fromStyle) +{ + ASSERT(animatingProperty != cAnimateAll); +} + +ImplicitAnimation::~ImplicitAnimation() +{ + // Do the cleanup here instead of in the base class so the specialized methods get called + if (!postActive()) + updateStateMachine(AnimationStateInputEndAnimation, -1); +} + +bool ImplicitAnimation::shouldSendEventForListener(Document::ListenerType inListenerType) +{ + return m_object->document()->hasListenerType(inListenerType); +} + +void ImplicitAnimation::animate(CompositeAnimation*, RenderObject*, RenderStyle*, RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle) +{ + // If we get this far and the animation is done, it means we are cleaning up a just finished animation. + // So just return. Everything is already all cleaned up. + if (postActive()) + return; + + // Reset to start the transition if we are new + if (isNew()) + reset(targetStyle); + + // Run a cycle of animation. + // We know we will need a new render style, so make one if needed + if (!animatedStyle) + animatedStyle = RenderStyle::clone(targetStyle); + + if (blendProperties(this, m_animatingProperty, animatedStyle.get(), m_fromStyle.get(), m_toStyle.get(), progress(1, 0, 0))) + setAnimating(); + + // Fire the start timeout if needed + fireAnimationEventsIfNeeded(); +} + +void ImplicitAnimation::onAnimationEnd(double elapsedTime) +{ + // If we have a keyframe animation on this property, this transition is being overridden. The keyframe + // animation keeps an unanimated style in case a transition starts while the keyframe animation is + // running. But now that the transition has completed, we need to update this style with its new + // destination. If we didn't, the next time through we would think a transition had started + // (comparing the old unanimated style with the new final style of the transition). + RefPtr<KeyframeAnimation> keyframeAnim = m_compAnim->getAnimationForProperty(m_animatingProperty); + if (keyframeAnim) + keyframeAnim->setUnanimatedStyle(m_toStyle); + + if (!sendTransitionEvent(eventNames().webkitTransitionEndEvent, elapsedTime)) { + // We didn't dispatch an event, which would call endAnimation(), so we'll just call it here. + endAnimation(true); + } +} + +bool ImplicitAnimation::sendTransitionEvent(const AtomicString& eventType, double elapsedTime) +{ + if (eventType == eventNames().webkitTransitionEndEvent) { + Document::ListenerType listenerType = Document::TRANSITIONEND_LISTENER; + + if (shouldSendEventForListener(listenerType)) { + String propertyName; + if (m_animatingProperty != cAnimateAll) + propertyName = getPropertyName(static_cast<CSSPropertyID>(m_animatingProperty)); + + // Dispatch the event + RefPtr<Element> element = 0; + if (m_object->node() && m_object->node()->isElementNode()) + element = static_cast<Element*>(m_object->node()); + + ASSERT(!element || element->document() && !element->document()->inPageCache()); + if (!element) + return false; + + // Schedule event handling + m_object->animation()->addEventToDispatch(element, eventType, propertyName, elapsedTime); + + // Restore the original (unanimated) style + if (eventType == eventNames().webkitTransitionEndEvent && element->renderer()) + setChanged(element.get()); + + return true; // Did dispatch an event + } + } + + return false; // Didn't dispatch an event +} + +void ImplicitAnimation::reset(RenderStyle* to) +{ + ASSERT(to); + ASSERT(m_fromStyle); + + + m_toStyle = to; + + // Restart the transition + if (m_fromStyle && m_toStyle) + updateStateMachine(AnimationStateInputRestartAnimation, -1); + + // set the transform animation list + validateTransformFunctionList(); +} + +void ImplicitAnimation::setOverridden(bool b) +{ + if (b == m_overridden) + return; + + m_overridden = b; + updateStateMachine(m_overridden ? AnimationStateInputPauseOverride : AnimationStateInputResumeOverride, -1); +} + +bool ImplicitAnimation::affectsProperty(int property) const +{ + return (m_animatingProperty == property); +} + +bool ImplicitAnimation::isTargetPropertyEqual(int prop, const RenderStyle* targetStyle) +{ + return propertiesEqual(prop, m_toStyle.get(), targetStyle); +} + +void ImplicitAnimation::blendPropertyValueInStyle(int prop, RenderStyle* currentStyle) +{ + blendProperties(this, prop, currentStyle, m_fromStyle.get(), m_toStyle.get(), progress(1, 0, 0)); +} + +void ImplicitAnimation::validateTransformFunctionList() +{ + m_transformFunctionListValid = false; + + if (!m_fromStyle || !m_toStyle) + return; + + const TransformOperations* val = &m_fromStyle->transform(); + const TransformOperations* toVal = &m_toStyle->transform(); + + if (val->operations().isEmpty()) + val = toVal; + + if (val->operations().isEmpty()) + return; + + // See if the keyframes are valid + if (val != toVal) { + // A list of length 0 matches anything + if (!toVal->operations().isEmpty()) { + // If the sizes of the function lists don't match, the lists don't match + if (val->operations().size() != toVal->operations().size()) + return; + + // If the types of each function are not the same, the lists don't match + for (size_t j = 0; j < val->operations().size(); ++j) { + if (!val->operations()[j]->isSameType(*toVal->operations()[j])) + return; + } + } + } + + // Keyframes are valid + m_transformFunctionListValid = true; +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/animation/ImplicitAnimation.h b/src/3rdparty/webkit/WebCore/page/animation/ImplicitAnimation.h new file mode 100644 index 0000000..cf98bba --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/animation/ImplicitAnimation.h @@ -0,0 +1,86 @@ +/* + * 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. + * 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. + */ + +#ifndef ImplicitAnimation_h +#define ImplicitAnimation_h + +#include "AnimationBase.h" +#include "Document.h" + +namespace WebCore { + +// An ImplicitAnimation tracks the state of a transition of a specific CSS property +// for a single RenderObject. +class ImplicitAnimation : public AnimationBase { +public: + static PassRefPtr<ImplicitAnimation> create(const Animation* animation, int animatingProperty, RenderObject* renderer, CompositeAnimation* compositeAnimation, RenderStyle* fromStyle) + { + return adoptRef(new ImplicitAnimation(animation, animatingProperty, renderer, compositeAnimation, fromStyle)); + }; + + int transitionProperty() const { return m_transitionProperty; } + int animatingProperty() const { return m_animatingProperty; } + + virtual void onAnimationEnd(double elapsedTime); + + virtual void animate(CompositeAnimation*, RenderObject*, RenderStyle* currentStyle, RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle); + virtual void reset(RenderStyle* to); + + void setOverridden(bool); + virtual bool overridden() const { return m_overridden; } + + virtual bool affectsProperty(int) const; + + bool hasStyle() const { return m_fromStyle && m_toStyle; } + + bool isTargetPropertyEqual(int, const RenderStyle* targetStyle); + + void blendPropertyValueInStyle(int, RenderStyle* currentStyle); + +protected: + bool shouldSendEventForListener(Document::ListenerType); + bool sendTransitionEvent(const AtomicString&, double elapsedTime); + + void validateTransformFunctionList(); + +private: + ImplicitAnimation(const Animation*, int animatingProperty, RenderObject*, CompositeAnimation*, RenderStyle* fromStyle); + virtual ~ImplicitAnimation(); + + int m_transitionProperty; // Transition property as specified in the RenderStyle. May be cAnimateAll + int m_animatingProperty; // Specific property for this ImplicitAnimation + bool m_overridden; // true when there is a keyframe animation that overrides the transitioning property + + // The two styles that we are blending. + RefPtr<RenderStyle> m_fromStyle; + RefPtr<RenderStyle> m_toStyle; +}; + +} // namespace WebCore + +#endif // ImplicitAnimation_h diff --git a/src/3rdparty/webkit/WebCore/page/animation/KeyframeAnimation.cpp b/src/3rdparty/webkit/WebCore/page/animation/KeyframeAnimation.cpp new file mode 100644 index 0000000..aae37a7 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/animation/KeyframeAnimation.cpp @@ -0,0 +1,293 @@ +/* + * 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. + * 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 "KeyframeAnimation.h" + +#include "AnimationController.h" +#include "CSSPropertyNames.h" +#include "CSSStyleSelector.h" +#include "CompositeAnimation.h" +#include "EventNames.h" +#include "RenderObject.h" +#include "SystemTime.h" + +namespace WebCore { + +KeyframeAnimation::KeyframeAnimation(const Animation* animation, RenderObject* renderer, int index, CompositeAnimation* compAnim, RenderStyle* unanimatedStyle) + : AnimationBase(animation, renderer, compAnim) + , m_keyframes(renderer, animation->name()) + , m_index(index) + , m_unanimatedStyle(unanimatedStyle) +{ + // Get the keyframe RenderStyles + if (m_object && m_object->element() && m_object->element()->isElementNode()) + m_object->document()->styleSelector()->keyframeStylesForAnimation(static_cast<Element*>(m_object->element()), unanimatedStyle, m_keyframes); + + // Update the m_transformFunctionListValid flag based on whether the function lists in the keyframes match. + validateTransformFunctionList(); +} + +KeyframeAnimation::~KeyframeAnimation() +{ + // Do the cleanup here instead of in the base class so the specialized methods get called + if (!postActive()) + updateStateMachine(AnimationStateInputEndAnimation, -1); +} + +void KeyframeAnimation::animate(CompositeAnimation*, RenderObject*, const RenderStyle*, const 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) + updateStateMachine(AnimationStateInputStartAnimation, -1); + + // If we get this far and the animation is done, it means we are cleaning up a just finished animation. + // If so, we need to send back the targetStyle. + if (postActive()) { + if (!animatedStyle) + animatedStyle = const_cast<RenderStyle*>(targetStyle); + return; + } + + // If we are waiting for the start timer, we don't want to change the style yet. + // Special case - if the delay time is 0, then we do want to set the first frame of the + // animation right away. This avoids a flash when the animation starts. + if (waitingToStart() && m_animation->delay() > 0) + return; + + // FIXME: we need to be more efficient about determining which keyframes we are animating between. + // We should cache the last pair or something. + + // Find the first key + double elapsedTime = (m_startTime > 0 || m_pauseTime > 0) ? ((!paused() ? beginAnimationUpdateTime() : m_pauseTime) - m_startTime) : 0; + if (elapsedTime < 0) + elapsedTime = 0; + + double t = m_animation->duration() ? (elapsedTime / m_animation->duration()) : 1; + int i = static_cast<int>(t); + t -= i; + if (m_animation->direction() && (i & 1)) + t = 1 - t; + + const RenderStyle* fromStyle = 0; + const RenderStyle* toStyle = 0; + double scale = 1; + double offset = 0; + Vector<KeyframeValue>::const_iterator endKeyframes = m_keyframes.endKeyframes(); + for (Vector<KeyframeValue>::const_iterator it = m_keyframes.beginKeyframes(); it != endKeyframes; ++it) { + if (t < it->key()) { + // The first key should always be 0, so we should never succeed on the first key + if (!fromStyle) + break; + scale = 1.0 / (it->key() - offset); + toStyle = it->style(); + break; + } + + offset = it->key(); + fromStyle = it->style(); + } + + // If either style is 0 we have an invalid case, just stop the animation. + if (!fromStyle || !toStyle) { + updateStateMachine(AnimationStateInputEndAnimation, -1); + return; + } + + // Run a cycle of animation. + // We know we will need a new render style, so make one if needed. + if (!animatedStyle) + animatedStyle = RenderStyle::clone(targetStyle); + + const TimingFunction* timingFunction = 0; + if (fromStyle->animations() && fromStyle->animations()->size() > 0) + timingFunction = &(fromStyle->animations()->animation(0)->timingFunction()); + + double prog = progress(scale, offset, timingFunction); + + HashSet<int>::const_iterator endProperties = m_keyframes.endProperties(); + for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) { + if (blendProperties(this, *it, animatedStyle.get(), fromStyle, toStyle, prog)) + setAnimating(); + } +} + +bool KeyframeAnimation::hasAnimationForProperty(int property) const +{ + HashSet<int>::const_iterator end = m_keyframes.endProperties(); + for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it) { + if (*it == property) + return true; + } + + return false; +} + +void KeyframeAnimation::endAnimation(bool) +{ + // Restore the original (unanimated) style + if (m_object) + setChanged(m_object->element()); +} + +bool KeyframeAnimation::shouldSendEventForListener(Document::ListenerType listenerType) +{ + return m_object->document()->hasListenerType(listenerType); +} + +void KeyframeAnimation::onAnimationStart(double elapsedTime) +{ + sendAnimationEvent(eventNames().webkitAnimationStartEvent, elapsedTime); +} + +void KeyframeAnimation::onAnimationIteration(double elapsedTime) +{ + sendAnimationEvent(eventNames().webkitAnimationIterationEvent, elapsedTime); +} + +void KeyframeAnimation::onAnimationEnd(double elapsedTime) +{ + if (!sendAnimationEvent(eventNames().webkitAnimationEndEvent, elapsedTime)) { + // We didn't dispatch an event, which would call endAnimation(), so we'll just call it here. + endAnimation(true); + } +} + +bool KeyframeAnimation::sendAnimationEvent(const AtomicString& eventType, double elapsedTime) +{ + Document::ListenerType listenerType; + if (eventType == eventNames().webkitAnimationIterationEvent) + listenerType = Document::ANIMATIONITERATION_LISTENER; + else if (eventType == eventNames().webkitAnimationEndEvent) + listenerType = Document::ANIMATIONEND_LISTENER; + else { + ASSERT(eventType == eventNames().webkitAnimationStartEvent); + listenerType = Document::ANIMATIONSTART_LISTENER; + } + + if (shouldSendEventForListener(listenerType)) { + // Dispatch the event + RefPtr<Element> element; + if (m_object->node() && m_object->node()->isElementNode()) + element = static_cast<Element*>(m_object->node()); + + ASSERT(!element || element->document() && !element->document()->inPageCache()); + if (!element) + return false; + + // Schedule event handling + m_object->animation()->addEventToDispatch(element, eventType, m_keyframes.animationName(), elapsedTime); + + // Restore the original (unanimated) style + if (eventType == eventNames().webkitAnimationEndEvent && element->renderer()) + setChanged(element.get()); + + return true; // Did dispatch an event + } + + return false; // Did not dispatch an event +} + +void KeyframeAnimation::overrideAnimations() +{ + // This will override implicit animations that match the properties in the keyframe animation + HashSet<int>::const_iterator end = m_keyframes.endProperties(); + for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it) + compositeAnimation()->overrideImplicitAnimations(*it); +} + +void KeyframeAnimation::resumeOverriddenAnimations() +{ + // This will resume overridden implicit animations + HashSet<int>::const_iterator end = m_keyframes.endProperties(); + for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it) + compositeAnimation()->resumeOverriddenImplicitAnimations(*it); +} + +bool KeyframeAnimation::affectsProperty(int property) const +{ + HashSet<int>::const_iterator end = m_keyframes.endProperties(); + for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it) { + if (*it == property) + return true; + } + return false; +} + +void KeyframeAnimation::validateTransformFunctionList() +{ + m_transformFunctionListValid = false; + + if (m_keyframes.size() < 2 || !m_keyframes.containsProperty(CSSPropertyWebkitTransform)) + return; + + Vector<KeyframeValue>::const_iterator end = m_keyframes.endKeyframes(); + + // Empty transforms match anything, so find the first non-empty entry as the reference + size_t firstIndex = 0; + Vector<KeyframeValue>::const_iterator firstIt = end; + + for (Vector<KeyframeValue>::const_iterator it = m_keyframes.beginKeyframes(); it != end; ++it, ++firstIndex) { + if (it->style()->transform().operations().size() > 0) { + firstIt = it; + break; + } + } + + if (firstIt == end) + return; + + const TransformOperations* firstVal = &firstIt->style()->transform(); + + // See if the keyframes are valid + for (Vector<KeyframeValue>::const_iterator it = firstIt+1; it != end; ++it) { + const TransformOperations* val = &it->style()->transform(); + + // A null transform matches anything + if (val->operations().isEmpty()) + continue; + + // If the sizes of the function lists don't match, the lists don't match + if (firstVal->operations().size() != val->operations().size()) + return; + + // If the types of each function are not the same, the lists don't match + for (size_t j = 0; j < firstVal->operations().size(); ++j) { + if (!firstVal->operations()[j]->isSameType(*val->operations()[j])) + return; + } + } + + // Keyframes are valid + m_transformFunctionListValid = true; +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/animation/KeyframeAnimation.h b/src/3rdparty/webkit/WebCore/page/animation/KeyframeAnimation.h new file mode 100644 index 0000000..5c3176c --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/animation/KeyframeAnimation.h @@ -0,0 +1,91 @@ +/* + * 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. + * 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. + */ + +#ifndef KeyframeAnimation_h +#define KeyframeAnimation_h + +#include "AnimationBase.h" +#include "Document.h" +#include "KeyframeList.h" +#include "RenderStyle.h" + +namespace WebCore { + +// A KeyframeAnimation tracks the state of an explicit animation +// for a single RenderObject. +class KeyframeAnimation : public AnimationBase { +public: + static PassRefPtr<KeyframeAnimation> create(const Animation* animation, RenderObject* renderer, int index, CompositeAnimation* compositeAnimation, RenderStyle* unanimatedStyle) + { + return adoptRef(new KeyframeAnimation(animation, renderer, index, compositeAnimation, unanimatedStyle)); + }; + + virtual void animate(CompositeAnimation*, RenderObject*, const RenderStyle* currentStyle, const RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle); + + const AtomicString& name() const { return m_keyframes.animationName(); } + int index() const { return m_index; } + void setIndex(int i) { m_index = i; } + + bool hasAnimationForProperty(int property) const; + + void setUnanimatedStyle(PassRefPtr<RenderStyle> style) { m_unanimatedStyle = style; } + RenderStyle* unanimatedStyle() const { return m_unanimatedStyle.get(); } + +protected: + virtual void onAnimationStart(double elapsedTime); + virtual void onAnimationIteration(double elapsedTime); + virtual void onAnimationEnd(double elapsedTime); + virtual void endAnimation(bool reset); + + virtual void overrideAnimations(); + virtual void resumeOverriddenAnimations(); + + bool shouldSendEventForListener(Document::ListenerType inListenerType); + bool sendAnimationEvent(const AtomicString&, double elapsedTime); + + virtual bool affectsProperty(int) const; + + void validateTransformFunctionList(); + +private: + KeyframeAnimation(const Animation* animation, RenderObject*, int index, CompositeAnimation*, RenderStyle* unanimatedStyle); + virtual ~KeyframeAnimation(); + + // The keyframes that we are blending. + KeyframeList m_keyframes; + + // The order in which this animation appears in the animation-name style. + int m_index; + + // The style just before we started animation + RefPtr<RenderStyle> m_unanimatedStyle; +}; + +} // namespace WebCore + +#endif // KeyframeAnimation_h diff --git a/src/3rdparty/webkit/WebCore/page/chromium/AccessibilityObjectChromium.cpp b/src/3rdparty/webkit/WebCore/page/chromium/AccessibilityObjectChromium.cpp new file mode 100644 index 0000000..e309ac8 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/chromium/AccessibilityObjectChromium.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2008 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" +#include "AccessibilityObject.h" + +namespace WebCore { + +bool AccessibilityObject::accessibilityIgnoreAttachment() const +{ + return false; +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/chromium/AccessibilityObjectWrapper.h b/src/3rdparty/webkit/WebCore/page/chromium/AccessibilityObjectWrapper.h new file mode 100644 index 0000000..0846d20 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/chromium/AccessibilityObjectWrapper.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2008 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 AccessibilityObjectWrapper_h +#define AccessibilityObjectWrapper_h + +namespace WebCore { + + class AccessibilityObject; + + class AccessibilityObjectWrapper : public RefCounted<AccessibilityObjectWrapper> { + public: + virtual ~AccessibilityObjectWrapper() {} + virtual void detach() = 0; + bool attached() const { return m_object; } + AccessibilityObject* accessibilityObject() const { return m_object; } + + protected: + AccessibilityObjectWrapper(AccessibilityObject* obj) + : RefCounted<AccessibilityObjectWrapper>(0), m_object(obj) { } + AccessibilityObjectWrapper() : m_object(0) { } + + AccessibilityObject* m_object; + }; + +} // namespace WebCore + +#endif // AccessibilityObjectWrapper_h diff --git a/src/3rdparty/webkit/WebCore/page/qt/AccessibilityObjectQt.cpp b/src/3rdparty/webkit/WebCore/page/qt/AccessibilityObjectQt.cpp new file mode 100644 index 0000000..1710027 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/qt/AccessibilityObjectQt.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2008 Apple Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "AccessibilityObject.h" + +#if HAVE(ACCESSIBILITY) + +namespace WebCore { + +bool AccessibilityObject::accessibilityIgnoreAttachment() const +{ + return false; +} + +} // namespace WebCore + +#endif // HAVE(ACCESSIBILITY) diff --git a/src/3rdparty/webkit/WebCore/page/qt/DragControllerQt.cpp b/src/3rdparty/webkit/WebCore/page/qt/DragControllerQt.cpp new file mode 100644 index 0000000..1fe56b4 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/qt/DragControllerQt.cpp @@ -0,0 +1,72 @@ +/* + * 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 "Page.h" + +namespace WebCore +{ + +// FIXME: These values are straight out of DragControllerMac, so probably have +// little correlation with Qt 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() +{ + return false; +} + +DragOperation DragController::dragOperation(DragData* dragData) +{ + //FIXME: This logic is incomplete + if (dragData->containsURL()) + return DragOperationCopy; + + return DragOperationNone; +} + +const IntSize& DragController::maxDragImageSize() +{ + static const IntSize maxDragImageSize(400, 400); + + return maxDragImageSize; +} + +void DragController::cleanupAfterSystemDrag() +{ +} + +} diff --git a/src/3rdparty/webkit/WebCore/page/qt/EventHandlerQt.cpp b/src/3rdparty/webkit/WebCore/page/qt/EventHandlerQt.cpp new file mode 100644 index 0000000..3425289 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/qt/EventHandlerQt.cpp @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2006 Zack Rusin <zack@kde.org> + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * 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. + */ + +#include "config.h" +#include "EventHandler.h" + +#include "ClipboardQt.h" +#include "Cursor.h" +#include "Document.h" +#include "EventNames.h" +#include "FloatPoint.h" +#include "FocusController.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameTree.h" +#include "FrameView.h" +#include "HTMLFrameSetElement.h" +#include "HitTestRequest.h" +#include "HitTestResult.h" +#include "KeyboardEvent.h" +#include "MouseEventWithHitTestResults.h" +#include "Page.h" +#include "PlatformKeyboardEvent.h" +#include "PlatformWheelEvent.h" +#include "RenderWidget.h" +#include "Scrollbar.h" +#include "NotImplemented.h" + +QT_BEGIN_NAMESPACE +extern Q_GUI_EXPORT bool qt_tab_all_widgets; // from qapplication.cpp +QT_END_NAMESPACE + +namespace WebCore { + +const double EventHandler::TextDragDelay = 0.0; + +static bool isKeyboardOptionTab(KeyboardEvent* event) +{ + return event + && (event->type() == eventNames().keydownEvent || event->type() == eventNames().keypressEvent) + && event->altKey() + && event->keyIdentifier() == "U+0009"; +} + +bool EventHandler::invertSenseOfTabsToLinks(KeyboardEvent* event) const +{ + return isKeyboardOptionTab(event); +} + +bool EventHandler::tabsToAllControls(KeyboardEvent* event) const +{ + return (isKeyboardOptionTab(event) ? !qt_tab_all_widgets : qt_tab_all_widgets); +} + +void EventHandler::focusDocumentView() +{ + Page* page = m_frame->page(); + if (!page) + return; + page->focusController()->setFocusedFrame(m_frame); +} + +bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults&) +{ + notImplemented(); + return false; +} + +bool EventHandler::eventActivatedView(const PlatformMouseEvent&) const +{ + //Qt has an activation event which is sent independently + // of mouse event so this thing will be a snafu to implement + // correctly + return false; +} + +bool EventHandler::passWheelEventToWidget(PlatformWheelEvent& event, Widget* widget) +{ + Q_ASSERT(widget); + if (!widget->isFrameView()) + return false; + + return static_cast<FrameView*>(widget)->frame()->eventHandler()->handleWheelEvent(event); +} + +PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const +{ + return ClipboardQt::create(ClipboardWritable, true); +} + +bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe) +{ + subframe->eventHandler()->handleMousePressEvent(mev.event()); + return true; +} + +bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe, HitTestResult* hoveredNode) +{ + subframe->eventHandler()->handleMouseMoveEvent(mev.event(), hoveredNode); + return true; +} + +bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe) +{ + subframe->eventHandler()->handleMouseReleaseEvent(mev.event()); + return true; +} + +unsigned EventHandler::accessKeyModifiers() +{ + return PlatformKeyboardEvent::CtrlKey; +} + +} diff --git a/src/3rdparty/webkit/WebCore/page/qt/FrameQt.cpp b/src/3rdparty/webkit/WebCore/page/qt/FrameQt.cpp new file mode 100644 index 0000000..1bbbff5 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/qt/FrameQt.cpp @@ -0,0 +1,53 @@ +/* + * 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 "Frame.h" +#include "FramePrivate.h" +#include "UserStyleSheetLoader.h" + +namespace WebCore { + +DragImageRef Frame::dragImageForSelection() +{ + return 0; +} + +void Frame::setUserStyleSheetLocation(const KURL& url) +{ + delete d->m_userStyleSheetLoader; + d->m_userStyleSheetLoader = 0; + if (d->m_doc && d->m_doc->docLoader()) + d->m_userStyleSheetLoader = new UserStyleSheetLoader(d->m_doc, url.string()); +} + +void Frame::setUserStyleSheet(const String& styleSheet) +{ + delete d->m_userStyleSheetLoader; + d->m_userStyleSheetLoader = 0; + if (d->m_doc) + d->m_doc->setUserStyleSheet(styleSheet); +} + +} +// vim: ts=4 sw=4 et diff --git a/src/3rdparty/webkit/WebCore/page/win/AXObjectCacheWin.cpp b/src/3rdparty/webkit/WebCore/page/win/AXObjectCacheWin.cpp new file mode 100644 index 0000000..da30ac5 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/win/AXObjectCacheWin.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2008 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" +#include "AXObjectCache.h" + +#include "AccessibilityObject.h" + +namespace WebCore { + +void AXObjectCache::detachWrapper(AccessibilityObject* obj) +{ + // On Windows, AccessibilityObjects are created when get_accChildCount is + // called, but they are not wrapped until get_accChild is called, so this + // object may not have a wrapper. + if (AccessibilityObjectWrapper* wrapper = obj->wrapper()) + wrapper->detach(); +} + +void AXObjectCache::attachWrapper(AccessibilityObject*) +{ + // On Windows, AccessibilityObjects are wrapped when the accessibility + // software requests them via get_accChild. +} + +void AXObjectCache::postNotification(RenderObject*, const String&) +{ +} + +void AXObjectCache::postNotificationToElement(RenderObject*, const String&) +{ +} + +void AXObjectCache::handleFocusedUIElementChanged() +{ +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/win/AccessibilityObjectWin.cpp b/src/3rdparty/webkit/WebCore/page/win/AccessibilityObjectWin.cpp new file mode 100644 index 0000000..0a386c7 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/win/AccessibilityObjectWin.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2008 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" +#include "AccessibilityObject.h" + +#if HAVE(ACCESSIBILITY) + +namespace WebCore { + +bool AccessibilityObject::accessibilityIgnoreAttachment() const +{ + return false; +} + +} // namespace WebCore + +#endif // HAVE(ACCESSIBILITY) diff --git a/src/3rdparty/webkit/WebCore/page/win/AccessibilityObjectWrapperWin.h b/src/3rdparty/webkit/WebCore/page/win/AccessibilityObjectWrapperWin.h new file mode 100644 index 0000000..779443c --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/win/AccessibilityObjectWrapperWin.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2008 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 AccessibilityObjectWrapperWin_h +#define AccessibilityObjectWrapperWin_h + +namespace WebCore { + + class AccessibilityObject; + + class AccessibilityObjectWrapper : public IUnknown { + public: + // IUnknown + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) = 0; + virtual ULONG STDMETHODCALLTYPE AddRef(void) = 0; + virtual ULONG STDMETHODCALLTYPE Release(void) = 0; + + virtual void detach() = 0; + bool attached() const { return m_object; } + AccessibilityObject* accessibilityObject() const { return m_object; } + + protected: + AccessibilityObjectWrapper(AccessibilityObject* obj) : m_object(obj) { } + AccessibilityObjectWrapper() : m_object(0) { } + + AccessibilityObject* m_object; + }; + +} // namespace WebCore + +#endif // AccessibilityObjectWrapperWin_h diff --git a/src/3rdparty/webkit/WebCore/page/win/DragControllerWin.cpp b/src/3rdparty/webkit/WebCore/page/win/DragControllerWin.cpp new file mode 100644 index 0000000..dca8ea2 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/win/DragControllerWin.cpp @@ -0,0 +1,68 @@ +/* + * 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 "windows.h" +#include "SelectionController.h" +#include <wtf/RefPtr.h> + +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() && !m_didInitiateDrag ? DragOperationCopy : DragOperationNone; +} + +bool DragController::isCopyKeyDown() { + return ::GetAsyncKeyState(VK_CONTROL); +} + +const IntSize& DragController::maxDragImageSize() +{ + static const IntSize maxDragImageSize(200, 200); + + return maxDragImageSize; +} + +void DragController::cleanupAfterSystemDrag() +{ +} + +} diff --git a/src/3rdparty/webkit/WebCore/page/win/EventHandlerWin.cpp b/src/3rdparty/webkit/WebCore/page/win/EventHandlerWin.cpp new file mode 100644 index 0000000..88bc373 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/win/EventHandlerWin.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2006, 2007, 2008 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 "EventHandler.h" + +#include "ClipboardWin.h" +#include "Cursor.h" +#include "FloatPoint.h" +#include "FocusController.h" +#include "FrameView.h" +#include "Frame.h" +#include "HitTestRequest.h" +#include "HitTestResult.h" +#include "MouseEventWithHitTestResults.h" +#include "Page.h" +#include "PlatformKeyboardEvent.h" +#include "PlatformWheelEvent.h" +#include "Scrollbar.h" +#include "SelectionController.h" +#include "WCDataObject.h" +#include "NotImplemented.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, 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(PlatformWheelEvent& wheelEvent, Widget* widget) +{ + if (!widget->isFrameView()) + return false; + + return static_cast<FrameView*>(widget)->frame()->eventHandler()->handleWheelEvent(wheelEvent); +} + +bool EventHandler::tabsToAllControls(KeyboardEvent*) const +{ + return true; +} + +bool EventHandler::eventActivatedView(const PlatformMouseEvent& event) const +{ + return event.activatedWebView(); +} + +PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const +{ + COMPtr<WCDataObject> dataObject; + WCDataObject::createInstance(&dataObject); + return ClipboardWin::create(true, dataObject.get(), ClipboardWritable); +} + +void EventHandler::focusDocumentView() +{ + Page* page = m_frame->page(); + if (!page) + return; + page->focusController()->setFocusedFrame(m_frame); +} + +bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults&) +{ + notImplemented(); + return false; +} + +unsigned EventHandler::accessKeyModifiers() +{ + return PlatformKeyboardEvent::AltKey; +} + +} diff --git a/src/3rdparty/webkit/WebCore/page/win/FrameCGWin.cpp b/src/3rdparty/webkit/WebCore/page/win/FrameCGWin.cpp new file mode 100644 index 0000000..da2d8b2 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/win/FrameCGWin.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2006, 2007, 2008 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 "FrameWin.h" + +#include <windows.h> + +#include "FramePrivate.h" +#include "FrameView.h" +#include "GraphicsContext.h" +#include "Settings.h" + +#include <CoreGraphics/CoreGraphics.h> + +using std::min; + +namespace WebCore { + +static void drawRectIntoContext(IntRect rect, FrameView* view, GraphicsContext* gc) +{ + IntSize offset = view->scrollOffset(); + rect.move(-offset.width(), -offset.height()); + rect = view->convertToContainingWindow(rect); + + gc->concatCTM(TransformationMatrix().translate(-rect.x(), -rect.y())); + + view->paint(gc, rect); +} + +static HBITMAP imageFromRect(const Frame* frame, IntRect& ir) +{ + void* bits; + HDC hdc = CreateCompatibleDC(0); + int w = ir.width(); + int h = ir.height(); + BITMAPINFO bmp = { { sizeof(BITMAPINFOHEADER), w, h, 1, 32 } }; + + HBITMAP hbmp = CreateDIBSection(0, &bmp, DIB_RGB_COLORS, static_cast<void**>(&bits), 0, 0); + HBITMAP hbmpOld = static_cast<HBITMAP>(SelectObject(hdc, hbmp)); + CGColorSpaceRef deviceRGB = CGColorSpaceCreateDeviceRGB(); + CGContextRef context = CGBitmapContextCreate(static_cast<void*>(bits), w, h, + 8, w * sizeof(RGBQUAD), deviceRGB, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst); + CGColorSpaceRelease(deviceRGB); + CGContextSaveGState(context); + + GraphicsContext gc(context); + + drawRectIntoContext(ir, frame->view(), &gc); + + CGContextRelease(context); + SelectObject(hdc, hbmpOld); + DeleteDC(hdc); + + return hbmp; +} + +HBITMAP imageFromSelection(Frame* frame, bool forceBlackText) +{ + frame->document()->updateLayout(); + + frame->view()->setPaintRestriction(forceBlackText ? PaintRestrictionSelectionOnlyBlackText : PaintRestrictionSelectionOnly); + FloatRect fr = frame->selectionBounds(); + IntRect ir(static_cast<int>(fr.x()), static_cast<int>(fr.y()), + static_cast<int>(fr.width()), static_cast<int>(fr.height())); + HBITMAP image = imageFromRect(frame, ir); + frame->view()->setPaintRestriction(PaintRestrictionNone); + return image; +} + +HBITMAP Frame::nodeImage(Node* node) const +{ + RenderObject* renderer = node->renderer(); + if (!renderer) + return 0; + + IntRect topLevelRect; + IntRect paintingRect = renderer->paintingRootRect(topLevelRect); + + document()->updateLayout(); + + d->m_view->setNodeToDraw(node); // invoke special sub-tree drawing mode + HBITMAP result = imageFromRect(this, paintingRect); + d->m_view->setNodeToDraw(0); + + return result; +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/win/FrameCairoWin.cpp b/src/3rdparty/webkit/WebCore/page/win/FrameCairoWin.cpp new file mode 100644 index 0000000..f5b832e --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/win/FrameCairoWin.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2008 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 "FrameWin.h" + +#include "EditorClient.h" +#include "NotImplemented.h" + +using std::min; + +namespace WebCore { + +HBITMAP imageFromSelection(Frame* frame, bool forceBlackText) +{ + notImplemented(); + return 0; +} + +HBITMAP Frame::nodeImage(Node*) const +{ + notImplemented(); + return 0; +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/win/FrameWin.cpp b/src/3rdparty/webkit/WebCore/page/win/FrameWin.cpp new file mode 100644 index 0000000..895d129 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/win/FrameWin.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2006, 2007, 2008 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 "runtime.h" +#include "FrameWin.h" + +#include "TransformationMatrix.h" +#include "FloatRect.h" +#include "Document.h" +#include "FramePrivate.h" +#include "RenderView.h" +#include "Settings.h" + +using std::min; + +namespace WebCore { + +void computePageRectsForFrame(Frame* frame, const IntRect& printRect, float headerHeight, float footerHeight, float userScaleFactor, Vector<IntRect>& pages, int& outPageHeight) +{ + ASSERT(frame); + + pages.clear(); + outPageHeight = 0; + + if (!frame->document() || !frame->view() || !frame->document()->renderer()) + return; + + RenderView* root = static_cast<RenderView*>(frame->document()->renderer()); + + if (!root) { + LOG_ERROR("document to be printed has no renderer"); + return; + } + + if (userScaleFactor <= 0) { + LOG_ERROR("userScaleFactor has bad value %.2f", userScaleFactor); + return; + } + + float ratio = static_cast<float>(printRect.height()) / static_cast<float>(printRect.width()); + + float pageWidth = static_cast<float>(root->docWidth()); + float pageHeight = pageWidth * ratio; + outPageHeight = static_cast<int>(pageHeight); // this is the height of the page adjusted by margins + pageHeight -= (headerHeight + footerHeight); + + if (pageHeight <= 0) { + LOG_ERROR("pageHeight has bad value %.2f", pageHeight); + return; + } + + float currPageHeight = pageHeight / userScaleFactor; + float docHeight = root->layer()->height(); + float docWidth = root->layer()->width(); + float currPageWidth = pageWidth / userScaleFactor; + + + // always return at least one page, since empty files should print a blank page + float printedPagesHeight = 0.0f; + do { + float proposedBottom = min(docHeight, printedPagesHeight + pageHeight); + frame->adjustPageHeight(&proposedBottom, printedPagesHeight, proposedBottom, printedPagesHeight); + currPageHeight = max(1.0f, proposedBottom - printedPagesHeight); + + pages.append(IntRect(0, printedPagesHeight, currPageWidth, currPageHeight)); + printedPagesHeight += currPageHeight; + } while (printedPagesHeight < docHeight); +} + +DragImageRef Frame::dragImageForSelection() +{ + if (selection()->isRange()) + return imageFromSelection(this, false); + + return 0; +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/page/win/FrameWin.h b/src/3rdparty/webkit/WebCore/page/win/FrameWin.h new file mode 100644 index 0000000..405c7b2 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/win/FrameWin.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2006, 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. + */ + +#ifndef FrameWin_H +#define FrameWin_H + +#include "Frame.h" + +// Forward declared so we don't need wingdi.h. +typedef struct HBITMAP__* HBITMAP; + +namespace WebCore { + + HBITMAP imageFromSelection(Frame* frame, bool forceWhiteText); + void computePageRectsForFrame(Frame*, const IntRect& printRect, float headerHeight, float footerHeight, float userScaleFactor,Vector<IntRect>& pages, int& pageHeight); + +} + +#endif diff --git a/src/3rdparty/webkit/WebCore/page/win/PageWin.cpp b/src/3rdparty/webkit/WebCore/page/win/PageWin.cpp new file mode 100644 index 0000000..f4c744a --- /dev/null +++ b/src/3rdparty/webkit/WebCore/page/win/PageWin.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2006, 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 "Page.h" + +#include "Frame.h" +#include "FrameView.h" +#include "FloatRect.h" +#include <windows.h> + +namespace WebCore { + +HINSTANCE Page::s_instanceHandle = 0; + +} // namespace WebCore |