diff options
Diffstat (limited to 'WebCore/page')
84 files changed, 2564 insertions, 1286 deletions
diff --git a/WebCore/page/AXObjectCache.cpp b/WebCore/page/AXObjectCache.cpp index d9c4c9a..f8167a5 100644 --- a/WebCore/page/AXObjectCache.cpp +++ b/WebCore/page/AXObjectCache.cpp @@ -58,6 +58,7 @@ AXObjectCache::~AXObjectCache() AccessibilityObject* obj = (*it).second.get(); detachWrapper(obj); obj->detach(); + removeAXID(obj); } } @@ -66,39 +67,52 @@ AccessibilityObject* AXObjectCache::get(RenderObject* renderer) if (!renderer) return 0; - RefPtr<AccessibilityObject> obj = 0; + AccessibilityObject* obj = 0; AXID axID = m_renderObjectMapping.get(renderer); ASSERT(!HashTraits<AXID>::isDeletedValue(axID)); if (axID) obj = m_objects.get(axID).get(); + + return obj; +} + +AccessibilityObject* AXObjectCache::getOrCreate(RenderObject* renderer) +{ + if (!renderer) + return 0; + + AccessibilityObject* obj = get(renderer); - Node* element = renderer->element(); if (!obj) { + Node* node = renderer->node(); + RefPtr<AccessibilityObject> newObj = 0; if (renderer->isListBox()) - obj = AccessibilityListBox::create(renderer); - else if (element && (element->hasTagName(ulTag) || element->hasTagName(olTag) || element->hasTagName(dlTag))) - obj = AccessibilityList::create(renderer); + newObj = AccessibilityListBox::create(renderer); + else if (node && (node->hasTagName(ulTag) || node->hasTagName(olTag) || node->hasTagName(dlTag))) + newObj = AccessibilityList::create(renderer); else if (renderer->isTable()) - obj = AccessibilityTable::create(renderer); + newObj = AccessibilityTable::create(renderer); else if (renderer->isTableRow()) - obj = AccessibilityTableRow::create(renderer); + newObj = AccessibilityTableRow::create(renderer); else if (renderer->isTableCell()) - obj = AccessibilityTableCell::create(renderer); + newObj = AccessibilityTableCell::create(renderer); else - obj = AccessibilityRenderObject::create(renderer); + newObj = AccessibilityRenderObject::create(renderer); - getAXID(obj.get()); + obj = newObj.get(); + + getAXID(obj); - m_renderObjectMapping.set(renderer, obj.get()->axObjectID()); - m_objects.set(obj.get()->axObjectID(), obj); - attachWrapper(obj.get()); + m_renderObjectMapping.set(renderer, obj->axObjectID()); + m_objects.set(obj->axObjectID(), obj); + attachWrapper(obj); } - return obj.get(); + return obj; } -AccessibilityObject* AXObjectCache::get(AccessibilityRole role) +AccessibilityObject* AXObjectCache::getOrCreate(AccessibilityRole role) { RefPtr<AccessibilityObject> obj = 0; @@ -186,6 +200,9 @@ AXID AXObjectCache::getAXID(AccessibilityObject* obj) void AXObjectCache::removeAXID(AccessibilityObject* obj) { + if (!obj) + return; + AXID objID = obj->axObjectID(); if (objID == 0) return; @@ -221,7 +238,7 @@ void AXObjectCache::handleActiveDescendantChanged(RenderObject* renderer) { if (!renderer) return; - AccessibilityObject* obj = get(renderer); + AccessibilityObject* obj = getOrCreate(renderer); if (obj) obj->handleActiveDescendantChanged(); } @@ -230,7 +247,7 @@ void AXObjectCache::handleAriaRoleChanged(RenderObject* renderer) { if (!renderer) return; - AccessibilityObject* obj = get(renderer); + AccessibilityObject* obj = getOrCreate(renderer); if (obj && obj->isAccessibilityRenderObject()) static_cast<AccessibilityRenderObject*>(obj)->setAriaRole(); } diff --git a/WebCore/page/AXObjectCache.h b/WebCore/page/AXObjectCache.h index 5e95f74..4fd6dc3 100644 --- a/WebCore/page/AXObjectCache.h +++ b/WebCore/page/AXObjectCache.h @@ -60,10 +60,13 @@ namespace WebCore { ~AXObjectCache(); // to be used with render objects - AccessibilityObject* get(RenderObject*); + AccessibilityObject* getOrCreate(RenderObject*); // used for objects without backing elements - AccessibilityObject* get(AccessibilityRole); + AccessibilityObject* getOrCreate(AccessibilityRole); + + // will only return the AccessibilityObject if it already exists + AccessibilityObject* get(RenderObject*); void remove(RenderObject*); void remove(AXID); diff --git a/WebCore/page/AccessibilityImageMapLink.cpp b/WebCore/page/AccessibilityImageMapLink.cpp index 5557446..86ca623 100644 --- a/WebCore/page/AccessibilityImageMapLink.cpp +++ b/WebCore/page/AccessibilityImageMapLink.cpp @@ -65,7 +65,7 @@ AccessibilityObject* AccessibilityImageMapLink::parentObject() const if (!m_mapElement || !m_mapElement->renderer()) return 0; - return m_mapElement->document()->axObjectCache()->get(m_mapElement->renderer()); + return m_mapElement->document()->axObjectCache()->getOrCreate(m_mapElement->renderer()); } Element* AccessibilityImageMapLink::actionElement() const diff --git a/WebCore/page/AccessibilityList.cpp b/WebCore/page/AccessibilityList.cpp index ad71ff4..3097b3b 100644 --- a/WebCore/page/AccessibilityList.cpp +++ b/WebCore/page/AccessibilityList.cpp @@ -68,8 +68,8 @@ bool AccessibilityList::isUnorderedList() const if (!m_renderer) return false; - Node* element = m_renderer->element(); - return element && element->hasTagName(ulTag); + Node* node = m_renderer->node(); + return node && node->hasTagName(ulTag); } bool AccessibilityList::isOrderedList() const @@ -77,8 +77,8 @@ bool AccessibilityList::isOrderedList() const if (!m_renderer) return false; - Node* element = m_renderer->element(); - return element && element->hasTagName(olTag); + Node* node = m_renderer->node(); + return node && node->hasTagName(olTag); } bool AccessibilityList::isDefinitionList() const @@ -86,8 +86,8 @@ bool AccessibilityList::isDefinitionList() const if (!m_renderer) return false; - Node* element = m_renderer->element(); - return element && element->hasTagName(dlTag); + Node* node = m_renderer->node(); + return node && node->hasTagName(dlTag); } diff --git a/WebCore/page/AccessibilityListBox.cpp b/WebCore/page/AccessibilityListBox.cpp index b94ccef..37baec9 100644 --- a/WebCore/page/AccessibilityListBox.cpp +++ b/WebCore/page/AccessibilityListBox.cpp @@ -144,7 +144,7 @@ AccessibilityObject* AccessibilityListBox::listBoxOptionAccessibilityObject(HTML if (!element || element->hasTagName(hrTag)) return 0; - AccessibilityObject* listBoxObject = m_renderer->document()->axObjectCache()->get(ListBoxOptionRole); + AccessibilityObject* listBoxObject = m_renderer->document()->axObjectCache()->getOrCreate(ListBoxOptionRole); static_cast<AccessibilityListBoxOption*>(listBoxObject)->setHTMLElement(element); return listBoxObject; @@ -157,13 +157,13 @@ AccessibilityObject* AccessibilityListBox::doAccessibilityHitTest(const IntPoint if (!m_renderer) return 0; - Node* element = m_renderer->element(); - if (!element) + Node* node = m_renderer->node(); + if (!node) return 0; IntRect parentRect = boundingBoxRect(); - const Vector<HTMLElement*>& listItems = static_cast<HTMLSelectElement*>(element)->listItems(); + const Vector<HTMLElement*>& listItems = static_cast<HTMLSelectElement*>(node)->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); @@ -171,7 +171,7 @@ AccessibilityObject* AccessibilityListBox::doAccessibilityHitTest(const IntPoint return listBoxOptionAccessibilityObject(listItems[i]); } - return axObjectCache()->get(m_renderer); + return axObjectCache()->getOrCreate(m_renderer); } } // namespace WebCore diff --git a/WebCore/page/AccessibilityListBoxOption.cpp b/WebCore/page/AccessibilityListBoxOption.cpp index fedfe91..088c556 100644 --- a/WebCore/page/AccessibilityListBoxOption.cpp +++ b/WebCore/page/AccessibilityListBoxOption.cpp @@ -97,7 +97,7 @@ IntRect AccessibilityListBoxOption::elementRect() const if (!listBoxRenderer) return rect; - IntRect parentRect = listBoxRenderer->document()->axObjectCache()->get(listBoxRenderer)->boundingBoxRect(); + IntRect parentRect = listBoxRenderer->document()->axObjectCache()->getOrCreate(listBoxRenderer)->boundingBoxRect(); int index = listBoxOptionIndex(); if (index != -1) rect = static_cast<RenderListBox*>(listBoxRenderer)->itemBoundingBoxRect(parentRect.x(), parentRect.y(), index); @@ -153,7 +153,7 @@ AccessibilityObject* AccessibilityListBoxOption::parentObject() const if (!parentNode) return 0; - return m_optionElement->document()->axObjectCache()->get(parentNode->renderer()); + return m_optionElement->document()->axObjectCache()->getOrCreate(parentNode->renderer()); } void AccessibilityListBoxOption::setSelected(bool selected) diff --git a/WebCore/page/AccessibilityObject.cpp b/WebCore/page/AccessibilityObject.cpp index 6d441d0..d5b7ff5 100644 --- a/WebCore/page/AccessibilityObject.cpp +++ b/WebCore/page/AccessibilityObject.cpp @@ -75,7 +75,6 @@ AccessibilityObject::~AccessibilityObject() void AccessibilityObject::detach() { - removeAXObjectID(); #if HAVE(ACCESSIBILITY) setWrapper(0); #endif @@ -114,6 +113,11 @@ AccessibilityObject* AccessibilityObject::parentObjectUnignored() const return parent; } +AccessibilityObject* AccessibilityObject::parentObjectIfExists() const +{ + return 0; +} + int AccessibilityObject::layoutCount() const { return 0; @@ -231,9 +235,9 @@ const AtomicString& AccessibilityObject::accessKey() const return nullAtom; } -Selection AccessibilityObject::selection() const +VisibleSelection AccessibilityObject::selection() const { - return Selection(); + return VisibleSelection(); } PlainTextRange AccessibilityObject::selectedTextRange() const @@ -357,7 +361,7 @@ VisiblePositionRange AccessibilityObject::visiblePositionRangeForUnorderedPositi // use selection order to see if the positions are in order else - alreadyInOrder = Selection(visiblePos1, visiblePos2).isBaseFirst(); + alreadyInOrder = VisibleSelection(visiblePos1, visiblePos2).isBaseFirst(); if (alreadyInOrder) { startPos = visiblePos1; @@ -400,7 +404,7 @@ static VisiblePosition updateAXLineStartForVisiblePosition(const VisiblePosition if (!p.node()) break; renderer = p.node()->renderer(); - if (!renderer || renderer->isRenderBlock() && !p.offset()) + if (!renderer || (renderer->isRenderBlock() && !p.m_offset)) break; InlineBox* box; int ignoredCaretOffset; @@ -514,7 +518,7 @@ static VisiblePosition startOfStyleRange(const VisiblePosition visiblePos) return VisiblePosition(startRenderer->node(), 0, VP_DEFAULT_AFFINITY); } -static VisiblePosition endOfStyleRange(const VisiblePosition visiblePos) +static VisiblePosition endOfStyleRange(const VisiblePosition& visiblePos) { RenderObject* renderer = visiblePos.deepEquivalent().node()->renderer(); RenderObject* endRenderer = renderer; @@ -534,7 +538,7 @@ static VisiblePosition endOfStyleRange(const VisiblePosition visiblePos) endRenderer = r; } - return VisiblePosition(endRenderer->node(), maxDeepOffset(endRenderer->node()), VP_DEFAULT_AFFINITY); + return lastDeepEditingPositionForNode(endRenderer->node()); } VisiblePositionRange AccessibilityObject::styleRangeForPosition(const VisiblePosition& visiblePos) const @@ -566,7 +570,7 @@ static bool replacedNodeNeedsCharacter(Node* replacedNode) } // create an AX object, but skip it if it is not supposed to be seen - AccessibilityObject* object = replacedNode->renderer()->document()->axObjectCache()->get(replacedNode->renderer()); + AccessibilityObject* object = replacedNode->renderer()->document()->axObjectCache()->getOrCreate(replacedNode->renderer()); if (object->accessibilityIsIgnored()) return false; @@ -814,7 +818,7 @@ AccessibilityObject* AccessibilityObject::accessibilityObjectForPosition(const V if (!obj) return 0; - return obj->document()->axObjectCache()->get(obj); + return obj->document()->axObjectCache()->getOrCreate(obj); } int AccessibilityObject::lineForPosition(const VisiblePosition& visiblePos) const @@ -996,11 +1000,6 @@ 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. diff --git a/WebCore/page/AccessibilityObject.h b/WebCore/page/AccessibilityObject.h index a751003..9141b36 100644 --- a/WebCore/page/AccessibilityObject.h +++ b/WebCore/page/AccessibilityObject.h @@ -83,7 +83,7 @@ class IntPoint; class IntSize; class Node; class RenderObject; -class Selection; +class VisibleSelection; class String; class Widget; @@ -266,6 +266,7 @@ public: virtual AccessibilityObject* nextSibling() const; virtual AccessibilityObject* parentObject() const; virtual AccessibilityObject* parentObjectUnignored() const; + virtual AccessibilityObject* parentObjectIfExists() const; virtual AccessibilityObject* observableObject() const; virtual void linkedUIElements(AccessibilityChildrenVector&) const; virtual AccessibilityObject* titleUIElement() const; @@ -285,7 +286,7 @@ public: virtual KURL url() const; virtual PlainTextRange selectedTextRange() const; - virtual Selection selection() const; + virtual VisibleSelection selection() const; unsigned selectionStart() const; unsigned selectionEnd() const; virtual String stringValue() const; @@ -410,7 +411,6 @@ protected: mutable bool m_haveChildren; virtual void clearChildren(); - virtual void removeAXObjectID(); virtual bool isDetached() const { return true; } #if PLATFORM(MAC) diff --git a/WebCore/page/AccessibilityRenderObject.cpp b/WebCore/page/AccessibilityRenderObject.cpp index 5cdc7b4..8ed352a 100644 --- a/WebCore/page/AccessibilityRenderObject.cpp +++ b/WebCore/page/AccessibilityRenderObject.cpp @@ -58,6 +58,7 @@ #include "RenderFieldset.h" #include "RenderFileUploadControl.h" #include "RenderImage.h" +#include "RenderInline.h" #include "RenderListBox.h" #include "RenderListMarker.h" #include "RenderMenuList.h" @@ -120,7 +121,7 @@ AccessibilityObject* AccessibilityRenderObject::firstChild() const if (!firstChild) return 0; - return m_renderer->document()->axObjectCache()->get(firstChild); + return m_renderer->document()->axObjectCache()->getOrCreate(firstChild); } AccessibilityObject* AccessibilityRenderObject::lastChild() const @@ -132,7 +133,7 @@ AccessibilityObject* AccessibilityRenderObject::lastChild() const if (!lastChild) return 0; - return m_renderer->document()->axObjectCache()->get(lastChild); + return m_renderer->document()->axObjectCache()->getOrCreate(lastChild); } AccessibilityObject* AccessibilityRenderObject::previousSibling() const @@ -144,7 +145,7 @@ AccessibilityObject* AccessibilityRenderObject::previousSibling() const if (!previousSibling) return 0; - return m_renderer->document()->axObjectCache()->get(previousSibling); + return m_renderer->document()->axObjectCache()->getOrCreate(previousSibling); } AccessibilityObject* AccessibilityRenderObject::nextSibling() const @@ -156,9 +157,21 @@ AccessibilityObject* AccessibilityRenderObject::nextSibling() const if (!nextSibling) return 0; - return m_renderer->document()->axObjectCache()->get(nextSibling); + return m_renderer->document()->axObjectCache()->getOrCreate(nextSibling); } +AccessibilityObject* AccessibilityRenderObject::parentObjectIfExists() const +{ + if (!m_renderer) + return 0; + + RenderObject *parent = m_renderer->parent(); + if (!parent) + return 0; + + return m_renderer->document()->axObjectCache()->get(parent); +} + AccessibilityObject* AccessibilityRenderObject::parentObject() const { if (!m_renderer) @@ -169,7 +182,7 @@ AccessibilityObject* AccessibilityRenderObject::parentObject() const return 0; if (ariaRoleAttribute() == MenuBarRole) - return m_renderer->document()->axObjectCache()->get(parent); + return m_renderer->document()->axObjectCache()->getOrCreate(parent); // menuButton and its corresponding menu are DOM siblings, but Accessibility needs them to be parent/child if (ariaRoleAttribute() == MenuRole) { @@ -178,7 +191,7 @@ AccessibilityObject* AccessibilityRenderObject::parentObject() const return parent; } - return m_renderer->document()->axObjectCache()->get(parent); + return m_renderer->document()->axObjectCache()->getOrCreate(parent); } bool AccessibilityRenderObject::isWebArea() const @@ -198,7 +211,7 @@ bool AccessibilityRenderObject::isAnchor() const bool AccessibilityRenderObject::isNativeTextControl() const { - return m_renderer->isTextField() || m_renderer->isTextArea(); + return m_renderer->isTextControl(); } bool AccessibilityRenderObject::isTextControl() const @@ -219,6 +232,9 @@ bool AccessibilityRenderObject::isImage() const bool AccessibilityRenderObject::isAttachment() const { + if (!m_renderer) + return false; + // 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())); @@ -228,9 +244,16 @@ bool AccessibilityRenderObject::isAttachment() const bool AccessibilityRenderObject::isPasswordField() const { ASSERT(m_renderer); - if (!m_renderer->element() || !m_renderer->element()->isHTMLElement()) + if (!m_renderer->node() || !m_renderer->node()->isHTMLElement()) + return false; + if (ariaRoleAttribute() != UnknownRole) + return false; + + InputElement* inputElement = toInputElement(static_cast<Element*>(m_renderer->node())); + if (!inputElement) return false; - return static_cast<HTMLElement*>(m_renderer->element())->isPasswordField() && ariaRoleAttribute() == UnknownRole; + + return inputElement->isPasswordField(); } bool AccessibilityRenderObject::isCheckboxOrRadio() const @@ -241,8 +264,8 @@ bool AccessibilityRenderObject::isCheckboxOrRadio() const bool AccessibilityRenderObject::isFileUploadButton() const { - if (m_renderer && m_renderer->element() && m_renderer->element()->hasTagName(inputTag)) { - HTMLInputElement* input = static_cast<HTMLInputElement*>(m_renderer->element()); + if (m_renderer && m_renderer->node() && m_renderer->node()->hasTagName(inputTag)) { + HTMLInputElement* input = static_cast<HTMLInputElement*>(m_renderer->node()); return input->inputType() == HTMLInputElement::FILE; } @@ -251,8 +274,8 @@ bool AccessibilityRenderObject::isFileUploadButton() const bool AccessibilityRenderObject::isInputImage() const { - if (m_renderer && m_renderer->element() && m_renderer->element()->hasTagName(inputTag)) { - HTMLInputElement* input = static_cast<HTMLInputElement*>(m_renderer->element()); + if (m_renderer && m_renderer->node() && m_renderer->node()->hasTagName(inputTag)) { + HTMLInputElement* input = static_cast<HTMLInputElement*>(m_renderer->node()); return input->inputType() == HTMLInputElement::IMAGE; } @@ -321,13 +344,27 @@ bool AccessibilityRenderObject::isPressed() const bool AccessibilityRenderObject::isIndeterminate() const { ASSERT(m_renderer); - return m_renderer->node() && m_renderer->node()->isIndeterminate(); + if (!m_renderer->node() || !m_renderer->node()->isElementNode()) + return false; + + InputElement* inputElement = toInputElement(static_cast<Element*>(m_renderer->node())); + if (!inputElement) + return false; + + return inputElement->isIndeterminate(); } bool AccessibilityRenderObject::isChecked() const { ASSERT(m_renderer); - return m_renderer->node() && m_renderer->node()->isChecked(); + if (!m_renderer->node() || !m_renderer->node()->isElementNode()) + return false; + + InputElement* inputElement = toInputElement(static_cast<Element*>(m_renderer->node())); + if (!inputElement) + return false; + + return inputElement->isChecked(); } bool AccessibilityRenderObject::isHovered() const @@ -341,7 +378,7 @@ bool AccessibilityRenderObject::isMultiSelect() const ASSERT(m_renderer); if (!m_renderer->isListBox()) return false; - return m_renderer->element() && static_cast<HTMLSelectElement*>(m_renderer->element())->multiple(); + return m_renderer->node() && static_cast<HTMLSelectElement*>(m_renderer->node())->multiple(); } bool AccessibilityRenderObject::isReadOnly() const @@ -384,7 +421,7 @@ int AccessibilityRenderObject::headingLevel(Node* node) return 0; if (RenderObject* renderer = node->renderer()) { - AccessibilityObject* axObjectForNode = node->document()->axObjectCache()->get(renderer); + AccessibilityObject* axObjectForNode = node->document()->axObjectCache()->getOrCreate(renderer); if (axObjectForNode->ariaRoleAttribute() == HeadingRole) { if (!node->isElementNode()) return 0; @@ -430,8 +467,9 @@ bool AccessibilityRenderObject::isControl() const if (!m_renderer) return false; - Node* node = m_renderer->element(); - return node && (node->isControl() || AccessibilityObject::isARIAControl(ariaRoleAttribute())); + Node* node = m_renderer->node(); + return node && ((node->isElementNode() && static_cast<Element*>(node)->isFormControlElement()) + || AccessibilityObject::isARIAControl(ariaRoleAttribute())); } bool AccessibilityRenderObject::isFieldset() const @@ -449,7 +487,7 @@ bool AccessibilityRenderObject::isGroup() const const AtomicString& AccessibilityRenderObject::getAttribute(const QualifiedName& attribute) const { - Node* node = m_renderer->element(); + Node* node = m_renderer->node(); if (!node) return nullAtom; @@ -469,10 +507,12 @@ Element* AccessibilityRenderObject::anchorElement() const 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()) { - RenderFlow* continuation = currRenderer->virtualContinuation(); - if (continuation) - return cache->get(continuation)->anchorElement(); + for (currRenderer = m_renderer; currRenderer && !currRenderer->node(); currRenderer = currRenderer->parent()) { + if (currRenderer->isRenderBlock()) { + RenderInline* continuation = toRenderBlock(currRenderer)->inlineContinuation(); + if (continuation) + return cache->getOrCreate(continuation)->anchorElement(); + } } // bail if none found @@ -483,7 +523,7 @@ Element* AccessibilityRenderObject::anchorElement() const // 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())) + if (node->hasTagName(aTag) || (node->renderer() && cache->getOrCreate(node->renderer())->isAnchor())) return static_cast<Element*>(node); } @@ -495,7 +535,7 @@ Element* AccessibilityRenderObject::actionElement() const if (!m_renderer) return 0; - Node* node = m_renderer->element(); + Node* node = m_renderer->node(); if (node) { if (node->hasTagName(inputTag)) { HTMLInputElement* input = static_cast<HTMLInputElement*>(node); @@ -506,13 +546,13 @@ Element* AccessibilityRenderObject::actionElement() const } if (isFileUploadButton()) - return static_cast<Element*>(m_renderer->element()); + return static_cast<Element*>(m_renderer->node()); if (AccessibilityObject::isARIAInput(ariaRoleAttribute())) - return static_cast<Element*>(m_renderer->element()); + return static_cast<Element*>(m_renderer->node()); if (isImageButton()) - return static_cast<Element*>(m_renderer->element()); + return static_cast<Element*>(m_renderer->node()); if (m_renderer->isMenuList()) return static_cast<RenderMenuList*>(m_renderer)->selectElement(); @@ -525,18 +565,18 @@ Element* AccessibilityRenderObject::actionElement() const Element* AccessibilityRenderObject::mouseButtonListener() const { - Node* node = m_renderer->element(); + Node* node = m_renderer->node(); if (!node) return 0; - if (!node->isEventTargetNode()) + if (!node->isElementNode()) 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); + for (Element* element = static_cast<Element*>(node); element; element = element->parentElement()) { + if (element->inlineEventListenerForType(eventNames().clickEvent) || element->inlineEventListenerForType(eventNames().mousedownEvent) || element->inlineEventListenerForType(eventNames().mouseupEvent)) + return element; } - + return 0; } @@ -567,7 +607,7 @@ AccessibilityObject* AccessibilityRenderObject::menuForMenuButton() const { Element* menu = menuElementForMenuButton(); if (menu && menu->renderer()) - return m_renderer->document()->axObjectCache()->get(menu->renderer()); + return m_renderer->document()->axObjectCache()->getOrCreate(menu->renderer()); return 0; } @@ -585,7 +625,7 @@ AccessibilityObject* AccessibilityRenderObject::menuButtonForMenu() const 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()); + AccessibilityObject* menuItemAX = m_renderer->document()->axObjectCache()->getOrCreate(menuItem->renderer()); if (menuItemAX->isMenuButton()) return menuItemAX; } @@ -598,11 +638,11 @@ String AccessibilityRenderObject::helpText() const 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 (curr->node() && curr->node()->isHTMLElement()) { + const AtomicString& summary = static_cast<Element*>(curr->node())->getAttribute(summaryAttr); if (!summary.isEmpty()) return summary; - const AtomicString& title = static_cast<Element*>(curr->element())->getAttribute(titleAttr); + const AtomicString& title = static_cast<Element*>(curr->node())->getAttribute(titleAttr); if (!title.isEmpty()) return title; } @@ -621,7 +661,7 @@ String AccessibilityRenderObject::textUnderElement() const return uploadControl->buttonValue(); } - Node* node = m_renderer->element(); + Node* node = m_renderer->node(); if (node) { if (Frame* frame = node->document()->frame()) { // catch stale WebCoreAXObject (see <rdar://problem/3960196>) @@ -641,7 +681,7 @@ bool AccessibilityRenderObject::hasIntValue() const if (isHeading()) return true; - if (m_renderer->element() && isCheckboxOrRadio()) + if (m_renderer->node() && isCheckboxOrRadio()) return true; return false; @@ -653,9 +693,9 @@ int AccessibilityRenderObject::intValue() const return 0; if (isHeading()) - return headingLevel(m_renderer->element()); + return headingLevel(m_renderer->node()); - Node* node = m_renderer->element(); + Node* node = m_renderer->node(); if (!node || !isCheckboxOrRadio()) return 0; @@ -830,7 +870,7 @@ HTMLLabelElement* AccessibilityRenderObject::labelElementContainer() const return false; // find if this has a parent that is a label - for (Node* parentNode = m_renderer->element(); parentNode; parentNode = parentNode->parentNode()) { + for (Node* parentNode = m_renderer->node(); parentNode; parentNode = parentNode->parentNode()) { if (parentNode->hasTagName(labelTag)) return static_cast<HTMLLabelElement*>(parentNode); } @@ -845,7 +885,7 @@ String AccessibilityRenderObject::title() const if (!m_renderer) return String(); - Node* node = m_renderer->element(); + Node* node = m_renderer->node(); if (!node) return String(); @@ -901,9 +941,10 @@ String AccessibilityRenderObject::accessibilityDescription() const 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 (isImage() || isInputImage()) { + Node* node = m_renderer->node(); + if (node && node->isHTMLElement()) { + const AtomicString& alt = static_cast<HTMLElement*>(node)->getAttribute(altAttr); if (alt.isEmpty()) return String(); return alt; @@ -944,8 +985,8 @@ IntRect AccessibilityRenderObject::boundingBoxRect() const if (!obj) return IntRect(); - if (obj->isInlineContinuation()) - obj = obj->element()->renderer(); + if (obj->node()) // If we are a continuation, we want to make sure to use the primary renderer. + obj = obj->node()->renderer(); // FIXME: This doesn't work correctly with transforms. Vector<IntRect> rects; @@ -968,11 +1009,11 @@ IntRect AccessibilityRenderObject::checkboxOrRadioRect() const if (!m_renderer) return IntRect(); - HTMLLabelElement* label = labelForElement(static_cast<Element*>(m_renderer->element())); + HTMLLabelElement* label = labelForElement(static_cast<Element*>(m_renderer->node())); if (!label || !label->renderer()) return boundingBoxRect(); - IntRect labelRect = axObjectCache()->get(label->renderer())->elementRect(); + IntRect labelRect = axObjectCache()->getOrCreate(label->renderer())->elementRect(); labelRect.unite(boundingBoxRect()); return labelRect; } @@ -1018,7 +1059,7 @@ AccessibilityObject* AccessibilityRenderObject::internalLinkElement() const 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()); + AccessibilityObject* linkedAXElement = m_renderer->document()->axObjectCache()->getOrCreate(linkedNode->renderer()); while (linkedAXElement && linkedAXElement->accessibilityIsIgnored()) { linkedNode = linkedNode->traverseNextNode(); @@ -1027,7 +1068,7 @@ AccessibilityObject* AccessibilityRenderObject::internalLinkElement() const if (!linkedNode) return 0; - linkedAXElement = m_renderer->document()->axObjectCache()->get(linkedNode->renderer()); + linkedAXElement = m_renderer->document()->axObjectCache()->getOrCreate(linkedNode->renderer()); } return linkedAXElement; @@ -1051,7 +1092,7 @@ void AccessibilityRenderObject::addRadioButtonGroupMembers(AccessibilityChildren 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())) + if (AccessibilityObject* object = m_renderer->document()->axObjectCache()->getOrCreate(associateElement->renderer())) linkedUIElements.append(object); } } else { @@ -1061,7 +1102,7 @@ void AccessibilityRenderObject::addRadioButtonGroupMembers(AccessibilityChildren 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())) + if (AccessibilityObject* object = m_renderer->document()->axObjectCache()->getOrCreate(associateElement->renderer())) linkedUIElements.append(object); } } @@ -1090,16 +1131,16 @@ AccessibilityObject* AccessibilityRenderObject::titleUIElement() const // if isFieldset is true, the renderer is guaranteed to be a RenderFieldset if (isFieldset()) - return axObjectCache()->get(static_cast<RenderFieldset*>(m_renderer)->findLegend()); + return axObjectCache()->getOrCreate(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(); + Node* element = m_renderer->node(); HTMLLabelElement* label = labelForElement(static_cast<Element*>(element)); if (label && label->renderer()) - return axObjectCache()->get(label->renderer()); + return axObjectCache()->getOrCreate(label->renderer()); return 0; } @@ -1125,7 +1166,7 @@ bool AccessibilityRenderObject::accessibilityIsIgnored() const if (labelElement) { HTMLElement* correspondingControl = labelElement->correspondingControl(); if (correspondingControl && correspondingControl->renderer()) { - AccessibilityObject* controlObject = axObjectCache()->get(correspondingControl->renderer()); + AccessibilityObject* controlObject = axObjectCache()->getOrCreate(correspondingControl->renderer()); if (controlObject->isCheckboxOrRadio()) return true; } @@ -1157,12 +1198,12 @@ bool AccessibilityRenderObject::accessibilityIsIgnored() const return false; // don't ignore labels, because they serve as TitleUIElements - Node* node = m_renderer->element(); + Node* node = m_renderer->node(); if (node && node->hasTagName(labelTag)) return false; if (m_renderer->isBlockFlow() && m_renderer->childrenInline()) - return !static_cast<RenderBlock*>(m_renderer)->firstLineBox() && !mouseButtonListener(); + return !toRenderBlock(m_renderer)->firstLineBox() && !mouseButtonListener(); // ignore images seemingly used as spacers if (isImage()) { @@ -1178,7 +1219,7 @@ bool AccessibilityRenderObject::accessibilityIsIgnored() const } // check for one-dimensional image - RenderImage* image = static_cast<RenderImage*>(m_renderer); + RenderImage* image = toRenderImage(m_renderer); if (image->height() <= 1 || image->width() <= 1) return true; @@ -1211,7 +1252,7 @@ int AccessibilityRenderObject::layoutCount() const { if (!m_renderer->isRenderView()) return 0; - return static_cast<RenderView*>(m_renderer)->frameView()->layoutCount(); + return toRenderView(m_renderer)->frameView()->layoutCount(); } String AccessibilityRenderObject::text() const @@ -1220,9 +1261,9 @@ String AccessibilityRenderObject::text() const return String(); if (isNativeTextControl()) - return static_cast<RenderTextControl*>(m_renderer)->text(); + return toRenderTextControl(m_renderer)->text(); - Node* node = m_renderer->element(); + Node* node = m_renderer->node(); if (!node) return String(); if (!node->isElementNode()) @@ -1243,11 +1284,11 @@ int AccessibilityRenderObject::textLength() const PassRefPtr<Range> AccessibilityRenderObject::ariaSelectedTextDOMRange() const { - Node* node = m_renderer->element(); + Node* node = m_renderer->node(); if (!node) return 0; - RefPtr<Range> currentSelectionRange = selection().toRange(); + RefPtr<Range> currentSelectionRange = selection().toNormalizedRange(); if (!currentSelectionRange) return 0; @@ -1280,7 +1321,7 @@ String AccessibilityRenderObject::selectedText() const return String(); // need to return something distinct from empty string if (isNativeTextControl()) { - RenderTextControl* textControl = static_cast<RenderTextControl*>(m_renderer); + RenderTextControl* textControl = toRenderTextControl(m_renderer); return textControl->text().substring(textControl->selectionStart(), textControl->selectionEnd() - textControl->selectionStart()); } @@ -1295,7 +1336,7 @@ String AccessibilityRenderObject::selectedText() const const AtomicString& AccessibilityRenderObject::accessKey() const { - Node* node = m_renderer->element(); + Node* node = m_renderer->node(); if (!node) return nullAtom; if (!node->isElementNode()) @@ -1303,7 +1344,7 @@ const AtomicString& AccessibilityRenderObject::accessKey() const return static_cast<Element*>(node)->getAttribute(accesskeyAttr); } -Selection AccessibilityRenderObject::selection() const +VisibleSelection AccessibilityRenderObject::selection() const { return m_renderer->document()->frame()->selection()->selection(); } @@ -1317,7 +1358,7 @@ PlainTextRange AccessibilityRenderObject::selectedTextRange() const AccessibilityRole ariaRole = ariaRoleAttribute(); if (isNativeTextControl() && ariaRole == UnknownRole) { - RenderTextControl* textControl = static_cast<RenderTextControl*>(m_renderer); + RenderTextControl* textControl = toRenderTextControl(m_renderer); return PlainTextRange(textControl->selectionStart(), textControl->selectionEnd() - textControl->selectionStart()); } @@ -1333,7 +1374,7 @@ PlainTextRange AccessibilityRenderObject::selectedTextRange() const void AccessibilityRenderObject::setSelectedTextRange(const PlainTextRange& range) { if (isNativeTextControl()) { - RenderTextControl* textControl = static_cast<RenderTextControl*>(m_renderer); + RenderTextControl* textControl = toRenderTextControl(m_renderer); textControl->setSelectionRange(range.start, range.start + range.length); return; } @@ -1344,14 +1385,14 @@ void AccessibilityRenderObject::setSelectedTextRange(const PlainTextRange& range Frame* frame = document->frame(); if (!frame) return; - Node* node = m_renderer->element(); - frame->selection()->setSelection(Selection(Position(node, range.start), + Node* node = m_renderer->node(); + frame->selection()->setSelection(VisibleSelection(Position(node, range.start), Position(node, range.start + range.length), DOWNSTREAM)); } KURL AccessibilityRenderObject::url() const { - if (isAnchor() && m_renderer->element()->hasTagName(aTag)) { + if (isAnchor() && m_renderer->node()->hasTagName(aTag)) { if (HTMLAnchorElement* anchor = static_cast<HTMLAnchorElement*>(anchorElement())) return anchor->href(); } @@ -1359,11 +1400,11 @@ KURL AccessibilityRenderObject::url() const 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(); + if (isImage() && m_renderer->node() && m_renderer->node()->hasTagName(imgTag)) + return static_cast<HTMLImageElement*>(m_renderer->node())->src(); if (isInputImage()) - return static_cast<HTMLInputElement*>(m_renderer->element())->src(); + return static_cast<HTMLInputElement*>(m_renderer->node())->src(); return KURL(); } @@ -1400,7 +1441,7 @@ bool AccessibilityRenderObject::isFocused() const // 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() || + if (focusedNode == m_renderer->node() || (roleValue() == WebAreaRole && document->frame()->selection()->isFocusedAndActive())) return true; @@ -1415,10 +1456,10 @@ void AccessibilityRenderObject::setFocused(bool on) if (!on) m_renderer->document()->setFocusedNode(0); else { - if (m_renderer->element()->isElementNode()) - static_cast<Element*>(m_renderer->element())->focus(); + if (m_renderer->node()->isElementNode()) + static_cast<Element*>(m_renderer->node())->focus(); else - m_renderer->document()->setFocusedNode(m_renderer->element()); + m_renderer->document()->setFocusedNode(m_renderer->node()); } } @@ -1426,17 +1467,25 @@ 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()); + HTMLInputElement* input = static_cast<HTMLInputElement*>(m_renderer->node()); input->setValue(string); } else if (m_renderer->isTextArea()) { - HTMLTextAreaElement* textArea = static_cast<HTMLTextAreaElement*>(m_renderer->element()); + HTMLTextAreaElement* textArea = static_cast<HTMLTextAreaElement*>(m_renderer->node()); textArea->setValue(string); } } bool AccessibilityRenderObject::isEnabled() const { - return m_renderer->element() ? m_renderer->element()->isEnabled() : true; + ASSERT(m_renderer); + if (!m_renderer->node() || !m_renderer->node()->isElementNode()) + return true; + + FormControlElement* formControlElement = toFormControlElement(static_cast<Element*>(m_renderer->node())); + if (!formControlElement) + return true; + + return formControlElement->isEnabled(); } RenderView* AccessibilityRenderObject::topRenderer() const @@ -1482,7 +1531,7 @@ AccessibilityObject* AccessibilityRenderObject::accessibilityParentForImageMap(H // 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 axObjectCache()->getOrCreate(obj); } return 0; @@ -1496,7 +1545,7 @@ void AccessibilityRenderObject::getDocumentLinks(AccessibilityChildrenVector& re while (curr) { RenderObject* obj = curr->renderer(); if (obj) { - RefPtr<AccessibilityObject> axobj = document->axObjectCache()->get(obj); + RefPtr<AccessibilityObject> axobj = document->axObjectCache()->getOrCreate(obj); ASSERT(axobj); ASSERT(axobj->roleValue() == WebCoreLinkRole); if (!axobj->accessibilityIsIgnored()) @@ -1504,7 +1553,7 @@ void AccessibilityRenderObject::getDocumentLinks(AccessibilityChildrenVector& re } else { Node* parent = curr->parent(); if (parent && curr->hasTagName(areaTag) && parent->hasTagName(mapTag)) { - AccessibilityImageMapLink* areaObject = static_cast<AccessibilityImageMapLink*>(axObjectCache()->get(ImageMapLinkRole)); + AccessibilityImageMapLink* areaObject = static_cast<AccessibilityImageMapLink*>(axObjectCache()->getOrCreate(ImageMapLinkRole)); areaObject->setHTMLAreaElement(static_cast<HTMLAreaElement*>(curr)); areaObject->setHTMLMapElement(static_cast<HTMLMapElement*>(parent)); areaObject->setParent(accessibilityParentForImageMap(static_cast<HTMLMapElement*>(parent))); @@ -1548,20 +1597,23 @@ VisiblePositionRange AccessibilityRenderObject::visiblePositionRange() const return VisiblePositionRange(); // construct VisiblePositions for start and end - Node* node = m_renderer->element(); + Node* node = m_renderer->node(); if (!node) return VisiblePositionRange(); - - VisiblePosition startPos = VisiblePosition(node, 0, VP_DEFAULT_AFFINITY); - VisiblePosition endPos = VisiblePosition(node, maxDeepOffset(node), VP_DEFAULT_AFFINITY); - + + VisiblePosition startPos = firstDeepEditingPositionForNode(node); + VisiblePosition endPos = lastDeepEditingPositionForNode(node); + // the VisiblePositions are equal for nodes like buttons, so adjust for that + // FIXME: Really? [button, 0] and [button, 1] are distinct (before and after the button) + // I expect this code is only hit for things like empty divs? In which case I don't think + // the behavior is correct here -- eseidel if (startPos == endPos) { endPos = endPos.next(); if (endPos.isNull()) endPos = startPos; } - + return VisiblePositionRange(startPos, endPos); } @@ -1587,7 +1639,7 @@ VisiblePositionRange AccessibilityRenderObject::visiblePositionRangeForLine(unsi // starting at an empty line. The resulting selection in that case // will be a caret at visiblePos. SelectionController selection; - selection.setSelection(Selection(visiblePos)); + selection.setSelection(VisibleSelection(visiblePos)); selection.modify(SelectionController::EXTEND, SelectionController::RIGHT, LineBoundary); return VisiblePositionRange(selection.selection().visibleStart(), selection.selection().visibleEnd()); @@ -1599,7 +1651,7 @@ VisiblePosition AccessibilityRenderObject::visiblePositionForIndex(int index) co return VisiblePosition(); if (isNativeTextControl()) - return static_cast<RenderTextControl*>(m_renderer)->visiblePositionForIndex(index); + return toRenderTextControl(m_renderer)->visiblePositionForIndex(index); if (!isTextControl() && !m_renderer->isText()) return VisiblePosition(); @@ -1622,7 +1674,7 @@ VisiblePosition AccessibilityRenderObject::visiblePositionForIndex(int index) co int AccessibilityRenderObject::indexForVisiblePosition(const VisiblePosition& pos) const { if (isNativeTextControl()) - return static_cast<RenderTextControl*>(m_renderer)->indexForVisiblePosition(pos); + return toRenderTextControl(m_renderer)->indexForVisiblePosition(pos); if (!isTextControl()) return 0; @@ -1638,7 +1690,7 @@ int AccessibilityRenderObject::indexForVisiblePosition(const VisiblePosition& po ExceptionCode ec = 0; RefPtr<Range> range = Range::create(m_renderer->document()); range->setStart(node, 0, ec); - range->setEnd(indexPosition.node(), indexPosition.offset(), ec); + range->setEnd(indexPosition.node(), indexPosition.m_offset, ec); return TextIterator::rangeLength(range.get()); } @@ -1694,7 +1746,7 @@ void AccessibilityRenderObject::setSelectedVisiblePositionRange(const VisiblePos m_renderer->document()->frame()->selection()->moveTo(range.start, true); } else { - Selection newSelection = Selection(range.start, range.end); + VisibleSelection newSelection = VisibleSelection(range.start, range.end); m_renderer->document()->frame()->selection()->setSelection(newSelection); } } @@ -1715,7 +1767,8 @@ VisiblePosition AccessibilityRenderObject::visiblePositionForPoint(const IntPoin #else ourpoint = point; #endif - HitTestRequest request(true, true); + HitTestRequest request(HitTestRequest::ReadOnly | + HitTestRequest::Active); HitTestResult result(ourpoint); renderView->layer()->hitTest(request, result); innerNode = result.innerNode(); @@ -1736,10 +1789,7 @@ VisiblePosition AccessibilityRenderObject::visiblePositionForPoint(const IntPoin Frame* frame = static_cast<FrameView*>(widget)->frame(); if (!frame) break; - Document* document = frame->document(); - if (!document) - break; - renderView = document->renderView(); + renderView = frame->document()->renderView(); frameView = static_cast<FrameView*>(widget); } @@ -1772,7 +1822,7 @@ int AccessibilityRenderObject::index(const VisiblePosition& position) const if (!node) return -1; - for (RenderObject* renderer = node->renderer(); renderer && renderer->element(); renderer = renderer->parent()) { + for (RenderObject* renderer = node->renderer(); renderer && renderer->node(); renderer = renderer->parent()) { if (renderer == m_renderer) return indexForVisiblePosition(position); } @@ -1802,7 +1852,7 @@ PlainTextRange AccessibilityRenderObject::doAXRangeForLine(unsigned lineNumber) // starting at an empty line. The resulting selection in that case // will be a caret at visiblePos. SelectionController selection; - selection.setSelection(Selection(visiblePos)); + selection.setSelection(VisibleSelection(visiblePos)); selection.modify(SelectionController::EXTEND, SelectionController::LEFT, LineBoundary); selection.modify(SelectionController::EXTEND, SelectionController::RIGHT, LineBoundary); @@ -1875,7 +1925,8 @@ AccessibilityObject* AccessibilityRenderObject::doAccessibilityHitTest(const Int RenderLayer* layer = toRenderBox(m_renderer)->layer(); - HitTestRequest request(true, true); + HitTestRequest request(HitTestRequest::ReadOnly | + HitTestRequest::Active); HitTestResult hitTestResult = HitTestResult(point); layer->hitTest(request, hitTestResult); if (!hitTestResult.innerNode()) @@ -1885,7 +1936,7 @@ AccessibilityObject* AccessibilityRenderObject::doAccessibilityHitTest(const Int if (!obj) return 0; - AccessibilityObject *result = obj->document()->axObjectCache()->get(obj); + AccessibilityObject *result = obj->document()->axObjectCache()->getOrCreate(obj); if (obj->isListBox()) return static_cast<AccessibilityListBox*>(result)->doAccessibilityHitTest(point); @@ -1912,7 +1963,7 @@ AccessibilityObject* AccessibilityRenderObject::focusedUIElement() const if (!focusedNodeRenderer) return 0; - AccessibilityObject* obj = focusedNodeRenderer->document()->axObjectCache()->get(focusedNodeRenderer); + AccessibilityObject* obj = focusedNodeRenderer->document()->axObjectCache()->getOrCreate(focusedNodeRenderer); if (obj->shouldFocusActiveDescendant()) { if (AccessibilityObject* descendant = obj->activeDescendant()) @@ -1957,9 +2008,9 @@ bool AccessibilityRenderObject::shouldFocusActiveDescendant() const AccessibilityObject* AccessibilityRenderObject::activeDescendant() const { - if (renderer()->element() && !renderer()->element()->isElementNode()) + if (renderer()->node() && !renderer()->node()->isElementNode()) return 0; - Element* element = static_cast<Element*>(renderer()->element()); + Element* element = static_cast<Element*>(renderer()->node()); String activeDescendantAttrStr = element->getAttribute(aria_activedescendantAttr).string(); if (activeDescendantAttrStr.isNull() || activeDescendantAttrStr.isEmpty()) @@ -1969,7 +2020,7 @@ AccessibilityObject* AccessibilityRenderObject::activeDescendant() const if (!target) return 0; - AccessibilityObject* obj = renderer()->document()->axObjectCache()->get(target->renderer()); + AccessibilityObject* obj = renderer()->document()->axObjectCache()->getOrCreate(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; @@ -1979,7 +2030,7 @@ AccessibilityObject* AccessibilityRenderObject::activeDescendant() const void AccessibilityRenderObject::handleActiveDescendantChanged() { - Element* element = static_cast<Element*>(renderer()->element()); + Element* element = static_cast<Element*>(renderer()->node()); if (!element) return; Document* doc = renderer()->document(); @@ -1994,9 +2045,9 @@ void AccessibilityRenderObject::handleActiveDescendantChanged() 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); + for (RenderObject* renderer = m_renderer; renderer && renderer->node(); renderer = renderer->parent()) { + if (renderer->isTextControl()) + return renderer->document()->axObjectCache()->getOrCreate(renderer); } return 0; @@ -2089,7 +2140,7 @@ AccessibilityRole AccessibilityRenderObject::roleValue() const if (!m_renderer) return UnknownRole; - Node* node = m_renderer->element(); + Node* node = m_renderer->node(); AccessibilityRole ariaRole = ariaRoleAttribute(); if (ariaRole != UnknownRole) return ariaRole; @@ -2138,7 +2189,7 @@ AccessibilityRole AccessibilityRenderObject::roleValue() const if (m_renderer->isMenuList()) return PopUpButtonRole; - if (headingLevel(m_renderer->element()) != 0) + if (headingLevel(m_renderer->node()) != 0) return HeadingRole; if (node && node->hasTagName(ddTag)) @@ -2178,12 +2229,18 @@ bool AccessibilityRenderObject::ariaRoleHasPresentationalChildren() const bool AccessibilityRenderObject::canSetFocusAttribute() const { + ASSERT(m_renderer); + // 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()) + if (!m_renderer->node() || !m_renderer->node()->isElementNode()) return false; - + + FormControlElement* formControlElement = toFormControlElement(static_cast<Element*>(m_renderer->node())); + if (formControlElement && !formControlElement->isEnabled()) + return false; + switch (roleValue()) { case WebCoreLinkRole: case ImageMapLinkRole: @@ -2219,13 +2276,15 @@ void AccessibilityRenderObject::childrenChanged() markChildrenDirty(); - // this object may not be accessible (and thus may not appear + // This object may not be accessible (and thus may not appear // in the hierarchy), which means we need to go up the parent // chain and mark the parent's dirty. Ideally, we would want // to only access the next object that is not ignored, but // asking an element if it's ignored can lead to an examination of the - // render tree which is dangerous. - for (AccessibilityObject* parent = parentObject(); parent; parent = parent->parentObject()) { + // render tree which is dangerous. + // Only parents that already exist must be retrieved, otherwise objects can be created + // at bad times + for (AccessibilityObject* parent = parentObjectIfExists(); parent; parent = parent->parentObjectIfExists()) { if (parent->isAccessibilityRenderObject()) static_cast<AccessibilityRenderObject *>(parent)->markChildrenDirty(); } @@ -2291,13 +2350,13 @@ void AccessibilityRenderObject::addChildren() // for a RenderImage, add the <area> elements as individual accessibility objects if (m_renderer->isRenderImage()) { - HTMLMapElement* map = static_cast<RenderImage*>(m_renderer)->imageMap(); + HTMLMapElement* map = toRenderImage(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)); + AccessibilityImageMapLink* areaObject = static_cast<AccessibilityImageMapLink*>(m_renderer->document()->axObjectCache()->getOrCreate(ImageMapLinkRole)); areaObject->setHTMLAreaElement(static_cast<HTMLAreaElement*>(current)); areaObject->setHTMLMapElement(map); areaObject->setParent(this); @@ -2314,7 +2373,7 @@ void AccessibilityRenderObject::ariaListboxSelectedChildren(AccessibilityChildre AccessibilityObject* child = firstChild(); bool isMultiselectable = false; - Element* element = static_cast<Element*>(renderer()->element()); + Element* element = static_cast<Element*>(renderer()->node()); if (!element || !element->isElementNode()) // do this check to ensure safety of static_cast above return; @@ -2328,7 +2387,7 @@ void AccessibilityRenderObject::ariaListboxSelectedChildren(AccessibilityChildre if (child->isAccessibilityRenderObject()) childRenderer = static_cast<AccessibilityRenderObject*>(child)->renderer(); if (childRenderer && ariaRole == ListBoxOptionRole) { - Element* childElement = static_cast<Element*>(childRenderer->element()); + Element* childElement = static_cast<Element*>(childRenderer->node()); 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")) { @@ -2378,15 +2437,6 @@ void AccessibilityRenderObject::visibleChildren(AccessibilityChildrenVector& res 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. diff --git a/WebCore/page/AccessibilityRenderObject.h b/WebCore/page/AccessibilityRenderObject.h index 03ba1db..5370eac 100644 --- a/WebCore/page/AccessibilityRenderObject.h +++ b/WebCore/page/AccessibilityRenderObject.h @@ -51,7 +51,7 @@ class RenderObject; class RenderListBox; class RenderTextControl; class RenderView; -class Selection; +class VisibleSelection; class String; class Widget; @@ -125,6 +125,7 @@ public: virtual AccessibilityObject* previousSibling() const; virtual AccessibilityObject* nextSibling() const; virtual AccessibilityObject* parentObject() const; + virtual AccessibilityObject* parentObjectIfExists() const; virtual AccessibilityObject* observableObject() const; virtual void linkedUIElements(AccessibilityChildrenVector&) const; virtual AccessibilityObject* titleUIElement() const; @@ -156,7 +157,7 @@ public: virtual KURL url() const; virtual PlainTextRange selectedTextRange() const; - virtual Selection selection() const; + virtual VisibleSelection selection() const; virtual String stringValue() const; virtual String ariaAccessiblityName(const String&) const; virtual String ariaLabeledByAttribute() const; @@ -218,7 +219,6 @@ protected: mutable bool m_childrenDirty; void setRenderObject(RenderObject* renderer) { m_renderer = renderer; } - virtual void removeAXObjectID(); virtual bool isDetached() const { return !m_renderer; } diff --git a/WebCore/page/AccessibilityTable.cpp b/WebCore/page/AccessibilityTable.cpp index 9409283..2b60d43 100644 --- a/WebCore/page/AccessibilityTable.cpp +++ b/WebCore/page/AccessibilityTable.cpp @@ -93,7 +93,7 @@ bool AccessibilityTable::isTableExposableThroughAccessibility() // Unfortunately, there is no good way to determine the difference // between a "layout" table and a "data" table - Node* tableNode = table->element(); + Node* tableNode = table->node(); if (!tableNode || !tableNode->hasTagName(tableTag)) return false; @@ -139,7 +139,7 @@ bool AccessibilityTable::isTableExposableThroughAccessibility() RenderTableCell* cell = firstBody->cellAt(row, col).cell; if (!cell) continue; - Node* cellNode = cell->element(); + Node* cellNode = cell->node(); if (!cellNode) continue; @@ -241,7 +241,7 @@ void AccessibilityTable::addChildren() if (!cell) continue; - AccessibilityObject* rowObject = axCache->get(cell->parent()); + AccessibilityObject* rowObject = axCache->getOrCreate(cell->parent()); if (!rowObject->isTableRow()) continue; @@ -264,7 +264,7 @@ void AccessibilityTable::addChildren() // 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)); + AccessibilityTableColumn* column = static_cast<AccessibilityTableColumn*>(axCache->getOrCreate(ColumnRole)); column->setColumnIndex((int)i); column->setParentTable(this); m_columns.append(column); @@ -281,7 +281,7 @@ AccessibilityObject* AccessibilityTable::headerContainer() if (m_headerContainer) return m_headerContainer; - m_headerContainer = static_cast<AccessibilityTableHeaderContainer*>(axObjectCache()->get(TableHeaderContainerRole)); + m_headerContainer = static_cast<AccessibilityTableHeaderContainer*>(axObjectCache()->getOrCreate(TableHeaderContainerRole)); m_headerContainer->setParentTable(this); return m_headerContainer; @@ -386,11 +386,13 @@ AccessibilityTableCell* AccessibilityTable::cellForColumnAndRow(unsigned column, unsigned rowOffset = 0; while (tableSection) { - rowCount += tableSection->numRows(); + unsigned numRows = tableSection->numRows(); unsigned numCols = tableSection->numColumns(); - if (row < rowCount && column < numCols) { - int sectionSpecificRow = row - rowOffset; + rowCount += numRows; + + unsigned sectionSpecificRow = row - rowOffset; + if (row < rowCount && column < numCols && sectionSpecificRow < numRows) { cell = tableSection->cellAt(sectionSpecificRow, column).cell; // we didn't find the cell, which means there's spanning happening @@ -422,9 +424,9 @@ AccessibilityTableCell* AccessibilityTable::cellForColumnAndRow(unsigned column, if (cell) break; - rowOffset += rowCount; + rowOffset += numRows; // we didn't find anything between the rows we should have - if (row < rowOffset) + if (row < rowCount) break; tableSection = table->sectionBelow(tableSection, true); } @@ -432,7 +434,7 @@ AccessibilityTableCell* AccessibilityTable::cellForColumnAndRow(unsigned column, if (!cell) return 0; - AccessibilityObject* cellObject = axObjectCache()->get(cell); + AccessibilityObject* cellObject = axObjectCache()->getOrCreate(cell); ASSERT(cellObject->isTableCell()); return static_cast<AccessibilityTableCell*>(cellObject); @@ -464,7 +466,7 @@ String AccessibilityTable::title() const return title; // see if there is a caption - Node *tableElement = m_renderer->element(); + Node* tableElement = m_renderer->node(); if (tableElement) { HTMLTableCaptionElement* caption = static_cast<HTMLTableElement*>(tableElement)->caption(); if (caption) diff --git a/WebCore/page/AccessibilityTableCell.cpp b/WebCore/page/AccessibilityTableCell.cpp index ff82811..f7cbe98 100644 --- a/WebCore/page/AccessibilityTableCell.cpp +++ b/WebCore/page/AccessibilityTableCell.cpp @@ -67,7 +67,7 @@ bool AccessibilityTableCell::isTableCell() const if (!m_renderer) return false; - AccessibilityObject* renderTable = axObjectCache()->get(static_cast<RenderTableCell*>(m_renderer)->table()); + AccessibilityObject* renderTable = axObjectCache()->getOrCreate(static_cast<RenderTableCell*>(m_renderer)->table()); if (!renderTable->isDataTable()) return false; @@ -147,11 +147,11 @@ AccessibilityObject* AccessibilityTableCell::titleUIElement() const if (!headerCell || headerCell == renderCell) return 0; - Node* cellElement = headerCell->element(); + Node* cellElement = headerCell->node(); if (!cellElement || !cellElement->hasTagName(thTag)) return 0; - return axObjectCache()->get(headerCell); + return axObjectCache()->getOrCreate(headerCell); } } // namespace WebCore diff --git a/WebCore/page/AccessibilityTableColumn.cpp b/WebCore/page/AccessibilityTableColumn.cpp index 6e03af9..ff330c0 100644 --- a/WebCore/page/AccessibilityTableColumn.cpp +++ b/WebCore/page/AccessibilityTableColumn.cpp @@ -124,7 +124,7 @@ AccessibilityObject* AccessibilityTableColumn::headerObjectForSection(RenderTabl if ((testCell->col() + (testCell->colSpan()-1)) < m_columnIndex) break; - Node* node = testCell->element(); + Node* node = testCell->node(); if (!node) continue; @@ -137,7 +137,7 @@ AccessibilityObject* AccessibilityTableColumn::headerObjectForSection(RenderTabl if (!cell) return 0; - return m_parentTable->axObjectCache()->get(cell); + return m_parentTable->axObjectCache()->getOrCreate(cell); } void AccessibilityTableColumn::addChildren() diff --git a/WebCore/page/AccessibilityTableRow.cpp b/WebCore/page/AccessibilityTableRow.cpp index caccff5..e67fcfe 100644 --- a/WebCore/page/AccessibilityTableRow.cpp +++ b/WebCore/page/AccessibilityTableRow.cpp @@ -70,7 +70,7 @@ bool AccessibilityTableRow::isTableRow() const if (!m_renderer) return true; - AccessibilityObject* renderTable = axObjectCache()->get(static_cast<RenderTableRow*>(m_renderer)->table()); + AccessibilityObject* renderTable = axObjectCache()->getOrCreate(static_cast<RenderTableRow*>(m_renderer)->table()); if (!renderTable->isDataTable()) return false; @@ -100,7 +100,7 @@ AccessibilityObject* AccessibilityTableRow::headerObject() if (!cellRenderer) return 0; - Node* cellNode = cellRenderer->element(); + Node* cellNode = cellRenderer->node(); if (!cellNode || !cellNode->hasTagName(thTag)) return 0; diff --git a/WebCore/page/Chrome.cpp b/WebCore/page/Chrome.cpp index 4698aa5..b37ebc4 100644 --- a/WebCore/page/Chrome.cpp +++ b/WebCore/page/Chrome.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2009 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 @@ -28,6 +28,7 @@ #include "FloatRect.h" #include "Frame.h" #include "FrameTree.h" +#include "Geolocation.h" #include "HTMLFormElement.h" #include "HTMLInputElement.h" #include "HTMLNames.h" @@ -387,6 +388,16 @@ void Chrome::enableSuddenTermination() m_client->enableSuddenTermination(); } +void Chrome::requestGeolocationPermissionForFrame(Frame* frame, Geolocation* geolocation) +{ + // 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); + m_client->requestGeolocationPermissionForFrame(frame, geolocation); +} + void Chrome::runOpenPanel(Frame* frame, PassRefPtr<FileChooser> fileChooser) { m_client->runOpenPanel(frame, fileChooser); @@ -457,10 +468,8 @@ PageGroupLoadDeferrer::PageGroupLoadDeferrer(Page* page, bool deferSelf) 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(); - } + for (Frame* frame = otherPage->mainFrame(); frame; frame = frame->tree()->traverseNext()) + frame->document()->suspendActiveDOMObjects(); #endif } } @@ -478,10 +487,8 @@ PageGroupLoadDeferrer::~PageGroupLoadDeferrer() page->setDefersLoading(false); #if !PLATFORM(MAC) - for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext()) { - if (Document* document = frame->document()) - document->resumeActiveDOMObjects(); - } + for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext()) + frame->document()->resumeActiveDOMObjects(); #endif } } diff --git a/WebCore/page/Chrome.h b/WebCore/page/Chrome.h index 47b912d..ab0b42f 100644 --- a/WebCore/page/Chrome.h +++ b/WebCore/page/Chrome.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008, 2009 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 @@ -38,6 +38,7 @@ namespace WebCore { class ContextMenu; class FloatRect; class Frame; + class Geolocation; class HitTestResult; class IntRect; class Page; @@ -119,6 +120,8 @@ namespace WebCore { void enableSuddenTermination(); void disableSuddenTermination(); + void requestGeolocationPermissionForFrame(Frame*, Geolocation*); + void runOpenPanel(Frame*, PassRefPtr<FileChooser>); #if PLATFORM(MAC) diff --git a/WebCore/page/ChromeClient.h b/WebCore/page/ChromeClient.h index 5d90b2f..6f82bc1 100644 --- a/WebCore/page/ChromeClient.h +++ b/WebCore/page/ChromeClient.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2008 Apple, Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008, 2009 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 @@ -42,16 +42,21 @@ namespace WebCore { class FileChooser; class FloatRect; class Frame; + class Geolocation; class HitTestResult; class IntRect; class Node; class Page; class String; class Widget; - + struct FrameLoadRequest; struct WindowFeatures; +#if USE(ACCELERATED_COMPOSITING) + class GraphicsLayer; +#endif + class ChromeClient { public: virtual void chromeDestroyed() = 0; @@ -148,12 +153,24 @@ namespace WebCore { float value, float proportion, ScrollbarControlPartMask); virtual bool paintCustomScrollCorner(GraphicsContext*, const FloatRect&); + // This is an asynchronous call. The ChromeClient can display UI asking the user for permission + // to use Geolococation. The ChromeClient must call Geolocation::setShouldClearCache() appropriately. + virtual void requestGeolocationPermissionForFrame(Frame*, Geolocation*) { } + 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 USE(ACCELERATED_COMPOSITING) + // Pass 0 as the GraphicsLayer to detatch the root layer. + virtual void attachRootGraphicsLayer(Frame*, GraphicsLayer*) { } + // Sets a flag to specify that the next time content is drawn to the window, + // the changes appear on the screen in synchrony with updates to GraphicsLayers. + virtual void setNeedsOneShotDrawingSynchronization() { } +#endif + #if PLATFORM(MAC) virtual KeyboardUIMode keyboardUIMode() { return KeyboardAccessDefault; } diff --git a/WebCore/page/Console.cpp b/WebCore/page/Console.cpp index 8755f0e..33128ea 100644 --- a/WebCore/page/Console.cpp +++ b/WebCore/page/Console.cpp @@ -68,7 +68,7 @@ static void printSourceURLAndLine(const String& sourceURL, unsigned lineNumber) } } -static bool getFirstArgumentAsString(const ScriptCallFrame& callFrame, String& result, bool checkForNullOrUndefined = false) +static bool getFirstArgumentAsString(ScriptState* scriptState, const ScriptCallFrame& callFrame, String& result, bool checkForNullOrUndefined = false) { if (!callFrame.argumentCount()) return false; @@ -77,7 +77,8 @@ static bool getFirstArgumentAsString(const ScriptCallFrame& callFrame, String& r if (checkForNullOrUndefined && (value.isNull() || value.isUndefined())) return false; - return value.getString(result); + result = value.toString(scriptState); + return true; } static void printMessageSourceAndLevelPrefix(MessageSource source, MessageLevel level) @@ -99,12 +100,13 @@ static void printMessageSourceAndLevelPrefix(MessageSource source, MessageLevel case CSSMessageSource: sourceString = "CSS"; break; - default: - ASSERT_NOT_REACHED(); - // Fall thru. case OtherMessageSource: sourceString = "OTHER"; break; + default: + ASSERT_NOT_REACHED(); + sourceString = "UNKNOWN"; + break; } const char* levelString; @@ -112,9 +114,6 @@ static void printMessageSourceAndLevelPrefix(MessageSource source, MessageLevel case TipMessageLevel: levelString = "TIP"; break; - default: - ASSERT_NOT_REACHED(); - // Fall thru. case LogMessageLevel: levelString = "LOG"; break; @@ -124,6 +123,22 @@ static void printMessageSourceAndLevelPrefix(MessageSource source, MessageLevel case ErrorMessageLevel: levelString = "ERROR"; break; + case ObjectMessageLevel: + levelString = "OBJECT"; + break; + case TraceMessageLevel: + levelString = "TRACE"; + break; + case StartGroupMessageLevel: + levelString = "START GROUP"; + break; + case EndGroupMessageLevel: + levelString = "END GROUP"; + break; + default: + ASSERT_NOT_REACHED(); + levelString = "UNKNOWN"; + break; } printf("%s %s:", sourceString, levelString); @@ -160,7 +175,7 @@ void Console::addMessage(MessageLevel level, ScriptCallStack* callStack, bool ac return; String message; - if (getFirstArgumentAsString(lastCaller, message)) + if (getFirstArgumentAsString(callStack->state(), lastCaller, message)) page->chrome()->client()->addMessageToConsole(message, lastCaller.lineNumber(), lastCaller.sourceURL().prettyURL()); page->inspectorController()->addMessageToConsole(JSMessageSource, level, callStack); @@ -207,7 +222,8 @@ void Console::dir(ScriptCallStack* callStack) void Console::dirxml(ScriptCallStack* callStack) { - addMessage(NodeMessageLevel, callStack); + // The standard behavior of our console.log will print the DOM tree for nodes. + log(callStack); } void Console::trace(ScriptCallStack* callStack) @@ -243,7 +259,7 @@ void Console::count(ScriptCallStack* callStack) // Follow Firebug's behavior of counting with null and undefined title in // the same bucket as no argument String title; - getFirstArgumentAsString(lastCaller, title); + getFirstArgumentAsString(callStack->state(), lastCaller, title); page->inspectorController()->count(title, lastCaller.lineNumber(), lastCaller.sourceURL().string()); } @@ -256,13 +272,15 @@ void Console::profile(const JSC::UString& title, ScriptCallStack* callStack) if (!page) return; - if (title.isNull()) - return; - // FIXME: log a console message when profiling is disabled. if (!page->inspectorController()->profilerEnabled()) return; + if (title.isNull()) { // no title so give it the next user initiated profile title. + page->inspectorController()->startUserInitiatedProfiling(0); + return; + } + JSC::Profiler::profiler()->startProfiling(callStack->state(), title); } diff --git a/WebCore/page/Console.h b/WebCore/page/Console.h index 7301fc9..2a24a2a 100644 --- a/WebCore/page/Console.h +++ b/WebCore/page/Console.h @@ -64,8 +64,8 @@ namespace WebCore { LogMessageLevel, WarningMessageLevel, ErrorMessageLevel, + // FIXME: the remaining levels should become a new MessageType enum. ObjectMessageLevel, - NodeMessageLevel, TraceMessageLevel, StartGroupMessageLevel, EndGroupMessageLevel diff --git a/WebCore/page/ContextMenuController.cpp b/WebCore/page/ContextMenuController.cpp index 47a0663..522e939 100644 --- a/WebCore/page/ContextMenuController.cpp +++ b/WebCore/page/ContextMenuController.cpp @@ -83,15 +83,10 @@ void ContextMenuController::handleContextMenuEvent(Event* event) if (!event->isMouseEvent()) return; MouseEvent* mouseEvent = static_cast<MouseEvent*>(event); - IntPoint point = IntPoint(mouseEvent->pageX(), mouseEvent->pageY()); - HitTestResult result(point); + HitTestResult result(mouseEvent->absoluteLocation()); - 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 (Frame* frame = event->target()->toNode()->document()->frame()) + result = frame->eventHandler()->hitTestResultAtPoint(mouseEvent->absoluteLocation(), false); if (!result.innerNonSharedNode()) return; @@ -193,14 +188,14 @@ void ContextMenuController::contextMenuItemSelected(ContextMenuItem* item) #endif case ContextMenuItemTagSpellingGuess: ASSERT(frame->selectedText().length()); - if (frame->editor()->shouldInsertText(item->title(), frame->selection()->toRange().get(), + if (frame->editor()->shouldInsertText(item->title(), frame->selection()->toNormalizedRange().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); + frame->revealSelection(ScrollAlignment::alignToEdgeIfNeeded); } break; case ContextMenuItemTagIgnoreSpelling: @@ -238,7 +233,7 @@ void ContextMenuController::contextMenuItemSelected(ContextMenuItem* item) break; case ContextMenuItemTagStartSpeaking: { ExceptionCode ec; - RefPtr<Range> selectedRange = frame->selection()->toRange(); + RefPtr<Range> selectedRange = frame->selection()->toNormalizedRange(); if (!selectedRange || selectedRange->collapsed(ec)) { Document* document = result.innerNonSharedNode()->document(); selectedRange = document->createRange(); diff --git a/WebCore/page/Coordinates.cpp b/WebCore/page/Coordinates.cpp new file mode 100644 index 0000000..637a8c2 --- /dev/null +++ b/WebCore/page/Coordinates.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2009 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Coordinates.h" + +namespace WebCore { + +String Coordinates::toString() const +{ + return String::format("coordinate(%.6lg, %.6lg, %.6lg, %.6lg, %.6lg, %.6lg, %.6lg)", + m_latitude, m_longitude, m_altitude, m_accuracy, + m_altitudeAccuracy, m_heading, m_speed); +} + +} // namespace WebCore diff --git a/WebCore/page/Coordinates.h b/WebCore/page/Coordinates.h new file mode 100644 index 0000000..743b04d --- /dev/null +++ b/WebCore/page/Coordinates.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2009 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef Coordinates_h +#define Coordinates_h + +#include "Event.h" +#include "PlatformString.h" +#include <wtf/RefCounted.h> + +namespace WebCore { + +typedef int ExceptionCode; + +class Coordinates : public RefCounted<Coordinates> { +public: + static PassRefPtr<Coordinates> create(double latitude, double longitude, double altitude, double accuracy, double altitudeAccuracy, double heading, double speed) { return adoptRef(new Coordinates(latitude, longitude, altitude, accuracy, altitudeAccuracy, heading, speed)); } + + double latitude() const { return m_latitude; } + double longitude() const { return m_longitude; } + double altitude() const { return m_altitude; } + double accuracy() const { return m_accuracy; } + double altitudeAccuracy() const { return m_altitudeAccuracy; } + double heading() const { return m_heading; } + double speed() const { return m_speed; } + + String toString() const; + +private: + Coordinates(double latitude, double longitude, double altitude, double accuracy, double altitudeAccuracy, double heading, double speed) + : m_latitude(latitude) + , m_longitude(longitude) + , m_altitude(altitude) + , m_accuracy(accuracy) + , m_altitudeAccuracy(altitudeAccuracy) + , m_heading(heading) + , m_speed(speed) + { + } + + double m_latitude; + double m_longitude; + double m_altitude; + double m_accuracy; + double m_altitudeAccuracy; + double m_heading; + double m_speed; +}; + +} // namespace WebCore + +#endif // Coordinates_h diff --git a/WebCore/page/Coordinates.idl b/WebCore/page/Coordinates.idl new file mode 100644 index 0000000..6318212 --- /dev/null +++ b/WebCore/page/Coordinates.idl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2009 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module core { + + interface Coordinates { + 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; + +#if defined(LANGUAGE_JAVASCRIPT) + [DontEnum] DOMString toString(); +#endif + }; +} diff --git a/WebCore/page/DOMSelection.cpp b/WebCore/page/DOMSelection.cpp index 5dab325..86fe911 100644 --- a/WebCore/page/DOMSelection.cpp +++ b/WebCore/page/DOMSelection.cpp @@ -56,76 +56,89 @@ void DOMSelection::disconnectFrame() m_frame = 0; } -Node* DOMSelection::anchorNode() const +const VisibleSelection& DOMSelection::visibleSelection() const { - if (!m_frame) - return 0; + ASSERT(m_frame); + return m_frame->selection()->selection(); +} - const Selection& selection = m_frame->selection()->selection(); +static Position anchorPosition(const VisibleSelection& selection) +{ Position anchor = selection.isBaseFirst() ? selection.start() : selection.end(); - anchor = rangeCompliantEquivalent(anchor); - return anchor.node(); + return rangeCompliantEquivalent(anchor); } -Node* DOMSelection::baseNode() const +static Position focusPosition(const VisibleSelection& selection) +{ + Position focus = selection.isBaseFirst() ? selection.end() : selection.start(); + return rangeCompliantEquivalent(focus); +} + +static Position basePosition(const VisibleSelection& selection) +{ + return rangeCompliantEquivalent(selection.base()); +} + +static Position extentPosition(const VisibleSelection& selection) +{ + return rangeCompliantEquivalent(selection.extent()); +} + +Node* DOMSelection::anchorNode() const { if (!m_frame) return 0; - return rangeCompliantEquivalent(m_frame->selection()->selection().base()).node(); + return anchorPosition(visibleSelection()).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(); + return anchorPosition(visibleSelection()).m_offset; } -int DOMSelection::baseOffset() const +Node* DOMSelection::focusNode() const { if (!m_frame) return 0; - return rangeCompliantEquivalent(m_frame->selection()->selection().base()).offset(); + return focusPosition(visibleSelection()).node(); } -Node* DOMSelection::focusNode() const +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.node(); + return focusPosition(visibleSelection()).m_offset; } -Node* DOMSelection::extentNode() const +Node* DOMSelection::baseNode() const { if (!m_frame) return 0; - return rangeCompliantEquivalent(m_frame->selection()->selection().extent()).node(); + return basePosition(visibleSelection()).node(); } -int DOMSelection::focusOffset() const +int DOMSelection::baseOffset() const { if (!m_frame) return 0; + return basePosition(visibleSelection()).m_offset; +} - const Selection& selection = m_frame->selection()->selection(); - Position focus = selection.isBaseFirst() ? selection.end() : selection.start(); - focus = rangeCompliantEquivalent(focus); - return focus.offset(); + +Node* DOMSelection::extentNode() const +{ + if (!m_frame) + return 0; + return extentPosition(visibleSelection()).node(); } int DOMSelection::extentOffset() const { if (!m_frame) return 0; - return rangeCompliantEquivalent(m_frame->selection()->selection().extent()).offset(); + return extentPosition(visibleSelection()).m_offset; } bool DOMSelection::isCollapsed() const @@ -142,6 +155,9 @@ String DOMSelection::type() const SelectionController* selection = m_frame->selection(); + // This is a WebKit DOM extension, incompatible with an IE extension + // IE has this same attribute, but returns "none", "text" and "control" + // http://msdn.microsoft.com/en-us/library/ms534692(VS.85).aspx if (selection->isNone()) return "None"; if (selection->isCaret()) @@ -173,7 +189,7 @@ void DOMSelection::collapseToEnd() if (!m_frame) return; - const Selection& selection = m_frame->selection()->selection(); + const VisibleSelection& selection = m_frame->selection()->selection(); m_frame->selection()->moveTo(VisiblePosition(selection.end(), DOWNSTREAM)); } @@ -182,7 +198,7 @@ void DOMSelection::collapseToStart() if (!m_frame) return; - const Selection& selection = m_frame->selection()->selection(); + const VisibleSelection& selection = m_frame->selection()->selection(); m_frame->selection()->moveTo(VisiblePosition(selection.start(), DOWNSTREAM)); } @@ -298,8 +314,11 @@ PassRefPtr<Range> DOMSelection::getRangeAt(int index, ExceptionCode& ec) return 0; } - const Selection& selection = m_frame->selection()->selection(); - return selection.toRange(); + // If you're hitting this, you've added broken multi-range selection support + ASSERT(rangeCount() == 1); + + const VisibleSelection& selection = m_frame->selection()->selection(); + return selection.firstRange(); } void DOMSelection::removeAllRanges() @@ -319,31 +338,31 @@ void DOMSelection::addRange(Range* r) SelectionController* selection = m_frame->selection(); if (selection->isNone()) { - selection->setSelection(Selection(r)); + selection->setSelection(VisibleSelection(r)); return; } - RefPtr<Range> range = selection->selection().toRange(); + RefPtr<Range> range = selection->selection().toNormalizedRange(); 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)); + selection->setSelection(VisibleSelection(r->startPosition(), range->endPosition(), DOWNSTREAM)); else // r contains the original range. - selection->setSelection(Selection(r)); + selection->setSelection(VisibleSelection(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())); + selection->setSelection(VisibleSelection(range.get())); else // The original range and r intersect. - selection->setSelection(Selection(range->startPosition(), r->endPosition(), DOWNSTREAM)); + selection->setSelection(VisibleSelection(range->startPosition(), r->endPosition(), DOWNSTREAM)); } } } @@ -361,7 +380,7 @@ void DOMSelection::deleteFromDocument() if (isCollapsed()) selection->modify(SelectionController::EXTEND, SelectionController::BACKWARD, CharacterGranularity); - RefPtr<Range> selectedRange = selection->selection().toRange(); + RefPtr<Range> selectedRange = selection->selection().toNormalizedRange(); ExceptionCode ec = 0; selectedRange->deleteContents(ec); @@ -383,7 +402,7 @@ bool DOMSelection::containsNode(const Node* n, bool allowPartial) const Node* parentNode = n->parentNode(); unsigned nodeIndex = n->nodeIndex(); - RefPtr<Range> selectedRange = selection->selection().toRange(); + RefPtr<Range> selectedRange = selection->selection().toNormalizedRange(); if (!parentNode) return false; @@ -418,7 +437,7 @@ String DOMSelection::toString() if (!m_frame) return String(); - return plainText(m_frame->selection()->selection().toRange().get()); + return plainText(m_frame->selection()->selection().toNormalizedRange().get()); } } // namespace WebCore diff --git a/WebCore/page/DOMSelection.h b/WebCore/page/DOMSelection.h index fd8d1fc..6a914d6 100644 --- a/WebCore/page/DOMSelection.h +++ b/WebCore/page/DOMSelection.h @@ -40,6 +40,7 @@ namespace WebCore { class Range; class Node; class String; + class VisibleSelection; typedef int ExceptionCode; @@ -88,12 +89,13 @@ namespace WebCore { // Microsoft Selection Object API void empty(); - //void clear(); - //TextRange *createRange(); private: DOMSelection(Frame*); - + + // Convenience method for accessors, does not NULL check m_frame. + const VisibleSelection& visibleSelection() const; + Frame* m_frame; }; diff --git a/WebCore/page/DOMSelection.idl b/WebCore/page/DOMSelection.idl index 85d23bf..a54f9e4 100644 --- a/WebCore/page/DOMSelection.idl +++ b/WebCore/page/DOMSelection.idl @@ -1,5 +1,6 @@ /* * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2009 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,35 +29,30 @@ module window { + // This is based off of Mozilla's Selection interface + // https://developer.mozilla.org/En/DOM/Selection 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(); @@ -65,6 +61,26 @@ module window { #if defined(LANGUAGE_JAVASCRIPT) [DontEnum] DOMString toString(); #endif + + // WebKit extensions + readonly attribute Node baseNode; + readonly attribute long baseOffset; + readonly attribute Node extentNode; + readonly attribute long extentOffset; + + // WebKit's "type" accessor returns "None", "Range" and "Caret" + // IE's type accessor returns "none", "text" and "control" + readonly attribute DOMString type; + + void modify(in DOMString alter, in DOMString direction, in DOMString granularity); + 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); + + // IE extentions + // http://msdn.microsoft.com/en-us/library/ms535869(VS.85).aspx + void empty(); }; } diff --git a/WebCore/page/DOMTimer.cpp b/WebCore/page/DOMTimer.cpp index 911da71..1cc7730 100644 --- a/WebCore/page/DOMTimer.cpp +++ b/WebCore/page/DOMTimer.cpp @@ -27,7 +27,6 @@ #include "config.h" #include "DOMTimer.h" -#include "Document.h" #include "ScheduledAction.h" #include "ScriptExecutionContext.h" #include <wtf/HashSet.h> @@ -39,7 +38,7 @@ namespace WebCore { static const int maxTimerNestingLevel = 5; static const double oneMillisecond = 0.001; -static const double minTimerInterval = 0.010; // 10 milliseconds +double DOMTimer::s_minTimerInterval = 0.010; // 10 milliseconds static int timerNestingLevel = 0; @@ -58,18 +57,15 @@ DOMTimer::DOMTimer(ScriptExecutionContext* context, ScheduledAction* action, int m_nestingLevel = timerNestingLevel + 1; - // FIXME: Move the timeout map and API to ScriptExecutionContext to be able - // to create timeouts from Workers. - ASSERT(scriptExecutionContext() && scriptExecutionContext()->isDocument()); - static_cast<Document*>(scriptExecutionContext())->addTimeout(m_timeoutId, this); + scriptExecutionContext()->addTimeout(m_timeoutId, this); double intervalMilliseconds = max(oneMillisecond, timeout * oneMillisecond); // Use a minimum interval of 10 ms to match other browsers, but only once we've // nested enough to notice that we're repeating. // Faster timers might be "better", but they're incompatible. - if (intervalMilliseconds < minTimerInterval && m_nestingLevel >= maxTimerNestingLevel) - intervalMilliseconds = minTimerInterval; + if (intervalMilliseconds < s_minTimerInterval && m_nestingLevel >= maxTimerNestingLevel) + intervalMilliseconds = s_minTimerInterval; if (singleShot) startOneShot(intervalMilliseconds); else @@ -79,8 +75,7 @@ DOMTimer::DOMTimer(ScriptExecutionContext* context, ScheduledAction* action, int DOMTimer::~DOMTimer() { if (scriptExecutionContext()) { - ASSERT(scriptExecutionContext()->isDocument()); - static_cast<Document*>(scriptExecutionContext())->removeTimeout(m_timeoutId); + scriptExecutionContext()->removeTimeout(m_timeoutId); } } @@ -100,8 +95,7 @@ void DOMTimer::removeById(ScriptExecutionContext* context, int timeoutId) // respectively if (timeoutId <= 0) return; - ASSERT(context && context->isDocument()); - delete static_cast<Document*>(context)->findTimeout(timeoutId); + delete context->findTimeout(timeoutId); } void DOMTimer::fired() @@ -111,10 +105,10 @@ void DOMTimer::fired() // Simple case for non-one-shot timers. if (isActive()) { - if (repeatInterval() && repeatInterval() < minTimerInterval) { + if (repeatInterval() && repeatInterval() < s_minTimerInterval) { m_nestingLevel++; if (m_nestingLevel >= maxTimerNestingLevel) - augmentRepeatInterval(minTimerInterval - repeatInterval()); + augmentRepeatInterval(s_minTimerInterval - repeatInterval()); } // No access to member variables after this point, it can delete the timer. diff --git a/WebCore/page/DOMTimer.h b/WebCore/page/DOMTimer.h index 200b9b1..f6343fc 100644 --- a/WebCore/page/DOMTimer.h +++ b/WebCore/page/DOMTimer.h @@ -51,6 +51,12 @@ public: virtual void suspend(); virtual void resume(); + // The lowest allowable timer setting (in seconds, 0.001 == 1 ms). + // Default is 10ms. + // Chromium uses a non-default timeout. + static double minTimerInterval() { return s_minTimerInterval; } + static void setMinTimerInterval(double value) { s_minTimerInterval = value; } + private: DOMTimer(ScriptExecutionContext*, ScheduledAction*, int timeout, bool singleShot); virtual void fired(); @@ -60,6 +66,7 @@ private: OwnPtr<ScheduledAction> m_action; double m_nextFireInterval; double m_repeatInterval; + static double s_minTimerInterval; }; } // namespace WebCore diff --git a/WebCore/page/DOMWindow.cpp b/WebCore/page/DOMWindow.cpp index 70ee79e..f6fde05 100644 --- a/WebCore/page/DOMWindow.cpp +++ b/WebCore/page/DOMWindow.cpp @@ -46,6 +46,7 @@ #include "FrameView.h" #include "HTMLFrameOwnerElement.h" #include "History.h" +#include "InspectorController.h" #include "Location.h" #include "MessageEvent.h" #include "Navigator.h" @@ -56,6 +57,7 @@ #include "Screen.h" #include "SecurityOrigin.h" #include "Settings.h" +#include "WebKitPoint.h" #include <algorithm> #include <wtf/MathExtras.h> @@ -323,10 +325,10 @@ Storage* DOMWindow::sessionStorage() const return 0; Document* document = m_frame->document(); - if (!document) - return 0; RefPtr<StorageArea> storageArea = page->sessionStorage()->storageArea(document->securityOrigin()); + page->inspectorController()->didUseDOMStorage(storageArea.get(), false, m_frame); + m_sessionStorage = Storage::create(m_frame, storageArea.release()); return m_sessionStorage.get(); } @@ -347,8 +349,10 @@ Storage* DOMWindow::localStorage() const LocalStorage* localStorage = page->group().localStorage(); RefPtr<StorageArea> storageArea = localStorage ? localStorage->storageArea(document->securityOrigin()) : 0; - if (storageArea) + if (storageArea) { + page->inspectorController()->didUseDOMStorage(storageArea.get(), true, m_frame); m_localStorage = Storage::create(m_frame, storageArea.release()); + } return m_localStorage.get(); } @@ -449,7 +453,20 @@ void DOMWindow::close() if (!m_frame) return; - if (m_frame->loader()->openedByDOM() || m_frame->loader()->getHistoryLength() <= 1) + Page* page = m_frame->page(); + if (!page) + return; + + if (m_frame != page->mainFrame()) + return; + + Settings* settings = m_frame->settings(); + bool allowScriptsToCloseWindows = + settings && settings->allowScriptsToCloseWindows(); + + if (m_frame->loader()->openedByDOM() + || m_frame->loader()->getHistoryLength() <= 1 + || allowScriptsToCloseWindows) m_frame->scheduleClose(); } @@ -480,10 +497,7 @@ void DOMWindow::alert(const String& message) if (!m_frame) return; - Document* doc = m_frame->document(); - ASSERT(doc); - if (doc) - doc->updateRendering(); + m_frame->document()->updateRendering(); Page* page = m_frame->page(); if (!page) @@ -497,10 +511,7 @@ bool DOMWindow::confirm(const String& message) if (!m_frame) return false; - Document* doc = m_frame->document(); - ASSERT(doc); - if (doc) - doc->updateRendering(); + m_frame->document()->updateRendering(); Page* page = m_frame->page(); if (!page) @@ -514,10 +525,7 @@ 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(); + m_frame->document()->updateRendering(); Page* page = m_frame->page(); if (!page) @@ -625,10 +633,7 @@ int DOMWindow::scrollX() const if (!view) return 0; - Document* doc = m_frame->document(); - ASSERT(doc); - if (doc) - doc->updateLayoutIgnorePendingStylesheets(); + m_frame->document()->updateLayoutIgnorePendingStylesheets(); return static_cast<int>(view->scrollX() / m_frame->pageZoomFactor()); } @@ -649,10 +654,7 @@ int DOMWindow::scrollY() const if (!view) return 0; - Document* doc = m_frame->document(); - ASSERT(doc); - if (doc) - doc->updateLayoutIgnorePendingStylesheets(); + m_frame->document()->updateLayoutIgnorePendingStylesheets(); return static_cast<int>(view->scrollY() / m_frame->pageZoomFactor()); } @@ -786,15 +788,32 @@ PassRefPtr<CSSRuleList> DOMWindow::getMatchedCSSRules(Element* elt, const String 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); } +PassRefPtr<WebKitPoint> DOMWindow::webkitConvertPointFromNodeToPage(Node* node, const WebKitPoint* p) const +{ + if (!node || !p) + return 0; + + FloatPoint pagePoint(p->x(), p->y()); + pagePoint = node->convertToPage(pagePoint); + return WebKitPoint::create(pagePoint.x(), pagePoint.y()); +} + +PassRefPtr<WebKitPoint> DOMWindow::webkitConvertPointFromPageToNode(Node* node, const WebKitPoint* p) const +{ + if (!node || !p) + return 0; + + FloatPoint nodePoint(p->x(), p->y()); + nodePoint = node->convertFromPage(nodePoint); + return WebKitPoint::create(nodePoint.x(), nodePoint.y()); +} + double DOMWindow::devicePixelRatio() const { if (!m_frame) @@ -814,9 +833,6 @@ PassRefPtr<Database> DOMWindow::openDatabase(const String& name, const String& v return 0; Document* doc = m_frame->document(); - ASSERT(doc); - if (!doc) - return 0; Settings* settings = m_frame->settings(); if (!settings || !settings->databasesEnabled()) @@ -831,10 +847,7 @@ void DOMWindow::scrollBy(int x, int y) const if (!m_frame) return; - Document* doc = m_frame->document(); - ASSERT(doc); - if (doc) - doc->updateLayoutIgnorePendingStylesheets(); + m_frame->document()->updateLayoutIgnorePendingStylesheets(); FrameView* view = m_frame->view(); if (!view) @@ -848,10 +861,7 @@ void DOMWindow::scrollTo(int x, int y) const if (!m_frame) return; - Document* doc = m_frame->document(); - ASSERT(doc); - if (doc) - doc->updateLayoutIgnorePendingStylesheets(); + m_frame->document()->updateLayoutIgnorePendingStylesheets(); FrameView* view = m_frame->view(); if (!view) diff --git a/WebCore/page/DOMWindow.h b/WebCore/page/DOMWindow.h index da84e35..b779cbd 100644 --- a/WebCore/page/DOMWindow.h +++ b/WebCore/page/DOMWindow.h @@ -52,6 +52,8 @@ namespace WebCore { class Navigator; class PostMessageTimer; class Screen; + class WebKitPoint; + class Node; #if ENABLE(DOM_STORAGE) class SessionStorage; @@ -163,6 +165,9 @@ namespace WebCore { PassRefPtr<CSSRuleList> getMatchedCSSRules(Element*, const String& pseudoElt, bool authorOnly = true) const; double devicePixelRatio() const; + PassRefPtr<WebKitPoint> webkitConvertPointFromPageToNode(Node* node, const WebKitPoint* p) const; + PassRefPtr<WebKitPoint> webkitConvertPointFromNodeToPage(Node* node, const WebKitPoint* p) 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&); diff --git a/WebCore/page/DOMWindow.idl b/WebCore/page/DOMWindow.idl index 78c780f..6bb08a8 100644 --- a/WebCore/page/DOMWindow.idl +++ b/WebCore/page/DOMWindow.idl @@ -53,7 +53,7 @@ module window { attribute [Replaceable] BarInfo toolbar; attribute [Replaceable] Navigator navigator; attribute [Replaceable] Navigator clientInformation; - attribute [DoNotCheckDomainSecurity, CustomSetter] Location location; + attribute [DoNotCheckDomainSecurity, CustomSetter, V8DisallowShadowing] Location location; DOMSelection getSelection(); @@ -120,12 +120,12 @@ module window { // Self referential attributes attribute [Replaceable, DoNotCheckDomainSecurityOnGet] DOMWindow self; - readonly attribute [DoNotCheckDomainSecurity] DOMWindow window; + readonly attribute [DoNotCheckDomainSecurity, V8DisallowShadowing] DOMWindow window; attribute [Replaceable, DoNotCheckDomainSecurityOnGet] DOMWindow frames; - attribute [Replaceable, DoNotCheckDomainSecurityOnGet] DOMWindow opener; + attribute [Replaceable, DoNotCheckDomainSecurityOnGet, V8CustomSetter] DOMWindow opener; attribute [Replaceable, DoNotCheckDomainSecurity] DOMWindow parent; - attribute [Replaceable, DoNotCheckDomainSecurity] DOMWindow top; + attribute [Replaceable, DoNotCheckDomainSecurity, V8DisallowShadowing, V8ReadOnly] DOMWindow top; // DOM Level 2 AbstractView Interface readonly attribute Document document; @@ -139,6 +139,9 @@ module window { in DOMString pseudoElement, in [Optional] boolean authorOnly); attribute [Replaceable] double devicePixelRatio; + + WebKitPoint webkitConvertPointFromPageToNode(in Node node, in WebKitPoint p); + WebKitPoint webkitConvertPointFromNodeToPage(in Node node, in WebKitPoint p); #if ENABLE_OFFLINE_WEB_APPLICATIONS readonly attribute DOMApplicationCache applicationCache; @@ -210,12 +213,17 @@ module window { attribute [ProtectedListener] EventListener ontouchcancel; #endif +#if defined(V8_BINDING) + attribute [ProtectedListener] EventListener ondragdrop; + attribute [ProtectedListener] EventListener onmove; +#endif + // EventTarget interface - [Custom] void addEventListener(in DOMString type, - in EventListener listener, + [Custom] void addEventListener(in DOMString type, + in EventListener listener, in boolean useCapture); - [Custom] void removeEventListener(in DOMString type, - in EventListener listener, + [Custom] void removeEventListener(in DOMString type, + in EventListener listener, in boolean useCapture); // FIXME: Implement dispatchEvent @@ -384,6 +392,17 @@ module window { attribute XMLHttpRequestUploadConstructor XMLHttpRequestUpload; attribute XMLHttpRequestExceptionConstructor XMLHttpRequestException; +#if defined(V8_BINDING) + // With JSC, these are added in JSDOMWindowBase.cpp. + attribute XMLHttpRequestConstructor XMLHttpRequest; + attribute XSLTProcessorConstructor XSLTProcessor; + attribute MessageChannelConstructor MessageChannel; + attribute WebKitPointConstructor WebKitPoint; +#if ENABLE_WORKERS + attribute WorkerConstructor Worker; +#endif + attribute WebKitCSSMatrixConstructor WebKitCSSMatrix; +#endif // V8_BINDING attribute PluginConstructor Plugin; attribute PluginArrayConstructor PluginArray; @@ -391,6 +410,9 @@ module window { attribute MimeTypeConstructor MimeType; attribute MimeTypeArrayConstructor MimeTypeArray; + attribute ClientRectConstructor ClientRect; + attribute ClientRectListConstructor ClientRectList; + #if ENABLE_DOM_STORAGE attribute StorageConstructor Storage; attribute StorageEventConstructor StorageEvent; @@ -440,6 +462,26 @@ module window { #endif #endif // defined(LANGUAGE_JAVASCRIPT) - }; +#if defined(V8_BINDING) + // These were implemented in JSCDOMWindowBase and not moved to IDL yet. + + [Custom] DOMWindow open(in DOMString url, + in DOMString name, + in [Optional] DOMString options); + + [Custom] DOMObject showModalDialog(in DOMString url, + in [Optional] DOMObject dialogArgs, + in [Optional] DOMString featureArgs); + + // These are defined on JSDOMWindowBase, but not implemented. + [Custom=DOMWindowNOP] void captureEvents(in long eventFlags); + [Custom=DOMWindowNOP] void releaseEvents(in long eventFlags); + + // window.toString requires special handling + [V8DoNotCheckSignature, DoNotCheckDomainSecurity, Custom, DontEnum] DOMString toString(); +#endif // defined(V8_BINDING) + }; } + + diff --git a/WebCore/page/DragController.cpp b/WebCore/page/DragController.cpp index 9911f34..cba109a 100644 --- a/WebCore/page/DragController.cpp +++ b/WebCore/page/DragController.cpp @@ -107,9 +107,9 @@ static PassRefPtr<DocumentFragment> documentFragmentFromDragData(DragData* dragD String title; String url = dragData->asURL(&title); if (!url.isEmpty()) { - ExceptionCode ec; - RefPtr<HTMLAnchorElement> anchor = static_cast<HTMLAnchorElement*>(document->createElement("a", ec).get()); + RefPtr<HTMLAnchorElement> anchor = new HTMLAnchorElement(document); anchor->setHref(url); + ExceptionCode ec; RefPtr<Node> anchorText = document->createTextNode(title); anchor->appendChild(anchorText, ec); RefPtr<DocumentFragment> fragment = document->createDocumentFragment(); @@ -280,7 +280,7 @@ DragOperation DragController::tryDocumentDrag(DragData* dragData, DragDestinatio Frame* innerFrame = element->document()->frame(); ASSERT(innerFrame); if (!asFileInput(element)) { - Selection dragCaret; + VisibleSelection dragCaret; if (Frame* frame = m_document->frame()) dragCaret = frame->visiblePositionForPoint(point); m_page->dragCaretController()->setSelection(dragCaret); @@ -309,13 +309,13 @@ DragOperation DragController::operationForLoad(DragData* dragData) return dragOperation(dragData); } -static bool setSelectionToDragCaret(Frame* frame, Selection& dragCaret, RefPtr<Range>& range, const IntPoint& point) +static bool setSelectionToDragCaret(Frame* frame, VisibleSelection& 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(); + range = dragCaret.toNormalizedRange(); } return !frame->selection()->isNone() && frame->selection()->isContentEditable(); } @@ -340,7 +340,7 @@ bool DragController::concludeEditDrag(DragData* dragData) return false; if (!innerFrame) return false; - RefPtr<Range> innerRange = innerFrame->selection()->toRange(); + RefPtr<Range> innerRange = innerFrame->selection()->toNormalizedRange(); RefPtr<CSSStyleDeclaration> style = m_document->createCSSStyleDeclaration(); ExceptionCode ec; style->setProperty("color", color.name(), ec); @@ -381,9 +381,9 @@ bool DragController::concludeEditDrag(DragData* dragData) return true; } - Selection dragCaret(m_page->dragCaretController()->selection()); + VisibleSelection dragCaret(m_page->dragCaretController()->selection()); m_page->dragCaretController()->clear(); - RefPtr<Range> range = dragCaret.toRange(); + RefPtr<Range> range = dragCaret.toNormalizedRange(); // For range to be null a WebKit client must have done something bad while // manually controlling drag behaviour @@ -531,7 +531,7 @@ static CachedImage* getCachedImage(Element* element) RenderObject* renderer = element->renderer(); if (!renderer || !renderer->isImage()) return 0; - RenderImage* image = static_cast<RenderImage*>(renderer); + RenderImage* image = toRenderImage(renderer); return image->cachedImage(); } @@ -542,7 +542,7 @@ static Image* getImage(Element* element) if (!renderer || !renderer->isImage()) return 0; - RenderImage* image = static_cast<RenderImage*>(renderer); + RenderImage* image = toRenderImage(renderer); if (image->cachedImage() && !image->cachedImage()->errorOccurred()) return image->cachedImage()->image(); return 0; @@ -554,7 +554,7 @@ static void prepareClipboardForImageDrag(Frame* src, Clipboard* clipboard, Eleme ExceptionCode ec = 0; range->selectNode(node, ec); ASSERT(ec == 0); - src->selection()->setSelection(Selection(range.get(), DOWNSTREAM)); + src->selection()->setSelection(VisibleSelection(range.get(), DOWNSTREAM)); clipboard->declareAndWriteDragImage(node, !linkURL.isEmpty() ? linkURL : imageURL, label, src); } @@ -661,7 +661,7 @@ bool DragController::startDrag(Frame* src, Clipboard* clipboard, DragOperation s Position pos = src->selection()->base(); Node* node = enclosingAnchorElement(pos); if (node) - src->selection()->setSelection(Selection::selectionFromContentsOfNode(node)); + src->selection()->setSelection(VisibleSelection::selectionFromContentsOfNode(node)); } m_client->willPerformDragSourceAction(DragSourceActionLink, dragOrigin, clipboard); @@ -673,7 +673,7 @@ bool DragController::startDrag(Frame* src, Clipboard* clipboard, DragOperation s } doSystemDrag(dragImage, dragLoc, mouseDraggedPoint, clipboard, src, true); } else if (isSelected && (m_dragSourceAction & DragSourceActionSelection)) { - RefPtr<Range> selectionRange = src->selection()->toRange(); + RefPtr<Range> selectionRange = src->selection()->toNormalizedRange(); ASSERT(selectionRange); if (!clipboard->hasData()) clipboard->writeRange(selectionRange.get(), src); @@ -771,7 +771,7 @@ void DragController::placeDragCaret(const IntPoint& windowPoint) if (!frameView) return; IntPoint framePoint = frameView->windowToContents(windowPoint); - Selection dragCaret(frame->visiblePositionForPoint(framePoint)); + VisibleSelection dragCaret(frame->visiblePositionForPoint(framePoint)); m_page->dragCaretController()->setSelection(dragCaret); } diff --git a/WebCore/page/EditorClient.h b/WebCore/page/EditorClient.h index 56d0435..67462c5 100644 --- a/WebCore/page/EditorClient.h +++ b/WebCore/page/EditorClient.h @@ -50,7 +50,7 @@ class HTMLElement; class KeyboardEvent; class Node; class Range; -class Selection; +class VisibleSelection; class String; class VisiblePosition; @@ -61,6 +61,13 @@ struct GrammarDetail { String userDescription; }; +struct TextCheckingResult { + int resultType; // 1 for spelling, 2 for grammar + int location; + int length; + Vector<GrammarDetail> details; +}; + class EditorClient { public: virtual ~EditorClient() { } @@ -130,6 +137,9 @@ public: 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; +#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + virtual void checkSpellingAndGrammarOfParagraph(const UChar* text, int length, bool checkGrammar, Vector<TextCheckingResult>& results) = 0; +#endif virtual void updateSpellingUIWithGrammarString(const String&, const GrammarDetail& detail) = 0; virtual void updateSpellingUIWithMisspelledWord(const String&) = 0; virtual void showSpellingUI(bool show) = 0; diff --git a/WebCore/page/EventHandler.cpp b/WebCore/page/EventHandler.cpp index 8cb46b7..7e79792 100644 --- a/WebCore/page/EventHandler.cpp +++ b/WebCore/page/EventHandler.cpp @@ -57,6 +57,7 @@ #include "PlatformKeyboardEvent.h" #include "PlatformWheelEvent.h" #include "RenderFrameSet.h" +#include "RenderTextControlSingleLine.h" #include "RenderWidget.h" #include "RenderView.h" #include "Scrollbar.h" @@ -117,8 +118,6 @@ static inline void scrollAndAcceptEvent(float delta, ScrollDirection positiveDir return; } float pixelsToScroll = delta > 0 ? delta : -delta; - if (e.granularity() == ScrollByLineWheelEvent) - pixelsToScroll *= cMouseWheelPixelsPerLineStep; if (enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPixel, pixelsToScroll)) e.accept(); } @@ -126,6 +125,7 @@ static inline void scrollAndAcceptEvent(float delta, ScrollDirection positiveDir EventHandler::EventHandler(Frame* frame) : m_frame(frame) , m_mousePressed(false) + , m_capturesDragging(false) , m_mouseDownMayStartSelect(false) , m_mouseDownMayStartDrag(false) , m_mouseDownWasSingleClickInSelection(false) @@ -186,18 +186,19 @@ void EventHandler::clear() m_currentMousePosition = IntPoint(); m_mousePressNode = 0; m_mousePressed = false; + m_capturesDragging = false; m_capturingMouseEventsNode = 0; } void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& result) { Node* innerNode = result.targetNode(); - Selection newSelection; + VisibleSelection newSelection; if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) { VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint())); if (pos.isNotNull()) { - newSelection = Selection(pos); + newSelection = VisibleSelection(pos); newSelection.expandUsingGranularity(WordGranularity); } @@ -221,11 +222,11 @@ void EventHandler::selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHit Node* innerNode = result.targetNode(); if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) { - Selection newSelection; + VisibleSelection 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); + newSelection = VisibleSelection::selectionFromContentsOfNode(URLElement); if (newSelection.isRange()) { m_frame->setSelectionGranularity(WordGranularity); @@ -264,10 +265,10 @@ bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestR if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect)) return false; - Selection newSelection; + VisibleSelection newSelection; VisiblePosition pos(innerNode->renderer()->positionForPoint(event.localPoint())); if (pos.isNotNull()) { - newSelection = Selection(pos); + newSelection = VisibleSelection(pos); newSelection.expandUsingGranularity(ParagraphGranularity); } if (newSelection.isRange()) { @@ -283,9 +284,6 @@ bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestR 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; @@ -306,7 +304,7 @@ bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestR visiblePos = VisiblePosition(innerNode, 0, DOWNSTREAM); Position pos = visiblePos.deepEquivalent(); - Selection newSelection = m_frame->selection()->selection(); + VisibleSelection newSelection = m_frame->selection()->selection(); if (extendSelection && newSelection.isCaretOrRange()) { m_frame->selection()->setLastChangeWasHorizontalExtension(false); @@ -314,17 +312,17 @@ bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestR // 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()); + short before = Range::compareBoundaryPoints(pos.node(), pos.m_offset, start.node(), start.m_offset); if (before <= 0) - newSelection = Selection(pos, end); + newSelection = VisibleSelection(pos, end); else - newSelection = Selection(start, pos); + newSelection = VisibleSelection(start, pos); if (m_frame->selectionGranularity() != CharacterGranularity) newSelection.expandUsingGranularity(m_frame->selectionGranularity()); m_beganSelectingText = true; } else { - newSelection = Selection(visiblePos); + newSelection = VisibleSelection(visiblePos); m_frame->setSelectionGranularity(CharacterGranularity); } @@ -375,18 +373,16 @@ bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& eve 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_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->renderBox() && m_mousePressNode->renderBox()->canBeProgramaticallyScrolled(true)); @@ -451,7 +447,7 @@ bool EventHandler::eventMayStartDrag(const PlatformMouseEvent& event) const if (!DHTMLFlag && !UAFlag) return false; - HitTestRequest request(true, false); + HitTestRequest request(HitTestRequest::ReadOnly); HitTestResult result(m_frame->view()->windowToContents(event.pos())); m_frame->contentRenderer()->layer()->hitTest(request, result); bool srcIsDHTML; @@ -470,8 +466,11 @@ void EventHandler::updateSelectionForMouseDrag() if (!layer) return; + HitTestRequest request(HitTestRequest::ReadOnly | + HitTestRequest::Active | + HitTestRequest::MouseMove); HitTestResult result(view->windowToContents(m_currentMousePosition)); - layer->hitTest(HitTestRequest(true, true, true), result); + layer->hitTest(request, result); updateSelectionForMouseDrag(result.innerNode(), result.localPoint()); } @@ -498,7 +497,7 @@ void EventHandler::updateSelectionForMouseDrag(Node* targetNode, const IntPoint& // 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(); + VisibleSelection newSelection = m_frame->selection()->selection(); #if ENABLE(SVG) // Special case to limit selection to the containing block for SVG text. @@ -512,7 +511,7 @@ void EventHandler::updateSelectionForMouseDrag(Node* targetNode, const IntPoint& if (!m_beganSelectingText) { m_beganSelectingText = true; - newSelection = Selection(targetPosition); + newSelection = VisibleSelection(targetPosition); } newSelection.setExtent(targetPosition); @@ -550,6 +549,7 @@ bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& e // the mouse is pressed again. m_frame->selection()->setCaretBlinkingSuspended(false); m_mousePressed = false; + m_capturesDragging = false; m_mouseDownMayStartDrag = false; m_mouseDownMayStartSelect = false; m_mouseDownMayStartAutoscroll = false; @@ -563,11 +563,11 @@ bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& e if (m_mouseDownWasSingleClickInSelection && !m_beganSelectingText && m_dragStartPos == event.event().pos() && m_frame->selection()->isRange()) { - Selection newSelection; + VisibleSelection newSelection; Node *node = event.targetNode(); if (node && node->isContentEditable() && node->renderer()) { VisiblePosition pos = node->renderer()->positionForPoint(event.localPoint()); - newSelection = Selection(pos); + newSelection = VisibleSelection(pos); } if (m_frame->shouldChangeSelection(newSelection)) m_frame->selection()->setSelection(newSelection); @@ -630,6 +630,7 @@ void EventHandler::autoscrollTimerFired(Timer<EventHandler>*) } } +#if ENABLE(PAN_SCROLLING) void EventHandler::setPanScrollCursor() { // At the original click location we draw a 4 arrowed icon. Over this icon there won't be any scroll @@ -661,6 +662,7 @@ void EventHandler::setPanScrollCursor() else m_frame->view()->setCursor(middlePanningCursor()); } +#endif // ENABLE(PAN_SCROLLING) RenderObject* EventHandler::autoscrollRenderer() const { @@ -688,7 +690,7 @@ void EventHandler::setAutoscrollRenderer(RenderObject* renderer) void EventHandler::allowDHTMLDrag(bool& flagDHTML, bool& flagUA) const { - if (!m_frame || !m_frame->document()) { + if (!m_frame) { flagDHTML = false; flagUA = false; return; @@ -699,12 +701,15 @@ void EventHandler::allowDHTMLDrag(bool& flagDHTML, bool& flagUA) const flagUA = ((mask & DragSourceActionImage) || (mask & DragSourceActionLink) || (mask & DragSourceActionSelection)); } -HitTestResult EventHandler::hitTestResultAtPoint(const IntPoint& point, bool allowShadowContent) +HitTestResult EventHandler::hitTestResultAtPoint(const IntPoint& point, bool allowShadowContent, bool ignoreClipping) { HitTestResult result(point); if (!m_frame->contentRenderer()) return result; - m_frame->contentRenderer()->layer()->hitTest(HitTestRequest(true, true), result); + int hitType = HitTestRequest::ReadOnly | HitTestRequest::Active; + if (ignoreClipping) + hitType |= HitTestRequest::IgnoreClipping; + m_frame->contentRenderer()->layer()->hitTest(HitTestRequest(hitType), result); while (true) { Node* n = result.innerNode(); @@ -721,7 +726,7 @@ HitTestResult EventHandler::hitTestResultAtPoint(const IntPoint& point, bool all IntPoint widgetPoint(result.localPoint().x() + view->scrollX() - renderWidget->borderLeft() - renderWidget->paddingLeft(), result.localPoint().y() + view->scrollY() - renderWidget->borderTop() - renderWidget->paddingTop()); HitTestResult widgetHitTestResult(widgetPoint); - frame->contentRenderer()->layer()->hitTest(HitTestRequest(true, true), widgetHitTestResult); + frame->contentRenderer()->layer()->hitTest(HitTestRequest(hitType), widgetHitTestResult); result = widgetHitTestResult; } @@ -732,7 +737,7 @@ HitTestResult EventHandler::hitTestResultAtPoint(const IntPoint& point, bool all 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); + result = mainFrame->eventHandler()->hitTestResultAtPoint(mainFramePoint, allowShadowContent, ignoreClipping); } if (!allowShadowContent) @@ -791,9 +796,6 @@ void EventHandler::setMousePressNode(PassRefPtr<Node> 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(); @@ -1002,12 +1004,10 @@ Cursor EventHandler::selectCursor(const MouseEventWithHitTestResults& event, Scr bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent) { - if (!m_frame->document()) - return false; - RefPtr<FrameView> protector(m_frame->view()); m_mousePressed = true; + m_capturesDragging = true; m_currentMousePosition = mouseEvent.pos(); m_mouseDownTimestamp = mouseEvent.timestamp(); m_mouseDownMayStartDrag = false; @@ -1016,7 +1016,8 @@ bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent) m_mouseDownPos = m_frame->view()->windowToContents(mouseEvent.pos()); m_mouseDownWasInSubframe = false; - MouseEventWithHitTestResults mev = prepareMouseEvent(HitTestRequest(false, true), mouseEvent); + HitTestRequest request(HitTestRequest::Active); + MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent); if (!mev.targetNode()) { invalidateClick(); @@ -1036,7 +1037,8 @@ bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent) 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_capturesDragging = subframe->eventHandler()->capturesDragging(); + if (m_mousePressed && m_capturesDragging) m_capturingMouseEventsNode = mev.targetNode(); invalidateClick(); return true; @@ -1082,12 +1084,15 @@ bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent) } bool swallowEvent = dispatchMouseEvent(eventNames().mousedownEvent, mev.targetNode(), true, m_clickCount, mouseEvent, true); + m_capturesDragging = !swallowEvent; // 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); + HitTestRequest request(HitTestRequest::ReadOnly | + HitTestRequest::Active); + mev = prepareMouseEvent(request, mouseEvent); if (wasLastScrollBar && mev.scrollbar() != m_lastScrollbarUnderMouse.get()) m_lastScrollbarUnderMouse = 0; @@ -1102,8 +1107,11 @@ bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent) // If a mouse event handler changes the input element type to one that has a widget associated, // we'd like to EventHandler::handleMousePressEvent to pass the event to the widget and thus the // event target node can't still be the shadow node. - if (mev.targetNode()->isShadowNode() && mev.targetNode()->shadowParentNode()->hasTagName(inputTag)) - mev = prepareMouseEvent(HitTestRequest(true, true), mouseEvent); + if (mev.targetNode()->isShadowNode() && mev.targetNode()->shadowParentNode()->hasTagName(inputTag)) { + HitTestRequest request(HitTestRequest::ReadOnly | + HitTestRequest::Active); + mev = prepareMouseEvent(request, mouseEvent); + } Scrollbar* scrollbar = m_frame->view()->scrollbarUnderMouse(mouseEvent); if (!scrollbar) @@ -1120,16 +1128,14 @@ bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent) // 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); + HitTestRequest request(HitTestRequest::Active); + MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent); Frame* subframe = subframeForHitTestResult(mev); if (subframe && passMousePressEventToSubframe(mev, subframe)) { m_capturingMouseEventsNode = 0; @@ -1178,7 +1184,7 @@ bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent, Hi // 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()) + if (!m_frame) return false; RefPtr<FrameView> protector(m_frame->view()); @@ -1205,7 +1211,12 @@ bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent, Hi // 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); + int hitType = HitTestRequest::MouseMove; + if (m_mousePressed && m_mouseDownMayStartSelect) + hitType |= HitTestRequest::ReadOnly; + if (m_mousePressed) + hitType |= HitTestRequest::Active; + HitTestRequest request(hitType); MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent); if (hoveredNode) *hoveredNode = mev.hitTestResult(); @@ -1271,9 +1282,6 @@ void EventHandler::invalidateClick() bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent) { - if (!m_frame->document()) - return false; - RefPtr<FrameView> protector(m_frame->view()); m_mousePressed = false; @@ -1295,7 +1303,8 @@ bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent) return m_lastScrollbarUnderMouse->mouseUp(); } - MouseEventWithHitTestResults mev = prepareMouseEvent(HitTestRequest(false, false, false, true), mouseEvent); + HitTestRequest request(HitTestRequest::MouseUp); + MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent); Frame* subframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev); if (subframe && passMouseReleaseEventToSubframe(mev, subframe)) { m_capturingMouseEventsNode = 0; @@ -1325,6 +1334,8 @@ bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent) bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Node* dragTarget, const PlatformMouseEvent& event, Clipboard* clipboard) { + m_frame->view()->resetDeferredRepaintDelay(); + IntPoint contentsPos = m_frame->view()->windowToContents(event.pos()); RefPtr<MouseEvent> me = MouseEvent::create(eventType, @@ -1334,7 +1345,7 @@ bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Node* dragTa 0, 0, clipboard); ExceptionCode ec = 0; - EventTargetNodeCast(dragTarget)->dispatchEvent(me.get(), ec); + dragTarget->dispatchEvent(me.get(), ec); return me->defaultPrevented(); } @@ -1342,13 +1353,11 @@ bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard* { bool accept = false; - if (!m_frame->document()) - return false; - if (!m_frame->view()) return false; - - MouseEventWithHitTestResults mev = prepareMouseEvent(HitTestRequest(true, false), event); + + HitTestRequest request(HitTestRequest::ReadOnly); + MouseEventWithHitTestResults mev = prepareMouseEvent(request, event); // Drag events should never go to text nodes (following IE, and proper mouseover/out dispatch) Node* newTarget = mev.targetNode(); @@ -1361,12 +1370,13 @@ bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard* // 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) { 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; @@ -1376,11 +1386,12 @@ bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard* dispatchDragEvent(eventNames().dragleaveEvent, m_dragTarget.get(), event, clipboard); } } else { - if (newTarget) + 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; @@ -1520,10 +1531,10 @@ void EventHandler::updateMouseEventTargetNode(Node* targetNode, const PlatformMo 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()); + m_lastNodeUnderMouse->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_nodeUnderMouse->dispatchMouseEvent(mouseEvent, eventNames().mouseoverEvent, 0, m_lastNodeUnderMouse.get()); } m_lastNodeUnderMouse = m_nodeUnderMouse; #if ENABLE(SVG) @@ -1534,12 +1545,14 @@ void EventHandler::updateMouseEventTargetNode(Node* targetNode, const PlatformMo bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targetNode, bool /*cancelable*/, int clickCount, const PlatformMouseEvent& mouseEvent, bool setUnder) { + m_frame->view()->resetDeferredRepaintDelay(); + updateMouseEventTargetNode(targetNode, mouseEvent, setUnder); bool swallowEvent = false; if (m_nodeUnderMouse) - swallowEvent = EventTargetNodeCast(m_nodeUnderMouse.get())->dispatchMouseEvent(mouseEvent, eventType, clickCount); + swallowEvent = m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, eventType, clickCount); if (!swallowEvent && eventType == eventNames().mousedownEvent) { // Blur current focus node when a link/button is clicked; this @@ -1551,7 +1564,7 @@ bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targe // 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(); + node = renderer->node(); 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 @@ -1560,7 +1573,7 @@ bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targe 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 && + m_frame->selection()->toNormalizedRange()->compareNode(n, ec) == Range::NODE_INSIDE && n->isDescendantOf(m_frame->document()->focusedNode())) return false; @@ -1586,8 +1599,6 @@ bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targe bool EventHandler::handleWheelEvent(PlatformWheelEvent& e) { Document* doc = m_frame->document(); - if (!doc) - return false; RenderObject* docRenderer = doc->renderer(); if (!docRenderer) @@ -1597,7 +1608,7 @@ bool EventHandler::handleWheelEvent(PlatformWheelEvent& e) IntPoint vPoint = m_frame->view()->windowToContents(e.pos()); - HitTestRequest request(true, false); + HitTestRequest request(HitTestRequest::ReadOnly); HitTestResult result(vPoint); doc->renderView()->layer()->hitTest(request, result); Node* node = result.innerNode(); @@ -1616,11 +1627,16 @@ bool EventHandler::handleWheelEvent(PlatformWheelEvent& e) } node = node->shadowAncestorNode(); - EventTargetNodeCast(node)->dispatchWheelEvent(e); + node->dispatchWheelEvent(e); if (e.isAccepted()) return true; - - if (node->renderer()) { + + // If we don't have a renderer, send the wheel event to the first node we find with a renderer. + // This is needed for <option> and <optgroup> elements so that <select>s get a wheel scroll. + while (node && !node->renderer()) + node = node->parent(); + + if (node && 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); @@ -1638,12 +1654,13 @@ bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event) { Document* doc = m_frame->document(); FrameView* v = m_frame->view(); - if (!doc || !v) + if (!v) return false; bool swallowEvent; IntPoint viewportPos = v->windowToContents(event.pos()); - MouseEventWithHitTestResults mev = doc->prepareMouseEvent(HitTestRequest(false, true), viewportPos, event); + HitTestRequest request(HitTestRequest::Active); + MouseEventWithHitTestResults mev = doc->prepareMouseEvent(request, viewportPos, event); // Context menu events shouldn't select text in GTK+ applications or in Chromium. // FIXME: This should probably be configurable by embedders. Consider making it a WebPreferences setting. @@ -1653,7 +1670,7 @@ bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event) // 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_frame->selection()->isContentEditable() || (mev.targetNode() && mev.targetNode()->isTextNode()))) { m_mouseDownMayStartSelect = true; // context menu events are always allowed to perform a selection selectClosestWordOrLinkFromMouseEvent(mev); } @@ -1680,10 +1697,11 @@ bool EventHandler::canMouseDownStartSelect(Node* node) 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); - + for (RenderObject* curr = node->renderer(); curr; curr = curr->parent()) { + if (Node* node = curr->node()) + return node->dispatchEventForType(eventNames().selectstartEvent, true, true); + } + return true; } @@ -1692,10 +1710,11 @@ 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); - + for (RenderObject* curr = node->renderer(); curr; curr = curr->parent()) { + if (Node* node = curr->node()) + return node->dispatchEventForType(eventNames().selectstartEvent, true, true); + } + return true; } @@ -1718,26 +1737,23 @@ void EventHandler::hoverTimerFired(Timer<EventHandler>*) ASSERT(m_frame->document()); if (RenderView* renderer = m_frame->contentRenderer()) { + HitTestRequest request(HitTestRequest::MouseMove); HitTestResult result(m_frame->view()->windowToContents(m_currentMousePosition)); - renderer->layer()->hitTest(HitTestRequest(false, false, true), result); + renderer->layer()->hitTest(request, result); m_frame->document()->updateRendering(); } } -static EventTargetNode* eventTargetNodeForDocument(Document* doc) +static Node* 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); + if (!node && doc->isHTMLDocument()) + node = doc->body(); + if (!node) + node = doc->documentElement(); + return node; } bool EventHandler::handleAccessKey(const PlatformKeyboardEvent& evt) @@ -1780,9 +1796,11 @@ bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent) // 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()); + RefPtr<Node> node = eventTargetNodeForDocument(m_frame->document()); if (!node) return false; + + m_frame->view()->resetDeferredRepaintDelay(); // FIXME: what is this doing here, in keyboard event handler? m_frame->loader()->resetMultipleFormSubmissionProtection(); @@ -1940,8 +1958,7 @@ void EventHandler::freeClipboard() bool EventHandler::shouldDragAutoNode(Node* node, const IntPoint& point) const { - ASSERT(node); - if (node->hasChildNodes() || !m_frame->view()) + if (!node || node->hasChildNodes() || !m_frame->view()) return false; return m_frame->page() && m_frame->page()->dragController()->mayStartDragAtEventLocation(m_frame, point); } @@ -1994,7 +2011,7 @@ bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event) if (m_mouseDownMayStartDrag && !dragState().m_dragSrc) { // try to find an element that wants to be dragged - HitTestRequest request(true, false); + HitTestRequest request(HitTestRequest::ReadOnly); HitTestResult result(m_mouseDownPos); m_frame->contentRenderer()->layer()->hitTest(request, result); Node* node = result.innerNode(); @@ -2118,6 +2135,8 @@ bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEve target = eventTargetNodeForDocument(m_frame->document()); if (!target) return false; + + m_frame->view()->resetDeferredRepaintDelay(); RefPtr<TextEvent> event = TextEvent::create(m_frame->domWindow(), text); event->setUnderlyingEvent(underlyingEvent); @@ -2219,10 +2238,13 @@ void EventHandler::defaultTabEventHandler(KeyboardEvent* event) void EventHandler::capsLockStateMayHaveChanged() { - if (Document* d = m_frame->document()) - if (Node* node = d->focusedNode()) - if (RenderObject* r = node->renderer()) - r->capsLockStateMayHaveChanged(); + Document* d = m_frame->document(); + if (Node* node = d->focusedNode()) { + if (RenderObject* r = node->renderer()) { + if (r->isTextField()) + static_cast<RenderTextControlSingleLine*>(r)->capsLockStateMayHaveChanged(); + } + } } unsigned EventHandler::pendingFrameUnloadEventCount() @@ -2252,6 +2274,20 @@ void EventHandler::clearPendingFrameUnloadEventCount() return; } +void EventHandler::sendResizeEvent() +{ + m_frame->document()->dispatchWindowEvent(eventNames().resizeEvent, false, false); +} + +void EventHandler::sendScrollEvent() +{ + FrameView* v = m_frame->view(); + if (!v) + return; + v->setWasScrolledByUser(true); + m_frame->document()->dispatchEventForType(eventNames().scrollEvent, true, false); +} + unsigned EventHandler::pendingFrameBeforeUnloadEventCount() { return m_pendingFrameBeforeUnloadEventCount; @@ -2308,7 +2344,7 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& e) if (type == TouchEventStart) { Frame* frame = m_frame; IntPoint vPoint = frame->view()->windowToContents(e.pos()); - HitTestRequest request(true, false); + HitTestRequest request(HitTestRequest::ReadOnly); HitTestResult result(vPoint); frame->contentRenderer()->layer()->hitTest(request, result); Node* node = result.innerNode(); @@ -2332,14 +2368,14 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& e) } } - if (!node || !node->isEventTargetNode()) { + if (!node) { // reset to the top document node node = doc; frame = m_frame; vPoint = frame->view()->windowToContents(e.pos()); } - m_touch = Touch::create(frame, EventTargetNodeCast(node), 0, + m_touch = Touch::create(frame, node, 0, e.x(), e.y(), vPoint.x(), vPoint.y()); } else if (m_touch) { if ((type == TouchEventMove) && (e.x() == m_touch->screenX()) && @@ -2386,7 +2422,7 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& e) return false; } ExceptionCode ec = 0; - static_cast<EventTargetNode*>(m_touch->target())->dispatchEvent(te.get(), ec); + m_touch->target()->dispatchEvent(te.get(), ec); if (type == TouchEventEnd || type == TouchEventCancel) { m_touch = 0; } diff --git a/WebCore/page/EventHandler.h b/WebCore/page/EventHandler.h index 944bbd3..0a59eb3 100644 --- a/WebCore/page/EventHandler.h +++ b/WebCore/page/EventHandler.h @@ -49,11 +49,11 @@ namespace WebCore { class AtomicString; class Clipboard; class Cursor; -class EventTargetNode; class Event; class FloatPoint; class FloatRect; class Frame; +class HitTestRequest; class HitTestResult; class HTMLFrameSetElement; class KeyboardEvent; @@ -75,8 +75,6 @@ class PlatformTouchEvent; class Touch; #endif -struct HitTestRequest; - extern const int LinkDragHysteresis; extern const int ImageDragHysteresis; extern const int TextDragHysteresis; @@ -101,7 +99,7 @@ public: RenderObject* autoscrollRenderer() const; void updateAutoscrollRenderer(); - HitTestResult hitTestResultAtPoint(const IntPoint&, bool allowShadowContent); + HitTestResult hitTestResultAtPoint(const IntPoint&, bool allowShadowContent, bool ignoreClipping = false); bool mousePressed() const { return m_mousePressed; } void setMousePressed(bool pressed) { m_mousePressed = pressed; } @@ -174,6 +172,9 @@ public: void addPendingFrameBeforeUnloadEventCount(); void removePendingFrameBeforeUnloadEventCount(); void clearPendingFrameBeforeUnloadEventCount(); + + void sendResizeEvent(); + void sendScrollEvent(); #if PLATFORM(MAC) PassRefPtr<KeyboardEvent> currentKeyboardEvent() const; @@ -224,7 +225,9 @@ private: void handleKeyboardSelectionMovement(KeyboardEvent*); Cursor selectCursor(const MouseEventWithHitTestResults&, Scrollbar*); +#if ENABLE(PAN_SCROLLING) void setPanScrollCursor(); +#endif void hoverTimerFired(Timer<EventHandler>*); @@ -293,9 +296,12 @@ private: void updateSelectionForMouseDrag(Node* targetNode, const IntPoint& localPoint); + bool capturesDragging() const { return m_capturesDragging; } + Frame* m_frame; bool m_mousePressed; + bool m_capturesDragging; RefPtr<Node> m_mousePressNode; bool m_mouseDownMayStartSelect; diff --git a/WebCore/page/FocusController.cpp b/WebCore/page/FocusController.cpp index 9b30362..9760b3c 100644 --- a/WebCore/page/FocusController.cpp +++ b/WebCore/page/FocusController.cpp @@ -90,8 +90,6 @@ static Node* deepFocusableNode(FocusDirection direction, Node* node, KeyboardEve break; Document* document = owner->contentFrame()->document(); - if (!document) - break; node = (direction == FocusDirectionForward) ? document->nextFocusableNode(0, event) @@ -115,8 +113,6 @@ bool FocusController::advanceFocus(FocusDirection direction, KeyboardEvent* even Frame* frame = focusedOrMainFrame(); ASSERT(frame); Document* document = frame->document(); - if (!document) - return false; Node* node = (direction == FocusDirectionForward) ? document->nextFocusableNode(document->focusedNode(), event) @@ -129,8 +125,6 @@ bool FocusController::advanceFocus(FocusDirection direction, KeyboardEvent* even break; Document* parentDocument = parentFrame->document(); - if (!parentDocument) - break; HTMLFrameOwnerElement* owner = frame->ownerElement(); if (!owner) @@ -155,10 +149,10 @@ bool FocusController::advanceFocus(FocusDirection direction, KeyboardEvent* even } // 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); + Document* d = m_page->mainFrame()->document(); + node = (direction == FocusDirectionForward) + ? d->nextFocusableNode(0, event) + : d->previousFocusableNode(0, event); node = deepFocusableNode(direction, node, event); @@ -266,9 +260,9 @@ bool FocusController::setFocusedNode(Node* node, PassRefPtr<Frame> newFocusedFra m_page->editorClient()->setInputMethodState(false); return true; } - - RefPtr<Document> newDocument = node ? node->document() : 0; - + + RefPtr<Document> newDocument = node->document(); + if (newDocument && newDocument->focusedNode() == node) { m_page->editorClient()->setInputMethodState(node->shouldUseInputMethod()); return true; diff --git a/WebCore/page/Frame.cpp b/WebCore/page/Frame.cpp index d4632e5..d379e13 100644 --- a/WebCore/page/Frame.cpp +++ b/WebCore/page/Frame.cpp @@ -5,7 +5,7 @@ * 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) 2004, 2005, 2006, 2007, 2008, 2009 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> @@ -43,6 +43,7 @@ #include "FocusController.h" #include "FloatQuad.h" #include "FrameLoader.h" +#include "FrameLoaderClient.h" #include "FrameView.h" #include "GraphicsContext.h" #include "HTMLDocument.h" @@ -52,7 +53,6 @@ #include "HTMLNames.h" #include "HTMLTableCellElement.h" #include "HitTestResult.h" -#include "JSDOMWindowShell.h" #include "Logging.h" #include "markup.h" #include "MediaFeatureNames.h" @@ -71,11 +71,15 @@ #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 USE(JSC) +#include "JSDOMWindowShell.h" +#include "runtime_root.h" +#endif + #if FRAME_LOADS_USER_STYLESHEET #include "UserStyleSheetLoader.h" #endif @@ -286,7 +290,7 @@ Settings* Frame::settings() const String Frame::selectedText() const { - return plainText(selection()->toRange().get()); + return plainText(selection()->toNormalizedRange().get()); } IntRect Frame::firstRectForRange(Range* range) const @@ -405,7 +409,7 @@ String Frame::searchForLabelsAboveCell(RegularExpression* regExp, HTMLTableCellE if (cellAboveRenderer) { HTMLTableCellElement* aboveCell = - static_cast<HTMLTableCellElement*>(cellAboveRenderer->element()); + static_cast<HTMLTableCellElement*>(cellAboveRenderer->node()); if (aboveCell) { // search within the above cell we found for a match @@ -511,12 +515,12 @@ String Frame::matchLabelsAgainstElement(const Vector<String>& labels, Element* e return String(); } -const Selection& Frame::mark() const +const VisibleSelection& Frame::mark() const { return m_mark; } -void Frame::setMark(const Selection& s) +void Frame::setMark(const VisibleSelection& s) { ASSERT(!s.base().node() || s.base().node()->document() == document()); ASSERT(!s.extent().node() || s.extent().node()->document() == document()); @@ -533,8 +537,8 @@ void Frame::notifyRendererOfSelectionChange(bool userTriggered) 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); + if (renderer && renderer->isTextControl()) + toRenderTextControl(renderer)->selectionChanged(userTriggered); } void Frame::invalidateSelection() @@ -577,7 +581,7 @@ static bool isFrameElement(const Node *n) void Frame::setFocusedNodeIfNeeded() { - if (!document() || selection()->isNone() || !selection()->isFocusedAndActive()) + if (selection()->isNone() || !selection()->isFocusedAndActive()) return; Node* target = selection()->rootEditableElement(); @@ -596,7 +600,7 @@ void Frame::setFocusedNodeIfNeeded() } renderer = renderer->parent(); if (renderer) - target = renderer->element(); + target = renderer->node(); } document()->setFocusedNode(0); } @@ -636,7 +640,7 @@ void Frame::selectionLayoutChanged() if (!view) return; - Selection selection = this->selection()->selection(); + VisibleSelection selection = this->selection()->selection(); if (!selection.isRange()) view->clearSelection(); @@ -657,7 +661,7 @@ void Frame::selectionLayoutChanged() 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()); + view->setSelection(startRenderer, startPos.m_offset, endRenderer, endPos.m_offset); } } } @@ -708,7 +712,7 @@ bool Frame::shouldApplyTextZoom() const if (m_zoomFactor == 1.0f || !isZoomFactorTextOnly()) return false; #if ENABLE(SVG) - if (m_doc && m_doc->isSVGDocument()) + if (m_doc->isSVGDocument()) return false; #endif return true; @@ -719,7 +723,7 @@ bool Frame::shouldApplyPageZoom() const if (m_zoomFactor == 1.0f || isZoomFactorTextOnly()) return false; #if ENABLE(SVG) - if (m_doc && m_doc->isSVGDocument()) + if (m_doc->isSVGDocument()) return false; #endif return true; @@ -733,7 +737,7 @@ void Frame::setZoomFactor(float percent, bool isTextOnly) #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 (m_doc && m_doc->isSVGDocument()) { + if (m_doc->isSVGDocument()) { if (!static_cast<SVGDocument*>(m_doc.get())->zoomAndPanEnabled()) return; m_zoomFactor = percent; @@ -747,25 +751,21 @@ void Frame::setZoomFactor(float percent, bool isTextOnly) m_zoomFactor = percent; m_page->settings()->setZoomsTextOnly(isTextOnly); - if (m_doc) - m_doc->recalcStyle(Node::Force); + m_doc->recalcStyle(Node::Force); for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling()) child->setZoomFactor(m_zoomFactor, isTextOnly); - if (m_doc && m_doc->renderer() && m_doc->renderer()->needsLayout() && view()->didFirstLayout()) + if (m_doc->renderer() && m_doc->renderer()->needsLayout() && view()->didFirstLayout()) view()->layout(); } void Frame::setPrinting(bool printing, float minPageWidth, float maxPageWidth, bool adjustViewSize) { - if (!m_doc) - return; - m_doc->setPrinting(printing); view()->setMediaType(printing ? "print" : "screen"); m_doc->updateStyleSelector(); - forceLayoutWithPageWidthRange(minPageWidth, maxPageWidth, adjustViewSize); + view()->forceLayoutWithPageWidthRange(minPageWidth, maxPageWidth, adjustViewSize); for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling()) child->setPrinting(printing, minPageWidth, maxPageWidth, adjustViewSize); @@ -797,6 +797,12 @@ String Frame::jsDefaultStatusBarText() const void Frame::setNeedsReapplyStyles() { + // When the frame is not showing web content, it doesn't make sense to apply styles. + // If we tried, we'd end up doing things with the document, but the document, if one + // exists, is not currently shown and should be in the page cache. + if (!m_loader.client()->hasHTMLView()) + return; + if (m_needsReapplyStyles) return; @@ -817,11 +823,9 @@ void Frame::reapplyStyles() { 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 (m_doc) - m_doc->docLoader()->setAutoLoadImages(m_page && m_page->settings()->loadsImagesAutomatically()); + // FIXME: This call doesn't really make sense in a function called reapplyStyles. + // We should probably eventually move it into its own function. + m_doc->docLoader()->setAutoLoadImages(m_page && m_page->settings()->loadsImagesAutomatically()); #if FRAME_LOADS_USER_STYLESHEET const KURL userStyleSheetLocation = m_page ? m_page->settings()->userStyleSheetLocation() : KURL(); @@ -835,32 +839,29 @@ void Frame::reapplyStyles() // 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 (m_doc) - m_doc->updateStyleSelector(); + m_doc->updateStyleSelector(); } -bool Frame::shouldChangeSelection(const Selection& newSelection) const +bool Frame::shouldChangeSelection(const VisibleSelection& newSelection) const { return shouldChangeSelection(selection()->selection(), newSelection, newSelection.affinity(), false); } -bool Frame::shouldChangeSelection(const Selection& oldSelection, const Selection& newSelection, EAffinity affinity, bool stillSelecting) const +bool Frame::shouldChangeSelection(const VisibleSelection& oldSelection, const VisibleSelection& newSelection, EAffinity affinity, bool stillSelecting) const { - return editor()->client()->shouldChangeSelectedRange(oldSelection.toRange().get(), newSelection.toRange().get(), + return editor()->client()->shouldChangeSelectedRange(oldSelection.toNormalizedRange().get(), newSelection.toNormalizedRange().get(), affinity, stillSelecting); } -bool Frame::shouldDeleteSelection(const Selection& selection) const +bool Frame::shouldDeleteSelection(const VisibleSelection& selection) const { - return editor()->client()->shouldDeleteRange(selection.toRange().get()); + return editor()->client()->shouldDeleteRange(selection.toNormalizedRange().get()); } bool Frame::isContentEditable() const { if (m_editor.clientIsEditable()) return true; - if (!m_doc) - return false; return m_doc->inDesignMode(); } @@ -929,7 +930,7 @@ void Frame::computeAndSetTypingStyle(CSSStyleDeclaration *style, EditAction edit // Handle block styles, substracting these from the typing style. RefPtr<CSSMutableStyleDeclaration> blockStyle = mutableStyle->copyBlockProperties(); blockStyle->diff(mutableStyle.get()); - if (document() && blockStyle->length() > 0) + if (blockStyle->length() > 0) applyCommand(ApplyStyleCommand::create(document(), blockStyle.get(), editingAction)); // Set the remaining style as the typing style. @@ -958,13 +959,10 @@ PassRefPtr<CSSComputedStyleDeclaration> Frame::selectionComputedStyle(Node*& nod { nodeToRemove = 0; - if (!document()) - return 0; - if (selection()->isNone()) return 0; - RefPtr<Range> range(selection()->toRange()); + RefPtr<Range> range(selection()->toNormalizedRange()); Position pos = range->editingStartPosition(); Element *elem = pos.element(); @@ -975,8 +973,7 @@ PassRefPtr<CSSComputedStyleDeclaration> Frame::selectionComputedStyle(Node*& nod ExceptionCode ec = 0; if (m_typingStyle) { - styleElement = document()->createElementNS(xhtmlNamespaceURI, "span", ec); - ASSERT(ec == 0); + styleElement = document()->createElement(spanTag, false); styleElement->setAttribute(styleAttr, m_typingStyle->cssText().impl(), ec); ASSERT(ec == 0); @@ -1044,9 +1041,6 @@ void Frame::textDidChangeInTextArea(Element* e) void Frame::applyEditingStyleToBodyElement() const { - if (!m_doc) - return; - RefPtr<NodeList> list = m_doc->getElementsByTagName("body"); unsigned len = list->length(); for (unsigned i = 0; i < len; i++) { @@ -1056,9 +1050,6 @@ void Frame::applyEditingStyleToBodyElement() const void Frame::removeEditingStyleFromBodyElement() const { - if (!m_doc) - return; - RefPtr<NodeList> list = m_doc->getElementsByTagName("body"); unsigned len = list->length(); for (unsigned i = 0; i < len; i++) { @@ -1145,7 +1136,7 @@ RenderView* Frame::contentRenderer() const if (!object) return 0; ASSERT(object->isRenderView()); - return static_cast<RenderView*>(object); + return toRenderView(object); } HTMLFrameOwnerElement* Frame::ownerElement() const @@ -1208,7 +1199,7 @@ void Frame::selectionTextRects(Vector<FloatRect>& rects, bool clipToVisibleConte if (!root) return; - RefPtr<Range> selectedRange = selection()->toRange(); + RefPtr<Range> selectedRange = selection()->toNormalizedRange(); Vector<IntRect> intRects; selectedRange->addLineBoxRects(intRects, true); @@ -1223,15 +1214,6 @@ void Frame::selectionTextRects(Vector<FloatRect>& rects, bool clipToVisibleConte } -bool Frame::isFrameSet() const -{ - Document* document = 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) { @@ -1271,66 +1253,32 @@ HTMLFormElement *Frame::currentForm() const return start ? scanForForm(start) : 0; } -// FIXME: should this go in SelectionController? -void Frame::revealSelection(const RenderLayer::ScrollAlignment& alignment) const +void Frame::revealSelection(const ScrollAlignment& alignment, bool revealExtent) { IntRect rect; - - switch (selection()->state()) { - case Selection::NONE: + + switch (selection()->selectionType()) { + case VisibleSelection::NoSelection: return; - - case Selection::CARET: + case VisibleSelection::CaretSelection: rect = selection()->absoluteCaretBounds(); break; - - case Selection::RANGE: - rect = enclosingIntRect(selectionBounds(false)); + case VisibleSelection::RangeSelection: + rect = revealExtent ? VisiblePosition(selection()->extent()).absoluteCaretBounds() : 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()) + 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); @@ -1345,67 +1293,6 @@ Frame* Frame::frameForWidget(const Widget* widget) return static_cast<const FrameView*>(widget)->frame(); } -void Frame::forceLayout(bool allowSubtree) -{ - FrameView *v = 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 = 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) { @@ -1428,8 +1315,6 @@ RenderStyle *Frame::styleForSelectionStart(Node *&nodeToRemove) const { nodeToRemove = 0; - if (!document()) - return 0; if (selection()->isNone()) return 0; @@ -1443,10 +1328,9 @@ RenderStyle *Frame::styleForSelectionStart(Node *&nodeToRemove) const if (!m_typingStyle) return node->renderer()->style(); - ExceptionCode ec = 0; - RefPtr<Element> styleElement = document()->createElementNS(xhtmlNamespaceURI, "span", ec); - ASSERT(ec == 0); + RefPtr<Element> styleElement = document()->createElement(spanTag, false); + ExceptionCode ec = 0; String styleText = m_typingStyle->cssText() + " display: inline"; styleElement->setAttribute(styleAttr, styleText.impl(), ec); ASSERT(ec == 0); @@ -1466,14 +1350,14 @@ 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()) + if (!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)); + selection()->setSelection(VisibleSelection(Position(node, 0), DOWNSTREAM)); } bool Frame::inViewSourceMode() const @@ -1489,7 +1373,7 @@ void Frame::setInViewSourceMode(bool mode) // 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()) + if (target.isEmpty()) return false; if (excludeFromTextSearch()) @@ -1498,7 +1382,7 @@ bool Frame::findString(const String& target, bool forward, bool caseFlag, bool w // 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(); + VisibleSelection selection = this->selection()->selection(); if (forward) setStart(searchRange.get(), startInSelection ? selection.visibleStart() : selection.visibleEnd()); @@ -1518,7 +1402,7 @@ bool Frame::findString(const String& target, bool forward, bool caseFlag, bool w // 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()) { + if (startInSelection && *VisibleSelection(resultRange.get()).toNormalizedRange() == *selection.toNormalizedRange()) { searchRange = rangeOfContents(document()); if (forward) setStart(searchRange.get(), selection.visibleEnd()); @@ -1568,14 +1452,14 @@ bool Frame::findString(const String& target, bool forward, bool caseFlag, bool w if (resultRange->collapsed(exception)) return false; - this->selection()->setSelection(Selection(resultRange.get(), DOWNSTREAM)); + this->selection()->setSelection(VisibleSelection(resultRange.get(), DOWNSTREAM)); revealSelection(); return true; } unsigned Frame::markAllMatchesForText(const String& target, bool caseFlag, unsigned limit) { - if (target.isEmpty() || !document()) + if (target.isEmpty()) return 0; RefPtr<Range> searchRange(rangeOfContents(document())); @@ -1618,7 +1502,7 @@ unsigned Frame::markAllMatchesForText(const String& target, bool caseFlag, unsig // Do a "fake" paint in order to execute the code that computes the rendered rect for // each text match. Document* doc = document(); - if (doc && m_view && contentRenderer()) { + if (m_view && contentRenderer()) { doc->updateLayout(); // Ensure layout is up to date. IntRect visibleRect = m_view->visibleContentRect(); if (!visibleRect.isEmpty()) { @@ -1638,7 +1522,7 @@ bool Frame::markedTextMatchesAreHighlighted() const void Frame::setMarkedTextMatchesAreHighlighted(bool flag) { - if (flag == m_highlightTextMatches || !document()) + if (flag == m_highlightTextMatches) return; m_highlightTextMatches = flag; @@ -1718,10 +1602,8 @@ void Frame::disconnectOwnerElement() String Frame::documentTypeString() const { - if (Document* doc = document()) { - if (DocumentType* doctype = doc->doctype()) - return createMarkup(doctype); - } + if (DocumentType* doctype = document()->doctype()) + return createMarkup(doctype); return String(); } @@ -1755,8 +1637,6 @@ bool Frame::shouldClose() return true; RefPtr<Document> doc = document(); - if (!doc) - return true; HTMLElement* body = doc->body(); if (!body) return true; @@ -1765,7 +1645,7 @@ bool Frame::shouldClose() beforeUnloadEvent->setTarget(doc); doc->handleWindowEvent(beforeUnloadEvent.get(), false); - if (!beforeUnloadEvent->defaultPrevented() && doc) + if (!beforeUnloadEvent->defaultPrevented()) doc->defaultEventHandler(beforeUnloadEvent.get()); if (beforeUnloadEvent->result().isNull()) return true; @@ -1785,52 +1665,50 @@ void Frame::scheduleClose() chrome->closeWindowSoon(); } -void Frame::respondToChangedSelection(const Selection& oldSelection, bool closeTyping) +void Frame::respondToChangedSelection(const VisibleSelection& 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)); - } + bool isContinuousSpellCheckingEnabled = editor()->isContinuousSpellCheckingEnabled(); + bool isContinuousGrammarCheckingEnabled = isContinuousSpellCheckingEnabled && editor()->isGrammarCheckingEnabled(); + if (isContinuousSpellCheckingEnabled) { + VisibleSelection newAdjacentWords; + VisibleSelection newSelectedSentence; + if (selection()->selection().isContentEditable()) { + VisiblePosition newStart(selection()->selection().visibleStart()); + newAdjacentWords = VisibleSelection(startOfWord(newStart, LeftWordIfOnBoundary), endOfWord(newStart, RightWordIfOnBoundary)); + if (isContinuousGrammarCheckingEnabled) + newSelectedSentence = VisibleSelection(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); - } + // 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()); + VisibleSelection oldAdjacentWords = VisibleSelection(startOfWord(oldStart, LeftWordIfOnBoundary), endOfWord(oldStart, RightWordIfOnBoundary)); + if (oldAdjacentWords != newAdjacentWords) { + if (isContinuousGrammarCheckingEnabled) { + VisibleSelection oldSelectedSentence = VisibleSelection(startOfSentence(oldStart), endOfSentence(oldStart)); + editor()->markMisspellingsAndBadGrammar(oldAdjacentWords, oldSelectedSentence != newSelectedSentence, oldSelectedSentence); + } else { + editor()->markMisspellingsAndBadGrammar(oldAdjacentWords, false, oldAdjacentWords); } } - - // 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); + // 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.toNormalizedRange()) + document()->removeMarkers(wordRange.get(), DocumentMarker::Spelling); + if (RefPtr<Range> sentenceRange = newSelectedSentence.toNormalizedRange()) + 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); } @@ -1843,7 +1721,7 @@ VisiblePosition Frame::visiblePositionForPoint(const IntPoint& framePoint) RenderObject* renderer = node->renderer(); if (!renderer) return VisiblePosition(); - VisiblePosition visiblePos = renderer->positionForCoordinates(result.localPoint().x(), result.localPoint().y()); + VisiblePosition visiblePos = renderer->positionForPoint(result.localPoint()); if (visiblePos.isNull()) visiblePos = VisiblePosition(Position(node, 0)); return visiblePos; @@ -1862,4 +1740,47 @@ Document* Frame::documentAtPoint(const IntPoint& point) return result.innerNode() ? result.innerNode()->document() : 0; } +void Frame::createView(const IntSize& viewportSize, + const Color& backgroundColor, bool transparent, + const IntSize& fixedLayoutSize, bool useFixedLayout, + ScrollbarMode horizontalScrollbarMode, ScrollbarMode verticalScrollbarMode) +{ + ASSERT(this); + ASSERT(m_page); + + bool isMainFrame = this == m_page->mainFrame(); + + if (isMainFrame && view()) + view()->setParentVisible(false); + + setView(0); + + FrameView* frameView; + if (isMainFrame) { + frameView = new FrameView(this, viewportSize); + frameView->setFixedLayoutSize(fixedLayoutSize); + frameView->setUseFixedLayout(useFixedLayout); + } else + frameView = new FrameView(this); + + frameView->setScrollbarModes(horizontalScrollbarMode, verticalScrollbarMode); + frameView->updateDefaultScrollbarState(); + + setView(frameView); + // FrameViews are created with a ref count of 1. Release this ref since we've assigned it to frame. + frameView->deref(); + + if (backgroundColor.isValid()) + frameView->updateBackgroundRecursively(backgroundColor, transparent); + + if (isMainFrame) + frameView->setParentVisible(true); + + if (ownerRenderer()) + ownerRenderer()->setWidget(frameView); + + if (HTMLFrameOwnerElement* owner = ownerElement()) + view()->setCanHaveScrollbars(owner->scrollingMode() != ScrollbarAlwaysOff); +} + } // namespace WebCore diff --git a/WebCore/page/Frame.h b/WebCore/page/Frame.h index bebdc63..5d46acd 100644 --- a/WebCore/page/Frame.h +++ b/WebCore/page/Frame.h @@ -29,6 +29,7 @@ #define Frame_h #include "AnimationController.h" +#include "Document.h" #include "DragImage.h" #include "EditAction.h" #include "Editor.h" @@ -36,7 +37,7 @@ #include "FrameLoader.h" #include "FrameTree.h" #include "Range.h" -#include "RenderLayer.h" +#include "ScrollBehavior.h" #include "ScriptController.h" #include "SelectionController.h" #include "TextGranularity.h" @@ -61,19 +62,21 @@ typedef struct HBITMAP__* HBITMAP; namespace WebCore { +class CSSMutableStyleDeclaration; class Editor; class EventHandler; class FrameLoader; class FrameLoaderClient; -class FramePrivate; class FrameTree; +class FrameView; class HTMLFrameOwnerElement; class HTMLTableCellElement; -class ScriptController; class RegularExpression; class RenderPart; -class Selection; +class ScriptController; class SelectionController; +class Settings; +class VisibleSelection; class Widget; #if FRAME_LOADS_USER_STYLESHEET @@ -122,7 +125,9 @@ public: bool excludeFromTextSearch() const; void setExcludeFromTextSearch(bool); - friend class FramePrivate; + void createView(const IntSize&, const Color&, bool, const IntSize &, bool, + ScrollbarMode = ScrollbarAuto, ScrollbarMode = ScrollbarAuto); + private: Frame(Page*, HTMLFrameOwnerElement*, FrameLoaderClient*); @@ -172,25 +177,9 @@ public: 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; @@ -218,8 +207,8 @@ 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&); + const VisibleSelection& mark() const; // Mark, to be used as emacs uses it. + void setMark(const VisibleSelection&); void computeAndSetTypingStyle(CSSStyleDeclaration* , EditAction = EditActionUnspecified); String selectionStartStylePropertyValue(int stylePropertyID) const; @@ -230,8 +219,8 @@ public: IntRect firstRectForRange(Range*) const; - void respondToChangedSelection(const Selection& oldSelection, bool closeTyping); - bool shouldChangeSelection(const Selection& oldSelection, const Selection& newSelection, EAffinity, bool stillSelecting) const; + void respondToChangedSelection(const VisibleSelection& oldSelection, bool closeTyping); + bool shouldChangeSelection(const VisibleSelection& oldSelection, const VisibleSelection& newSelection, EAffinity, bool stillSelecting) const; RenderStyle* styleForSelectionStart(Node*& nodeToRemove) const; @@ -256,8 +245,8 @@ public: TextGranularity selectionGranularity() const; void setSelectionGranularity(TextGranularity); - bool shouldChangeSelection(const Selection&) const; - bool shouldDeleteSelection(const Selection&) const; + bool shouldChangeSelection(const VisibleSelection&) const; + bool shouldDeleteSelection(const VisibleSelection&) const; void clearCaretRectIfNeeded(); void setFocusedNodeIfNeeded(); void selectionLayoutChanged(); @@ -281,9 +270,8 @@ public: 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 revealSelection(const ScrollAlignment& = ScrollAlignment::alignCenterIfNeeded, bool revealExtent = false); void setSelectionFromNone(); void setUseSecureKeyboardEntry(bool); @@ -359,7 +347,7 @@ private: TextGranularity m_selectionGranularity; mutable SelectionController m_selectionController; - mutable Selection m_mark; + mutable VisibleSelection m_mark; Timer<Frame> m_caretBlinkTimer; mutable Editor m_editor; mutable EventHandler m_eventHandler; diff --git a/WebCore/page/FrameTree.cpp b/WebCore/page/FrameTree.cpp index c9b4172..adb5c90 100644 --- a/WebCore/page/FrameTree.cpp +++ b/WebCore/page/FrameTree.cpp @@ -82,10 +82,6 @@ void FrameTree::appendChild(PassRefPtr<Frame> child) 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 diff --git a/WebCore/page/FrameTree.h b/WebCore/page/FrameTree.h index 3b74d5d..d4c8c43 100644 --- a/WebCore/page/FrameTree.h +++ b/WebCore/page/FrameTree.h @@ -56,6 +56,7 @@ namespace WebCore { Frame* traversePreviousWithWrap(bool) const; void appendChild(PassRefPtr<Frame>); + void detachFromParent() { m_parent = 0; } void removeChild(Frame*); Frame* child(unsigned index) const; diff --git a/WebCore/page/FrameView.cpp b/WebCore/page/FrameView.cpp index 2eefd6c..5f1ee65 100644 --- a/WebCore/page/FrameView.cpp +++ b/WebCore/page/FrameView.cpp @@ -28,6 +28,7 @@ #include "AXObjectCache.h" #include "CSSStyleSelector.h" #include "ChromeClient.h" +#include "DocLoader.h" #include "EventHandler.h" #include "FloatRect.h" #include "FocusController.h" @@ -55,15 +56,41 @@ #include "TimeCounter.h" #endif +#if USE(ACCELERATED_COMPOSITING) +#include "RenderLayerCompositor.h" +#endif + namespace WebCore { using namespace HTMLNames; double FrameView::sCurrentPaintTimeStamp = 0.0; +#if ENABLE(REPAINT_THROTTLING) +// Normal delay +static const double deferredRepaintDelay = 0.025; +// Negative value would mean that first few repaints happen without a delay +static const double initialDeferredRepaintDelayDuringLoading = 0; +// The delay grows on each repaint to this maximum value +static const double maxDeferredRepaintDelayDuringLoading = 2.5; +// On each repaint the delay increses by this amount +static const double deferredRepaintDelayIncrementDuringLoading = 0.5; +#else +// FIXME: Repaint throttling could be good to have on all platform. +// The balance between CPU use and repaint frequency will need some tuning for desktop. +// More hooks may be needed to reset the delay on things like GIF and CSS animations. +static const double deferredRepaintDelay = 0; +static const double initialDeferredRepaintDelayDuringLoading = 0; +static const double maxDeferredRepaintDelayDuringLoading = 0; +static const double deferredRepaintDelayIncrementDuringLoading = 0; +#endif + +// The maximum number of updateWidgets iterations that should be done before returning. +static const unsigned maxUpdateWidgetsIterations = 2; + struct ScheduledEvent { RefPtr<Event> m_event; - RefPtr<EventTargetNode> m_eventTarget; + RefPtr<Node> m_eventTarget; }; FrameView::FrameView(Frame* frame) @@ -84,6 +111,7 @@ FrameView::FrameView(Frame* frame) , m_viewportRenderer(0) , m_wasScrolledByUser(false) , m_inProgrammaticScroll(false) + , m_deferredRepaintTimer(this, &FrameView::deferredRepaintTimerFired) , m_shouldUpdateWhileOffscreen(true) { init(); @@ -108,6 +136,7 @@ FrameView::FrameView(Frame* frame, const IntSize& initialSize) , m_viewportRenderer(0) , m_wasScrolledByUser(false) , m_inProgrammaticScroll(false) + , m_deferredRepaintTimer(this, &FrameView::deferredRepaintTimerFired) , m_shouldUpdateWhileOffscreen(true) { init(); @@ -132,7 +161,7 @@ FrameView::~FrameView() ASSERT(!m_enqueueEvents); if (m_frame) { - ASSERT(m_frame->view() != this || !m_frame->document() || !m_frame->contentRenderer()); + ASSERT(m_frame->view() != this || !m_frame->contentRenderer()); RenderPart* renderer = m_frame->ownerRenderer(); if (renderer && renderer->widget() == this) renderer->setWidget(0); @@ -160,8 +189,10 @@ void FrameView::reset() m_lastZoomFactor = 1.0f; m_deferringRepaints = 0; m_repaintCount = 0; - m_repaintRect = IntRect(); m_repaintRects.clear(); + m_deferredRepaintDelay = initialDeferredRepaintDelayDuringLoading; + m_deferredRepaintTimer.stop(); + m_lastPaintTime = 0; m_paintRestriction = PaintRestrictionNone; m_isPainting = false; m_isVisuallyNonEmpty = false; @@ -286,22 +317,20 @@ PassRefPtr<Scrollbar> FrameView::createScrollbar(ScrollbarOrientation orientatio { // 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)) + if (body && body->renderer() && body->renderer()->style()->hasPseudoStyle(SCROLLBAR)) return RenderScrollbar::createCustomScrollbar(this, orientation, body->renderBox()); // 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)) + if (docElement && docElement->renderer() && docElement->renderer()->style()->hasPseudoStyle(SCROLLBAR)) return RenderScrollbar::createCustomScrollbar(this, orientation, docElement->renderBox()); // 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)) + if (frameRenderer && frameRenderer->style()->hasPseudoStyle(SCROLLBAR)) return RenderScrollbar::createCustomScrollbar(this, orientation, frameRenderer); // Nobody set a custom style, so we just use a native scrollbar. @@ -367,6 +396,41 @@ void FrameView::applyOverflowToViewport(RenderObject* o, ScrollbarMode& hMode, S m_viewportRenderer = o; } +#if USE(ACCELERATED_COMPOSITING) +void FrameView::updateCompositingLayers(CompositingUpdate updateType) +{ + RenderView* view = m_frame->contentRenderer(); + if (!view || !view->usesCompositing()) + return; + + if (updateType == ForcedCompositingUpdate) + view->compositor()->setCompositingLayersNeedUpdate(); + + view->compositor()->updateCompositingLayers(); +} + +void FrameView::setNeedsOneShotDrawingSynchronization() +{ + Page* page = frame() ? frame()->page() : 0; + if (page) + page->chrome()->client()->setNeedsOneShotDrawingSynchronization(); +} +#endif // USE(ACCELERATED_COMPOSITING) + +void FrameView::didMoveOnscreen() +{ + RenderView* view = m_frame->contentRenderer(); + if (view) + view->didMoveOnscreen(); +} + +void FrameView::willMoveOffscreen() +{ + RenderView* view = m_frame->contentRenderer(); + if (view) + view->willMoveOffscreen(); +} + RenderObject* FrameView::layoutRoot(bool onlyDuringLayout) const { return onlyDuringLayout && layoutPending() ? 0 : m_layoutRoot; @@ -408,11 +472,6 @@ void FrameView::layout(bool allowSubtree) return; Document* document = m_frame->document(); - if (!document) { - // FIXME: Should we set m_size.height here too? - m_size.setWidth(layoutWidth()); - return; - } m_layoutSchedulingEnabled = false; @@ -484,7 +543,7 @@ void FrameView::layout(bool allowSubtree) #endif } - m_doFullRepaint = !subtree && (m_firstLayout || static_cast<RenderView*>(root)->printing()); + m_doFullRepaint = !subtree && (m_firstLayout || toRenderView(root)->printing()); if (!subtree) { // Now set our scrollbar state for the layout. @@ -539,13 +598,17 @@ void FrameView::layout(bool allowSubtree) m_layoutSchedulingEnabled = true; - if (!subtree && !static_cast<RenderView*>(root)->printing()) + if (!subtree && !toRenderView(root)->printing()) adjustViewSize(); // Now update the positions of all layers. beginDeferredRepaints(); layer->updateLayerPositions(m_doFullRepaint); endDeferredRepaints(); + +#if USE(ACCELERATED_COMPOSITING) + updateCompositingLayers(); +#endif m_layoutCount++; @@ -573,7 +636,7 @@ void FrameView::layout(bool allowSubtree) // Calls resumeScheduledEvents() performPostLayoutTasks(); - if (needsLayout()) { + if (!m_postLayoutTasksTimer.isActive() && 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. @@ -680,21 +743,31 @@ void FrameView::repaintContentRectangle(const IntRect& r, bool immediate) { ASSERT(!m_frame->document()->ownerElement()); - if (m_deferringRepaints && !immediate) { + double delay = adjustedDeferredRepaintDelay(); + if ((m_deferringRepaints || m_deferredRepaintTimer.isActive() || delay) && !immediate) { IntRect visibleContent = visibleContentRect(); visibleContent.intersect(r); - if (!visibleContent.isEmpty()) { - m_repaintCount++; - m_repaintRect.unite(r); - if (m_repaintCount == cRepaintRectUnionThreshold) - m_repaintRects.clear(); - else if (m_repaintCount < cRepaintRectUnionThreshold) - m_repaintRects.append(r); - } #ifdef ANDROID_CAPTURE_OFFSCREEN_PAINTS - else + if (visibleContent.isEmpty()) ScrollView::platformOffscreenContentRectangle(r); #endif + if (visibleContent.isEmpty()) + return; + if (m_repaintCount == cRepaintRectUnionThreshold) { + IntRect unionedRect; + for (unsigned i = 0; i < cRepaintRectUnionThreshold; ++i) + unionedRect.unite(m_repaintRects[i]); + m_repaintRects.clear(); + m_repaintRects.append(unionedRect); + } + if (m_repaintCount < cRepaintRectUnionThreshold) + m_repaintRects.append(r); + else + m_repaintRects[0].unite(r); + m_repaintCount++; + + if (!m_deferringRepaints && !m_deferredRepaintTimer.isActive()) + m_deferredRepaintTimer.startOneShot(delay); return; } @@ -711,15 +784,6 @@ void FrameView::beginDeferredRepaints() return page->mainFrame()->view()->beginDeferredRepaints(); m_deferringRepaints++; -#ifdef ANDROID_FIX // This allows sub frames to accumulate deferred repaints - if (m_deferringRepaints == 1) { -#endif - m_repaintCount = 0; - m_repaintRect = IntRect(); - m_repaintRects.clear(); -#ifdef ANDROID_FIX - } -#endif } @@ -730,22 +794,90 @@ void FrameView::endDeferredRepaints() return page->mainFrame()->view()->endDeferredRepaints(); ASSERT(m_deferringRepaints > 0); - if (--m_deferringRepaints == 0) { - if (m_repaintCount >= cRepaintRectUnionThreshold) - repaintContentRectangle(m_repaintRect, false); - else { - unsigned size = m_repaintRects.size(); - for (unsigned i = 0; i < size; i++) - repaintContentRectangle(m_repaintRects[i], false); - m_repaintRects.clear(); - } + + if (--m_deferringRepaints) + return; + + if (m_deferredRepaintTimer.isActive()) + return; + + if (double delay = adjustedDeferredRepaintDelay()) { + m_deferredRepaintTimer.startOneShot(delay); + return; } + + doDeferredRepaints(); } +void FrameView::checkStopDelayingDeferredRepaints() +{ + if (!m_deferredRepaintTimer.isActive()) + return; + + Document* document = m_frame->document(); + if (document && (document->parsing() || document->docLoader()->requestCount())) + return; + + m_deferredRepaintTimer.stop(); + + doDeferredRepaints(); +} + +void FrameView::doDeferredRepaints() +{ + ASSERT(!m_deferringRepaints); + if (isOffscreen() && !shouldUpdateWhileOffscreen()) { + m_repaintRects.clear(); + m_repaintCount = 0; + return; + } + unsigned size = m_repaintRects.size(); + for (unsigned i = 0; i < size; i++) + ScrollView::repaintContentRectangle(m_repaintRects[i], false); + m_repaintRects.clear(); + m_repaintCount = 0; + + updateDeferredRepaintDelay(); +} + +void FrameView::updateDeferredRepaintDelay() +{ + Document* document = m_frame->document(); + if (!document || (!document->parsing() && !document->docLoader()->requestCount())) { + m_deferredRepaintDelay = deferredRepaintDelay; + return; + } + if (m_deferredRepaintDelay < maxDeferredRepaintDelayDuringLoading) { + m_deferredRepaintDelay += deferredRepaintDelayIncrementDuringLoading; + if (m_deferredRepaintDelay > maxDeferredRepaintDelayDuringLoading) + m_deferredRepaintDelay = maxDeferredRepaintDelayDuringLoading; + } +} + +void FrameView::resetDeferredRepaintDelay() +{ + m_deferredRepaintDelay = 0; + if (m_deferredRepaintTimer.isActive()) + m_deferredRepaintTimer.startOneShot(0); +} + +double FrameView::adjustedDeferredRepaintDelay() const +{ + if (!m_deferredRepaintDelay) + return 0; + double timeSinceLastPaint = currentTime() - m_lastPaintTime; + return max(0., m_deferredRepaintDelay - timeSinceLastPaint); +} + +void FrameView::deferredRepaintTimerFired(Timer<FrameView>*) +{ + doDeferredRepaints(); +} + void FrameView::layoutTimerFired(Timer<FrameView>*) { #ifdef INSTRUMENT_LAYOUT_SCHEDULING - if (m_frame->document() && !m_frame->document()->ownerElement()) + if (!m_frame->document()->ownerElement()) printf("Layout timer fired at %d\n", m_frame->document()->elapsedTime()); #endif layout(); @@ -753,7 +885,7 @@ void FrameView::layoutTimerFired(Timer<FrameView>*) void FrameView::scheduleRelayout() { - ASSERT(!m_frame->document() || !m_frame->document()->inPageCache()); + ASSERT(!m_frame->document()->inPageCache()); ASSERT(m_frame->view() == this); if (m_layoutRoot) { @@ -764,7 +896,7 @@ void FrameView::scheduleRelayout() return; if (!needsLayout()) return; - if (!m_frame->document() || !m_frame->document()->shouldScheduleLayout()) + if (!m_frame->document()->shouldScheduleLayout()) return; #if defined(FLATTEN_IFRAME) || defined(FLATTEN_FRAMESET) @@ -858,7 +990,7 @@ bool FrameView::needsLayout() const return layoutPending() || (root && root->needsLayout()) || m_layoutRoot - || (document && document->hasChangedChild()) // can occur when using WebKit ObjC interface + || document->hasChangedChild() // can occur when using WebKit ObjC interface || m_frame->needsReapplyStyles(); } @@ -875,7 +1007,7 @@ void FrameView::unscheduleRelayout() return; #ifdef INSTRUMENT_LAYOUT_SCHEDULING - if (m_frame->document() && !m_frame->document()->ownerElement()) + if (!m_frame->document()->ownerElement()) printf("Layout timer unscheduled at %d\n", m_frame->document()->elapsedTime()); #endif @@ -927,7 +1059,7 @@ void FrameView::setShouldUpdateWhileOffscreen(bool shouldUpdateWhileOffscreen) m_shouldUpdateWhileOffscreen = shouldUpdateWhileOffscreen; } -void FrameView::scheduleEvent(PassRefPtr<Event> event, PassRefPtr<EventTargetNode> eventTarget) +void FrameView::scheduleEvent(PassRefPtr<Event> event, PassRefPtr<Node> eventTarget) { if (!m_enqueueEvents) { ExceptionCode ec = 0; @@ -955,6 +1087,29 @@ void FrameView::resumeScheduledEvents() ASSERT(m_scheduledEvents.isEmpty() || m_enqueueEvents); } +bool FrameView::updateWidgets() +{ + if (m_nestedLayoutCount > 1 || !m_widgetUpdateSet || m_widgetUpdateSet->isEmpty()) + return true; + + 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->remove(object); + } + } + + return m_widgetUpdateSet->isEmpty(); +} + void FrameView::performPostLayoutTasks() { if (m_firstLayoutCallbackPending) { @@ -970,22 +1125,12 @@ void FrameView::performPostLayoutTasks() RenderView* root = m_frame->contentRenderer(); root->updateWidgetPositions(); - if (m_widgetUpdateSet && 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(); + + for (unsigned i = 0; i < maxUpdateWidgetsIterations; i++) { + if (updateWidgets()) + break; } - + resumeScheduledEvents(); if (!root->printing()) { @@ -995,7 +1140,7 @@ void FrameView::performPostLayoutTasks() m_lastLayoutSize = currentSize; m_lastZoomFactor = currentZoomFactor; if (resized) - m_frame->sendResizeEvent(); + m_frame->eventHandler()->sendResizeEvent(); } } @@ -1025,7 +1170,7 @@ void FrameView::updateOverflowStatus(bool horizontalOverflow, bool verticalOverf scheduleEvent(OverflowEvent::create(horizontalOverflowChanged, horizontalOverflow, verticalOverflowChanged, verticalOverflow), - EventTargetNodeCast(m_viewportRenderer->element())); + m_viewportRenderer->node()); } } @@ -1058,7 +1203,7 @@ IntRect FrameView::windowClipRect(bool clipToContents) const // Set our clip rect to be our contents. IntRect clipRect = contentsToWindow(visibleContentRect(!clipToContents)); - if (!m_frame || !m_frame->document() || !m_frame->document()->ownerElement()) + if (!m_frame || !m_frame->document()->ownerElement()) return clipRect; // Take our owner element and get the clip rect from the enclosing layer. @@ -1100,7 +1245,7 @@ void FrameView::valueChanged(Scrollbar* bar) IntSize offset = scrollOffset(); ScrollView::valueChanged(bar); if (offset != scrollOffset()) - frame()->sendScrollEvent(); + frame()->eventHandler()->sendScrollEvent(); } void FrameView::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect) @@ -1184,12 +1329,10 @@ void FrameView::paintContents(GraphicsContext* p, const IntRect& rect) return; Document* document = frame()->document(); - if (!document) - return; #ifndef NDEBUG bool fillWithRed; - if (document || document->printing()) + if (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. @@ -1226,8 +1369,9 @@ void FrameView::paintContents(GraphicsContext* p, const IntRect& rect) if (m_paintRestriction == PaintRestrictionNone) document->invalidateRenderedRectsForMarkersInRect(rect); contentRenderer->layer()->paint(p, rect, m_paintRestriction, eltRenderer); - + m_isPainting = false; + m_lastPaintTime = currentTime(); #if ENABLE(DASHBOARD_SUPPORT) // Regions may have changed as a result of the visibility/z-index of element changing. @@ -1275,4 +1419,60 @@ void FrameView::layoutIfNeededRecursive() static_cast<FrameView*>(*current)->layoutIfNeededRecursive(); } +void FrameView::forceLayout(bool allowSubtree) +{ + 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 + //unscheduleRelayout(); +} + +void FrameView::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 = toRenderView(m_frame->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 = std::min(rightmostPos, (int)ceilf(maxPageWidth)); + root->setWidth(pageW); + root->setNeedsLayoutAndPrefWidthsRecalc(); + forceLayout(); + } + } + + if (_adjustViewSize) + adjustViewSize(); +} + +void FrameView::adjustPageHeight(float *newBottom, float oldTop, float oldBottom, float /*bottomLimit*/) +{ + RenderView* root = m_frame->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; +} + } // namespace WebCore diff --git a/WebCore/page/FrameView.h b/WebCore/page/FrameView.h index a1d514f..07295d3 100644 --- a/WebCore/page/FrameView.h +++ b/WebCore/page/FrameView.h @@ -35,7 +35,6 @@ namespace WebCore { class Color; class Event; -class EventTargetNode; class Frame; class FrameViewPrivate; class IntRect; @@ -97,6 +96,18 @@ public: bool needsFullRepaint() const { return m_doFullRepaint; } +#if USE(ACCELERATED_COMPOSITING) + enum CompositingUpdate { NormalCompositingUpdate, ForcedCompositingUpdate }; + void updateCompositingLayers(CompositingUpdate updateType = NormalCompositingUpdate); + + // Called when changes to the GraphicsLayer hierarchy have to be synchronized with + // content rendered via the normal painting path. + void setNeedsOneShotDrawingSynchronization(); +#endif + + void didMoveOnscreen(); + void willMoveOffscreen(); + void resetScrollbars(); void clear(); @@ -138,6 +149,8 @@ public: void beginDeferredRepaints(); void endDeferredRepaints(); + void checkStopDelayingDeferredRepaints(); + void resetDeferredRepaintDelay(); #if ENABLE(DASHBOARD_SUPPORT) void updateDashboardRegions(); @@ -146,7 +159,7 @@ public: void restoreScrollbar(); - void scheduleEvent(PassRefPtr<Event>, PassRefPtr<EventTargetNode>); + void scheduleEvent(PassRefPtr<Event>, PassRefPtr<Node>); void pauseScheduledEvents(); void resumeScheduledEvents(); void postLayoutTimerFired(Timer<FrameView>*); @@ -168,6 +181,12 @@ public: void setIsVisuallyNonEmpty() { m_isVisuallyNonEmpty = true; } + void forceLayout(bool allowSubtree = false); + void forceLayoutWithPageWidthRange(float minPageWidth, float maxPageWidth, bool adjustViewSize); + + void adjustPageHeight(float* newBottom, float oldTop, float oldBottom, float bottomLimit); + + private: void reset(); void init(); @@ -186,7 +205,14 @@ private: virtual void repaintContentRectangle(const IntRect&, bool immediate); virtual void contentsResized() { setNeedsLayout(); } virtual void visibleContentsResized() { layout(); } + + void deferredRepaintTimerFired(Timer<FrameView>*); + void doDeferredRepaints(); + void updateDeferredRepaintDelay(); + double adjustedDeferredRepaintDelay() const; + bool updateWidgets(); + static double sCurrentPaintTimeStamp; // used for detecting decoded resource thrash in the cache unsigned m_refCount; @@ -237,8 +263,10 @@ private: unsigned m_deferringRepaints; unsigned m_repaintCount; - IntRect m_repaintRect; Vector<IntRect> m_repaintRects; + Timer<FrameView> m_deferredRepaintTimer; + double m_deferredRepaintDelay; + double m_lastPaintTime; bool m_shouldUpdateWhileOffscreen; diff --git a/WebCore/page/Geolocation.cpp b/WebCore/page/Geolocation.cpp index f82e95d..e2f31a1 100644 --- a/WebCore/page/Geolocation.cpp +++ b/WebCore/page/Geolocation.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,8 +26,10 @@ #include "config.h" #include "Geolocation.h" +#include "Chrome.h" #include "Document.h" #include "Frame.h" +#include "Page.h" #include "PositionError.h" namespace WebCore { @@ -54,7 +56,11 @@ void Geolocation::GeoNotifier::timerFired(Timer<GeoNotifier>*) Geolocation::Geolocation(Frame* frame) : m_frame(frame) , m_service(GeolocationService::create(this)) + , m_allowGeolocation(Unknown) + , m_shouldClearCache(false) { + if (!m_frame) + return; ASSERT(m_frame->document()); m_frame->document()->setUsingGeolocation(true); } @@ -62,8 +68,6 @@ Geolocation::Geolocation(Frame* frame) void Geolocation::disconnectFrame() { m_service->stopUpdating(); - if (m_frame->document()) - m_frame->document()->setUsingGeolocation(false); m_frame = 0; } @@ -121,6 +125,18 @@ void Geolocation::resume() m_service->resume(); } +void Geolocation::setIsAllowed(bool allowed) +{ + m_allowGeolocation = allowed ? Yes : No; + + if (isAllowed()) + geolocationServicePositionChanged(m_service.get()); + else { + WTF::RefPtr<WebCore::PositionError> error = WebCore::PositionError::create(PositionError::PERMISSION_DENIED, "User disallowed GeoLocation"); + handleError(error.get()); + } +} + void Geolocation::sendErrorToOneShots(PositionError* error) { Vector<RefPtr<GeoNotifier> > copy; @@ -199,10 +215,32 @@ void Geolocation::handleError(PositionError* error) m_oneShots.clear(); } +void Geolocation::requestPermission() +{ + if (m_allowGeolocation > Unknown) + return; + + if (!m_frame) + return; + + Page* page = m_frame->page(); + if (!page) + return; + + // Ask the chrome: it maintains the geolocation challenge policy itself. + page->chrome()->requestGeolocationPermissionForFrame(m_frame, this); + + m_allowGeolocation = InProgress; +} + void Geolocation::geolocationServicePositionChanged(GeolocationService* service) { ASSERT(service->lastPosition()); + requestPermission(); + if (!isAllowed()) + return; + sendPositionToOneShots(service->lastPosition()); sendPositionToWatchers(service->lastPosition()); diff --git a/WebCore/page/Geolocation.h b/WebCore/page/Geolocation.h index 572cbd8..a14fc4b 100644 --- a/WebCore/page/Geolocation.h +++ b/WebCore/page/Geolocation.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -60,6 +60,12 @@ public: void suspend(); void resume(); + + void setIsAllowed(bool); + bool isAllowed() const { return m_allowGeolocation == Yes; } + + void setShouldClearCache(bool shouldClearCache) { m_shouldClearCache = shouldClearCache; } + bool shouldClearCache() const { return m_shouldClearCache; } private: Geolocation(Frame*); @@ -77,7 +83,7 @@ private: private: GeoNotifier(PassRefPtr<PositionCallback>, PassRefPtr<PositionErrorCallback>, PositionOptions*); }; - + bool hasListeners() const { return !m_oneShots.isEmpty() || !m_watchers.isEmpty(); } void sendErrorToOneShots(PositionError*); @@ -86,10 +92,13 @@ private: void sendPositionToWatchers(Geoposition*); void handleError(PositionError*); - + + void requestPermission(); + + // GeolocationServiceClient virtual void geolocationServicePositionChanged(GeolocationService*); virtual void geolocationServiceErrorOccurred(GeolocationService*); - + typedef HashSet<RefPtr<GeoNotifier> > GeoNotifierSet; typedef HashMap<int, RefPtr<GeoNotifier> > GeoNotifierMap; @@ -97,6 +106,14 @@ private: GeoNotifierMap m_watchers; Frame* m_frame; OwnPtr<GeolocationService> m_service; + + enum { + Unknown, + InProgress, + Yes, + No + } m_allowGeolocation; + bool m_shouldClearCache; }; } // namespace WebCore diff --git a/WebCore/page/Geoposition.cpp b/WebCore/page/Geoposition.cpp index 1792a1f..8f7a5c8 100644 --- a/WebCore/page/Geoposition.cpp +++ b/WebCore/page/Geoposition.cpp @@ -30,9 +30,7 @@ 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); + return "position(" + m_coordinates->toString() + String::format(", %.lld)", m_timestamp); } } // namespace WebCore diff --git a/WebCore/page/Geoposition.h b/WebCore/page/Geoposition.h index 9ce50e5..505e8b3 100644 --- a/WebCore/page/Geoposition.h +++ b/WebCore/page/Geoposition.h @@ -26,6 +26,7 @@ #ifndef Geoposition_h #define Geoposition_h +#include "Coordinates.h" #include "Event.h" #include "PlatformString.h" #include <wtf/RefCounted.h> @@ -36,39 +37,21 @@ 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)); } + static PassRefPtr<Geoposition> create(PassRefPtr<Coordinates> coordinates, DOMTimeStamp timestamp) { return adoptRef(new Geoposition(coordinates, 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; } - + Coordinates* coords() const { return m_coordinates.get(); } + 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) + Geoposition(PassRefPtr<Coordinates> coordinates, DOMTimeStamp timestamp) + : m_coordinates(coordinates) , m_timestamp(timestamp) { } - double m_latitude; - double m_longitude; - double m_altitude; - double m_accuracy; - double m_altitudeAccuracy; - double m_heading; - double m_speed; + RefPtr<Coordinates> m_coordinates; DOMTimeStamp m_timestamp; }; diff --git a/WebCore/page/Geoposition.idl b/WebCore/page/Geoposition.idl index 554bb30..2bcd40d 100644 --- a/WebCore/page/Geoposition.idl +++ b/WebCore/page/Geoposition.idl @@ -26,13 +26,7 @@ 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 Coordinates coords; readonly attribute DOMTimeStamp timestamp; #if defined(LANGUAGE_JAVASCRIPT) diff --git a/WebCore/page/History.idl b/WebCore/page/History.idl index e86cf92..c8cddae 100644 --- a/WebCore/page/History.idl +++ b/WebCore/page/History.idl @@ -26,6 +26,9 @@ module window { interface [ +#if defined(V8_BINDING) + CheckDomainSecurity, +#endif CustomGetOwnPropertySlot, CustomPutFunction, CustomDeleteProperty, @@ -33,9 +36,9 @@ module window { ] History { readonly attribute unsigned long length; - void back(); - void forward(); - void go(in long distance); + [DoNotCheckDomainSecurity] void back(); + [DoNotCheckDomainSecurity] void forward(); + [DoNotCheckDomainSecurity] void go(in long distance); }; } diff --git a/WebCore/page/Location.cpp b/WebCore/page/Location.cpp index 454aa78..ba28086 100644 --- a/WebCore/page/Location.cpp +++ b/WebCore/page/Location.cpp @@ -111,7 +111,8 @@ String Location::search() const if (!m_frame) return String(); - return url().query(); + const KURL& url = this->url(); + return url.query().isEmpty() ? "" : "?" + url.query(); } String Location::hash() const @@ -120,7 +121,7 @@ String Location::hash() const return String(); const KURL& url = this->url(); - return url.ref().isNull() ? "" : "#" + url.ref(); + return url.ref().isEmpty() ? "" : "#" + url.ref(); } String Location::toString() const diff --git a/WebCore/page/Location.idl b/WebCore/page/Location.idl index 91822ab..20f8bbd 100644 --- a/WebCore/page/Location.idl +++ b/WebCore/page/Location.idl @@ -29,16 +29,19 @@ module window { interface [ +#if defined(V8_BINDING) + CheckDomainSecurity, +#endif CustomGetOwnPropertySlot, CustomPutFunction, CustomDeleteProperty, CustomGetPropertyNames ] Location { - attribute [CustomSetter] DOMString href; + attribute [DoNotCheckDomainSecurityOnSet, CustomSetter, V8DisallowShadowing] DOMString href; - [Custom] void assign(in DOMString url); - [Custom] void replace(in DOMString url); - [Custom] void reload(); + [Custom, V8OnInstance] void assign(in DOMString url); + [Custom, V8OnInstance] void replace(in DOMString url); + [Custom, V8OnInstance] void reload(); // URI decomposition attributes attribute [CustomSetter] DOMString protocol; @@ -50,7 +53,10 @@ module window { attribute [CustomSetter] DOMString hash; #if defined(LANGUAGE_JAVASCRIPT) - [DontEnum, Custom] DOMString toString(); + [DontEnum, Custom, V8OnInstance, V8ReadOnly] DOMString toString(); +#endif +#if defined(V8_BINDING) + [DontEnum, Custom, V8OnInstance, V8ReadOnly] DOMObject valueOf(); #endif }; diff --git a/WebCore/page/Navigator.cpp b/WebCore/page/Navigator.cpp index 429ec00..dd4d27d 100644 --- a/WebCore/page/Navigator.cpp +++ b/WebCore/page/Navigator.cpp @@ -102,7 +102,13 @@ String Navigator::userAgent() const { if (!m_frame) return String(); - return m_frame->loader()->userAgent(m_frame->document() ? m_frame->document()->url() : KURL()); + + // If the frame is already detached, FrameLoader::userAgent may malfunction, because it calls a client method + // that uses frame's WebView (at least, in Mac WebKit). + if (!m_frame->page()) + return String(); + + return m_frame->loader()->userAgent(m_frame->document()->url()); } PluginArray* Navigator::plugins() const @@ -121,6 +127,9 @@ MimeTypeArray* Navigator::mimeTypes() const bool Navigator::cookieEnabled() const { + if (!m_frame) + return false; + if (m_frame->page() && !m_frame->page()->cookieEnabled()) return false; @@ -129,8 +138,9 @@ bool Navigator::cookieEnabled() const bool Navigator::javaEnabled() const { - if (!m_frame) + if (!m_frame || !m_frame->settings()) return false; + return m_frame->settings()->isJavaEnabled(); } diff --git a/WebCore/page/NavigatorBase.cpp b/WebCore/page/NavigatorBase.cpp index 27c9fdd..5138b0f 100644 --- a/WebCore/page/NavigatorBase.cpp +++ b/WebCore/page/NavigatorBase.cpp @@ -31,9 +31,9 @@ #include "PlatformString.h" #ifndef WEBCORE_NAVIGATOR_PLATFORM -#if PLATFORM(MAC) && PLATFORM(PPC) +#if PLATFORM(MAC) && (PLATFORM(PPC) || PLATFORM(PPC64)) #define WEBCORE_NAVIGATOR_PLATFORM "MacPPC" -#elif PLATFORM(MAC) && PLATFORM(X86) +#elif PLATFORM(MAC) && (PLATFORM(X86) || PLATFORM(X86_64)) #define WEBCORE_NAVIGATOR_PLATFORM "MacIntel" #elif PLATFORM(WIN_OS) #define WEBCORE_NAVIGATOR_PLATFORM "Win32" diff --git a/WebCore/page/Page.cpp b/WebCore/page/Page.cpp index 460183a..457bcde 100644 --- a/WebCore/page/Page.cpp +++ b/WebCore/page/Page.cpp @@ -93,11 +93,8 @@ static void networkStateChanged() 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(); + Node* eventTarget = document->body(); if (!eventTarget) eventTarget = document; @@ -111,7 +108,7 @@ Page::Page(ChromeClient* chromeClient, ContextMenuClient* contextMenuClient, Edi , m_dragController(new DragController(this, dragClient)) , m_focusController(new FocusController(this)) , m_contextMenuController(new ContextMenuController(this, contextMenuClient)) - , m_inspectorController(new InspectorController(this, inspectorClient)) + , m_inspectorController(InspectorController::create(this, inspectorClient)) , m_settings(new Settings(this)) , m_progress(new ProgressTracker) , m_backForwardList(BackForwardList::create(this)) @@ -157,11 +154,9 @@ Page::~Page() setGroupName(String()); allPages->remove(this); - for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) { - if (frame->document()) - frame->document()->documentWillBecomeInactive(); + for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) frame->pageDestroyed(); - } + m_editorClient->pageDestroyed(); if (m_parentInspectorController) m_parentInspectorController->pageDestroyed(); @@ -233,7 +228,7 @@ void Page::setGroupName(const String& name) } if (name.isEmpty()) - m_group = 0; + m_group = m_singlePageGroup.get(); else { m_singlePageGroup.clear(); m_group = PageGroup::pageGroup(name); @@ -358,13 +353,12 @@ void Page::unmarkAllTextMatches() Frame* frame = mainFrame(); do { - if (Document* document = frame->document()) - document->removeMarkers(DocumentMarker::TextMatch); + frame->document()->removeMarkers(DocumentMarker::TextMatch); frame = incrementFrame(frame, true, false); } while (frame); } -const Selection& Page::selection() const +const VisibleSelection& Page::selection() const { return focusController()->focusedOrMainFrame()->selection()->selection(); } @@ -404,8 +398,23 @@ void Page::setMediaVolume(float volume) m_mediaVolume = volume; for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) { - if (frame->document()) - frame->document()->mediaVolumeDidChange(); + frame->document()->mediaVolumeDidChange(); + } +} + +void Page::didMoveOnscreen() +{ + for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) { + if (frame->view()) + frame->view()->didMoveOnscreen(); + } +} + +void Page::willMoveOffscreen() +{ + for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) { + if (frame->view()) + frame->view()->willMoveOffscreen(); } } @@ -461,7 +470,9 @@ const String& Page::userStyleSheet() const if (!data) return m_userStyleSheet; - m_userStyleSheet = TextResourceDecoder::create("text/css")->decode(data->data(), data->size()); + RefPtr<TextResourceDecoder> decoder = TextResourceDecoder::create("text/css"); + m_userStyleSheet = decoder->decode(data->data(), data->size()); + m_userStyleSheet += decoder->flush(); return m_userStyleSheet; } diff --git a/WebCore/page/Page.h b/WebCore/page/Page.h index aea16a2..f140783 100644 --- a/WebCore/page/Page.h +++ b/WebCore/page/Page.h @@ -60,7 +60,7 @@ namespace WebCore { class PageGroup; class PluginData; class ProgressTracker; - class Selection; + class VisibleSelection; class SelectionController; #if ENABLE(DOM_STORAGE) class SessionStorage; @@ -137,7 +137,7 @@ namespace WebCore { OwnPtr<SchedulePairHashSet> m_scheduledRunLoopPairs; #endif - const Selection& selection() const; + const VisibleSelection& selection() const; void setDefersLoading(bool); bool defersLoading() const { return m_defersLoading; } @@ -153,6 +153,10 @@ namespace WebCore { float mediaVolume() const { return m_mediaVolume; } void setMediaVolume(float volume); + // Notifications when the Page starts and stops being presented via a native window. + void didMoveOnscreen(); + void willMoveOffscreen(); + void userStyleSheetLocationChanged(); const String& userStyleSheet() const; @@ -204,7 +208,7 @@ namespace WebCore { OwnPtr<DragController> m_dragController; OwnPtr<FocusController> m_focusController; OwnPtr<ContextMenuController> m_contextMenuController; - OwnPtr<InspectorController> m_inspectorController; + RefPtr<InspectorController> m_inspectorController; OwnPtr<Settings> m_settings; OwnPtr<ProgressTracker> m_progress; diff --git a/WebCore/page/PositionOptions.h b/WebCore/page/PositionOptions.h index dc9c167..10845d3 100644 --- a/WebCore/page/PositionOptions.h +++ b/WebCore/page/PositionOptions.h @@ -33,22 +33,26 @@ namespace WebCore { class PositionOptions : public RefCounted<PositionOptions> { public: - static PassRefPtr<PositionOptions> create(bool highAccuracy, unsigned timeout) { return adoptRef(new PositionOptions(highAccuracy, timeout)); } + static PassRefPtr<PositionOptions> create(bool highAccuracy, unsigned timeout, unsigned maximumAge) { return adoptRef(new PositionOptions(highAccuracy, timeout, maximumAge)); } 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; } + unsigned maximumAge() const { return m_maximumAge; } + void setMaximumAge(unsigned a) { m_maximumAge = a; } private: - PositionOptions(bool highAccuracy, unsigned timeout) + PositionOptions(bool highAccuracy, unsigned timeout, unsigned maximumAge) : m_highAccuracy(highAccuracy) , m_timeout(timeout) + , m_maximumAge(maximumAge) { } bool m_highAccuracy; unsigned m_timeout; + unsigned m_maximumAge; }; } // namespace WebCore diff --git a/WebCore/page/PrintContext.cpp b/WebCore/page/PrintContext.cpp index 79672a3..b83d714 100644 --- a/WebCore/page/PrintContext.cpp +++ b/WebCore/page/PrintContext.cpp @@ -85,7 +85,7 @@ void PrintContext::computePageRects(const FloatRect& printRect, float headerHeig float printedPagesHeight = 0.0; do { float proposedBottom = std::min(docHeight, printedPagesHeight + pageHeight); - m_frame->adjustPageHeight(&proposedBottom, printedPagesHeight, proposedBottom, printedPagesHeight); + m_frame->view()->adjustPageHeight(&proposedBottom, printedPagesHeight, proposedBottom, printedPagesHeight); currPageHeight = max(1.0f, proposedBottom - printedPagesHeight); m_pageRects.append(IntRect(0, (int)printedPagesHeight, (int)currPageWidth, (int)currPageHeight)); diff --git a/WebCore/page/SecurityOrigin.cpp b/WebCore/page/SecurityOrigin.cpp index fd8144f..a1863c9 100644 --- a/WebCore/page/SecurityOrigin.cpp +++ b/WebCore/page/SecurityOrigin.cpp @@ -58,14 +58,15 @@ SecurityOrigin::SecurityOrigin(const KURL& url) , m_host(url.host().isNull() ? "" : url.host().lower()) , m_port(url.port()) , m_noAccess(false) + , m_universalAccess(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") + // Some URLs are not allowed access to anything other than themselves. + if (FrameLoader::shouldTreatURLSchemeAsNoAccess(m_protocol)) m_noAccess = true; // document.domain starts as m_host, but can be set by the DOM. @@ -84,6 +85,7 @@ SecurityOrigin::SecurityOrigin(const SecurityOrigin* other) , m_domain(other->m_domain.copy()) , m_port(other->m_port) , m_noAccess(other->m_noAccess) + , m_universalAccess(other->m_universalAccess) , m_domainWasSetInDOM(other->m_domainWasSetInDOM) , m_canLoadLocalResources(other->m_canLoadLocalResources) { @@ -119,7 +121,7 @@ void SecurityOrigin::setDomainFromDOM(const String& newDomain) bool SecurityOrigin::canAccess(const SecurityOrigin* other) const { - if (isLocal()) + if (m_universalAccess) return true; if (m_noAccess || other->m_noAccess) @@ -160,7 +162,7 @@ bool SecurityOrigin::canAccess(const SecurityOrigin* other) const bool SecurityOrigin::canRequest(const KURL& url) const { - if (isLocal()) + if (m_universalAccess) return true; if (m_noAccess) @@ -184,9 +186,14 @@ void SecurityOrigin::grantLoadLocalResources() m_canLoadLocalResources = true; } +void SecurityOrigin::grantUniversalAccess() +{ + m_universalAccess = true; +} + bool SecurityOrigin::isLocal() const { - return FrameLoader::shouldTreatSchemeAsLocal(m_protocol); + return FrameLoader::shouldTreatURLSchemeAsLocal(m_protocol); } bool SecurityOrigin::isSecureTransitionTo(const KURL& url) const @@ -211,7 +218,7 @@ String SecurityOrigin::toString() const return String("file://"); Vector<UChar> result; - result.reserveCapacity(m_protocol.length() + m_host.length() + 10); + result.reserveInitialCapacity(m_protocol.length() + m_host.length() + 10); append(result, m_protocol); append(result, "://"); append(result, m_host); @@ -259,7 +266,7 @@ PassRefPtr<SecurityOrigin> SecurityOrigin::createFromDatabaseIdentifier(const St // 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))); + return create(KURL(KURL(), protocol + "://" + host + ":" + String::number(port))); } String SecurityOrigin::databaseIdentifier() const diff --git a/WebCore/page/SecurityOrigin.h b/WebCore/page/SecurityOrigin.h index 1f2624e..96f85df 100644 --- a/WebCore/page/SecurityOrigin.h +++ b/WebCore/page/SecurityOrigin.h @@ -90,6 +90,11 @@ namespace WebCore { // with older versions of WebKit. void grantLoadLocalResources(); + // Explicitly grant the ability to access very other SecurityOrigin. + // + // WARNING: This is an extremely powerful ability. Use with caution! + void grantUniversalAccess(); + bool isSecureTransitionTo(const KURL&) const; // The local SecurityOrigin is the most privileged SecurityOrigin. @@ -132,6 +137,7 @@ namespace WebCore { String m_domain; unsigned short m_port; bool m_noAccess; + bool m_universalAccess; bool m_domainWasSetInDOM; bool m_canLoadLocalResources; }; diff --git a/WebCore/page/Settings.cpp b/WebCore/page/Settings.cpp index 8c9bb44..1815535 100644 --- a/WebCore/page/Settings.cpp +++ b/WebCore/page/Settings.cpp @@ -72,6 +72,8 @@ Settings::Settings(Page* page) , m_databasesEnabled(false) , m_localStorageEnabled(false) , m_isJavaScriptEnabled(false) + , m_isWebSecurityEnabled(true) + , m_allowUniversalAccessFromFileURLs(true) , m_javaScriptCanOpenWindowsAutomatically(false) , m_shouldPrintBackgrounds(false) , m_textAreasAreResizable(false) @@ -80,6 +82,8 @@ Settings::Settings(Page* page) #endif , m_needsAdobeFrameReloadingQuirk(false) , m_needsKeyboardEventDisambiguationQuirks(false) + , m_needsLeopardMailQuirks(false) + , m_needsTigerMailQuirks(false) , m_isDOMPasteAllowed(false) , m_shrinksStandaloneImagesToFit(true) , m_usesPageCache(false) @@ -92,12 +96,12 @@ Settings::Settings(Page* page) , m_webArchiveDebugModeEnabled(false) , m_inApplicationChromeMode(false) , m_offlineWebApplicationCacheEnabled(false) - , m_rangeMutationDisabledForOldAppleMail(false) , m_shouldPaintCustomScrollbars(false) , m_zoomsTextOnly(false) , m_enforceCSSMIMETypeInStrictMode(true) + , m_usesEncodingDetector(false) , m_maximumDecodedImageSize(std::numeric_limits<size_t>::max()) - , m_needsIChatMemoryCacheCallsQuirk(false) + , m_allowScriptsToCloseWindows(false) { // A Frame may not have been created yet, so we initialize the AtomicString // hash before trying to use it. @@ -214,6 +218,16 @@ void Settings::setJavaScriptEnabled(bool isJavaScriptEnabled) m_isJavaScriptEnabled = isJavaScriptEnabled; } +void Settings::setWebSecurityEnabled(bool isWebSecurityEnabled) +{ + m_isWebSecurityEnabled = isWebSecurityEnabled; +} + +void Settings::setAllowUniversalAccessFromFileURLs(bool allowUniversalAccessFromFileURLs) +{ + m_allowUniversalAccessFromFileURLs = allowUniversalAccessFromFileURLs; +} + void Settings::setJavaEnabled(bool isJavaEnabled) { m_isJavaEnabled = isJavaEnabled; @@ -313,6 +327,16 @@ void Settings::setNeedsKeyboardEventDisambiguationQuirks(bool needsQuirks) m_needsKeyboardEventDisambiguationQuirks = needsQuirks; } +void Settings::setNeedsLeopardMailQuirks(bool needsQuirks) +{ + m_needsLeopardMailQuirks = needsQuirks; +} + +void Settings::setNeedsTigerMailQuirks(bool needsQuirks) +{ + m_needsTigerMailQuirks = needsQuirks; +} + void Settings::setDOMPasteAllowed(bool DOMPasteAllowed) { m_isDOMPasteAllowed = DOMPasteAllowed; @@ -483,11 +507,6 @@ 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; @@ -524,9 +543,14 @@ void Settings::setShouldPaintNativeControls(bool shouldPaintNativeControls) } #endif -void Settings::setNeedsIChatMemoryCacheCallsQuirk(bool needsIChatMemoryCacheCallsQuirk) +void Settings::setUsesEncodingDetector(bool usesEncodingDetector) +{ + m_usesEncodingDetector = usesEncodingDetector; +} + +void Settings::setAllowScriptsToCloseWindows(bool allowScriptsToCloseWindows) { - m_needsIChatMemoryCacheCallsQuirk = needsIChatMemoryCacheCallsQuirk; + m_allowScriptsToCloseWindows = allowScriptsToCloseWindows; } } // namespace WebCore diff --git a/WebCore/page/Settings.h b/WebCore/page/Settings.h index b9b888f..925324f 100644 --- a/WebCore/page/Settings.h +++ b/WebCore/page/Settings.h @@ -112,6 +112,12 @@ namespace WebCore { void setJavaScriptEnabled(bool); bool isJavaScriptEnabled() const { return m_isJavaScriptEnabled; } + void setWebSecurityEnabled(bool); + bool isWebSecurityEnabled() const { return m_isWebSecurityEnabled; } + + void setAllowUniversalAccessFromFileURLs(bool); + bool allowUniversalAccessFromFileURLs() const { return m_allowUniversalAccessFromFileURLs; } + void setJavaScriptCanOpenWindowsAutomatically(bool); bool JavaScriptCanOpenWindowsAutomatically() const { return m_javaScriptCanOpenWindowsAutomatically; } @@ -137,6 +143,9 @@ namespace WebCore { void setDefaultTextEncodingName(const String&); const String& defaultTextEncodingName() const { return m_defaultTextEncodingName; } + + void setUsesEncodingDetector(bool); + bool usesEncodingDetector() const { return m_usesEncodingDetector; } void setUserStyleSheetLocation(const KURL&); const KURL& userStyleSheetLocation() const { return m_userStyleSheetLocation; } @@ -164,6 +173,12 @@ namespace WebCore { void setNeedsKeyboardEventDisambiguationQuirks(bool); bool needsKeyboardEventDisambiguationQuirks() const { return m_needsKeyboardEventDisambiguationQuirks; } + void setNeedsLeopardMailQuirks(bool); + bool needsLeopardMailQuirks() const { return m_needsLeopardMailQuirks; } + + void setNeedsTigerMailQuirks(bool); + bool needsTigerMailQuirks() const { return m_needsTigerMailQuirks; } + void setDOMPasteAllowed(bool); bool isDOMPasteAllowed() const { return m_isDOMPasteAllowed; } @@ -218,9 +233,6 @@ namespace WebCore { 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; } @@ -245,8 +257,8 @@ namespace WebCore { static bool shouldPaintNativeControls() { return gShouldPaintNativeControls; } #endif - void setNeedsIChatMemoryCacheCallsQuirk(bool); - bool needsIChatMemoryCacheCallsQuirk() const { return m_needsIChatMemoryCacheCallsQuirk; } + void setAllowScriptsToCloseWindows(bool); + bool allowScriptsToCloseWindows() const { return m_allowScriptsToCloseWindows; } private: Page* m_page; @@ -311,6 +323,8 @@ namespace WebCore { bool m_databasesEnabled : 1; bool m_localStorageEnabled : 1; bool m_isJavaScriptEnabled : 1; + bool m_isWebSecurityEnabled : 1; + bool m_allowUniversalAccessFromFileURLs: 1; bool m_javaScriptCanOpenWindowsAutomatically : 1; bool m_shouldPrintBackgrounds : 1; bool m_textAreasAreResizable : 1; @@ -319,6 +333,8 @@ namespace WebCore { #endif bool m_needsAdobeFrameReloadingQuirk : 1; bool m_needsKeyboardEventDisambiguationQuirks : 1; + bool m_needsLeopardMailQuirks : 1; + bool m_needsTigerMailQuirks : 1; bool m_isDOMPasteAllowed : 1; bool m_shrinksStandaloneImagesToFit : 1; bool m_usesPageCache: 1; @@ -331,12 +347,12 @@ namespace WebCore { 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; + bool m_usesEncodingDetector : 1; size_t m_maximumDecodedImageSize; - bool m_needsIChatMemoryCacheCallsQuirk : 1; + bool m_allowScriptsToCloseWindows : 1; #if USE(SAFARI_THEME) static bool gShouldPaintNativeControls; diff --git a/WebCore/page/WebKitPoint.h b/WebCore/page/WebKitPoint.h new file mode 100644 index 0000000..501b17f --- /dev/null +++ b/WebCore/page/WebKitPoint.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE 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 WebKitPoint_h +#define WebKitPoint_h + +#include <wtf/RefCounted.h> + +namespace WebCore { + + class WebKitPoint : public RefCounted<WebKitPoint> { + public: + + static PassRefPtr<WebKitPoint> create() + { + return adoptRef(new WebKitPoint()); + } + static PassRefPtr<WebKitPoint> create(float x, float y) + { + return adoptRef(new WebKitPoint(x, y)); + } + + float x() const { return m_x; } + float y() const { return m_y; } + + void setX(float x) { m_x = x; } + void setY(float y) { m_y = y; } + + private: + WebKitPoint(float x=0, float y=0) + : m_x(x) + , m_y(y) + { + } + + float m_x, m_y; + }; + +} // namespace WebCore + +#endif // WebKitPoint_h diff --git a/WebCore/page/WebKitPoint.idl b/WebCore/page/WebKitPoint.idl new file mode 100644 index 0000000..1eefbc3 --- /dev/null +++ b/WebCore/page/WebKitPoint.idl @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE 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 WebKitPoint { + attribute float x; + attribute float y; + }; + +} diff --git a/WebCore/page/android/InspectorControllerAndroid.cpp b/WebCore/page/android/InspectorControllerAndroid.cpp index d6222d7..8763df1 100644 --- a/WebCore/page/android/InspectorControllerAndroid.cpp +++ b/WebCore/page/android/InspectorControllerAndroid.cpp @@ -106,4 +106,6 @@ void InspectorController::failedToParseSource(JSC::ExecState* exec, const JSC::S void InspectorController::didParseSource(JSC::ExecState* exec, const JSC::SourceCode& source) {} void InspectorController::didPause() {} +void InspectorController::scriptImported(unsigned long identifier, const JSC::UString& sourceString) {} +void InspectorController::startUserInitiatedProfiling(Timer<InspectorController>*) {} } // namespace WebCore diff --git a/WebCore/page/animation/AnimationBase.cpp b/WebCore/page/animation/AnimationBase.cpp index 3e43f66..e500fe4 100644 --- a/WebCore/page/animation/AnimationBase.cpp +++ b/WebCore/page/animation/AnimationBase.cpp @@ -29,7 +29,7 @@ #include "config.h" #include "AnimationBase.h" -#include "AnimationController.h" +#include "AnimationControllerPrivate.h" #include "CSSMutableStyleDeclaration.h" #include "CSSPropertyLonghand.h" #include "CSSPropertyNames.h" @@ -43,10 +43,15 @@ #include "ImplicitAnimation.h" #include "KeyframeAnimation.h" #include "MatrixTransformOperation.h" -#include "RenderObject.h" +#include "Matrix3DTransformOperation.h" +#include "RenderBox.h" #include "RenderStyle.h" #include "UnitBezier.h" +#include <algorithm> + +using namespace std; + namespace WebCore { // The epsilon value we pass to UnitBezier::solve given that the animation is going to run over |dur| seconds. The longer the @@ -143,7 +148,7 @@ static inline TransformOperations blendFunc(const AnimationBase* anim, const Tra toT.blend(fromT, progress); // Append the result - result.operations().append(MatrixTransformOperation::create(toT.a(), toT.b(), toT.c(), toT.d(), toT.e(), toT.f())); + result.operations().append(Matrix3DTransformOperation::create(toT)); } return result; } @@ -180,6 +185,10 @@ public: int property() const { return m_prop; } +#if USE(ACCELERATED_COMPOSITING) + virtual bool animationIsAccelerated() const { return false; } +#endif + private: int m_prop; }; @@ -197,7 +206,7 @@ public: { // 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) + if ((!a && !b) || a == b) return true; if (!a || !b) return false; @@ -226,6 +235,41 @@ protected: void (RenderStyle::*m_setter)(T); }; +#if USE(ACCELERATED_COMPOSITING) +class PropertyWrapperAcceleratedOpacity : public PropertyWrapper<float> { +public: + PropertyWrapperAcceleratedOpacity() + : PropertyWrapper<float>(CSSPropertyOpacity, &RenderStyle::opacity, &RenderStyle::setOpacity) + { + } + + virtual bool animationIsAccelerated() const { return true; } + + virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const + { + float fromOpacity = a->opacity(); + + // This makes sure we put the object being animated into a RenderLayer during the animation + dst->setOpacity(blendFunc(anim, (fromOpacity == 1) ? 0.999999f : fromOpacity, b->opacity(), progress)); + } +}; + +class PropertyWrapperAcceleratedTransform : public PropertyWrapper<const TransformOperations&> { +public: + PropertyWrapperAcceleratedTransform() + : PropertyWrapper<const TransformOperations&>(CSSPropertyWebkitTransform, &RenderStyle::transform, &RenderStyle::setTransform) + { + } + + virtual bool animationIsAccelerated() const { return true; } + + virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const + { + dst->setTransform(blendFunc(anim, a->transform(), b->transform(), progress)); + } +}; +#endif // USE(ACCELERATED_COMPOSITING) + class PropertyWrapperShadow : public PropertyWrapperGetter<ShadowData*> { public: PropertyWrapperShadow(int prop, ShadowData* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(ShadowData*, bool)) @@ -239,7 +283,7 @@ public: ShadowData* shadowA = (a->*m_getter)(); ShadowData* shadowB = (b->*m_getter)(); - if (!shadowA && shadowB || shadowA && !shadowB) + if ((!shadowA && shadowB) || (shadowA && !shadowB)) return false; if (shadowA && shadowB && (*shadowA != *shadowB)) return false; @@ -368,7 +412,6 @@ static void ensurePropertyMap() 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)); @@ -384,15 +427,27 @@ static void ensurePropertyMap() 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<float>(CSSPropertyWebkitPerspective, &RenderStyle::perspective, &RenderStyle::setPerspective)); + gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitPerspectiveOriginX, &RenderStyle::perspectiveOriginX, &RenderStyle::setPerspectiveOriginX)); + gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitPerspectiveOriginY, &RenderStyle::perspectiveOriginY, &RenderStyle::setPerspectiveOriginY)); gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitTransformOriginX, &RenderStyle::transformOriginX, &RenderStyle::setTransformOriginX)); gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitTransformOriginY, &RenderStyle::transformOriginY, &RenderStyle::setTransformOriginY)); + gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitTransformOriginZ, &RenderStyle::transformOriginZ, &RenderStyle::setTransformOriginZ)); 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)); + +#if USE(ACCELERATED_COMPOSITING) + gPropertyWrappers->append(new PropertyWrapperAcceleratedOpacity()); + gPropertyWrappers->append(new PropertyWrapperAcceleratedTransform()); +#else + gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyOpacity, &RenderStyle::opacity, &RenderStyle::setOpacity)); + gPropertyWrappers->append(new PropertyWrapper<const TransformOperations&>(CSSPropertyWebkitTransform, &RenderStyle::transform, &RenderStyle::setTransform)); +#endif + 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)); @@ -507,13 +562,13 @@ static PropertyWrapperBase* wrapperForProperty(int propertyID) 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_fallbackAnimating(false) , m_transformFunctionListValid(false) , m_nextIterationDuration(-1) , m_next(0) @@ -526,8 +581,8 @@ AnimationBase::AnimationBase(const Animation* transition, RenderObject* renderer AnimationBase::~AnimationBase() { - if (m_animState == AnimationStateStartWaitStyleAvailable) - m_compAnim->removeFromStyleAvailableWaitList(this); + m_compAnim->removeFromStyleAvailableWaitList(this); + m_compAnim->removeFromStartTimeResponseWaitList(this); } bool AnimationBase::propertiesEqual(int prop, const RenderStyle* a, const RenderStyle* b) @@ -575,12 +630,25 @@ bool AnimationBase::blendProperties(const AnimationBase* anim, int prop, RenderS PropertyWrapperBase* wrapper = wrapperForProperty(prop); if (wrapper) { wrapper->blend(anim, dst, a, b, progress); +#if USE(ACCELERATED_COMPOSITING) + return !wrapper->animationIsAccelerated() || anim->isFallbackAnimating(); +#else return true; +#endif } return false; } +#if USE(ACCELERATED_COMPOSITING) +bool AnimationBase::animationOfPropertyIsAccelerated(int prop) +{ + ensurePropertyMap(); + PropertyWrapperBase* wrapper = wrapperForProperty(prop); + return wrapper ? wrapper->animationIsAccelerated() : false; +} +#endif + void AnimationBase::setChanged(Node* node) { ASSERT(!node || (node->document() && !node->document()->inPageCache())); @@ -614,7 +682,6 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) m_pauseTime = -1; m_requestedStartTime = 0; m_nextIterationDuration = -1; - m_waitedForResponse = false; endAnimation(false); return; } @@ -661,11 +728,10 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) } // Execute state machine - switch(m_animState) { + 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; } @@ -681,7 +747,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) // Trigger a render so we can start the animation if (m_object) - m_object->animation()->addNodeChangeToDispatch(m_object->element()); + m_compAnim->animationControllerPriv()->addNodeChangeToDispatch(m_object->node()); } else { ASSERT(!paused()); // We're waiting for the start timer to fire and we got a pause. Cancel the timer, pause and wait @@ -701,12 +767,18 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) 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 + if (overridden()) { + // We won't try to start accelerated animations if we are overridden and + // just move on to the next state. m_animState = AnimationStateStartWaitResponse; + m_fallbackAnimating = true; updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUpdateTime()); - } else - m_waitedForResponse = true; + } + else { + bool started = startAnimation(0); + m_compAnim->addToStartTimeResponseWaitList(this, started); + m_fallbackAnimating = !started; + } break; case AnimationStateStartWaitResponse: ASSERT(input == AnimationStateInputStartTimeSet || input == AnimationStateInputPlayStatePaused); @@ -722,7 +794,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) // Dispatch updateRendering so we can start the animation if (m_object) - m_object->animation()->addNodeChangeToDispatch(m_object->element()); + m_compAnim->animationControllerPriv()->addNodeChangeToDispatch(m_object->node()); } 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 @@ -762,7 +834,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) resumeOverriddenAnimations(); // Fire off another style change so we can set the final value - m_object->animation()->addNodeChangeToDispatch(m_object->element()); + m_compAnim->animationControllerPriv()->addNodeChangeToDispatch(m_object->node()); } } else { // We are pausing while running. Cancel the animation and wait @@ -789,8 +861,19 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) // AnimationStatePausedWaitResponse, we don't yet have a valid startTime, so we send 0 to startAnimation. // When the AnimationStateInputStartTimeSet comes in and we were in AnimationStatePausedRun, we will notice // that we have already set the startTime and will ignore it. - ASSERT(input == AnimationStateInputPlayStateRunnning); + ASSERT(input == AnimationStateInputPlayStateRunnning || input == AnimationStateInputStartTimeSet); ASSERT(paused()); + + // If we are paused, but we get the callback that notifies us that an accelerated animation started, + // then we ignore the start time and just move into the paused-run state. + if (m_animState == AnimationStatePausedWaitResponse && input == AnimationStateInputStartTimeSet) { + m_animState = AnimationStatePausedRun; + ASSERT(m_startTime == 0); + m_startTime = param; + m_pauseTime += m_startTime; + break; + } + // Update the times if (m_animState == AnimationStatePausedRun) m_startTime += beginAnimationUpdateTime() - m_pauseTime; @@ -802,11 +885,16 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) 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 + if (overridden()) { + // We won't try to start accelerated animations if we are overridden and + // just move on to the next state. updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUpdateTime()); - } else - m_waitedForResponse = true; + m_fallbackAnimating = true; + } else { + bool started = startAnimation(0); + m_compAnim->addToStartTimeResponseWaitList(this, started); + m_fallbackAnimating = !started; + } break; case AnimationStateDone: // We're done. Stay in this state until we are deleted @@ -835,14 +923,16 @@ void AnimationBase::fireAnimationEventsIfNeeded() } double elapsedDuration = beginAnimationUpdateTime() - m_startTime; - ASSERT(elapsedDuration >= 0); + // FIXME: we need to ensure that elapsedDuration is never < 0. If it is, this suggests that + // we had a recalcStyle() outside of beginAnimationUpdate()/endAnimationUpdate(). + // Also check in getTimeToNextEvent(). + elapsedDuration = max(elapsedDuration, 0.0); // Check for end timeout if (m_totalDuration >= 0 && elapsedDuration >= m_totalDuration) { // Fire an end event updateStateMachine(AnimationStateInputEndTimerFired, m_totalDuration); - } - else { + } else { // Check for iteration timeout if (m_nextIterationDuration < 0) { // Hasn't been set yet, set it @@ -868,18 +958,20 @@ void AnimationBase::updatePlayState(bool run) updateStateMachine(run ? AnimationStateInputPlayStateRunnning : AnimationStateInputPlayStatePaused, -1); } -double AnimationBase::willNeedService() const +double AnimationBase::willNeedService() { // 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); + return max(timeFromNow, 0.0); } + fireAnimationEventsIfNeeded(); + // In all other cases, we need service right away. return 0; } @@ -926,31 +1018,40 @@ double AnimationBase::progress(double scale, double offset, const TimingFunction return result; } -void AnimationBase::goIntoEndingOrLoopingState() +void AnimationBase::getTimeToNextEvent(double& time, bool& isLooping) const { // 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); + const double elapsedDuration = max(beginAnimationUpdateTime() - m_startTime, 0.0); double durationLeft = 0; - double nextIterationTime = totalDuration; + double nextIterationTime = m_totalDuration; - if (totalDuration < 0 || elapsedDuration < totalDuration) { + if (m_totalDuration < 0 || elapsedDuration < m_totalDuration) { durationLeft = m_animation->duration() - fmod(elapsedDuration, m_animation->duration()); nextIterationTime = elapsedDuration + durationLeft; } - - if (totalDuration < 0 || nextIterationTime < totalDuration) { + + if (m_totalDuration < 0 || nextIterationTime < m_totalDuration) { // We are not at the end yet ASSERT(nextIterationTime > 0); - m_animState = AnimationStateLooping; + isLooping = true; } else { // We are at the end - m_animState = AnimationStateEnding; + isLooping = false; } + + time = durationLeft; +} + +void AnimationBase::goIntoEndingOrLoopingState() +{ + double t; + bool isLooping; + getTimeToNextEvent(t, isLooping); + m_animState = isLooping ? AnimationStateLooping : AnimationStateEnding; } void AnimationBase::pauseAtTime(double t) @@ -961,7 +1062,7 @@ void AnimationBase::pauseAtTime(double t) double AnimationBase::beginAnimationUpdateTime() const { - return m_compAnim->animationController()->beginAnimationUpdateTime(); + return m_compAnim->animationControllerPriv()->beginAnimationUpdateTime(); } double AnimationBase::getElapsedTime() const diff --git a/WebCore/page/animation/AnimationBase.h b/WebCore/page/animation/AnimationBase.h index ce16f93..da4341b 100644 --- a/WebCore/page/animation/AnimationBase.h +++ b/WebCore/page/animation/AnimationBase.h @@ -94,7 +94,10 @@ public: void updateStateMachine(AnimStateInput, double param); // Animation has actually started, at passed time - void onAnimationStartResponse(double startTime); + void onAnimationStartResponse(double startTime) + { + updateStateMachine(AnimationBase::AnimationStateInputStartTimeSet, startTime); + } // Called to change to or from paused state void updatePlayState(bool running); @@ -117,12 +120,12 @@ public: // "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; + virtual double willNeedService(); double progress(double scale, double offset, const TimingFunction*) const; - virtual void animate(CompositeAnimation*, RenderObject*, const RenderStyle* /*currentStyle*/, - const RenderStyle* /*targetStyle*/, RefPtr<RenderStyle>& /*animatedStyle*/) { } + virtual void animate(CompositeAnimation*, RenderObject*, const RenderStyle* /*currentStyle*/, RenderStyle* /*targetStyle*/, RefPtr<RenderStyle>& /*animatedStyle*/) = 0; + virtual void getAnimatedStyle(RefPtr<RenderStyle>& /*animatedStyle*/) = 0; virtual bool shouldFireEvents() const { return false; } @@ -142,6 +145,9 @@ public: virtual bool affectsProperty(int /*property*/) const { return false; } bool isAnimatingProperty(int property, bool isRunningNow) const { + if (m_fallbackAnimating) + return false; + if (isRunningNow) return (!waitingToStart() && !postActive()) && affectsProperty(property); @@ -164,7 +170,11 @@ public: ASSERT(waitingForStyleAvailable()); updateStateMachine(AnimationBase::AnimationStateInputStyleAvailable, -1); } - + +#if USE(ACCELERATED_COMPOSITING) + static bool animationOfPropertyIsAccelerated(int prop); +#endif + protected: virtual void overrideAnimations() { } virtual void resumeOverriddenAnimations() { } @@ -176,23 +186,26 @@ protected: virtual void onAnimationIteration(double /*elapsedTime*/) { } virtual void onAnimationEnd(double /*elapsedTime*/) { } virtual bool startAnimation(double /*beginTime*/) { return false; } - virtual void endAnimation(bool /*reset*/) { } + virtual void endAnimation(bool /*reset*/, double /*forcePauseTime*/ = -1) { } void goIntoEndingOrLoopingState(); + bool isFallbackAnimating() const { return m_fallbackAnimating; } + static bool propertiesEqual(int prop, const RenderStyle* a, const RenderStyle* b); static int getPropertyAtIndex(int, bool& isShorthand); 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*); + + void getTimeToNextEvent(double& time, bool& isLooping) const; AnimState m_animState; bool m_isAnimating; // transition/animation requires continual timer firing - bool m_waitedForResponse; double m_startTime; double m_pauseTime; double m_requestedStartTime; @@ -200,6 +213,7 @@ protected: RefPtr<Animation> m_animation; CompositeAnimation* m_compAnim; + bool m_fallbackAnimating; // true when animating an accelerated property but have to fall back to software bool m_transformFunctionListValid; double m_totalDuration, m_nextIterationDuration; diff --git a/WebCore/page/animation/AnimationController.cpp b/WebCore/page/animation/AnimationController.cpp index f85e6c1..f9c9a47 100644 --- a/WebCore/page/animation/AnimationController.cpp +++ b/WebCore/page/animation/AnimationController.cpp @@ -28,84 +28,22 @@ #include "config.h" #include "AnimationController.h" + #include "AnimationBase.h" -#include "CompositeAnimation.h" +#include "AnimationControllerPrivate.h" #include "CSSParser.h" +#include "CompositeAnimation.h" #include "EventNames.h" #include "Frame.h" -#include "Timer.h" +#include "RenderObject.h" #include <wtf/CurrentTime.h> +#include <wtf/UnusedParam.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); - void addNodeChangeToDispatch(PassRefPtr<Node>); - - 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; } - - void addToStyleAvailableWaitList(AnimationBase*); - void removeFromStyleAvailableWaitList(AnimationBase*); - -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; - Vector<RefPtr<Node> > m_nodeChangesToDispatch; - - double m_beginAnimationUpdateTime; - AnimationBase* m_styleAvailableWaiters; - AnimationBase* m_lastStyleAvailableWaiter; -}; - AnimationControllerPrivate::AnimationControllerPrivate(Frame* frame) : m_animationTimer(this, &AnimationControllerPrivate::animationTimerFired) , m_updateRenderingDispatcher(this, &AnimationControllerPrivate::updateRenderingDispatcherFired) @@ -113,6 +51,9 @@ AnimationControllerPrivate::AnimationControllerPrivate(Frame* frame) , m_beginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet) , m_styleAvailableWaiters(0) , m_lastStyleAvailableWaiter(0) + , m_responseWaiters(0) + , m_lastResponseWaiter(0) + , m_waitingForAResponse(false) { } @@ -124,7 +65,7 @@ PassRefPtr<CompositeAnimation> AnimationControllerPrivate::accessCompositeAnimat { RefPtr<CompositeAnimation> animation = m_compositeAnimations.get(renderer); if (!animation) { - animation = CompositeAnimation::create(m_frame->animation()); + animation = CompositeAnimation::create(this); m_compositeAnimations.set(renderer, animation); } return animation; @@ -155,7 +96,7 @@ void AnimationControllerPrivate::updateAnimationTimer(bool callSetChanged/* = fa needsService = t; if (needsService == 0) { if (callSetChanged) { - Node* node = it->first->element(); + Node* node = it->first->node(); ASSERT(!node || (node->document() && !node->document()->inPageCache())); node->setChanged(AnimationStyleChange); calledSetChanged = true; @@ -209,7 +150,7 @@ void AnimationControllerPrivate::updateRenderingDispatcherFired(Timer<AnimationC m_nodeChangesToDispatch.clear(); - if (m_frame && m_frame->document()) + if (m_frame) m_frame->document()->updateRendering(); } @@ -233,6 +174,10 @@ void AnimationControllerPrivate::addEventToDispatch(PassRefPtr<Element> element, void AnimationControllerPrivate::addNodeChangeToDispatch(PassRefPtr<Node> node) { + ASSERT(!node || (node->document() && !node->document()->inPageCache())); + if (!node) + return; + m_nodeChangesToDispatch.append(node); startUpdateRenderingDispatcher(); } @@ -240,7 +185,7 @@ void AnimationControllerPrivate::addNodeChangeToDispatch(PassRefPtr<Node> node) 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) + // styleChange has happened (e.g. accelerated 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 @@ -248,7 +193,7 @@ void AnimationControllerPrivate::animationTimerFired(Timer<AnimationControllerPr updateAnimationTimer(true); } -bool AnimationControllerPrivate::isAnimatingPropertyOnRenderer(RenderObject* renderer, int property, bool isRunningNow) const +bool AnimationControllerPrivate::isAnimatingPropertyOnRenderer(RenderObject* renderer, CSSPropertyID property, bool isRunningNow) const { RefPtr<CompositeAnimation> animation = m_compositeAnimations.get(renderer); if (!animation) @@ -294,6 +239,7 @@ bool AnimationControllerPrivate::pauseAnimationAtTime(RenderObject* renderer, co if (compAnim->pauseAnimationAtTime(name, t)) { renderer->node()->setChanged(AnimationStyleChange); + startUpdateRenderingDispatcher(); return true; } @@ -311,12 +257,39 @@ bool AnimationControllerPrivate::pauseTransitionAtTime(RenderObject* renderer, c if (compAnim->pauseTransitionAtTime(cssPropertyID(property), t)) { renderer->node()->setChanged(AnimationStyleChange); + startUpdateRenderingDispatcher(); return true; } return false; } +double AnimationControllerPrivate::beginAnimationUpdateTime() +{ + if (m_beginAnimationUpdateTime == cBeginAnimationUpdateTimeNotSet) + m_beginAnimationUpdateTime = currentTime(); + return m_beginAnimationUpdateTime; +} + +PassRefPtr<RenderStyle> AnimationControllerPrivate::getAnimatedStyleForRenderer(RenderObject* renderer) +{ + if (!renderer) + return 0; + + RefPtr<CompositeAnimation> rendererAnimations = m_compositeAnimations.get(renderer); + if (!rendererAnimations) + return renderer->style(); + + // Make sure animationUpdateTime is updated, so that it is current even if no + // styleChange has happened (e.g. accelerated animations). + setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet); + RefPtr<RenderStyle> animatingStyle = rendererAnimations->getAnimatedStyle(); + if (!animatingStyle) + animatingStyle = renderer->style(); + + return animatingStyle.release(); +} + unsigned AnimationControllerPrivate::numberOfActiveAnimations() const { unsigned count = 0; @@ -364,13 +337,83 @@ void AnimationControllerPrivate::removeFromStyleAvailableWaitList(AnimationBase* void AnimationControllerPrivate::styleAvailable() { // Go through list of waiters and send them on their way - for (AnimationBase* animation = m_styleAvailableWaiters; animation; animation = animation->next()) + for (AnimationBase* animation = m_styleAvailableWaiters; animation; ) { + AnimationBase* nextAnimation = animation->next(); + animation->setNext(0); animation->styleAvailable(); + animation = nextAnimation; + } m_styleAvailableWaiters = 0; m_lastStyleAvailableWaiter = 0; } +void AnimationControllerPrivate::addToStartTimeResponseWaitList(AnimationBase* animation, bool willGetResponse) +{ + // If willGetResponse is true, it means this animation is actually waiting for a response + // (which will come in as a call to notifyAnimationStarted()). + // In that case we don't need to add it to this list. We just set a waitingForAResponse flag + // which says we are waiting for the response. If willGetResponse is false, this animation + // is not waiting for a response for itself, but rather for a notifyXXXStarted() call for + // another animation to which it will sync. + // + // When endAnimationUpdate() is called we check to see if the waitingForAResponse flag is + // true. If so, we just return and will do our work when the first notifyXXXStarted() call + // comes in. If it is false, we will not be getting a notifyXXXStarted() call, so we will + // do our work right away. In both cases we call the onAnimationStartResponse() method + // on each animation. In the first case we send in the time we got from notifyXXXStarted(). + // In the second case, we just pass in the beginAnimationUpdateTime(). + // + // This will synchronize all software and accelerated animations started in the same + // updateRendering cycle. + // + ASSERT(!animation->next()); + + if (willGetResponse) + m_waitingForAResponse = true; + + if (m_responseWaiters) + m_lastResponseWaiter->setNext(animation); + else + m_responseWaiters = animation; + + m_lastResponseWaiter = animation; + animation->setNext(0); +} + +void AnimationControllerPrivate::removeFromStartTimeResponseWaitList(AnimationBase* animationToRemove) +{ + AnimationBase* prevAnimation = 0; + for (AnimationBase* animation = m_responseWaiters; animation; animation = animation->next()) { + if (animation == animationToRemove) { + if (prevAnimation) + prevAnimation->setNext(animation->next()); + else + m_responseWaiters = animation->next(); + + if (m_lastResponseWaiter == animation) + m_lastResponseWaiter = prevAnimation; + + animationToRemove->setNext(0); + } + prevAnimation = animation; + } +} + +void AnimationControllerPrivate::startTimeResponse(double t) +{ + // Go through list of waiters and send them on their way + for (AnimationBase* animation = m_responseWaiters; animation; ) { + AnimationBase* nextAnimation = animation->next(); + animation->setNext(0); + animation->onAnimationStartResponse(t); + animation = nextAnimation; + } + + m_responseWaiters = 0; + m_lastResponseWaiter = 0; +} + AnimationController::AnimationController(Frame* frame) : m_data(new AnimationControllerPrivate(frame)) { @@ -387,7 +430,7 @@ void AnimationController::cancelAnimations(RenderObject* renderer) return; if (m_data->clear(renderer)) { - Node* node = renderer->element(); + Node* node = renderer->node(); ASSERT(!node || (node->document() && !node->document()->inPageCache())); node->setChanged(AnimationStyleChange); } @@ -408,7 +451,7 @@ PassRefPtr<RenderStyle> AnimationController::updateAnimations(RenderObject* rend // against the animations in the style and make sure we're in sync. If destination values // have changed, we reset the animation. We then do a blend to get new values and we return // a new style. - ASSERT(renderer->element()); // FIXME: We do not animate generated content yet. + ASSERT(renderer->node()); // FIXME: We do not animate generated content yet. RefPtr<CompositeAnimation> rendererAnimations = m_data->accessCompositeAnimation(renderer); RefPtr<RenderStyle> blendedStyle = rendererAnimations->animate(renderer, oldStyle, newStyle); @@ -425,16 +468,14 @@ PassRefPtr<RenderStyle> AnimationController::updateAnimations(RenderObject* rend return blendedStyle.release(); } -void AnimationController::setAnimationStartTime(RenderObject* renderer, double t) +PassRefPtr<RenderStyle> AnimationController::getAnimatedStyleForRenderer(RenderObject* renderer) { - RefPtr<CompositeAnimation> rendererAnimations = m_data->accessCompositeAnimation(renderer); - rendererAnimations->setAnimationStartTime(t); + return m_data->getAnimatedStyleForRenderer(renderer); } -void AnimationController::setTransitionStartTime(RenderObject* renderer, int property, double t) +void AnimationController::notifyAnimationStarted(RenderObject*, double startTime) { - RefPtr<CompositeAnimation> rendererAnimations = m_data->accessCompositeAnimation(renderer); - rendererAnimations->setTransitionStartTime(property, t); + m_data->receivedStartTimeResponse(startTime); } bool AnimationController::pauseAnimationAtTime(RenderObject* renderer, const String& name, double t) @@ -452,7 +493,7 @@ bool AnimationController::pauseTransitionAtTime(RenderObject* renderer, const St return m_data->pauseTransitionAtTime(renderer, property, t); } -bool AnimationController::isAnimatingPropertyOnRenderer(RenderObject* renderer, int property, bool isRunningNow) const +bool AnimationController::isAnimatingPropertyOnRenderer(RenderObject* renderer, CSSPropertyID property, bool isRunningNow) const { return m_data->isAnimatingPropertyOnRenderer(renderer, property, isRunningNow); } @@ -467,28 +508,6 @@ 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::addNodeChangeToDispatch(PassRefPtr<Node> node) -{ - ASSERT(!node || (node->document() && !node->document()->inPageCache())); - if (node) - m_data->addNodeChangeToDispatch(node); -} - -double AnimationController::beginAnimationUpdateTime() -{ - return m_data->beginAnimationUpdateTime(); -} - void AnimationController::beginAnimationUpdate() { m_data->setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet); @@ -496,17 +515,17 @@ void AnimationController::beginAnimationUpdate() void AnimationController::endAnimationUpdate() { - m_data->styleAvailable(); + m_data->endAnimationUpdate(); } -void AnimationController::addToStyleAvailableWaitList(AnimationBase* animation) +bool AnimationController::supportsAcceleratedAnimationOfProperty(CSSPropertyID property) { - m_data->addToStyleAvailableWaitList(animation); -} - -void AnimationController::removeFromStyleAvailableWaitList(AnimationBase* animation) -{ - m_data->removeFromStyleAvailableWaitList(animation); +#if USE(ACCELERATED_COMPOSITING) + return AnimationBase::animationOfPropertyIsAccelerated(property); +#else + UNUSED_PARAM(property); + return false; +#endif } } // namespace WebCore diff --git a/WebCore/page/animation/AnimationController.h b/WebCore/page/animation/AnimationController.h index 13ea1bd..db82618 100644 --- a/WebCore/page/animation/AnimationController.h +++ b/WebCore/page/animation/AnimationController.h @@ -29,6 +29,7 @@ #ifndef AnimationController_h #define AnimationController_h +#include "CSSPropertyNames.h" #include <wtf/Forward.h> namespace WebCore { @@ -51,30 +52,24 @@ public: void cancelAnimations(RenderObject*); PassRefPtr<RenderStyle> updateAnimations(RenderObject*, RenderStyle* newStyle); + PassRefPtr<RenderStyle> getAnimatedStyleForRenderer(RenderObject*); - void setAnimationStartTime(RenderObject*, double t); - void setTransitionStartTime(RenderObject*, int property, double t); + // This is called when an accelerated animation or transition has actually started to animate. + void notifyAnimationStarted(RenderObject*, double startTime); bool pauseAnimationAtTime(RenderObject*, const String& name, double t); // To be used only for testing bool 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; + bool isAnimatingPropertyOnRenderer(RenderObject*, CSSPropertyID, bool isRunningNow = true) const; void suspendAnimations(Document*); void resumeAnimations(Document*); - void startUpdateRenderingDispatcher(); - void addEventToDispatch(PassRefPtr<Element>, const AtomicString& eventType, const String& name, double elapsedTime); - void addNodeChangeToDispatch(PassRefPtr<Node>); - - void addToStyleAvailableWaitList(AnimationBase*); - void removeFromStyleAvailableWaitList(AnimationBase*); - - double beginAnimationUpdateTime(); - void beginAnimationUpdate(); void endAnimationUpdate(); + + static bool supportsAcceleratedAnimationOfProperty(CSSPropertyID); private: AnimationControllerPrivate* m_data; diff --git a/WebCore/page/animation/AnimationControllerPrivate.h b/WebCore/page/animation/AnimationControllerPrivate.h new file mode 100644 index 0000000..f9a3405 --- /dev/null +++ b/WebCore/page/animation/AnimationControllerPrivate.h @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 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 AnimationControllerPrivate_h +#define AnimationControllerPrivate_h + +#include "AtomicString.h" +#include "CSSPropertyNames.h" +#include "PlatformString.h" +#include "Timer.h" +#include <wtf/HashMap.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class AnimationBase; +class CompositeAnimation; +class Document; +class Element; +class Frame; +class Node; +class RenderObject; +class RenderStyle; + +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); + void addNodeChangeToDispatch(PassRefPtr<Node>); + + bool hasAnimations() const { return !m_compositeAnimations.isEmpty(); } + + void suspendAnimations(Document*); + void resumeAnimations(Document*); + + bool isAnimatingPropertyOnRenderer(RenderObject*, CSSPropertyID, bool isRunningNow) const; + + bool pauseAnimationAtTime(RenderObject*, const String& name, double t); + bool pauseTransitionAtTime(RenderObject*, const String& property, double t); + unsigned numberOfActiveAnimations() const; + + PassRefPtr<RenderStyle> getAnimatedStyleForRenderer(RenderObject* renderer); + + double beginAnimationUpdateTime(); + void setBeginAnimationUpdateTime(double t) { m_beginAnimationUpdateTime = t; } + void endAnimationUpdate() + { + styleAvailable(); + if (!m_waitingForAResponse) + startTimeResponse(beginAnimationUpdateTime()); + } + + void receivedStartTimeResponse(double t) + { + m_waitingForAResponse = false; + startTimeResponse(t); + } + + void addToStyleAvailableWaitList(AnimationBase*); + void removeFromStyleAvailableWaitList(AnimationBase*); + + void addToStartTimeResponseWaitList(AnimationBase*, bool willGetResponse); + void removeFromStartTimeResponseWaitList(AnimationBase*); + void startTimeResponse(double t); + +private: + void styleAvailable(); + + 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; + Vector<RefPtr<Node> > m_nodeChangesToDispatch; + + double m_beginAnimationUpdateTime; + AnimationBase* m_styleAvailableWaiters; + AnimationBase* m_lastStyleAvailableWaiter; + + AnimationBase* m_responseWaiters; + AnimationBase* m_lastResponseWaiter; + bool m_waitingForAResponse; +}; + +} // namespace WebCore + +#endif // AnimationControllerPrivate_h diff --git a/WebCore/page/animation/CompositeAnimation.cpp b/WebCore/page/animation/CompositeAnimation.cpp index bf61b78..d386f1b 100644 --- a/WebCore/page/animation/CompositeAnimation.cpp +++ b/WebCore/page/animation/CompositeAnimation.cpp @@ -29,7 +29,7 @@ #include "config.h" #include "CompositeAnimation.h" -#include "AnimationController.h" +#include "AnimationControllerPrivate.h" #include "CSSPropertyNames.h" #include "ImplicitAnimation.h" #include "KeyframeAnimation.h" @@ -40,7 +40,7 @@ namespace WebCore { class CompositeAnimationPrivate { public: - CompositeAnimationPrivate(AnimationController* animationController, CompositeAnimation* compositeAnimation) + CompositeAnimationPrivate(AnimationControllerPrivate* animationController, CompositeAnimation* compositeAnimation) : m_isSuspended(false) , m_animationController(animationController) , m_compositeAnimation(compositeAnimation) @@ -53,8 +53,9 @@ public: void clearRenderer(); PassRefPtr<RenderStyle> animate(RenderObject*, RenderStyle* currentStyle, RenderStyle* targetStyle); + PassRefPtr<RenderStyle> getAnimatedStyle(); - AnimationController* animationController() { return m_animationController; } + AnimationControllerPrivate* animationControllerPriv() const { return m_animationController; } void setAnimating(bool); double willNeedService() const; @@ -63,9 +64,6 @@ public: void cleanupFinishedAnimations(RenderObject*); - void setAnimationStartTime(double t); - void setTransitionStartTime(int property, double t); - void suspendAnimations(); void resumeAnimations(); bool isSuspended() const { return m_isSuspended; } @@ -80,6 +78,9 @@ public: void addToStyleAvailableWaitList(AnimationBase*); void removeFromStyleAvailableWaitList(AnimationBase*); + void addToStartTimeResponseWaitList(AnimationBase*, bool willGetResponse); + void removeFromStartTimeResponseWaitList(AnimationBase*); + bool pauseAnimationAtTime(const AtomicString& name, double t); bool pauseTransitionAtTime(int property, double t); unsigned numberOfActiveAnimations() const; @@ -94,8 +95,9 @@ private: CSSPropertyTransitionsMap m_transitions; AnimationNameMap m_keyframeAnimations; + Vector<AtomicStringImpl*> m_keyframeAnimationOrderMap; bool m_isSuspended; - AnimationController* m_animationController; + AnimationControllerPrivate* m_animationController; CompositeAnimation* m_compositeAnimation; unsigned m_numStyleAvailableWaiters; }; @@ -126,9 +128,11 @@ void CompositeAnimationPrivate::clearRenderer() } } } - + void CompositeAnimationPrivate::updateTransitions(RenderObject* renderer, RenderStyle* currentStyle, RenderStyle* targetStyle) { + RefPtr<RenderStyle> modifiedCurrentStyle; + // If currentStyle is null, we don't do transitions if (!currentStyle || !targetStyle->transitions()) return; @@ -176,6 +180,16 @@ void CompositeAnimationPrivate::updateTransitions(RenderObject* renderer, Render // list. In this case, the latter one overrides the earlier one, so we // behave as though this is a running animation being replaced. if (!implAnim->isTargetPropertyEqual(prop, targetStyle)) { +#if USE(ACCELERATED_COMPOSITING) + // For accelerated animations we need to return a new RenderStyle with the _current_ value + // of the property, so that restarted transitions use the correct starting point. + if (AnimationBase::animationOfPropertyIsAccelerated(prop) && !implAnim->isFallbackAnimating()) { + if (!modifiedCurrentStyle) + modifiedCurrentStyle = RenderStyle::clone(currentStyle); + + implAnim->blendPropertyValueInStyle(prop, modifiedCurrentStyle.get()); + } +#endif m_transitions.remove(prop); equal = false; } @@ -186,7 +200,7 @@ void CompositeAnimationPrivate::updateTransitions(RenderObject* renderer, Render if (!equal) { // Add the new transition - m_transitions.set(prop, ImplicitAnimation::create(const_cast<Animation*>(anim), prop, renderer, m_compositeAnimation, fromStyle)); + m_transitions.set(prop, ImplicitAnimation::create(const_cast<Animation*>(anim), prop, renderer, m_compositeAnimation, modifiedCurrentStyle ? modifiedCurrentStyle.get() : fromStyle)); } // We only need one pass for the single prop case @@ -210,6 +224,9 @@ void CompositeAnimationPrivate::updateKeyframeAnimations(RenderObject* renderer, AnimationNameMap::const_iterator kfend = m_keyframeAnimations.end(); for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != kfend; ++it) it->second->setIndex(-1); + + // Toss the animation order map + m_keyframeAnimationOrderMap.clear(); // Now mark any still active animations as active and add any new animations if (targetStyle->animations()) { @@ -237,6 +254,10 @@ void CompositeAnimationPrivate::updateKeyframeAnimations(RenderObject* renderer, keyframeAnim = KeyframeAnimation::create(const_cast<Animation*>(anim), renderer, i, m_compositeAnimation, currentStyle ? currentStyle : targetStyle); m_keyframeAnimations.set(keyframeAnim->name().impl(), keyframeAnim); } + + // Add this to the animation order map + if (keyframeAnim) + m_keyframeAnimationOrderMap.append(keyframeAnim->name().impl()); } } @@ -278,17 +299,10 @@ PassRefPtr<RenderStyle> CompositeAnimationPrivate::animate(RenderObject* rendere // 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); - } - } + for (Vector<AtomicStringImpl*>::const_iterator it = m_keyframeAnimationOrderMap.begin(); it != m_keyframeAnimationOrderMap.end(); ++it) { + RefPtr<KeyframeAnimation> keyframeAnim = m_keyframeAnimations.get(*it); + if (keyframeAnim) + keyframeAnim->animate(m_compositeAnimation, renderer, currentStyle, targetStyle, resultStyle); } cleanupFinishedAnimations(renderer); @@ -296,6 +310,24 @@ PassRefPtr<RenderStyle> CompositeAnimationPrivate::animate(RenderObject* rendere return resultStyle ? resultStyle.release() : targetStyle; } +PassRefPtr<RenderStyle> CompositeAnimationPrivate::getAnimatedStyle() +{ + RefPtr<RenderStyle> resultStyle; + CSSPropertyTransitionsMap::const_iterator end = m_transitions.end(); + for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) { + if (ImplicitAnimation* implicitAnimation = it->second.get()) + implicitAnimation->getAnimatedStyle(resultStyle); + } + + for (Vector<AtomicStringImpl*>::const_iterator it = m_keyframeAnimationOrderMap.begin(); it != m_keyframeAnimationOrderMap.end(); ++it) { + RefPtr<KeyframeAnimation> keyframeAnimation = m_keyframeAnimations.get(*it); + if (keyframeAnimation) + keyframeAnimation->getAnimatedStyle(resultStyle); + } + + return resultStyle; +} + // "animating" means that something is running that requires the timer to keep firing void CompositeAnimationPrivate::setAnimating(bool animating) { @@ -409,32 +441,6 @@ void CompositeAnimationPrivate::cleanupFinishedAnimations(RenderObject*) } } -void CompositeAnimationPrivate::setAnimationStartTime(double t) -{ - // Set start time on all animations waiting for it - if (!m_keyframeAnimations.isEmpty()) { - 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 - if (!m_transitions.isEmpty()) { - 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) @@ -541,6 +547,16 @@ void CompositeAnimationPrivate::removeFromStyleAvailableWaitList(AnimationBase* m_animationController->removeFromStyleAvailableWaitList(animation); } +void CompositeAnimationPrivate::addToStartTimeResponseWaitList(AnimationBase* animation, bool willGetResponse) +{ + m_animationController->addToStartTimeResponseWaitList(animation, willGetResponse); +} + +void CompositeAnimationPrivate::removeFromStartTimeResponseWaitList(AnimationBase* animation) +{ + m_animationController->removeFromStartTimeResponseWaitList(animation); +} + bool CompositeAnimationPrivate::pauseAnimationAtTime(const AtomicString& name, double t) { if (!name) @@ -601,7 +617,7 @@ unsigned CompositeAnimationPrivate::numberOfActiveAnimations() const return count; } -CompositeAnimation::CompositeAnimation(AnimationController* animationController) +CompositeAnimation::CompositeAnimation(AnimationControllerPrivate* animationController) : m_data(new CompositeAnimationPrivate(animationController, this)) { } @@ -611,9 +627,9 @@ CompositeAnimation::~CompositeAnimation() delete m_data; } -AnimationController* CompositeAnimation::animationController() +AnimationControllerPrivate* CompositeAnimation::animationControllerPriv() const { - return m_data->animationController(); + return m_data->animationControllerPriv(); } void CompositeAnimation::clearRenderer() @@ -626,6 +642,11 @@ PassRefPtr<RenderStyle> CompositeAnimation::animate(RenderObject* renderer, Rend return m_data->animate(renderer, currentStyle, targetStyle); } +PassRefPtr<RenderStyle> CompositeAnimation::getAnimatedStyle() +{ + return m_data->getAnimatedStyle(); +} + double CompositeAnimation::willNeedService() const { return m_data->willNeedService(); @@ -641,6 +662,16 @@ void CompositeAnimation::removeFromStyleAvailableWaitList(AnimationBase* animati m_data->removeFromStyleAvailableWaitList(animation); } +void CompositeAnimation::addToStartTimeResponseWaitList(AnimationBase* animation, bool willGetResponse) +{ + m_data->addToStartTimeResponseWaitList(animation, willGetResponse); +} + +void CompositeAnimation::removeFromStartTimeResponseWaitList(AnimationBase* animation) +{ + m_data->removeFromStartTimeResponseWaitList(animation); +} + void CompositeAnimation::suspendAnimations() { m_data->suspendAnimations(); @@ -676,16 +707,6 @@ PassRefPtr<KeyframeAnimation> CompositeAnimation::getAnimationForProperty(int pr 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); diff --git a/WebCore/page/animation/CompositeAnimation.h b/WebCore/page/animation/CompositeAnimation.h index 3517b34..b5857aa 100644 --- a/WebCore/page/animation/CompositeAnimation.h +++ b/WebCore/page/animation/CompositeAnimation.h @@ -36,6 +36,7 @@ namespace WebCore { +class AnimationControllerPrivate; class CompositeAnimationPrivate; class AnimationBase; class AnimationController; @@ -47,7 +48,7 @@ class RenderStyle; // 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) + static PassRefPtr<CompositeAnimation> create(AnimationControllerPrivate* animationController) { return adoptRef(new CompositeAnimation(animationController)); }; @@ -57,9 +58,17 @@ public: void clearRenderer(); PassRefPtr<RenderStyle> animate(RenderObject*, RenderStyle* currentStyle, RenderStyle* targetStyle); + PassRefPtr<RenderStyle> getAnimatedStyle(); + double willNeedService() const; - AnimationController* animationController(); + AnimationControllerPrivate* animationControllerPriv() const; + + void addToStyleAvailableWaitList(AnimationBase*); + void removeFromStyleAvailableWaitList(AnimationBase*); + + void addToStartTimeResponseWaitList(AnimationBase*, bool willGetResponse); + void removeFromStartTimeResponseWaitList(AnimationBase*); void suspendAnimations(); void resumeAnimations(); @@ -72,10 +81,6 @@ public: PassRefPtr<KeyframeAnimation> getAnimationForProperty(int property); - - void setAnimationStartTime(double t); - void setTransitionStartTime(int property, double t); - void overrideImplicitAnimations(int property); void resumeOverriddenImplicitAnimations(int property); @@ -83,11 +88,8 @@ public: bool pauseTransitionAtTime(int property, double t); unsigned numberOfActiveAnimations() const; - void addToStyleAvailableWaitList(AnimationBase*); - void removeFromStyleAvailableWaitList(AnimationBase*); - private: - CompositeAnimation(AnimationController* animationController); + CompositeAnimation(AnimationControllerPrivate* animationController); CompositeAnimationPrivate* m_data; }; diff --git a/WebCore/page/animation/ImplicitAnimation.cpp b/WebCore/page/animation/ImplicitAnimation.cpp index f984909..8ec0be0 100644 --- a/WebCore/page/animation/ImplicitAnimation.cpp +++ b/WebCore/page/animation/ImplicitAnimation.cpp @@ -28,13 +28,15 @@ #include "config.h" -#include "AnimationController.h" +#include "AnimationControllerPrivate.h" #include "CompositeAnimation.h" #include "CSSPropertyNames.h" #include "EventNames.h" #include "ImplicitAnimation.h" #include "KeyframeAnimation.h" -#include "RenderObject.h" +#include "RenderLayer.h" +#include "RenderLayerBacking.h" +#include <wtf/UnusedParam.h> namespace WebCore { @@ -55,12 +57,12 @@ ImplicitAnimation::~ImplicitAnimation() updateStateMachine(AnimationStateInputEndAnimation, -1); } -bool ImplicitAnimation::shouldSendEventForListener(Document::ListenerType inListenerType) +bool ImplicitAnimation::shouldSendEventForListener(Document::ListenerType inListenerType) const { return m_object->document()->hasListenerType(inListenerType); } -void ImplicitAnimation::animate(CompositeAnimation*, RenderObject*, RenderStyle*, RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle) +void ImplicitAnimation::animate(CompositeAnimation*, RenderObject*, const 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. @@ -76,13 +78,58 @@ void ImplicitAnimation::animate(CompositeAnimation*, RenderObject*, RenderStyle* if (!animatedStyle) animatedStyle = RenderStyle::clone(targetStyle); - if (blendProperties(this, m_animatingProperty, animatedStyle.get(), m_fromStyle.get(), m_toStyle.get(), progress(1, 0, 0))) + bool needsAnim = blendProperties(this, m_animatingProperty, animatedStyle.get(), m_fromStyle.get(), m_toStyle.get(), progress(1, 0, 0)); + // FIXME: we also need to detect cases where we have to software animate for other reasons, + // such as a child using inheriting the transform. https://bugs.webkit.org/show_bug.cgi?id=23902 + if (needsAnim) setAnimating(); + else { +#if USE(ACCELERATED_COMPOSITING) + // If we are running an accelerated animation, set a flag in the style which causes the style + // to compare as different to any other style. This ensures that changes to the property + // that is animating are correctly detected during the animation (e.g. when a transition + // gets interrupted). + animatedStyle->setIsRunningAcceleratedAnimation(); +#endif + } // Fire the start timeout if needed fireAnimationEventsIfNeeded(); } +void ImplicitAnimation::getAnimatedStyle(RefPtr<RenderStyle>& animatedStyle) +{ + if (!animatedStyle) + animatedStyle = RenderStyle::clone(m_toStyle.get()); + + blendProperties(this, m_animatingProperty, animatedStyle.get(), m_fromStyle.get(), m_toStyle.get(), progress(1, 0, 0)); +} + +bool ImplicitAnimation::startAnimation(double beginTime) +{ +#if USE(ACCELERATED_COMPOSITING) + if (m_object && m_object->hasLayer()) { + RenderLayer* layer = toRenderBoxModelObject(m_object)->layer(); + if (layer->isComposited()) + return layer->backing()->startTransition(beginTime, m_animatingProperty, m_fromStyle.get(), m_toStyle.get()); + } +#else + UNUSED_PARAM(beginTime); +#endif + return false; +} + +void ImplicitAnimation::endAnimation(bool /*reset*/) +{ +#if USE(ACCELERATED_COMPOSITING) + if (m_object && m_object->hasLayer()) { + RenderLayer* layer = toRenderBoxModelObject(m_object)->layer(); + if (layer->isComposited()) + layer->backing()->transitionFinished(m_animatingProperty); + } +#endif +} + void ImplicitAnimation::onAnimationEnd(double elapsedTime) { // If we have a keyframe animation on this property, this transition is being overridden. The keyframe @@ -120,7 +167,7 @@ bool ImplicitAnimation::sendTransitionEvent(const AtomicString& eventType, doubl return false; // Schedule event handling - m_object->animation()->addEventToDispatch(element, eventType, propertyName, elapsedTime); + m_compAnim->animationControllerPriv()->addEventToDispatch(element, eventType, propertyName, elapsedTime); // Restore the original (unanimated) style if (eventType == eventNames().webkitTransitionEndEvent && element->renderer()) @@ -137,7 +184,6 @@ void ImplicitAnimation::reset(RenderStyle* to) { ASSERT(to); ASSERT(m_fromStyle); - m_toStyle = to; @@ -209,4 +255,21 @@ void ImplicitAnimation::validateTransformFunctionList() m_transformFunctionListValid = true; } +double ImplicitAnimation::willNeedService() +{ + double t = AnimationBase::willNeedService(); +#if USE(ACCELERATED_COMPOSITING) + if (t != 0 || preActive()) + return t; + + // A return value of 0 means we need service. But if this is an accelerated animation we + // only need service at the end of the transition. + if (animationOfPropertyIsAccelerated(m_animatingProperty) && !isFallbackAnimating()) { + bool isLooping; + getTimeToNextEvent(t, isLooping); + } +#endif + return t; +} + } // namespace WebCore diff --git a/WebCore/page/animation/ImplicitAnimation.h b/WebCore/page/animation/ImplicitAnimation.h index cf98bba..221c45e 100644 --- a/WebCore/page/animation/ImplicitAnimation.h +++ b/WebCore/page/animation/ImplicitAnimation.h @@ -47,8 +47,11 @@ public: int animatingProperty() const { return m_animatingProperty; } virtual void onAnimationEnd(double elapsedTime); + virtual bool startAnimation(double beginTime); + virtual void endAnimation(bool reset); - virtual void animate(CompositeAnimation*, RenderObject*, RenderStyle* currentStyle, RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle); + virtual void animate(CompositeAnimation*, RenderObject*, const RenderStyle* currentStyle, RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle); + virtual void getAnimatedStyle(RefPtr<RenderStyle>& animatedStyle); virtual void reset(RenderStyle* to); void setOverridden(bool); @@ -62,8 +65,10 @@ public: void blendPropertyValueInStyle(int, RenderStyle* currentStyle); + virtual double willNeedService(); + protected: - bool shouldSendEventForListener(Document::ListenerType); + bool shouldSendEventForListener(Document::ListenerType) const; bool sendTransitionEvent(const AtomicString&, double elapsedTime); void validateTransformFunctionList(); diff --git a/WebCore/page/animation/KeyframeAnimation.cpp b/WebCore/page/animation/KeyframeAnimation.cpp index 2efa578..88a5f6a 100644 --- a/WebCore/page/animation/KeyframeAnimation.cpp +++ b/WebCore/page/animation/KeyframeAnimation.cpp @@ -29,12 +29,14 @@ #include "config.h" #include "KeyframeAnimation.h" -#include "AnimationController.h" +#include "AnimationControllerPrivate.h" #include "CSSPropertyNames.h" #include "CSSStyleSelector.h" #include "CompositeAnimation.h" #include "EventNames.h" -#include "RenderObject.h" +#include "RenderLayer.h" +#include "RenderLayerBacking.h" +#include <wtf/UnusedParam.h> namespace WebCore { @@ -45,8 +47,8 @@ KeyframeAnimation::KeyframeAnimation(const Animation* animation, RenderObject* r , 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); + if (m_object && m_object->node() && m_object->node()->isElementNode()) + m_object->document()->styleSelector()->keyframeStylesForAnimation(static_cast<Element*>(m_object->node()), unanimatedStyle, m_keyframes); // Update the m_transformFunctionListValid flag based on whether the function lists in the keyframes match. validateTransformFunctionList(); @@ -59,32 +61,8 @@ KeyframeAnimation::~KeyframeAnimation() updateStateMachine(AnimationStateInputEndAnimation, -1); } -void KeyframeAnimation::animate(CompositeAnimation*, RenderObject*, const RenderStyle*, const RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle) +void KeyframeAnimation::getKeyframeAnimationInterval(const RenderStyle*& fromStyle, const RenderStyle*& toStyle, double& prog) const { - // 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 = getElapsedTime(); @@ -94,8 +72,6 @@ void KeyframeAnimation::animate(CompositeAnimation*, RenderObject*, const Render 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(); @@ -113,6 +89,48 @@ void KeyframeAnimation::animate(CompositeAnimation*, RenderObject*, const Render fromStyle = it->style(); } + if (!fromStyle || !toStyle) + return; + + const TimingFunction* timingFunction = 0; + if (fromStyle->animations() && fromStyle->animations()->size() > 0) + timingFunction = &(fromStyle->animations()->animation(0)->timingFunction()); + + prog = progress(scale, offset, timingFunction); +} + +void KeyframeAnimation::animate(CompositeAnimation*, RenderObject*, const RenderStyle*, RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle) +{ + // Fire the start timeout if needed + fireAnimationEventsIfNeeded(); + + // If we have not yet started, we will not have a valid start time, so just start the animation if needed. + if (isNew() && m_animation->playState() == AnimPlayStatePlaying) + 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. + + // Get the from/to styles and progress between + const RenderStyle* fromStyle = 0; + const RenderStyle* toStyle = 0; + double progress; + getKeyframeAnimationInterval(fromStyle, toStyle, progress); + // If either style is 0 we have an invalid case, just stop the animation. if (!fromStyle || !toStyle) { updateStateMachine(AnimationStateInputEndAnimation, -1); @@ -124,19 +142,42 @@ void KeyframeAnimation::animate(CompositeAnimation*, RenderObject*, const Render 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)) + bool needsAnim = blendProperties(this, *it, animatedStyle.get(), fromStyle, toStyle, progress); + if (needsAnim) setAnimating(); + else { +#if USE(ACCELERATED_COMPOSITING) + // If we are running an accelerated animation, set a flag in the style + // to indicate it. This can be used to make sure we get an updated + // style for hit testing, etc. + animatedStyle->setIsRunningAcceleratedAnimation(); +#endif + } } } +void KeyframeAnimation::getAnimatedStyle(RefPtr<RenderStyle>& animatedStyle) +{ + // Get the from/to styles and progress between + const RenderStyle* fromStyle = 0; + const RenderStyle* toStyle = 0; + double progress; + getKeyframeAnimationInterval(fromStyle, toStyle, progress); + + // If either style is 0 we have an invalid case + if (!fromStyle || !toStyle) + return; + + if (!animatedStyle) + animatedStyle = RenderStyle::clone(m_object->style()); + + HashSet<int>::const_iterator endProperties = m_keyframes.endProperties(); + for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) + blendProperties(this, *it, animatedStyle.get(), fromStyle, toStyle, progress); +} + bool KeyframeAnimation::hasAnimationForProperty(int property) const { HashSet<int>::const_iterator end = m_keyframes.endProperties(); @@ -148,14 +189,38 @@ bool KeyframeAnimation::hasAnimationForProperty(int property) const return false; } -void KeyframeAnimation::endAnimation(bool) +bool KeyframeAnimation::startAnimation(double beginTime) +{ +#if USE(ACCELERATED_COMPOSITING) + if (m_object && m_object->hasLayer()) { + RenderLayer* layer = toRenderBoxModelObject(m_object)->layer(); + if (layer->isComposited()) + return layer->backing()->startAnimation(beginTime, m_animation.get(), m_keyframes); + } +#else + UNUSED_PARAM(beginTime); +#endif + return false; +} + +void KeyframeAnimation::endAnimation(bool reset) { - // Restore the original (unanimated) style - if (m_object) - setChanged(m_object->element()); + if (m_object) { +#if USE(ACCELERATED_COMPOSITING) + if (m_object->hasLayer()) { + RenderLayer* layer = toRenderBoxModelObject(m_object)->layer(); + if (layer->isComposited()) + layer->backing()->animationFinished(m_keyframes.animationName(), 0, reset); + } +#else + UNUSED_PARAM(reset); +#endif + // Restore the original (unanimated) style + setChanged(m_object->node()); + } } -bool KeyframeAnimation::shouldSendEventForListener(Document::ListenerType listenerType) +bool KeyframeAnimation::shouldSendEventForListener(Document::ListenerType listenerType) const { return m_object->document()->hasListenerType(listenerType); } @@ -201,7 +266,7 @@ bool KeyframeAnimation::sendAnimationEvent(const AtomicString& eventType, double return false; // Schedule event handling - m_object->animation()->addEventToDispatch(element, eventType, m_keyframes.animationName(), elapsedTime); + m_compAnim->animationControllerPriv()->addEventToDispatch(element, eventType, m_keyframes.animationName(), elapsedTime); // Restore the original (unanimated) style if (eventType == eventNames().webkitAnimationEndEvent && element->renderer()) @@ -287,4 +352,31 @@ void KeyframeAnimation::validateTransformFunctionList() m_transformFunctionListValid = true; } +double KeyframeAnimation::willNeedService() +{ + double t = AnimationBase::willNeedService(); +#if USE(ACCELERATED_COMPOSITING) + if (t != 0 || preActive()) + return t; + + // A return value of 0 means we need service. But if we only have accelerated animations we + // only need service at the end of the transition + HashSet<int>::const_iterator endProperties = m_keyframes.endProperties(); + bool acceleratedPropertiesOnly = true; + + for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) { + if (!animationOfPropertyIsAccelerated(*it) || isFallbackAnimating()) { + acceleratedPropertiesOnly = false; + break; + } + } + + if (acceleratedPropertiesOnly) { + bool isLooping; + getTimeToNextEvent(t, isLooping); + } +#endif + return t; +} + } // namespace WebCore diff --git a/WebCore/page/animation/KeyframeAnimation.h b/WebCore/page/animation/KeyframeAnimation.h index 5c3176c..1090e5b 100644 --- a/WebCore/page/animation/KeyframeAnimation.h +++ b/WebCore/page/animation/KeyframeAnimation.h @@ -44,8 +44,9 @@ public: { return adoptRef(new KeyframeAnimation(animation, renderer, index, compositeAnimation, unanimatedStyle)); }; - - virtual void animate(CompositeAnimation*, RenderObject*, const RenderStyle* currentStyle, const RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle); + + virtual void animate(CompositeAnimation*, RenderObject*, const RenderStyle* currentStyle, RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle); + virtual void getAnimatedStyle(RefPtr<RenderStyle>& animatedStyle); const AtomicString& name() const { return m_keyframes.animationName(); } int index() const { return m_index; } @@ -56,16 +57,19 @@ public: void setUnanimatedStyle(PassRefPtr<RenderStyle> style) { m_unanimatedStyle = style; } RenderStyle* unanimatedStyle() const { return m_unanimatedStyle.get(); } + virtual double willNeedService(); + protected: virtual void onAnimationStart(double elapsedTime); virtual void onAnimationIteration(double elapsedTime); virtual void onAnimationEnd(double elapsedTime); + virtual bool startAnimation(double beginTime); virtual void endAnimation(bool reset); virtual void overrideAnimations(); virtual void resumeOverriddenAnimations(); - bool shouldSendEventForListener(Document::ListenerType inListenerType); + bool shouldSendEventForListener(Document::ListenerType inListenerType) const; bool sendAnimationEvent(const AtomicString&, double elapsedTime); virtual bool affectsProperty(int) const; @@ -76,6 +80,9 @@ private: KeyframeAnimation(const Animation* animation, RenderObject*, int index, CompositeAnimation*, RenderStyle* unanimatedStyle); virtual ~KeyframeAnimation(); + // Get the styles surrounding the current animation time and the progress between them + void getKeyframeAnimationInterval(const RenderStyle*& fromStyle, const RenderStyle*& toStyle, double& progress) const; + // The keyframes that we are blending. KeyframeList m_keyframes; diff --git a/WebCore/page/chromium/AccessibilityObjectWrapper.h b/WebCore/page/chromium/AccessibilityObjectWrapper.h index 9920e4d..6420b32 100644 --- a/WebCore/page/chromium/AccessibilityObjectWrapper.h +++ b/WebCore/page/chromium/AccessibilityObjectWrapper.h @@ -39,7 +39,11 @@ namespace WebCore { protected: AccessibilityObjectWrapper(AccessibilityObject* obj) - : RefCounted<AccessibilityObjectWrapper>(0), m_object(obj) { } + : m_object(obj) + { + // FIXME: Remove this once our immediate subclass no longer uses COM. + m_refCount = 0; + } AccessibilityObjectWrapper() : m_object(0) { } AccessibilityObject* m_object; diff --git a/WebCore/page/chromium/EventHandlerChromium.cpp b/WebCore/page/chromium/EventHandlerChromium.cpp index 883bece..0cfc12d 100644 --- a/WebCore/page/chromium/EventHandlerChromium.cpp +++ b/WebCore/page/chromium/EventHandlerChromium.cpp @@ -62,7 +62,7 @@ bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& m if (m_frame->selection()->contains(p)) { VisiblePosition visiblePos( mev.targetNode()->renderer()->positionForPoint(mev.localPoint())); - Selection newSelection(visiblePos); + VisibleSelection newSelection(visiblePos); if (m_frame->shouldChangeSelection(newSelection)) m_frame->selection()->setSelection(newSelection); } @@ -148,7 +148,11 @@ bool EventHandler::passWidgetMouseDownEventToWidget(RenderWidget* renderWidget) unsigned EventHandler::accessKeyModifiers() { +#if PLATFORM(DARWIN) + return PlatformKeyboardEvent::CtrlKey | PlatformKeyboardEvent::AltKey; +#else return PlatformKeyboardEvent::AltKey; +#endif } } // namespace WebCore diff --git a/WebCore/page/chromium/FrameChromium.cpp b/WebCore/page/chromium/FrameChromium.cpp index 1e4ed16..d85fbcc 100644 --- a/WebCore/page/chromium/FrameChromium.cpp +++ b/WebCore/page/chromium/FrameChromium.cpp @@ -79,7 +79,7 @@ void computePageRectsForFrame(Frame* frame, const IntRect& printRect, float head float printedPagesHeight = 0.0f; do { float proposedBottom = min(docHeight, printedPagesHeight + pageHeight); - frame->adjustPageHeight(&proposedBottom, printedPagesHeight, proposedBottom, printedPagesHeight); + frame->view()->adjustPageHeight(&proposedBottom, printedPagesHeight, proposedBottom, printedPagesHeight); currPageHeight = max(1.0f, proposedBottom - printedPagesHeight); pages.append(IntRect(0, printedPagesHeight, currPageWidth, currPageHeight)); diff --git a/WebCore/page/gtk/AccessibilityObjectWrapperAtk.cpp b/WebCore/page/gtk/AccessibilityObjectWrapperAtk.cpp index c1a405e..84f3d34 100644 --- a/WebCore/page/gtk/AccessibilityObjectWrapperAtk.cpp +++ b/WebCore/page/gtk/AccessibilityObjectWrapperAtk.cpp @@ -110,7 +110,7 @@ static const gchar* webkit_accessible_get_name(AtkObject* object) { // TODO: Deal with later changes. if (!object->name) - atk_object_set_name(object, core(object)->title().utf8().data()); + atk_object_set_name(object, core(object)->stringValue().utf8().data()); return object->name; } @@ -650,7 +650,7 @@ void webkit_accessible_detach(WebKitAccessible* accessible) // detachment. // FIXME: Using fallbackCache->get(ListBoxOptionRole) is a hack. - accessible->m_object = fallbackCache->get(ListBoxOptionRole); + accessible->m_object = fallbackCache->getOrCreate(ListBoxOptionRole); } } diff --git a/WebCore/page/mac/AXObjectCacheMac.mm b/WebCore/page/mac/AXObjectCacheMac.mm index d5ce8f3..936d9de 100644 --- a/WebCore/page/mac/AXObjectCacheMac.mm +++ b/WebCore/page/mac/AXObjectCacheMac.mm @@ -58,9 +58,9 @@ void AXObjectCache::postNotification(RenderObject* renderer, const String& messa // notifications for text input objects are sent to that object // all others are sent to the top WebArea - RefPtr<AccessibilityObject> obj = get(renderer)->observableObject(); + RefPtr<AccessibilityObject> obj = getOrCreate(renderer)->observableObject(); if (!obj) - obj = get(renderer->document()->renderer()); + obj = getOrCreate(renderer->document()->renderer()); if (!obj) return; @@ -74,7 +74,7 @@ void AXObjectCache::postNotificationToElement(RenderObject* renderer, const Stri if (!renderer) return; - RefPtr<AccessibilityObject> obj = get(renderer); + RefPtr<AccessibilityObject> obj = getOrCreate(renderer); if (!obj) return; diff --git a/WebCore/page/mac/AccessibilityObjectWrapper.h b/WebCore/page/mac/AccessibilityObjectWrapper.h index 5a55fe0..3b584a9 100644 --- a/WebCore/page/mac/AccessibilityObjectWrapper.h +++ b/WebCore/page/mac/AccessibilityObjectWrapper.h @@ -25,8 +25,11 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - -#import <wtf/RefPtr.h> + +#ifndef AccessibilityObjectWrapper_h +#define AccessibilityObjectWrapper_h + +#import <wtf/RefPtr.h> #ifdef __OBJC__ @class WebCoreTextMarker; @@ -53,3 +56,5 @@ namespace WebCore { - (NSView*)attachmentView; @end + +#endif // AccessibilityObjectWrapper_h diff --git a/WebCore/page/mac/AccessibilityObjectWrapper.mm b/WebCore/page/mac/AccessibilityObjectWrapper.mm index 1e28f00..1e596eb 100644 --- a/WebCore/page/mac/AccessibilityObjectWrapper.mm +++ b/WebCore/page/mac/AccessibilityObjectWrapper.mm @@ -181,9 +181,11 @@ static WebCoreTextMarker* textMarkerForVisiblePosition(const VisiblePosition& vi if (!domNode) return nil; - if (domNode->isHTMLElement()) - if (static_cast<HTMLElement*>(domNode)->isPasswordField()) + if (domNode->isHTMLElement()) { + InputElement* inputElement = toInputElement(static_cast<Element*>(domNode)); + if (inputElement && inputElement->isPasswordField()) return nil; + } // locate the renderer, which must exist for a visible dom node RenderObject* renderer = domNode->renderer(); @@ -191,7 +193,7 @@ static WebCoreTextMarker* textMarkerForVisiblePosition(const VisiblePosition& vi // find or create an accessibility object for this renderer AXObjectCache* cache = renderer->document()->axObjectCache(); - RefPtr<AccessibilityObject> obj = cache->get(renderer); + RefPtr<AccessibilityObject> obj = cache->getOrCreate(renderer); // create a text marker, adding an ID for the AccessibilityObject if needed TextMarkerData textMarkerData; @@ -201,7 +203,7 @@ static WebCoreTextMarker* textMarkerForVisiblePosition(const VisiblePosition& vi bzero(&textMarkerData, sizeof(TextMarkerData)); textMarkerData.axID = obj.get()->axObjectID(); textMarkerData.node = domNode; - textMarkerData.offset = deepPos.offset(); + textMarkerData.offset = deepPos.m_offset; textMarkerData.affinity = visiblePos.affinity(); return [[WebCoreViewFactory sharedFactory] textMarkerWithBytes:&textMarkerData length:sizeof(textMarkerData)]; } @@ -226,7 +228,7 @@ static VisiblePosition visiblePositionForTextMarker(WebCoreTextMarker* textMarke if (!cache->isIDinUse(textMarkerData.axID)) return VisiblePosition(); - if (deepPos.node() != textMarkerData.node || deepPos.offset() != textMarkerData.offset) + if (deepPos.node() != textMarkerData.node || deepPos.m_offset != textMarkerData.offset) return VisiblePosition(); return visiblePos; @@ -374,7 +376,7 @@ static int blockquoteLevel(RenderObject* renderer) return 0; int result = 0; - for (Node* node = renderer->element(); node; node = node->parent()) { + for (Node* node = renderer->node(); node; node = node->parent()) { if (node->hasTagName(blockquoteTag)) result += 1; } @@ -423,7 +425,7 @@ static void AXAttributeStringSetSpelling(NSMutableAttributedString* attrString, static void AXAttributeStringSetHeadingLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range) { - int parentHeadingLevel = AccessibilityRenderObject::headingLevel(renderer->parent()->element()); + int parentHeadingLevel = AccessibilityRenderObject::headingLevel(renderer->parent()->node()); if (parentHeadingLevel) [attrString addAttribute:@"AXHeadingLevel" value:[NSNumber numberWithInt:parentHeadingLevel] range:range]; @@ -437,7 +439,7 @@ static AccessibilityObject* AXLinkElementForNode(Node* node) if (!obj) return 0; - RefPtr<AccessibilityObject> axObj = obj->document()->axObjectCache()->get(obj); + RefPtr<AccessibilityObject> axObj = obj->document()->axObjectCache()->getOrCreate(obj); Element* anchor = axObj->anchorElement(); if (!anchor) return 0; @@ -446,7 +448,7 @@ static AccessibilityObject* AXLinkElementForNode(Node* node) if (!anchorRenderer) return 0; - return anchorRenderer->document()->axObjectCache()->get(anchorRenderer); + return anchorRenderer->document()->axObjectCache()->getOrCreate(anchorRenderer); } static void AXAttributeStringSetElement(NSMutableAttributedString* attrString, NSString* attribute, AccessibilityObject* object, NSRange range) @@ -515,7 +517,7 @@ static NSString* nsStringForReplacedNode(Node* replacedNode) } // create an AX object, but skip it if it is not supposed to be seen - RefPtr<AccessibilityObject> obj = replacedNode->renderer()->document()->axObjectCache()->get(replacedNode->renderer()); + RefPtr<AccessibilityObject> obj = replacedNode->renderer()->document()->axObjectCache()->getOrCreate(replacedNode->renderer()); if (obj->accessibilityIsIgnored()) return nil; @@ -561,7 +563,7 @@ static NSString* nsStringForReplacedNode(Node* replacedNode) [attrString setAttributes:nil range:attrStringRange]; // add the attachment attribute - AccessibilityObject* obj = replacedNode->renderer()->document()->axObjectCache()->get(replacedNode->renderer()); + AccessibilityObject* obj = replacedNode->renderer()->document()->axObjectCache()->getOrCreate(replacedNode->renderer()); AXAttributeStringSetElement(attrString, NSAccessibilityAttachmentTextAttribute, obj, attrStringRange); } } @@ -580,6 +582,9 @@ static WebCoreTextMarkerRange* textMarkerRangeFromVisiblePositions(VisiblePositi - (NSArray*)accessibilityActionNames { + if (!m_object) + return nil; + m_object->updateBackingStore(); static NSArray* actionElementActions = [[NSArray alloc] initWithObjects: NSAccessibilityPressAction, NSAccessibilityShowMenuAction, nil]; @@ -601,6 +606,9 @@ static WebCoreTextMarkerRange* textMarkerRangeFromVisiblePositions(VisiblePositi - (NSArray*)accessibilityAttributeNames { + if (!m_object) + return nil; + m_object->updateBackingStore(); if (m_object->isAttachment()) @@ -871,7 +879,7 @@ static WebCoreTextMarkerRange* textMarkerRangeFromVisiblePositions(VisiblePositi static void convertToVector(NSArray* array, AccessibilityObject::AccessibilityChildrenVector& vector) { unsigned length = [array count]; - vector.reserveCapacity(length); + vector.reserveInitialCapacity(length); for (unsigned i = 0; i < length; ++i) { AccessibilityObject* obj = [[array objectAtIndex:i] accessibilityObject]; if (obj) @@ -884,16 +892,23 @@ static NSMutableArray* convertToNSArray(const AccessibilityObject::Accessibility unsigned length = vector.size(); NSMutableArray* array = [NSMutableArray arrayWithCapacity: length]; for (unsigned i = 0; i < length; ++i) { - ASSERT(vector[i]->wrapper()); - if (vector[i]->wrapper()) - [array addObject:vector[i]->wrapper()]; + AccessibilityObjectWrapper* wrapper = vector[i]->wrapper(); + ASSERT(wrapper); + if (wrapper) { + // we want to return the attachment view instead of the object representing the attachment. + // otherwise, we get palindrome errors in the AX hierarchy + if (vector[i]->isAttachment() && [wrapper attachmentView]) + [array addObject:[wrapper attachmentView]]; + else + [array addObject:wrapper]; + } } return array; } - (WebCoreTextMarkerRange*)textMarkerRangeForSelection { - Selection selection = m_object->selection(); + VisibleSelection selection = m_object->selection(); if (selection.isNone()) return nil; return textMarkerRangeFromVisiblePositions(selection.visibleStart(), selection.visibleEnd()); @@ -1436,6 +1451,9 @@ static NSString* roleValueToNSString(AccessibilityRole value) - (id)accessibilityFocusedUIElement { + if (!m_object) + return nil; + m_object->updateBackingStore(); RefPtr<AccessibilityObject> focusedObj = m_object->focusedUIElement(); @@ -1448,6 +1466,9 @@ static NSString* roleValueToNSString(AccessibilityRole value) - (id)accessibilityHitTest:(NSPoint)point { + if (!m_object) + return nil; + m_object->updateBackingStore(); RefPtr<AccessibilityObject> axObject = m_object->doAccessibilityHitTest(IntPoint(point)); @@ -1458,6 +1479,9 @@ static NSString* roleValueToNSString(AccessibilityRole value) - (BOOL)accessibilityIsAttributeSettable:(NSString*)attributeName { + if (!m_object) + return nil; + m_object->updateBackingStore(); if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"]) @@ -1494,6 +1518,9 @@ static NSString* roleValueToNSString(AccessibilityRole value) // Registering an object is also required for observing notifications. Only registered objects can be observed. - (BOOL)accessibilityIsIgnored { + if (!m_object) + return nil; + m_object->updateBackingStore(); if (m_object->isAttachment()) @@ -1503,6 +1530,9 @@ static NSString* roleValueToNSString(AccessibilityRole value) - (NSArray* )accessibilityParameterizedAttributeNames { + if (!m_object) + return nil; + m_object->updateBackingStore(); if (m_object->isAttachment()) @@ -1585,6 +1615,9 @@ static NSString* roleValueToNSString(AccessibilityRole value) - (void)accessibilityPerformPressAction { + if (!m_object) + return; + m_object->updateBackingStore(); if (m_object->isAttachment()) @@ -1631,6 +1664,9 @@ static NSString* roleValueToNSString(AccessibilityRole value) - (void)accessibilityPerformAction:(NSString*)action { + if (!m_object) + return; + m_object->updateBackingStore(); if ([action isEqualToString:NSAccessibilityPressAction]) @@ -1642,6 +1678,9 @@ static NSString* roleValueToNSString(AccessibilityRole value) - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attributeName { + if (!m_object) + return; + m_object->updateBackingStore(); WebCoreTextMarkerRange* textMarkerRange = nil; @@ -1721,7 +1760,7 @@ static RenderObject* rendererForView(NSView* view) if (!renderer) return nil; - AccessibilityObject* obj = renderer->document()->axObjectCache()->get(renderer); + AccessibilityObject* obj = renderer->document()->axObjectCache()->getOrCreate(renderer); if (obj) return obj->parentObjectUnignored()->wrapper(); return nil; @@ -2013,6 +2052,9 @@ static RenderObject* rendererForView(NSView* view) // API that AppKit uses for faster access - (NSUInteger)accessibilityIndexOfChild:(id)child { + if (!m_object) + return NSNotFound; + m_object->updateBackingStore(); const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children(); @@ -2022,7 +2064,8 @@ static RenderObject* rendererForView(NSView* view) unsigned count = children.size(); for (unsigned k = 0; k < count; ++k) { - if (children[k]->wrapper() == child) + AccessibilityObjectWrapper* wrapper = children[k]->wrapper(); + if (wrapper == child || (children[k]->isAttachment() && [wrapper attachmentView] == child)) return k; } @@ -2031,6 +2074,9 @@ static RenderObject* rendererForView(NSView* view) - (NSUInteger)accessibilityArrayAttributeCount:(NSString *)attribute { + if (!m_object) + return 0; + m_object->updateBackingStore(); if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) { @@ -2046,6 +2092,9 @@ static RenderObject* rendererForView(NSView* view) - (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount { + if (!m_object) + return nil; + m_object->updateBackingStore(); if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) { @@ -2070,8 +2119,16 @@ static RenderObject* rendererForView(NSView* view) unsigned available = min(childCount - index, maxCount); NSMutableArray *subarray = [NSMutableArray arrayWithCapacity:available]; - for (unsigned added = 0; added < available; ++index, ++added) - [subarray addObject:children[index]->wrapper()]; + for (unsigned added = 0; added < available; ++index, ++added) { + AccessibilityObjectWrapper* wrapper = children[index]->wrapper(); + if (wrapper) { + // The attachment view should be returned, otherwise AX palindrome errors occur. + if (children[index]->isAttachment() && [wrapper attachmentView]) + [subarray addObject:[wrapper attachmentView]]; + else + [subarray addObject:wrapper]; + } + } return subarray; } diff --git a/WebCore/page/mac/EventHandlerMac.mm b/WebCore/page/mac/EventHandlerMac.mm index 5d09843..33d1c5f 100644 --- a/WebCore/page/mac/EventHandlerMac.mm +++ b/WebCore/page/mac/EventHandlerMac.mm @@ -83,10 +83,10 @@ PassRefPtr<KeyboardEvent> EventHandler::currentKeyboardEvent() const case NSKeyDown: { PlatformKeyboardEvent platformEvent(event); platformEvent.disambiguateKeyDownEvent(PlatformKeyboardEvent::RawKeyDown); - return KeyboardEvent::create(platformEvent, m_frame->document() ? m_frame->document()->defaultView() : 0); + return KeyboardEvent::create(platformEvent, m_frame->document()->defaultView()); } case NSKeyUp: - return KeyboardEvent::create(event, m_frame->document() ? m_frame->document()->defaultView() : 0); + return KeyboardEvent::create(event, m_frame->document()->defaultView()); default: return 0; } @@ -140,8 +140,6 @@ bool EventHandler::needsKeyboardEventDisambiguationQuirks() const } Document* document = m_frame->document(); - if (!document) - return false; // RSS view needs arrow key keypress events. if (isSafari && document->url().protocolIs("feed") || document->url().protocolIs("feeds")) diff --git a/WebCore/page/mac/FrameMac.mm b/WebCore/page/mac/FrameMac.mm index 84d7549..f360511 100644 --- a/WebCore/page/mac/FrameMac.mm +++ b/WebCore/page/mac/FrameMac.mm @@ -156,7 +156,7 @@ NSString* Frame::searchForNSLabelsAboveCell(RegularExpression* regExp, HTMLTable if (cellAboveRenderer) { HTMLTableCellElement* aboveCell = - static_cast<HTMLTableCellElement*>(cellAboveRenderer->element()); + static_cast<HTMLTableCellElement*>(cellAboveRenderer->node()); if (aboveCell) { // search within the above cell we found for a match @@ -490,8 +490,6 @@ void Frame::setUseSecureKeyboardEntry(bool enable) NSMutableDictionary* Frame::dashboardRegionsDictionary() { Document* doc = document(); - if (!doc) - return nil; const Vector<DashboardRegionValue>& regions = doc->dashboardRegions(); size_t n = regions.size(); @@ -537,7 +535,7 @@ void Frame::setUserStyleSheetLocation(const KURL& url) { delete m_userStyleSheetLoader; m_userStyleSheetLoader = 0; - if (m_doc && m_doc->docLoader()) + if (m_doc->docLoader()) m_userStyleSheetLoader = new UserStyleSheetLoader(m_doc, url.string()); } @@ -545,8 +543,7 @@ void Frame::setUserStyleSheet(const String& styleSheet) { delete m_userStyleSheetLoader; m_userStyleSheetLoader = 0; - if (m_doc) - m_doc->setUserStyleSheet(styleSheet); + m_doc->setUserStyleSheet(styleSheet); } } // namespace WebCore diff --git a/WebCore/page/win/FrameWin.cpp b/WebCore/page/win/FrameWin.cpp index fef1ffa..db55d30 100644 --- a/WebCore/page/win/FrameWin.cpp +++ b/WebCore/page/win/FrameWin.cpp @@ -81,7 +81,7 @@ void computePageRectsForFrame(Frame* frame, const IntRect& printRect, float head float printedPagesHeight = 0.0f; do { float proposedBottom = min(docHeight, printedPagesHeight + pageHeight); - frame->adjustPageHeight(&proposedBottom, printedPagesHeight, proposedBottom, printedPagesHeight); + frame->view()->adjustPageHeight(&proposedBottom, printedPagesHeight, proposedBottom, printedPagesHeight); currPageHeight = max(1.0f, proposedBottom - printedPagesHeight); pages.append(IntRect(0, printedPagesHeight, currPageWidth, currPageHeight)); |