diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-05 14:34:32 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-05 14:34:32 -0800 |
commit | 635860845790a19bf50bbc51ba8fb66a96dde068 (patch) | |
tree | ef6ad9ff73a5b57f65249d4232a202fa77e6a140 /WebCore/page | |
parent | 8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2 (diff) | |
download | external_webkit-635860845790a19bf50bbc51ba8fb66a96dde068.zip external_webkit-635860845790a19bf50bbc51ba8fb66a96dde068.tar.gz external_webkit-635860845790a19bf50bbc51ba8fb66a96dde068.tar.bz2 |
auto import from //depot/cupcake/@136594
Diffstat (limited to 'WebCore/page')
96 files changed, 3863 insertions, 1852 deletions
diff --git a/WebCore/page/AccessibilityListBox.cpp b/WebCore/page/AccessibilityListBox.cpp index 912351e..b94ccef 100644 --- a/WebCore/page/AccessibilityListBox.cpp +++ b/WebCore/page/AccessibilityListBox.cpp @@ -150,30 +150,28 @@ AccessibilityObject* AccessibilityListBox::listBoxOptionAccessibilityObject(HTML return listBoxObject; } -AccessibilityObject* AccessibilityListBox::doAccessibilityHitTest(const IntPoint& point) +AccessibilityObject* AccessibilityListBox::doAccessibilityHitTest(const IntPoint& point) const { // the internal HTMLSelectElement methods for returning a listbox option at a point // ignore optgroup elements. if (!m_renderer) return 0; - Node *element = m_renderer->element(); + Node* element = m_renderer->element(); if (!element) return 0; - - if (!hasChildren()) - addChildren(); IntRect parentRect = boundingBoxRect(); - unsigned length = m_children.size(); + const Vector<HTMLElement*>& listItems = static_cast<HTMLSelectElement*>(element)->listItems(); + unsigned length = listItems.size(); for (unsigned i = 0; i < length; i++) { IntRect rect = static_cast<RenderListBox*>(m_renderer)->itemBoundingBoxRect(parentRect.x(), parentRect.y(), i); if (rect.contains(point)) - return m_children[i].get(); + return listBoxOptionAccessibilityObject(listItems[i]); } - return this; + return axObjectCache()->get(m_renderer); } } // namespace WebCore diff --git a/WebCore/page/AccessibilityListBox.h b/WebCore/page/AccessibilityListBox.h index f95a921..3f3352d 100644 --- a/WebCore/page/AccessibilityListBox.h +++ b/WebCore/page/AccessibilityListBox.h @@ -42,7 +42,7 @@ public: static PassRefPtr<AccessibilityListBox> create(RenderObject*); virtual ~AccessibilityListBox(); - virtual AccessibilityObject* doAccessibilityHitTest(const IntPoint&); + virtual AccessibilityObject* doAccessibilityHitTest(const IntPoint&) const; virtual bool isListBox() const { return true; }; virtual bool canSetFocusAttribute() const { return true; } diff --git a/WebCore/page/AccessibilityObject.cpp b/WebCore/page/AccessibilityObject.cpp index 6be8c1a..6d441d0 100644 --- a/WebCore/page/AccessibilityObject.cpp +++ b/WebCore/page/AccessibilityObject.cpp @@ -51,6 +51,7 @@ #include "TextIterator.h" #include "htmlediting.h" #include "visible_units.h" +#include <wtf/StdLibExtras.h> using namespace std; @@ -256,7 +257,7 @@ void AccessibilityObject::setSelectedText(const String&) notImplemented(); } -void AccessibilityObject::setSelectedTextRange(const PlainTextRange& range) +void AccessibilityObject::setSelectedTextRange(const PlainTextRange&) { } @@ -271,11 +272,11 @@ KURL AccessibilityObject::url() const return KURL(); } -void AccessibilityObject::setFocused(bool on) +void AccessibilityObject::setFocused(bool) { } -void AccessibilityObject::setValue(const String& string) +void AccessibilityObject::setValue(const String&) { } @@ -326,17 +327,17 @@ VisiblePositionRange AccessibilityObject::visiblePositionRange() const return VisiblePositionRange(); } -VisiblePositionRange AccessibilityObject::visiblePositionRangeForLine(unsigned lineCount) const +VisiblePositionRange AccessibilityObject::visiblePositionRangeForLine(unsigned) const { return VisiblePositionRange(); } -VisiblePosition AccessibilityObject::visiblePositionForIndex(int index) const +VisiblePosition AccessibilityObject::visiblePositionForIndex(int) const { return VisiblePosition(); } -int AccessibilityObject::indexForVisiblePosition(const VisiblePosition& pos) const +int AccessibilityObject::indexForVisiblePosition(const VisiblePosition&) const { return 0; } @@ -599,7 +600,7 @@ String AccessibilityObject::stringForVisiblePositionRange(const VisiblePositionR return String::adopt(resultVector); } -IntRect AccessibilityObject::boundsForVisiblePositionRange(const VisiblePositionRange& visiblePositionRange) const +IntRect AccessibilityObject::boundsForVisiblePositionRange(const VisiblePositionRange&) const { return IntRect(); } @@ -635,7 +636,7 @@ void AccessibilityObject::setSelectedVisiblePositionRange(const VisiblePositionR { } -VisiblePosition AccessibilityObject::visiblePositionForPoint(const IntPoint& point) const +VisiblePosition AccessibilityObject::visiblePositionForPoint(const IntPoint&) const { return VisiblePosition(); } @@ -738,7 +739,8 @@ VisiblePosition AccessibilityObject::nextSentenceEndPosition(const VisiblePositi // an empty line is considered a sentence. If it's skipped, then the sentence parser will not // see this empty line. Instead, return the end position of the empty line. VisiblePosition endPosition; - String lineString = plainText(makeRange(startOfLine(visiblePos), endOfLine(visiblePos)).get()); + + String lineString = plainText(makeRange(startOfLine(nextVisiblePos), endOfLine(nextVisiblePos)).get()); if (lineString.isEmpty()) endPosition = nextVisiblePos; else @@ -761,6 +763,7 @@ VisiblePosition AccessibilityObject::previousSentenceStartPosition(const Visible // treat empty line as a separate sentence. VisiblePosition startPosition; + String lineString = plainText(makeRange(startOfLine(previousVisiblePos), endOfLine(previousVisiblePos)).get()); if (lineString.isEmpty()) startPosition = previousVisiblePos; @@ -797,7 +800,7 @@ VisiblePosition AccessibilityObject::previousParagraphStartPosition(const Visibl } // NOTE: Consider providing this utility method as AX API -VisiblePosition AccessibilityObject::visiblePositionForIndex(unsigned indexValue, bool lastIndexOK) const +VisiblePosition AccessibilityObject::visiblePositionForIndex(unsigned, bool) const { return VisiblePosition(); } @@ -848,14 +851,14 @@ PlainTextRange AccessibilityObject::plainTextRangeForVisiblePositionRange(const } // NOTE: Consider providing this utility method as AX API -int AccessibilityObject::index(const VisiblePosition& position) const +int AccessibilityObject::index(const VisiblePosition&) const { return -1; } // Given a line number, the range of characters of the text associated with this accessibility // object that contains the line number. -PlainTextRange AccessibilityObject::doAXRangeForLine(unsigned lineNumber) const +PlainTextRange AccessibilityObject::doAXRangeForLine(unsigned) const { return PlainTextRange(); } @@ -878,7 +881,7 @@ PlainTextRange AccessibilityObject::doAXRangeForPosition(const IntPoint& point) // The composed character range in the text associated with this accessibility object that // is specified by the given index value. This parameterized attribute returns the complete // range of characters (including surrogate pairs of multi-byte glyphs) at the given index. -PlainTextRange AccessibilityObject::doAXRangeForIndex(unsigned index) const +PlainTextRange AccessibilityObject::doAXRangeForIndex(unsigned) const { return PlainTextRange(); } @@ -893,7 +896,7 @@ PlainTextRange AccessibilityObject::doAXStyleRangeForIndex(unsigned index) const // A substring of the text associated with this accessibility object that is // specified by the given character range. -String AccessibilityObject::doAXStringForRange(const PlainTextRange& range) const +String AccessibilityObject::doAXStringForRange(const PlainTextRange&) const { return String(); } @@ -901,7 +904,7 @@ String AccessibilityObject::doAXStringForRange(const PlainTextRange& range) cons // The bounding rectangle of the text associated with this accessibility object that is // specified by the given range. This is the bounding rectangle a sighted user would see // on the display screen, in pixels. -IntRect AccessibilityObject::doAXBoundsForRange(const PlainTextRange& range) const +IntRect AccessibilityObject::doAXBoundsForRange(const PlainTextRange&) const { return IntRect(); } @@ -925,7 +928,7 @@ FrameView* AccessibilityObject::documentFrameView() const return object->documentFrameView(); } -AccessibilityObject* AccessibilityObject::doAccessibilityHitTest(const IntPoint& point) const +AccessibilityObject* AccessibilityObject::doAccessibilityHitTest(const IntPoint&) const { return 0; } @@ -1001,13 +1004,13 @@ void AccessibilityObject::removeAXObjectID() const String& AccessibilityObject::actionVerb() const { // FIXME: Need to add verbs for select elements. - static const String buttonAction = AXButtonActionVerb(); - static const String textFieldAction = AXTextFieldActionVerb(); - static const String radioButtonAction = AXRadioButtonActionVerb(); - static const String checkedCheckBoxAction = AXCheckedCheckBoxActionVerb(); - static const String uncheckedCheckBoxAction = AXUncheckedCheckBoxActionVerb(); - static const String linkAction = AXLinkActionVerb(); - static const String noAction; + DEFINE_STATIC_LOCAL(const String, buttonAction, (AXButtonActionVerb())); + DEFINE_STATIC_LOCAL(const String, textFieldAction, (AXTextFieldActionVerb())); + DEFINE_STATIC_LOCAL(const String, radioButtonAction, (AXRadioButtonActionVerb())); + DEFINE_STATIC_LOCAL(const String, checkedCheckBoxAction, (AXCheckedCheckBoxActionVerb())); + DEFINE_STATIC_LOCAL(const String, uncheckedCheckBoxAction, (AXUncheckedCheckBoxActionVerb())); + DEFINE_STATIC_LOCAL(const String, linkAction, (AXLinkActionVerb())); + DEFINE_STATIC_LOCAL(const String, noAction, ()); switch (roleValue()) { case ButtonRole: @@ -1027,4 +1030,8 @@ const String& AccessibilityObject::actionVerb() const } } +void AccessibilityObject::updateBackingStore() +{ +} + } // namespace WebCore diff --git a/WebCore/page/AccessibilityObject.h b/WebCore/page/AccessibilityObject.h index 947757a..a751003 100644 --- a/WebCore/page/AccessibilityObject.h +++ b/WebCore/page/AccessibilityObject.h @@ -213,6 +213,7 @@ public: virtual bool isMenuButton() const { return false; } virtual bool isMenuItem() const { return false; } virtual bool isFileUploadButton() const { return false; }; + virtual bool isInputImage() const { return false; } virtual bool isProgressIndicator() const { return false; }; virtual bool isSlider() const { return false; }; virtual bool isControl() const { return false; }; @@ -222,6 +223,7 @@ public: virtual bool isTableColumn() const { return false; }; virtual bool isTableCell() const { return false; }; virtual bool isFieldset() const { return false; }; + virtual bool isGroup() const { return false; }; virtual bool isChecked() const { return false; }; virtual bool isEnabled() const { return false; }; @@ -392,7 +394,15 @@ public: #endif // a platform-specific method for determining if an attachment is ignored +#if HAVE(ACCESSIBILITY) bool accessibilityIgnoreAttachment() const; +#else + bool accessibilityIgnoreAttachment() const { return true; } +#endif + + // allows for an AccessibilityObject to update its render tree or perform + // other operations update type operations + virtual void updateBackingStore(); protected: unsigned m_id; diff --git a/WebCore/page/AccessibilityRenderObject.cpp b/WebCore/page/AccessibilityRenderObject.cpp index 144aab0..5cdc7b4 100644 --- a/WebCore/page/AccessibilityRenderObject.cpp +++ b/WebCore/page/AccessibilityRenderObject.cpp @@ -61,6 +61,7 @@ #include "RenderListBox.h" #include "RenderListMarker.h" #include "RenderMenuList.h" +#include "RenderText.h" #include "RenderTextControl.h" #include "RenderTheme.h" #include "RenderView.h" @@ -70,6 +71,7 @@ #include "TextIterator.h" #include "htmlediting.h" #include "visible_units.h" +#include <wtf/StdLibExtras.h> using namespace std; @@ -246,6 +248,16 @@ bool AccessibilityRenderObject::isFileUploadButton() const return false; } + +bool AccessibilityRenderObject::isInputImage() const +{ + if (m_renderer && m_renderer->element() && m_renderer->element()->hasTagName(inputTag)) { + HTMLInputElement* input = static_cast<HTMLInputElement*>(m_renderer->element()); + return input->inputType() == HTMLInputElement::IMAGE; + } + + return false; +} bool AccessibilityRenderObject::isProgressIndicator() const { @@ -341,6 +353,10 @@ bool AccessibilityRenderObject::isReadOnly() const if (!document) return true; + HTMLElement* body = document->body(); + if (body && body->isContentEditable()) + return false; + Frame* frame = document->frame(); if (!frame) return true; @@ -425,6 +441,11 @@ bool AccessibilityRenderObject::isFieldset() const return m_renderer->isFieldset(); } + +bool AccessibilityRenderObject::isGroup() const +{ + return roleValue() == GroupRole; +} const AtomicString& AccessibilityRenderObject::getAttribute(const QualifiedName& attribute) const { @@ -449,8 +470,9 @@ Element* AccessibilityRenderObject::anchorElement() const // Search up the render tree for a RenderObject with a DOM node. Defer to an earlier continuation, though. for (currRenderer = m_renderer; currRenderer && !currRenderer->element(); currRenderer = currRenderer->parent()) { - if (currRenderer->continuation()) - return cache->get(currRenderer->continuation())->anchorElement(); + RenderFlow* continuation = currRenderer->virtualContinuation(); + if (continuation) + return cache->get(continuation)->anchorElement(); } // bail if none found @@ -470,10 +492,17 @@ Element* AccessibilityRenderObject::anchorElement() const Element* AccessibilityRenderObject::actionElement() const { - if (m_renderer->element() && m_renderer->element()->hasTagName(inputTag)) { - HTMLInputElement* input = static_cast<HTMLInputElement*>(m_renderer->element()); - if (!input->disabled() && (isCheckboxOrRadio() || input->isTextButton())) - return input; + if (!m_renderer) + return 0; + + Node* node = m_renderer->element(); + if (node) { + if (node->hasTagName(inputTag)) { + HTMLInputElement* input = static_cast<HTMLInputElement*>(node); + if (!input->disabled() && (isCheckboxOrRadio() || input->isTextButton())) + return input; + } else if (node->hasTagName(buttonTag)) + return static_cast<Element*>(node); } if (isFileUploadButton()) @@ -837,7 +866,7 @@ String AccessibilityRenderObject::title() const if (isInputTag || AccessibilityObject::isARIAInput(ariaRole) || isControl()) { HTMLLabelElement* label = labelForElement(static_cast<Element*>(node)); - if (label) + if (label && !titleUIElement()) return label->innerText(); } @@ -920,9 +949,8 @@ IntRect AccessibilityRenderObject::boundingBoxRect() const // FIXME: This doesn't work correctly with transforms. Vector<IntRect> rects; - int x, y; - obj->absolutePosition(x, y); - obj->absoluteRects(rects, x, y); + FloatPoint absPos = obj->localToAbsolute(); + obj->absoluteRects(rects, absPos.x(), absPos.y()); const size_t n = rects.size(); for (size_t i = 0; i < n; ++i) { IntRect r = rects[i]; @@ -985,12 +1013,9 @@ AccessibilityObject* AccessibilityRenderObject::internalLinkElement() const if (m_renderer->document()->url() != linkURL) return 0; - Node* linkedNode = m_renderer->document()->getElementById(ref); - if (!linkedNode) { - linkedNode = m_renderer->document()->anchors()->namedItem(ref, !m_renderer->document()->inCompatMode()); - if (!linkedNode) - return 0; - } + Node* linkedNode = m_renderer->document()->findAnchor(ref); + if (!linkedNode) + return 0; // the element we find may not be accessible, keep searching until we find a good one AccessibilityObject* linkedAXElement = m_renderer->document()->axObjectCache()->get(linkedNode->renderer()); @@ -1118,7 +1143,7 @@ bool AccessibilityRenderObject::accessibilityIsIgnored() const if (parentObjectUnignored()->ariaRoleAttribute() == MenuItemRole || parentObjectUnignored()->ariaRoleAttribute() == MenuButtonRole) return true; - return m_renderer->isBR() || !static_cast<RenderText*>(m_renderer)->firstTextBox(); + return m_renderer->isBR() || !toRenderText(m_renderer)->firstTextBox(); } if (isHeading()) @@ -1153,12 +1178,12 @@ bool AccessibilityRenderObject::accessibilityIsIgnored() const } // check for one-dimensional image - if (m_renderer->height() <= 1 || m_renderer->width() <= 1) + RenderImage* image = static_cast<RenderImage*>(m_renderer); + if (image->height() <= 1 || image->width() <= 1) return true; // check whether rendered image was stretched from one-dimensional file image if (isNativeImage()) { - RenderImage* image = static_cast<RenderImage*>(m_renderer); if (image->cachedImage()) { IntSize imageSize = image->cachedImage()->imageSize(image->view()->zoomFactor()); return imageSize.height() <= 1 || imageSize.width() <= 1; @@ -1337,6 +1362,9 @@ KURL AccessibilityRenderObject::url() const if (isImage() && m_renderer->element() && m_renderer->element()->hasTagName(imgTag)) return static_cast<HTMLImageElement*>(m_renderer->element())->src(); + if (isInputImage()) + return static_cast<HTMLInputElement*>(m_renderer->element())->src(); + return KURL(); } @@ -1411,9 +1439,9 @@ bool AccessibilityRenderObject::isEnabled() const return m_renderer->element() ? m_renderer->element()->isEnabled() : true; } -RenderObject* AccessibilityRenderObject::topRenderer() const +RenderView* AccessibilityRenderObject::topRenderer() const { - return m_renderer->document()->topDocument()->renderer(); + return m_renderer->document()->topDocument()->renderView(); } Document* AccessibilityRenderObject::document() const @@ -1621,19 +1649,19 @@ IntRect AccessibilityRenderObject::boundsForVisiblePositionRange(const VisiblePo // Create a mutable VisiblePositionRange. VisiblePositionRange range(visiblePositionRange); - IntRect rect1 = range.start.caretRect(); - IntRect rect2 = range.end.caretRect(); + IntRect rect1 = range.start.absoluteCaretBounds(); + IntRect rect2 = range.end.absoluteCaretBounds(); // readjust for position at the edge of a line. This is to exclude line rect that doesn't need to be accounted in the range bounds if (rect2.y() != rect1.y()) { VisiblePosition endOfFirstLine = endOfLine(range.start); if (range.start == endOfFirstLine) { range.start.setAffinity(DOWNSTREAM); - rect1 = range.start.caretRect(); + rect1 = range.start.absoluteCaretBounds(); } if (range.end == endOfFirstLine) { range.end.setAffinity(UPSTREAM); - rect2 = range.end.caretRect(); + rect2 = range.end.absoluteCaretBounds(); } } @@ -1675,7 +1703,7 @@ VisiblePosition AccessibilityRenderObject::visiblePositionForPoint(const IntPoin { // convert absolute point to view coordinates FrameView* frameView = m_renderer->document()->topDocument()->renderer()->view()->frameView(); - RenderObject* renderer = topRenderer(); + RenderView* renderView = topRenderer(); Node* innerNode = 0; // locate the node containing the point @@ -1689,7 +1717,7 @@ VisiblePosition AccessibilityRenderObject::visiblePositionForPoint(const IntPoin #endif HitTestRequest request(true, true); HitTestResult result(ourpoint); - renderer->layer()->hitTest(request, result); + renderView->layer()->hitTest(request, result); innerNode = result.innerNode(); if (!innerNode || !innerNode->renderer()) return VisiblePosition(); @@ -1697,7 +1725,7 @@ VisiblePosition AccessibilityRenderObject::visiblePositionForPoint(const IntPoin pointResult = result.localPoint(); // done if hit something other than a widget - renderer = innerNode->renderer(); + RenderObject* renderer = innerNode->renderer(); if (!renderer->isWidget()) break; @@ -1711,7 +1739,7 @@ VisiblePosition AccessibilityRenderObject::visiblePositionForPoint(const IntPoin Document* document = frame->document(); if (!document) break; - renderer = document->renderer(); + renderView = document->renderView(); frameView = static_cast<FrameView*>(widget); } @@ -1842,13 +1870,11 @@ IntRect AccessibilityRenderObject::doAXBoundsForRange(const PlainTextRange& rang AccessibilityObject* AccessibilityRenderObject::doAccessibilityHitTest(const IntPoint& point) const { - if (!m_renderer) - return 0; - - RenderLayer* layer = m_renderer->layer(); - if (!layer) + if (!m_renderer || !m_renderer->hasLayer()) return 0; + RenderLayer* layer = toRenderBox(m_renderer)->layer(); + HitTestRequest request(true, true); HitTestResult hitTestResult = HitTestResult(point); layer->hitTest(request, hitTestResult); @@ -1940,6 +1966,9 @@ AccessibilityObject* AccessibilityRenderObject::activeDescendant() const return 0; Element* target = renderer()->document()->getElementById(activeDescendantAttrStr); + if (!target) + return 0; + AccessibilityObject* obj = renderer()->document()->axObjectCache()->get(target->renderer()); if (obj->isAccessibilityRenderObject()) // an activedescendant is only useful if it has a renderer, because that's what's needed to post the notification @@ -1982,7 +2011,7 @@ static const ARIARoleMap& createARIARoleMap() AccessibilityRole webcoreRole; }; - static const RoleEntry roles[] = { + const RoleEntry roles[] = { { "button", ButtonRole }, { "checkbox", CheckBoxRole }, { "group", GroupRole }, @@ -2185,12 +2214,20 @@ bool AccessibilityRenderObject::canSetTextRangeAttributes() const void AccessibilityRenderObject::childrenChanged() { - clearChildren(); + // this method is meant as a quick way of marking dirty + // a portion of the accessibility tree - if (accessibilityIsIgnored()) { - AccessibilityObject* parent = parentObject(); - if (parent) - parent->childrenChanged(); + markChildrenDirty(); + + // 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()) { + if (parent->isAccessibilityRenderObject()) + static_cast<AccessibilityRenderObject *>(parent)->markChildrenDirty(); } } @@ -2214,6 +2251,11 @@ bool AccessibilityRenderObject::canHaveChildren() const const AccessibilityObject::AccessibilityChildrenVector& AccessibilityRenderObject::children() { + if (m_childrenDirty) { + clearChildren(); + m_childrenDirty = false; + } + if (!m_haveChildren) addChildren(); return m_children; @@ -2348,13 +2390,13 @@ void AccessibilityRenderObject::removeAXObjectID() const String& AccessibilityRenderObject::actionVerb() const { // FIXME: Need to add verbs for select elements. - static const String buttonAction = AXButtonActionVerb(); - static const String textFieldAction = AXTextFieldActionVerb(); - static const String radioButtonAction = AXRadioButtonActionVerb(); - static const String checkedCheckBoxAction = AXCheckedCheckBoxActionVerb(); - static const String uncheckedCheckBoxAction = AXUncheckedCheckBoxActionVerb(); - static const String linkAction = AXLinkActionVerb(); - static const String noAction; + DEFINE_STATIC_LOCAL(const String, buttonAction, (AXButtonActionVerb())); + DEFINE_STATIC_LOCAL(const String, textFieldAction, (AXTextFieldActionVerb())); + DEFINE_STATIC_LOCAL(const String, radioButtonAction, (AXRadioButtonActionVerb())); + DEFINE_STATIC_LOCAL(const String, checkedCheckBoxAction, (AXCheckedCheckBoxActionVerb())); + DEFINE_STATIC_LOCAL(const String, uncheckedCheckBoxAction, (AXUncheckedCheckBoxActionVerb())); + DEFINE_STATIC_LOCAL(const String, linkAction, (AXLinkActionVerb())); + DEFINE_STATIC_LOCAL(const String, noAction, ()); switch (roleValue()) { case ButtonRole: @@ -2374,5 +2416,11 @@ const String& AccessibilityRenderObject::actionVerb() const } } +void AccessibilityRenderObject::updateBackingStore() +{ + if (!m_renderer) + return; + m_renderer->view()->layoutIfNeeded(); +} } // namespace WebCore diff --git a/WebCore/page/AccessibilityRenderObject.h b/WebCore/page/AccessibilityRenderObject.h index c859b5a..03ba1db 100644 --- a/WebCore/page/AccessibilityRenderObject.h +++ b/WebCore/page/AccessibilityRenderObject.h @@ -50,6 +50,7 @@ class Node; class RenderObject; class RenderListBox; class RenderTextControl; +class RenderView; class Selection; class String; class Widget; @@ -76,6 +77,7 @@ public: virtual bool isWebArea() const; virtual bool isCheckboxOrRadio() const; virtual bool isFileUploadButton() const; + virtual bool isInputImage() const; virtual bool isProgressIndicator() const; virtual bool isSlider() const; virtual bool isMenuRelated() const; @@ -85,6 +87,7 @@ public: virtual bool isMenuItem() const; virtual bool isControl() const; virtual bool isFieldset() const; + virtual bool isGroup() const; virtual bool isEnabled() const; virtual bool isSelected() const; @@ -145,7 +148,7 @@ public: void setRenderer(RenderObject* renderer) { m_renderer = renderer; } RenderObject* renderer() const { return m_renderer; } - RenderObject* topRenderer() const; + RenderView* topRenderer() const; RenderTextControl* textControl() const; Document* document() const; FrameView* topDocumentFrameView() const; @@ -207,9 +210,12 @@ public: virtual String doAXStringForRange(const PlainTextRange&) const; virtual IntRect doAXBoundsForRange(const PlainTextRange&) const; + virtual void updateBackingStore(); + protected: RenderObject* m_renderer; AccessibilityRole m_ariaRole; + mutable bool m_childrenDirty; void setRenderObject(RenderObject* renderer) { m_renderer = renderer; } virtual void removeAXObjectID(); @@ -229,6 +235,7 @@ private: AccessibilityObject* internalLinkElement() const; AccessibilityObject* accessibilityParentForImageMap(HTMLMapElement* map) const; + void markChildrenDirty() const { m_childrenDirty = true; } }; } // namespace WebCore diff --git a/WebCore/page/AccessibilityTable.cpp b/WebCore/page/AccessibilityTable.cpp index 11c36ef..9409283 100644 --- a/WebCore/page/AccessibilityTable.cpp +++ b/WebCore/page/AccessibilityTable.cpp @@ -53,13 +53,11 @@ AccessibilityTable::AccessibilityTable(RenderObject* renderer) : AccessibilityRenderObject(renderer), m_headerContainer(0) { - // AXTables should not appear in tiger or leopard, on the mac -#if PLATFORM(MAC) && (defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD)) +#if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) m_isAccessibilityTable = false; -#else +#else m_isAccessibilityTable = isTableExposableThroughAccessibility(); #endif - } AccessibilityTable::~AccessibilityTable() diff --git a/WebCore/page/AccessibilityTableCell.cpp b/WebCore/page/AccessibilityTableCell.cpp index 2062a88..ff82811 100644 --- a/WebCore/page/AccessibilityTableCell.cpp +++ b/WebCore/page/AccessibilityTableCell.cpp @@ -30,6 +30,7 @@ #include "AccessibilityTableCell.h" #include "AXObjectCache.h" +#include "HTMLNames.h" #include "RenderObject.h" #include "RenderTableCell.h" @@ -37,6 +38,8 @@ using namespace std; namespace WebCore { +using namespace HTMLNames; + AccessibilityTableCell::AccessibilityTableCell(RenderObject* renderer) : AccessibilityRenderObject(renderer) { @@ -84,7 +87,7 @@ void AccessibilityTableCell::rowIndexRange(pair<int, int>& rowRange) if (!m_renderer) return; - RenderTableCell *renderCell = static_cast<RenderTableCell*>(m_renderer); + RenderTableCell* renderCell = static_cast<RenderTableCell*>(m_renderer); rowRange.first = renderCell->row(); rowRange.second = renderCell->rowSpan(); @@ -114,9 +117,41 @@ void AccessibilityTableCell::columnIndexRange(pair<int, int>& columnRange) if (!m_renderer) return; - RenderTableCell *renderCell = static_cast<RenderTableCell*>(m_renderer); + RenderTableCell* renderCell = static_cast<RenderTableCell*>(m_renderer); columnRange.first = renderCell->col(); columnRange.second = renderCell->colSpan(); } +AccessibilityObject* AccessibilityTableCell::titleUIElement() const +{ + // Try to find if the first cell in this row is a <th>. If it is, + // then it can act as the title ui element. (This is only in the + // case when the table is not appearing as an AXTable.) + if (!m_renderer || isTableCell()) + return 0; + + RenderTableCell* renderCell = static_cast<RenderTableCell*>(m_renderer); + + // If this cell is in the first column, there is no need to continue. + int col = renderCell->col(); + if (!col) + return 0; + + int row = renderCell->row(); + + RenderTableSection* section = renderCell->section(); + if (!section) + return 0; + + RenderTableCell* headerCell = section->cellAt(row, 0).cell; + if (!headerCell || headerCell == renderCell) + return 0; + + Node* cellElement = headerCell->element(); + if (!cellElement || !cellElement->hasTagName(thTag)) + return 0; + + return axObjectCache()->get(headerCell); +} + } // namespace WebCore diff --git a/WebCore/page/AccessibilityTableCell.h b/WebCore/page/AccessibilityTableCell.h index e77dfb2..8f8dd77 100644 --- a/WebCore/page/AccessibilityTableCell.h +++ b/WebCore/page/AccessibilityTableCell.h @@ -51,6 +51,10 @@ public: // fills in the start location and column span of cell void columnIndexRange(pair<int, int>& columnRange); + // if a table cell is not exposed as a table cell, a TH element can + // serve as its title ui element + AccessibilityObject* titleUIElement() const; + private: int m_rowIndex; diff --git a/WebCore/page/Chrome.cpp b/WebCore/page/Chrome.cpp index c9b57f2..4698aa5 100644 --- a/WebCore/page/Chrome.cpp +++ b/WebCore/page/Chrome.cpp @@ -35,7 +35,6 @@ #include "InspectorController.h" #include "Page.h" #include "PageGroup.h" -#include "PausedTimeouts.h" #include "ResourceHandle.h" #include "ScriptController.h" #include "SecurityOrigin.h" @@ -60,9 +59,6 @@ public: ~PageGroupLoadDeferrer(); private: Vector<RefPtr<Frame>, 16> m_deferredFrames; -#if !PLATFORM(MAC) - Vector<pair<RefPtr<Frame>, PausedTimeouts*>, 16> m_pausedTimeouts; -#endif }; Chrome::Chrome(Page* page, ChromeClient* client) @@ -102,6 +98,16 @@ PlatformWidget Chrome::platformWindow() const return m_client->platformWindow(); } +void Chrome::contentsSizeChanged(Frame* frame, const IntSize& size) const +{ + m_client->contentsSizeChanged(frame, size); +} + +void Chrome::scrollRectIntoView(const IntRect& rect, const ScrollView* scrollView) const +{ + m_client->scrollRectIntoView(rect, scrollView); +} + void Chrome::setWindowRect(const FloatRect& rect) const { m_client->setWindowRect(rect); @@ -253,10 +259,7 @@ void Chrome::runJavaScriptAlert(Frame* frame, const String& message) PageGroupLoadDeferrer deferrer(m_page, true); ASSERT(frame); - String text = message; - text.replace('\\', frame->backslashAsCurrencySymbol()); - - m_client->runJavaScriptAlert(frame, text); + m_client->runJavaScriptAlert(frame, frame->displayStringModifiedByEncoding(message)); } bool Chrome::runJavaScriptConfirm(Frame* frame, const String& message) @@ -266,10 +269,7 @@ bool Chrome::runJavaScriptConfirm(Frame* frame, const String& message) PageGroupLoadDeferrer deferrer(m_page, true); ASSERT(frame); - String text = message; - text.replace('\\', frame->backslashAsCurrencySymbol()); - - return m_client->runJavaScriptConfirm(frame, text); + return m_client->runJavaScriptConfirm(frame, frame->displayStringModifiedByEncoding(message)); } bool Chrome::runJavaScriptPrompt(Frame* frame, const String& prompt, const String& defaultValue, String& result) @@ -279,15 +279,10 @@ bool Chrome::runJavaScriptPrompt(Frame* frame, const String& prompt, const Strin PageGroupLoadDeferrer deferrer(m_page, true); ASSERT(frame); - String promptText = prompt; - promptText.replace('\\', frame->backslashAsCurrencySymbol()); - String defaultValueText = defaultValue; - defaultValueText.replace('\\', frame->backslashAsCurrencySymbol()); - - bool ok = m_client->runJavaScriptPrompt(frame, promptText, defaultValueText, result); + bool ok = m_client->runJavaScriptPrompt(frame, frame->displayStringModifiedByEncoding(prompt), frame->displayStringModifiedByEncoding(defaultValue), result); if (ok) - result.replace(frame->backslashAsCurrencySymbol(), '\\'); + result = frame->displayStringModifiedByEncoding(result); return ok; } @@ -295,10 +290,7 @@ bool Chrome::runJavaScriptPrompt(Frame* frame, const String& prompt, const Strin void Chrome::setStatusbarText(Frame* frame, const String& status) { ASSERT(frame); - String text = status; - text.replace('\\', frame->backslashAsCurrencySymbol()); - - m_client->setStatusbarText(text); + m_client->setStatusbarText(frame->displayStringModifiedByEncoding(status)); } bool Chrome::shouldInterruptJavaScript() @@ -440,8 +432,8 @@ void ChromeClient::enableSuddenTermination() } bool ChromeClient::paintCustomScrollbar(GraphicsContext*, const FloatRect&, ScrollbarControlSize, - ScrollbarControlState, ScrollbarPart, bool vertical, - float value, float proportion, ScrollbarControlPartMask) + ScrollbarControlState, ScrollbarPart, bool, + float, float, ScrollbarControlPartMask) { return false; } @@ -466,10 +458,8 @@ PageGroupLoadDeferrer::PageGroupLoadDeferrer(Page* page, bool deferSelf) #if !PLATFORM(MAC) for (Frame* frame = otherPage->mainFrame(); frame; frame = frame->tree()->traverseNext()) { - OwnPtr<PausedTimeouts> timeouts; - frame->script()->pauseTimeouts(timeouts); - if (timeouts) - m_pausedTimeouts.append(make_pair(RefPtr<Frame>(frame), timeouts.release())); + if (Document* document = frame->document()) + document->suspendActiveDOMObjects(); } #endif } @@ -483,17 +473,18 @@ PageGroupLoadDeferrer::PageGroupLoadDeferrer(Page* page, bool deferSelf) PageGroupLoadDeferrer::~PageGroupLoadDeferrer() { - for (size_t i = 0; i < m_deferredFrames.size(); ++i) - if (Page* page = m_deferredFrames[i]->page()) + for (size_t i = 0; i < m_deferredFrames.size(); ++i) { + if (Page* page = m_deferredFrames[i]->page()) { page->setDefersLoading(false); #if !PLATFORM(MAC) - for (size_t i = 0; i < m_pausedTimeouts.size(); i++) { - Frame* frame = m_pausedTimeouts[i].first.get(); - OwnPtr<PausedTimeouts> timeouts(m_pausedTimeouts[i].second); - frame->script()->resumeTimeouts(timeouts); - } + for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext()) { + if (Document* document = frame->document()) + document->resumeActiveDOMObjects(); + } #endif + } + } } diff --git a/WebCore/page/Chrome.h b/WebCore/page/Chrome.h index 0dd4013..47b912d 100644 --- a/WebCore/page/Chrome.h +++ b/WebCore/page/Chrome.h @@ -59,6 +59,9 @@ namespace WebCore { virtual IntPoint screenToWindow(const IntPoint&) const; virtual IntRect windowToScreen(const IntRect&) const; virtual PlatformWidget platformWindow() const; + virtual void scrollRectIntoView(const IntRect&, const ScrollView*) const; + + void contentsSizeChanged(Frame*, const IntSize&) const; void setWindowRect(const FloatRect&) const; FloatRect windowRect() const; diff --git a/WebCore/page/ChromeClient.h b/WebCore/page/ChromeClient.h index 7678dc2..5d90b2f 100644 --- a/WebCore/page/ChromeClient.h +++ b/WebCore/page/ChromeClient.h @@ -115,6 +115,8 @@ namespace WebCore { virtual IntPoint screenToWindow(const IntPoint&) const = 0; virtual IntRect windowToScreen(const IntRect&) const = 0; virtual PlatformWidget platformWindow() const = 0; + virtual void contentsSizeChanged(Frame*, const IntSize&) const = 0; + virtual void scrollRectIntoView(const IntRect&, const ScrollView*) const {} // Platforms other than Mac can implement this if it ever becomes necessary for them to do so. // End methods used by HostWindow. virtual void mouseDidMoveOverElement(const HitTestResult&, unsigned modifierFlags) = 0; @@ -148,6 +150,10 @@ namespace WebCore { virtual void runOpenPanel(Frame*, PassRefPtr<FileChooser>) = 0; + // Notification that the given form element has changed. This function + // will be called frequently, so handling should be very fast. + virtual void formStateDidChange(const Node*) = 0; + #if PLATFORM(MAC) virtual KeyboardUIMode keyboardUIMode() { return KeyboardAccessDefault; } diff --git a/WebCore/page/Console.cpp b/WebCore/page/Console.cpp index bfcc478..8755f0e 100644 --- a/WebCore/page/Console.cpp +++ b/WebCore/page/Console.cpp @@ -35,18 +35,16 @@ #include "FrameLoader.h" #include "FrameTree.h" #include "InspectorController.h" -#include "JSDOMBinding.h" #include "Page.h" #include "PageGroup.h" #include "PlatformString.h" -#include <runtime/ArgList.h> -#include <kjs/interpreter.h> -#include <runtime/JSObject.h> -#include <VM/Machine.h> + +#if USE(JSC) #include <profiler/Profiler.h> -#include <stdio.h> +#endif -using namespace JSC; +#include "ScriptCallStack.h" +#include <stdio.h> namespace WebCore { @@ -70,6 +68,18 @@ static void printSourceURLAndLine(const String& sourceURL, unsigned lineNumber) } } +static bool getFirstArgumentAsString(const ScriptCallFrame& callFrame, String& result, bool checkForNullOrUndefined = false) +{ + if (!callFrame.argumentCount()) + return false; + + const ScriptValue& value = callFrame.argumentAt(0); + if (checkForNullOrUndefined && (value.isNull() || value.isUndefined())) + return false; + + return value.getString(result); +} + static void printMessageSourceAndLevelPrefix(MessageSource source, MessageLevel level) { const char* sourceString; @@ -77,6 +87,9 @@ static void printMessageSourceAndLevelPrefix(MessageSource source, MessageLevel case HTMLMessageSource: sourceString = "HTML"; break; + case WMLMessageSource: + sourceString = "WML"; + break; case XMLMessageSource: sourceString = "XML"; break; @@ -116,8 +129,17 @@ static void printMessageSourceAndLevelPrefix(MessageSource source, MessageLevel printf("%s %s:", sourceString, levelString); } -static void printToStandardOut(MessageSource source, MessageLevel level, const String& message, const String& sourceURL, unsigned lineNumber) +void Console::addMessage(MessageSource source, MessageLevel level, const String& message, unsigned lineNumber, const String& sourceURL) { + Page* page = this->page(); + if (!page) + return; + + if (source == JSMessageSource || source == WMLMessageSource) + page->chrome()->client()->addMessageToConsole(message, lineNumber, sourceURL); + + page->inspectorController()->addMessageToConsole(source, level, message, lineNumber, sourceURL); + if (!Console::shouldPrintExceptions()) return; @@ -127,217 +149,124 @@ static void printToStandardOut(MessageSource source, MessageLevel level, const S printf(" %s\n", message.utf8().data()); } -static void printToStandardOut(MessageLevel level, ExecState* exec, const ArgList& args, const KURL& url) -{ - if (!Console::shouldPrintExceptions()) +void Console::addMessage(MessageLevel level, ScriptCallStack* callStack, bool acceptNoArguments) { + Page* page = this->page(); + if (!page) return; - printSourceURLAndLine(url.prettyURL(), 0); - printMessageSourceAndLevelPrefix(JSMessageSource, level); - - for (size_t i = 0; i < args.size(); ++i) { - UString argAsString = args.at(exec, i)->toString(exec); - printf(" %s", argAsString.UTF8String().c_str()); - } - - printf("\n"); -} + const ScriptCallFrame& lastCaller = callStack->at(0); -static inline void retrieveLastCaller(ExecState* exec, KURL& url, unsigned& lineNumber) -{ - int signedLineNumber; - intptr_t sourceID; - UString urlString; - JSValue* function; + if (!acceptNoArguments && !lastCaller.argumentCount()) + return; - exec->machine()->retrieveLastCaller(exec, signedLineNumber, sourceID, urlString, function); + String message; + if (getFirstArgumentAsString(lastCaller, message)) + page->chrome()->client()->addMessageToConsole(message, lastCaller.lineNumber(), lastCaller.sourceURL().prettyURL()); - url = KURL(urlString); - lineNumber = (signedLineNumber >= 0 ? signedLineNumber : 0); -} + page->inspectorController()->addMessageToConsole(JSMessageSource, level, callStack); -void Console::addMessage(MessageSource source, MessageLevel level, const String& message, unsigned lineNumber, const String& sourceURL) -{ - Page* page = this->page(); - if (!page) + if (!Console::shouldPrintExceptions()) return; - if (source == JSMessageSource) - page->chrome()->client()->addMessageToConsole(message, lineNumber, sourceURL); - - page->inspectorController()->addMessageToConsole(source, level, message, lineNumber, sourceURL); + printSourceURLAndLine(lastCaller.sourceURL().prettyURL(), 0); + printMessageSourceAndLevelPrefix(JSMessageSource, level); - printToStandardOut(source, level, message, sourceURL, lineNumber); + for (unsigned i = 0; i < lastCaller.argumentCount(); ++i) { + String argAsString; + if (lastCaller.argumentAt(i).getString(argAsString)) + printf(" %s", argAsString.utf8().data()); + } + printf("\n"); } -void Console::debug(ExecState* exec, const ArgList& args) +void Console::debug(ScriptCallStack* callStack) { // In Firebug, console.debug has the same behavior as console.log. So we'll do the same. - log(exec, args); + log(callStack); } -void Console::error(ExecState* exec, const ArgList& args) +void Console::error(ScriptCallStack* callStack) { - if (args.isEmpty()) - return; - - Page* page = this->page(); - if (!page) - return; - - String message = args.at(exec, 0)->toString(exec); - - KURL url; - unsigned lineNumber; - retrieveLastCaller(exec, url, lineNumber); - - page->chrome()->client()->addMessageToConsole(message, lineNumber, url.prettyURL()); - page->inspectorController()->addMessageToConsole(JSMessageSource, ErrorMessageLevel, exec, args, lineNumber, url.string()); - - printToStandardOut(ErrorMessageLevel, exec, args, url); + addMessage(ErrorMessageLevel, callStack); } -void Console::info(ExecState* exec, const ArgList& args) +void Console::info(ScriptCallStack* callStack) { - if (args.isEmpty()) - return; - - Page* page = this->page(); - if (!page) - return; - - String message = args.at(exec, 0)->toString(exec); - - KURL url; - unsigned lineNumber; - retrieveLastCaller(exec, url, lineNumber); - - page->chrome()->client()->addMessageToConsole(message, lineNumber, url.prettyURL()); - page->inspectorController()->addMessageToConsole(JSMessageSource, LogMessageLevel, exec, args, lineNumber, url.string()); - - printToStandardOut(LogMessageLevel, exec, args, url); + log(callStack); } -void Console::log(ExecState* exec, const ArgList& args) +void Console::log(ScriptCallStack* callStack) { - if (args.isEmpty()) - return; - - Page* page = this->page(); - if (!page) - return; - - String message = args.at(exec, 0)->toString(exec); - - KURL url; - unsigned lineNumber; - retrieveLastCaller(exec, url, lineNumber); - - page->chrome()->client()->addMessageToConsole(message, lineNumber, url.prettyURL()); - page->inspectorController()->addMessageToConsole(JSMessageSource, LogMessageLevel, exec, args, lineNumber, url.string()); - - printToStandardOut(LogMessageLevel, exec, args, url); + addMessage(LogMessageLevel, callStack); } -void Console::dir(ExecState* exec, const ArgList& args) +void Console::dir(ScriptCallStack* callStack) { - if (args.isEmpty()) - return; - - Page* page = this->page(); - if (!page) - return; - - page->inspectorController()->addMessageToConsole(JSMessageSource, ObjectMessageLevel, exec, args, 0, String()); + addMessage(ObjectMessageLevel, callStack); } -void Console::dirxml(ExecState* exec, const ArgList& args) +void Console::dirxml(ScriptCallStack* callStack) { - if (args.isEmpty()) - return; - - Page* page = this->page(); - if (!page) - return; - - page->inspectorController()->addMessageToConsole(JSMessageSource, NodeMessageLevel, exec, args, 0, String()); + addMessage(NodeMessageLevel, callStack); } -void Console::trace(ExecState* exec) +void Console::trace(ScriptCallStack* callStack) { - Page* page = this->page(); - if (!page) - return; + addMessage(TraceMessageLevel, callStack, true); - int signedLineNumber; - intptr_t sourceID; - UString urlString; - JSValue* func; - - exec->machine()->retrieveLastCaller(exec, signedLineNumber, sourceID, urlString, func); + if (!shouldPrintExceptions()) + return; - ArgList args; - while (!func->isNull()) { - args.append(func); - func = exec->machine()->retrieveCaller(exec, asInternalFunction(func)); + printf("Stack Trace\n"); + for (unsigned i = 0; i < callStack->size(); ++i) { + String functionName = String(callStack->at(i).functionName()); + printf("\t%s\n", functionName.utf8().data()); } - - page->inspectorController()->addMessageToConsole(JSMessageSource, TraceMessageLevel, exec, args, 0, String()); } -void Console::assertCondition(bool condition, ExecState* exec, const ArgList& args) +void Console::assertCondition(bool condition, ScriptCallStack* callStack) { if (condition) return; - Page* page = this->page(); - if (!page) - return; - - KURL url; - unsigned lineNumber; - retrieveLastCaller(exec, url, lineNumber); - // FIXME: <https://bugs.webkit.org/show_bug.cgi?id=19135> It would be nice to prefix assertion failures with a message like "Assertion failed: ". - // FIXME: <https://bugs.webkit.org/show_bug.cgi?id=19136> We should print a message even when args.isEmpty() is true. - - page->inspectorController()->addMessageToConsole(JSMessageSource, ErrorMessageLevel, exec, args, lineNumber, url.string()); - - printToStandardOut(ErrorMessageLevel, exec, args, url); + addMessage(ErrorMessageLevel, callStack, true); } -void Console::count(ExecState* exec, const ArgList& args) +void Console::count(ScriptCallStack* callStack) { Page* page = this->page(); if (!page) return; - KURL url; - unsigned lineNumber; - retrieveLastCaller(exec, url, lineNumber); + const ScriptCallFrame& lastCaller = callStack->at(0); + // Follow Firebug's behavior of counting with null and undefined title in + // the same bucket as no argument + String title; + getFirstArgumentAsString(lastCaller, title); - UString title; - if (args.size() >= 1) - title = valueToStringWithUndefinedOrNullCheck(exec, args.at(exec, 0)); - - page->inspectorController()->count(title, lineNumber, url.string()); + page->inspectorController()->count(title, lastCaller.lineNumber(), lastCaller.sourceURL().string()); } -void Console::profile(ExecState* exec, const ArgList& args) +#if USE(JSC) + +void Console::profile(const JSC::UString& title, ScriptCallStack* callStack) { Page* page = this->page(); if (!page) return; + if (title.isNull()) + return; + // FIXME: log a console message when profiling is disabled. if (!page->inspectorController()->profilerEnabled()) return; - UString title = args.at(exec, 0)->toString(exec); - Profiler::profiler()->startProfiling(exec, title); + JSC::Profiler::profiler()->startProfiling(callStack->state(), title); } -void Console::profileEnd(ExecState* exec, const ArgList& args) +void Console::profileEnd(const JSC::UString& title, ScriptCallStack* callStack) { Page* page = this->page(); if (!page) @@ -346,69 +275,62 @@ void Console::profileEnd(ExecState* exec, const ArgList& args) if (!page->inspectorController()->profilerEnabled()) return; - UString title; - if (args.size() >= 1) - title = valueToStringWithUndefinedOrNullCheck(exec, args.at(exec, 0)); - - RefPtr<Profile> profile = Profiler::profiler()->stopProfiling(exec, title); + RefPtr<JSC::Profile> profile = JSC::Profiler::profiler()->stopProfiling(callStack->state(), title); if (!profile) return; m_profiles.append(profile); if (Page* page = this->page()) { - KURL url; - unsigned lineNumber; - retrieveLastCaller(exec, url, lineNumber); - - page->inspectorController()->addProfile(profile, lineNumber, url); + const ScriptCallFrame& lastCaller = callStack->at(0); + page->inspectorController()->addProfile(profile, lastCaller.lineNumber(), lastCaller.sourceURL()); } } -void Console::time(const UString& title) -{ - if (title.isNull()) - return; +#endif +void Console::time(const String& title) +{ Page* page = this->page(); if (!page) return; + + // Follow Firebug's behavior of requiring a title that is not null or + // undefined for timing functions + if (title.isNull()) + return; page->inspectorController()->startTiming(title); } -void Console::timeEnd(ExecState* exec, const ArgList& args) +void Console::timeEnd(const String& title, ScriptCallStack* callStack) { - UString title; - if (args.size() >= 1) - title = valueToStringWithUndefinedOrNullCheck(exec, args.at(exec, 0)); - if (title.isNull()) - return; - Page* page = this->page(); if (!page) return; + // Follow Firebug's behavior of requiring a title that is not null or + // undefined for timing functions + if (title.isNull()) + return; + double elapsed; if (!page->inspectorController()->stopTiming(title, elapsed)) return; - String message = String(title) + String::format(": %.0fms", elapsed); + String message = title + String::format(": %.0fms", elapsed); - KURL url; - unsigned lineNumber; - retrieveLastCaller(exec, url, lineNumber); - - page->inspectorController()->addMessageToConsole(JSMessageSource, LogMessageLevel, message, lineNumber, url.string()); + const ScriptCallFrame& lastCaller = callStack->at(0); + page->inspectorController()->addMessageToConsole(JSMessageSource, LogMessageLevel, message, lastCaller.lineNumber(), lastCaller.sourceURL().string()); } -void Console::group(ExecState* exec, const ArgList& arguments) +void Console::group(ScriptCallStack* callStack) { Page* page = this->page(); if (!page) return; - page->inspectorController()->startGroup(JSMessageSource, exec, arguments, 0, String()); + page->inspectorController()->startGroup(JSMessageSource, callStack); } void Console::groupEnd() @@ -420,43 +342,9 @@ void Console::groupEnd() page->inspectorController()->endGroup(JSMessageSource, 0, String()); } -void Console::warn(ExecState* exec, const ArgList& args) -{ - if (args.isEmpty()) - return; - - Page* page = this->page(); - if (!page) - return; - - String message = args.at(exec, 0)->toString(exec); - - KURL url; - unsigned lineNumber; - retrieveLastCaller(exec, url, lineNumber); - - page->chrome()->client()->addMessageToConsole(message, lineNumber, url.prettyURL()); - page->inspectorController()->addMessageToConsole(JSMessageSource, WarningMessageLevel, exec, args, lineNumber, url.string()); - - printToStandardOut(WarningMessageLevel, exec, args, url); -} - -void Console::reportException(ExecState* exec, JSValue* exception) -{ - UString errorMessage = exception->toString(exec); - JSObject* exceptionObject = exception->toObject(exec); - int lineNumber = exceptionObject->get(exec, Identifier(exec, "line"))->toInt32(exec); - UString exceptionSourceURL = exceptionObject->get(exec, Identifier(exec, "sourceURL"))->toString(exec); - addMessage(JSMessageSource, ErrorMessageLevel, errorMessage, lineNumber, exceptionSourceURL); - if (exec->hadException()) - exec->clearException(); -} - -void Console::reportCurrentException(ExecState* exec) +void Console::warn(ScriptCallStack* callStack) { - JSValue* exception = exec->exception(); - exec->clearException(); - reportException(exec, exception); + addMessage(WarningMessageLevel, callStack); } static bool printExceptions = false; diff --git a/WebCore/page/Console.h b/WebCore/page/Console.h index 8f33e96..7301fc9 100644 --- a/WebCore/page/Console.h +++ b/WebCore/page/Console.h @@ -30,25 +30,29 @@ #define Console_h #include "PlatformString.h" + +#if USE(JSC) #include <profiler/Profile.h> +#endif + #include <wtf/RefCounted.h> #include <wtf/PassRefPtr.h> -namespace JSC { - class ExecState; - class ArgList; -} - namespace WebCore { +#if USE(JSC) typedef Vector<RefPtr<JSC::Profile> > ProfilesArray; +#endif class Frame; class Page; class String; + class ScriptCallStack; + // Keep in sync with inspector/front-end/Console.js enum MessageSource { HTMLMessageSource, + WMLMessageSource, XMLMessageSource, JSMessageSource, CSSMessageSource, @@ -75,40 +79,42 @@ namespace WebCore { void addMessage(MessageSource, MessageLevel, const String& message, unsigned lineNumber, const String& sourceURL); + void debug(ScriptCallStack*); + void error(ScriptCallStack*); + void info(ScriptCallStack*); + void log(ScriptCallStack*); + void warn(ScriptCallStack*); + void dir(ScriptCallStack*); + void dirxml(ScriptCallStack*); + void trace(ScriptCallStack*); + void assertCondition(bool condition, ScriptCallStack*); + void count(ScriptCallStack*); #if USE(JSC) - void debug(JSC::ExecState*, const JSC::ArgList&); - void error(JSC::ExecState*, const JSC::ArgList&); - void info(JSC::ExecState*, const JSC::ArgList&); - void log(JSC::ExecState*, const JSC::ArgList&); - void warn(JSC::ExecState*, const JSC::ArgList&); - void dir(JSC::ExecState*, const JSC::ArgList&); - void dirxml(JSC::ExecState*, const JSC::ArgList& arguments); - void trace(JSC::ExecState*); - void assertCondition(bool condition, JSC::ExecState*, const JSC::ArgList&); - void count(JSC::ExecState*, const JSC::ArgList&); - void profile(JSC::ExecState*, const JSC::ArgList&); - void profileEnd(JSC::ExecState*, const JSC::ArgList&); - void time(const JSC::UString& title); - void timeEnd(JSC::ExecState*, const JSC::ArgList&); - void group(JSC::ExecState*, const JSC::ArgList&); + void profile(const JSC::UString&, ScriptCallStack*); + void profileEnd(const JSC::UString&, ScriptCallStack*); +#endif + void time(const String&); + void timeEnd(const String&, ScriptCallStack*); + void group(ScriptCallStack*); void groupEnd(); - void reportException(JSC::ExecState*, JSC::JSValue*); - void reportCurrentException(JSC::ExecState*); - static bool shouldPrintExceptions(); static void setShouldPrintExceptions(bool); +#if USE(JSC) const ProfilesArray& profiles() const { return m_profiles; } #endif private: inline Page* page() const; + void addMessage(MessageLevel, ScriptCallStack*, bool acceptNoArguments = false); Console(Frame*); Frame* m_frame; +#if USE(JSC) ProfilesArray m_profiles; +#endif }; } // namespace WebCore diff --git a/WebCore/page/Console.idl b/WebCore/page/Console.idl index 9075963..fb7688d 100644 --- a/WebCore/page/Console.idl +++ b/WebCore/page/Console.idl @@ -29,24 +29,30 @@ module window { interface Console { - readonly attribute [CustomGetter] Array profiles; + +#if !defined(V8_BINDING) + readonly attribute [CustomGetter] Array profiles; +#endif - [Custom] void debug(); - [Custom] void error(); - [Custom] void info(); - [Custom] void log(); - [Custom] void warn(); - [Custom] void dir(); - [Custom] void dirxml(); - [Custom] void trace(); - [Custom, ImplementationFunction=assertCondition] void assert(in boolean condition); - [Custom] void count(); + [CustomArgumentHandling] void debug(); + [CustomArgumentHandling] void error(); + [CustomArgumentHandling] void info(); + [CustomArgumentHandling] void log(); + [CustomArgumentHandling] void warn(); + [CustomArgumentHandling] void dir(); + [CustomArgumentHandling] void dirxml(); + [CustomArgumentHandling] void trace(); + [CustomArgumentHandling, ImplementationFunction=assertCondition] void assert(in boolean condition); + [CustomArgumentHandling] void count(); + +#if !defined(V8_BINDING) + [CustomArgumentHandling] void profile(in [ConvertUndefinedOrNullToNullString] DOMString title); + [CustomArgumentHandling] void profileEnd(in [ConvertUndefinedOrNullToNullString] DOMString title); +#endif - [Custom] void profile(in DOMString title); - [Custom] void profileEnd(); void time(in [ConvertUndefinedOrNullToNullString] DOMString title); - [Custom] void timeEnd(); - [Custom] void group(); + [CustomArgumentHandling] void timeEnd(in [ConvertUndefinedOrNullToNullString] DOMString title); + [CustomArgumentHandling] void group(); void groupEnd(); }; diff --git a/WebCore/page/ContextMenuController.cpp b/WebCore/page/ContextMenuController.cpp index 813f8e2..47a0663 100644 --- a/WebCore/page/ContextMenuController.cpp +++ b/WebCore/page/ContextMenuController.cpp @@ -86,9 +86,13 @@ void ContextMenuController::handleContextMenuEvent(Event* event) IntPoint point = IntPoint(mouseEvent->pageX(), mouseEvent->pageY()); HitTestResult result(point); - if (Frame* frame = event->target()->toNode()->document()->frame()) + if (Frame* frame = event->target()->toNode()->document()->frame()) { + float zoomFactor = frame->pageZoomFactor(); + point.setX(static_cast<int>(point.x() * zoomFactor)); + point.setY(static_cast<int>(point.y() * zoomFactor)); result = frame->eventHandler()->hitTestResultAtPoint(point, false); - + } + if (!result.innerNonSharedNode()) return; @@ -215,7 +219,7 @@ void ContextMenuController::contextMenuItemSelected(ContextMenuItem* item) case ContextMenuItemTagOpenLink: if (Frame* targetFrame = result.targetFrame()) targetFrame->loader()->loadFrameRequestWithFormAndValues(FrameLoadRequest(ResourceRequest(result.absoluteLinkURL(), - frame->loader()->outgoingReferrer())), false, 0, 0, HashMap<String, String>()); + frame->loader()->outgoingReferrer())), false, false, 0, 0, HashMap<String, String>()); else openNewWindow(result.absoluteLinkURL(), frame); break; @@ -255,6 +259,15 @@ void ContextMenuController::contextMenuItemSelected(ContextMenuItem* item) case ContextMenuItemTagRightToLeft: frame->editor()->setBaseWritingDirection(RightToLeftWritingDirection); break; + case ContextMenuItemTagTextDirectionDefault: + frame->editor()->command("MakeTextWritingDirectionNatural").execute(); + break; + case ContextMenuItemTagTextDirectionLeftToRight: + frame->editor()->command("MakeTextWritingDirectionLeftToRight").execute(); + break; + case ContextMenuItemTagTextDirectionRightToLeft: + frame->editor()->command("MakeTextWritingDirectionRightToLeft").execute(); + break; #if PLATFORM(MAC) case ContextMenuItemTagSearchInSpotlight: m_client->searchWithSpotlight(); diff --git a/WebCore/page/DOMTimer.cpp b/WebCore/page/DOMTimer.cpp new file mode 100644 index 0000000..911da71 --- /dev/null +++ b/WebCore/page/DOMTimer.cpp @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "config.h" +#include "DOMTimer.h" + +#include "Document.h" +#include "ScheduledAction.h" +#include "ScriptExecutionContext.h" +#include <wtf/HashSet.h> +#include <wtf/StdLibExtras.h> + +using namespace std; + +namespace WebCore { + +static const int maxTimerNestingLevel = 5; +static const double oneMillisecond = 0.001; +static const double minTimerInterval = 0.010; // 10 milliseconds + +static int timerNestingLevel = 0; + +DOMTimer::DOMTimer(ScriptExecutionContext* context, ScheduledAction* action, int timeout, bool singleShot) + : ActiveDOMObject(context, this) + , m_action(action) + , m_nextFireInterval(0) + , m_repeatInterval(0) +{ + static int lastUsedTimeoutId = 0; + ++lastUsedTimeoutId; + // Avoid wraparound going negative on us. + if (lastUsedTimeoutId <= 0) + lastUsedTimeoutId = 1; + m_timeoutId = lastUsedTimeoutId; + + 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); + + 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 (singleShot) + startOneShot(intervalMilliseconds); + else + startRepeating(intervalMilliseconds); +} + +DOMTimer::~DOMTimer() +{ + if (scriptExecutionContext()) { + ASSERT(scriptExecutionContext()->isDocument()); + static_cast<Document*>(scriptExecutionContext())->removeTimeout(m_timeoutId); + } +} + +int DOMTimer::install(ScriptExecutionContext* context, ScheduledAction* action, int timeout, bool singleShot) +{ + // DOMTimer constructor links the new timer into a list of ActiveDOMObjects held by the 'context'. + // The timer is deleted when context is deleted (DOMTimer::contextDestroyed) or explicitly via DOMTimer::removeById(), + // or if it is a one-time timer and it has fired (DOMTimer::fired). + DOMTimer* timer = new DOMTimer(context, action, timeout, singleShot); + return timer->m_timeoutId; +} + +void DOMTimer::removeById(ScriptExecutionContext* context, int timeoutId) +{ + // timeout IDs have to be positive, and 0 and -1 are unsafe to + // even look up since they are the empty and deleted value + // respectively + if (timeoutId <= 0) + return; + ASSERT(context && context->isDocument()); + delete static_cast<Document*>(context)->findTimeout(timeoutId); +} + +void DOMTimer::fired() +{ + ScriptExecutionContext* context = scriptExecutionContext(); + timerNestingLevel = m_nestingLevel; + + // Simple case for non-one-shot timers. + if (isActive()) { + if (repeatInterval() && repeatInterval() < minTimerInterval) { + m_nestingLevel++; + if (m_nestingLevel >= maxTimerNestingLevel) + augmentRepeatInterval(minTimerInterval - repeatInterval()); + } + + // No access to member variables after this point, it can delete the timer. + m_action->execute(context); + return; + } + + // Delete timer before executing the action for one-shot timers. + ScheduledAction* action = m_action.release(); + + // No access to member variables after this point. + delete this; + + action->execute(context); + delete action; + timerNestingLevel = 0; +} + +bool DOMTimer::hasPendingActivity() const +{ + return isActive(); +} + +void DOMTimer::contextDestroyed() +{ + ActiveDOMObject::contextDestroyed(); + delete this; +} + +void DOMTimer::stop() +{ + TimerBase::stop(); + // Need to release JS objects potentially protected by ScheduledAction + // because they can form circular references back to the ScriptExecutionContext + // which will cause a memory leak. + m_action.clear(); +} + +void DOMTimer::suspend() +{ + ASSERT(m_nextFireInterval == 0 && m_repeatInterval == 0); + m_nextFireInterval = nextFireInterval(); + m_repeatInterval = repeatInterval(); + TimerBase::stop(); +} + +void DOMTimer::resume() +{ + start(m_nextFireInterval, m_repeatInterval); + m_nextFireInterval = 0; + m_repeatInterval = 0; +} + + +bool DOMTimer::canSuspend() const +{ + return true; +} + +} // namespace WebCore diff --git a/WebCore/page/DOMTimer.h b/WebCore/page/DOMTimer.h new file mode 100644 index 0000000..200b9b1 --- /dev/null +++ b/WebCore/page/DOMTimer.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef DOMTimer_h +#define DOMTimer_h + +#include "ActiveDOMObject.h" +#include "Timer.h" +#include <wtf/OwnPtr.h> + +namespace WebCore { + +class ScheduledAction; + +class DOMTimer : public TimerBase, public ActiveDOMObject { +public: + virtual ~DOMTimer(); + // Creates a new timer owned by specified ScriptExecutionContext, starts it + // and returns its Id. + static int install(ScriptExecutionContext*, ScheduledAction*, int timeout, bool singleShot); + static void removeById(ScriptExecutionContext*, int timeoutId); + + // ActiveDOMObject + virtual bool hasPendingActivity() const; + virtual void contextDestroyed(); + virtual void stop(); + virtual bool canSuspend() const; + virtual void suspend(); + virtual void resume(); + +private: + DOMTimer(ScriptExecutionContext*, ScheduledAction*, int timeout, bool singleShot); + virtual void fired(); + + int m_timeoutId; + int m_nestingLevel; + OwnPtr<ScheduledAction> m_action; + double m_nextFireInterval; + double m_repeatInterval; +}; + +} // namespace WebCore + +#endif // DOMTimer_h + diff --git a/WebCore/page/DOMWindow.cpp b/WebCore/page/DOMWindow.cpp index 4ab69ca..70ee79e 100644 --- a/WebCore/page/DOMWindow.cpp +++ b/WebCore/page/DOMWindow.cpp @@ -55,6 +55,7 @@ #include "PlatformString.h" #include "Screen.h" #include "SecurityOrigin.h" +#include "Settings.h" #include <algorithm> #include <wtf/MathExtras.h> @@ -339,9 +340,13 @@ Storage* DOMWindow::localStorage() const Page* page = document->page(); if (!page) return 0; - + + Settings* settings = document->settings(); + if (!settings || !settings->localStorageEnabled()) + return 0; + LocalStorage* localStorage = page->group().localStorage(); - RefPtr<StorageArea> storageArea = localStorage ? localStorage->storageArea(m_frame, document->securityOrigin()) : 0; + RefPtr<StorageArea> storageArea = localStorage ? localStorage->storageArea(document->securityOrigin()) : 0; if (storageArea) m_localStorage = Storage::create(m_frame, storageArea.release()); @@ -358,7 +363,7 @@ void DOMWindow::postMessage(const String& message, MessagePort* messagePort, con // to generate the SYNTAX_ERR exception correctly. RefPtr<SecurityOrigin> target; if (targetOrigin != "*") { - target = SecurityOrigin::create(KURL(targetOrigin)); + target = SecurityOrigin::createFromString(targetOrigin); if (target->isEmpty()) { ec = SYNTAX_ERR; return; @@ -367,7 +372,7 @@ void DOMWindow::postMessage(const String& message, MessagePort* messagePort, con RefPtr<MessagePort> newMessagePort; if (messagePort) - newMessagePort = messagePort->clone(document(), ec); + newMessagePort = messagePort->clone(ec); if (ec) return; @@ -400,6 +405,11 @@ void DOMWindow::postMessageTimerFired(PostMessageTimer* t) } } + MessagePort* messagePort = timer->event()->messagePort(); + ASSERT(!messagePort || !messagePort->scriptExecutionContext()); + if (messagePort) + messagePort->attachToContext(document()); + document()->dispatchWindowEvent(timer->event()); } @@ -520,7 +530,7 @@ String DOMWindow::prompt(const String& message, const String& defaultValue) return String(); } -bool DOMWindow::find(const String& string, bool caseSensitive, bool backwards, bool wrap, bool wholeWord, bool searchInFrames, bool showDialog) const +bool DOMWindow::find(const String& string, bool caseSensitive, bool backwards, bool wrap, bool /*wholeWord*/, bool /*searchInFrames*/, bool /*showDialog*/) const { if (!m_frame) return false; @@ -808,6 +818,10 @@ PassRefPtr<Database> DOMWindow::openDatabase(const String& name, const String& v if (!doc) return 0; + Settings* settings = m_frame->settings(); + if (!settings || !settings->databasesEnabled()) + return 0; + return Database::openDatabase(doc, name, version, displayName, estimatedSize, ec); } #endif diff --git a/WebCore/page/DOMWindow.idl b/WebCore/page/DOMWindow.idl index ce519b5..78c780f 100644 --- a/WebCore/page/DOMWindow.idl +++ b/WebCore/page/DOMWindow.idl @@ -38,6 +38,7 @@ module window { CustomMarkFunction, CustomNativeConverter, CustomPutFunction, + ExtendsDOMGlobalObject, GenerateNativeConverter, LegacyParent=JSDOMWindowBase ] DOMWindow { @@ -226,6 +227,7 @@ module window { attribute CSSValueConstructor CSSValue; attribute CSSPrimitiveValueConstructor CSSPrimitiveValue; attribute CSSValueListConstructor CSSValueList; + attribute WebKitCSSTransformValueConstructor WebKitCSSTransformValue; attribute CSSRuleConstructor CSSRule; attribute CSSCharsetRuleConstructor CSSCharsetRule; @@ -247,7 +249,7 @@ module window { // FIXME: Implement the commented-out global constructors for interfaces listed in DOM Level 3 Core specification. attribute DOMCoreExceptionConstructor DOMException; -// attribute DOMStringListConstructor DOMStringList; + attribute DOMStringListConstructor DOMStringList; // attribute NameListConstructor NameList; // attribute DOMImplementationListConstructor DOMImplementationList; // attribute DOMImplementationSourceConstructor DOMImplementationSource; @@ -348,6 +350,8 @@ module window { attribute ProgressEventConstructor ProgressEvent; attribute TextEventConstructor TextEvent; attribute UIEventConstructor UIEvent; + attribute WebKitAnimationEventConstructor WebKitAnimationEvent; + attribute WebKitTransitionEventConstructor WebKitTransitionEvent; attribute WheelEventConstructor WheelEvent; attribute MessageEventConstructor MessageEvent; attribute EventExceptionConstructor EventException; @@ -355,7 +359,12 @@ module window { attribute TouchEventConstructor TouchEvent; #endif + attribute WebKitCSSKeyframeRuleConstructor WebKitCSSKeyframeRule; + attribute WebKitCSSKeyframesRuleConstructor WebKitCSSKeyframesRule; + +#if ENABLE_CHANNEL_MESSAGING attribute MessagePortConstructor MessagePort; +#endif attribute ClipboardConstructor Clipboard; @@ -376,6 +385,12 @@ module window { attribute XMLHttpRequestUploadConstructor XMLHttpRequestUpload; attribute XMLHttpRequestExceptionConstructor XMLHttpRequestException; + attribute PluginConstructor Plugin; + attribute PluginArrayConstructor PluginArray; + + attribute MimeTypeConstructor MimeType; + attribute MimeTypeArrayConstructor MimeTypeArray; + #if ENABLE_DOM_STORAGE attribute StorageConstructor Storage; attribute StorageEventConstructor StorageEvent; diff --git a/WebCore/page/DragController.cpp b/WebCore/page/DragController.cpp index 268397e..9911f34 100644 --- a/WebCore/page/DragController.cpp +++ b/WebCore/page/DragController.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007, 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 @@ -57,10 +57,10 @@ #include "ResourceRequest.h" #include "SelectionController.h" #include "Settings.h" -#include "SystemTime.h" #include "Text.h" #include "htmlediting.h" #include "markup.h" +#include <wtf/CurrentTime.h> #include <wtf/RefPtr.h> namespace WebCore { @@ -126,11 +126,9 @@ static PassRefPtr<DocumentFragment> documentFragmentFromDragData(DragData* dragD return 0; } -bool DragController::dragIsMove(SelectionController* selection, DragData* dragData) +bool DragController::dragIsMove(SelectionController* selection) { - return m_document == m_dragInitiator - && selection->isContentEditable() - && !isCopyKeyDown(); + return m_document == m_dragInitiator && selection->isContentEditable() && !isCopyKeyDown(); } void DragController::cancelDrag() @@ -191,7 +189,7 @@ bool DragController::performDrag(DragData* dragData) return true; } - if ((m_dragDestinationAction & DragDestinationActionEdit) && concludeDrag(dragData, m_dragDestinationAction)) { + if ((m_dragDestinationAction & DragDestinationActionEdit) && concludeEditDrag(dragData)) { m_document = 0; return true; } @@ -202,7 +200,7 @@ bool DragController::performDrag(DragData* dragData) return false; m_client->willPerformDragDestinationAction(DragDestinationActionLoad, dragData); - m_page->mainFrame()->loader()->load(ResourceRequest(dragData->asURL())); + m_page->mainFrame()->loader()->load(ResourceRequest(dragData->asURL()), false); return true; } @@ -288,7 +286,7 @@ DragOperation DragController::tryDocumentDrag(DragData* dragData, DragDestinatio m_page->dragCaretController()->setSelection(dragCaret); } - return dragIsMove(innerFrame->selection(), dragData) ? DragOperationMove : DragOperationCopy; + return dragIsMove(innerFrame->selection()) ? DragOperationMove : DragOperationCopy; } m_page->dragCaretController()->clear(); @@ -322,11 +320,10 @@ static bool setSelectionToDragCaret(Frame* frame, Selection& dragCaret, RefPtr<R return !frame->selection()->isNone() && frame->selection()->isContentEditable(); } -bool DragController::concludeDrag(DragData* dragData, DragDestinationAction actionMask) +bool DragController::concludeEditDrag(DragData* dragData) { ASSERT(dragData); ASSERT(!m_isHandlingDrag); - ASSERT(actionMask & DragDestinationActionEdit); if (!m_document) return false; @@ -394,7 +391,7 @@ bool DragController::concludeDrag(DragData* dragData, DragDestinationAction acti return false; DocLoader* loader = range->ownerDocument()->docLoader(); loader->setAllowStaleResources(true); - if (dragIsMove(innerFrame->selection(), dragData) || dragCaret.isContentRichlyEditable()) { + if (dragIsMove(innerFrame->selection()) || dragCaret.isContentRichlyEditable()) { bool chosePlainText = false; RefPtr<DocumentFragment> fragment = documentFragmentFromDragData(dragData, range, true, chosePlainText); if (!fragment || !innerFrame->editor()->shouldInsertFragment(fragment, range, EditorInsertActionDropped)) { @@ -403,7 +400,7 @@ bool DragController::concludeDrag(DragData* dragData, DragDestinationAction acti } m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dragData); - if (dragIsMove(innerFrame->selection(), dragData)) { + if (dragIsMove(innerFrame->selection())) { bool smartMove = innerFrame->selectionGranularity() == WordGranularity && innerFrame->editor()->smartInsertDeleteEnabled() && dragData->canSmartReplace(); @@ -579,7 +576,7 @@ static IntPoint dragLocForDHTMLDrag(const IntPoint& mouseDraggedPoint, const Int static IntPoint dragLocForSelectionDrag(Frame* src) { - IntRect draggingRect = enclosingIntRect(src->selectionRect()); + IntRect draggingRect = enclosingIntRect(src->selectionBounds()); int xpos = draggingRect.right(); xpos = draggingRect.x() < xpos ? draggingRect.x() : xpos; int ypos = draggingRect.bottom(); @@ -629,9 +626,12 @@ bool DragController::startDrag(Frame* src, Clipboard* clipboard, DragOperation s Node* node = dragSource.innerNonSharedNode(); - if (!imageURL.isEmpty() && node && node->isElementNode() - && getImage(static_cast<Element*>(node)) + Image* image = getImage(static_cast<Element*>(node)); + if (!imageURL.isEmpty() && node && node->isElementNode() && image && (m_dragSourceAction & DragSourceActionImage)) { + // We shouldn't be starting a drag for an image that can't provide an extension. + // This is an early detection for problems encountered later upon drop. + ASSERT(!image->filenameExtension().isEmpty()); Element* element = static_cast<Element*>(node); if (!clipboard->hasData()) { m_draggingImageURL = imageURL; @@ -698,7 +698,7 @@ bool DragController::startDrag(Frame* src, Clipboard* clipboard, DragOperation s deleteDragImage(dragImage); return startedDrag; } - + void DragController::doImageDrag(Element* element, const IntPoint& dragOrigin, const IntRect& rect, Clipboard* clipboard, Frame* frame, IntPoint& dragImageOffset) { IntPoint mouseDownPoint = dragOrigin; @@ -750,11 +750,7 @@ void DragController::doSystemDrag(DragImageRef image, const IntPoint& dragLoc, c m_client->startDrag(image, viewProtector->windowToContents(frame->view()->contentsToWindow(dragLoc)), viewProtector->windowToContents(frame->view()->contentsToWindow(eventPos)), clipboard, frameProtector.get(), forLink); - // Drag has ended, dragEnded *should* have been called, however it is possible - // for the UIDelegate to take over the drag, and fail to send the appropriate - // drag termination event. As dragEnded just resets drag variables, we just - // call it anyway to be on the safe side - dragEnded(); + cleanupAfterSystemDrag(); } // Manual drag caret manipulation diff --git a/WebCore/page/DragController.h b/WebCore/page/DragController.h index efa8292..3beff5a 100644 --- a/WebCore/page/DragController.h +++ b/WebCore/page/DragController.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007, 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 @@ -29,7 +29,6 @@ #include "DragActions.h" #include "DragImage.h" #include "IntPoint.h" -#include "IntRect.h" #include "KURL.h" namespace WebCore { @@ -41,6 +40,7 @@ namespace WebCore { class Element; class Frame; class Image; + class IntRect; class Node; class Page; class PlatformMouseEvent; @@ -58,8 +58,8 @@ namespace WebCore { DragOperation dragUpdated(DragData*); bool performDrag(DragData*); - //FIXME: It should be possible to remove a number of these accessors once all - //drag logic is in WebCore + // FIXME: It should be possible to remove a number of these accessors once all + // drag logic is in WebCore. void setDidInitiateDrag(bool initiated) { m_didInitiateDrag = initiated; } bool didInitiateDrag() const { return m_didInitiateDrag; } void setIsHandlingDrag(bool handling) { m_isHandlingDrag = handling; } @@ -73,7 +73,7 @@ namespace WebCore { void setDragOffset(const IntPoint& offset) { m_dragOffset = offset; } const IntPoint& dragOffset() const { return m_dragOffset; } DragSourceAction dragSourceAction() const { return m_dragSourceAction; } - + Document* document() const { return m_document; } DragDestinationAction dragDestinationAction() const { return m_dragDestinationAction; } DragSourceAction delegateDragSourceAction(const IntPoint& pagePoint); @@ -91,30 +91,30 @@ namespace WebCore { static const int DragIconRightInset; static const int DragIconBottomInset; static const float DragImageAlpha; + private: bool canProcessDrag(DragData*); - bool concludeDrag(DragData*, DragDestinationAction); + bool concludeEditDrag(DragData*); DragOperation dragEnteredOrUpdated(DragData*); DragOperation operationForLoad(DragData*); DragOperation tryDocumentDrag(DragData*, DragDestinationAction); DragOperation tryDHTMLDrag(DragData*); DragOperation dragOperation(DragData*); void cancelDrag(); - bool dragIsMove(SelectionController*, DragData*); + bool dragIsMove(SelectionController*); bool isCopyKeyDown(); IntRect selectionDraggingRect(Frame*); bool doDrag(Frame* src, Clipboard* clipboard, DragImageRef dragImage, const KURL& linkURL, const KURL& imageURL, Node* node, IntPoint& dragLoc, IntPoint& dragImageOffset); void doImageDrag(Element*, const IntPoint&, const IntRect&, Clipboard*, Frame*, IntPoint&); void doSystemDrag(DragImageRef, const IntPoint&, const IntPoint&, Clipboard*, Frame*, bool forLink); + void cleanupAfterSystemDrag(); + Page* m_page; DragClient* m_client; - //The Document the mouse was last dragged over - Document* m_document; - - //The Document (if any) that initiated the drag - Document* m_dragInitiator; + Document* m_document; // The document the mouse was last dragged over. + Document* m_dragInitiator; // The Document (if any) that initiated the drag. DragDestinationAction m_dragDestinationAction; DragSourceAction m_dragSourceAction; diff --git a/WebCore/page/EditorClient.h b/WebCore/page/EditorClient.h index b36709f..56d0435 100644 --- a/WebCore/page/EditorClient.h +++ b/WebCore/page/EditorClient.h @@ -69,6 +69,7 @@ public: virtual bool shouldDeleteRange(Range*) = 0; virtual bool shouldShowDeleteInterface(HTMLElement*) = 0; virtual bool smartInsertDeleteEnabled() = 0; + virtual bool isSelectTrailingWhitespaceEnabled() = 0; virtual bool isContinuousSpellCheckingEnabled() = 0; virtual void toggleContinuousSpellChecking() = 0; virtual bool isGrammarCheckingEnabled() = 0; diff --git a/WebCore/page/EventHandler.cpp b/WebCore/page/EventHandler.cpp index 3f45b92..32648cc 100644 --- a/WebCore/page/EventHandler.cpp +++ b/WebCore/page/EventHandler.cpp @@ -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. * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) * * Redistribution and use in source and binary forms, with or without @@ -63,6 +63,7 @@ #include "SelectionController.h" #include "Settings.h" #include "TextEvent.h" +#include <wtf/StdLibExtras.h> #if ENABLE(SVG) #include "SVGDocument.h" @@ -106,15 +107,19 @@ static inline void scrollAndAcceptEvent(float delta, ScrollDirection positiveDir { if (!delta) return; + + // Find the nearest enclosing box. + RenderBox* enclosingBox = node->renderer()->enclosingBox(); + if (e.granularity() == ScrollByPageWheelEvent) { - if (node->renderer()->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPage, 1)) + if (enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPage, 1)) e.accept(); return; } float pixelsToScroll = delta > 0 ? delta : -delta; if (e.granularity() == ScrollByLineWheelEvent) pixelsToScroll *= cMouseWheelPixelsPerLineStep; - if (node->renderer()->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPixel, pixelsToScroll)) + if (enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPixel, pixelsToScroll)) e.accept(); } @@ -155,7 +160,7 @@ EventHandler::~EventHandler() EventHandler::EventHandlerDragState& EventHandler::dragState() { - static EventHandlerDragState state; + DEFINE_STATIC_LOCAL(EventHandlerDragState, state, ()); return state; } @@ -199,6 +204,8 @@ void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestRe if (newSelection.isRange()) { m_frame->setSelectionGranularity(WordGranularity); m_beganSelectingText = true; + if (result.event().clickCount() == 2 && m_frame->editor()->isSelectTrailingWhitespaceEnabled()) + newSelection.appendTrailingWhitespace(); } if (m_frame->shouldChangeSelection(newSelection)) @@ -381,8 +388,8 @@ bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& eve swallowEvent = handleMousePressEventSingleClick(event); } - m_mouseDownMayStartAutoscroll = m_mouseDownMayStartSelect || - (m_mousePressNode && m_mousePressNode->renderer() && m_mousePressNode->renderer()->canBeProgramaticallyScrolled(true)); + m_mouseDownMayStartAutoscroll = m_mouseDownMayStartSelect || + (m_mousePressNode && m_mousePressNode->renderBox() && m_mousePressNode->renderBox()->canBeProgramaticallyScrolled(true)); return swallowEvent; } @@ -409,7 +416,7 @@ bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& e // If the selection is contained in a layer that can scroll, that layer should handle the autoscroll // Otherwise, let the bridge handle it so the view can scroll itself. RenderObject* renderer = targetNode->renderer(); - while (renderer && !renderer->canBeProgramaticallyScrolled(false)) { + while (renderer && (!renderer->isBox() || !toRenderBox(renderer)->canBeProgramaticallyScrolled(false))) { if (!renderer->parent() && renderer->node() == renderer->document() && renderer->document()->ownerElement()) renderer = renderer->document()->ownerElement()->renderer(); else @@ -456,7 +463,7 @@ void EventHandler::updateSelectionForMouseDrag() FrameView* view = m_frame->view(); if (!view) return; - RenderObject* renderer = m_frame->contentRenderer(); + RenderView* renderer = m_frame->contentRenderer(); if (!renderer) return; RenderLayer* layer = renderer->layer(); @@ -599,7 +606,7 @@ void EventHandler::handleAutoscroll(RenderObject* renderer) void EventHandler::autoscrollTimerFired(Timer<EventHandler>*) { RenderObject* r = autoscrollRenderer(); - if (!r) { + if (!r || !r->isBox()) { stopAutoscrollTimer(); return; } @@ -609,7 +616,7 @@ void EventHandler::autoscrollTimerFired(Timer<EventHandler>*) stopAutoscrollTimer(); return; } - r->autoscroll(); + toRenderBox(r)->autoscroll(); } else { // we verify that the main frame hasn't received the order to stop the panScroll if (!m_frame->page()->mainFrame()->eventHandler()->panScrollInProgress()) { @@ -618,7 +625,7 @@ void EventHandler::autoscrollTimerFired(Timer<EventHandler>*) } #if ENABLE(PAN_SCROLLING) setPanScrollCursor(); - r->panScroll(m_panScrollStartPos); + toRenderBox(r)->panScroll(m_panScrollStartPos); #endif } } @@ -670,7 +677,7 @@ void EventHandler::updateAutoscrollRenderer() if (Node* nodeAtPoint = hitTest.innerNode()) m_autoscrollRenderer = nodeAtPoint->renderer(); - while (m_autoscrollRenderer && !m_autoscrollRenderer->canBeProgramaticallyScrolled(false)) + while (m_autoscrollRenderer && (!m_autoscrollRenderer->isBox() || !toRenderBox(m_autoscrollRenderer)->canBeProgramaticallyScrolled(false))) m_autoscrollRenderer = m_autoscrollRenderer->parent(); } @@ -703,15 +710,16 @@ HitTestResult EventHandler::hitTestResultAtPoint(const IntPoint& point, bool all Node* n = result.innerNode(); if (!result.isOverWidget() || !n || !n->renderer() || !n->renderer()->isWidget()) break; - Widget* widget = static_cast<RenderWidget*>(n->renderer())->widget(); + RenderWidget* renderWidget = static_cast<RenderWidget*>(n->renderer()); + Widget* widget = renderWidget->widget(); if (!widget || !widget->isFrameView()) break; Frame* frame = static_cast<HTMLFrameElementBase*>(n)->contentFrame(); if (!frame || !frame->contentRenderer()) break; FrameView* view = static_cast<FrameView*>(widget); - IntPoint widgetPoint(result.localPoint().x() + view->scrollX() - n->renderer()->borderLeft() - n->renderer()->paddingLeft(), - result.localPoint().y() + view->scrollY() - n->renderer()->borderTop() - n->renderer()->paddingTop()); + 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); result = widgetHitTestResult; @@ -751,7 +759,7 @@ void EventHandler::stopAutoscrollTimer(bool rendererIsBeingDestroyed) if (autoscrollRenderer()) { if (!rendererIsBeingDestroyed && (m_autoscrollInProgress || m_panScrollInProgress)) - autoscrollRenderer()->stopAutoscroll(); + toRenderBox(autoscrollRenderer())->stopAutoscroll(); #if ENABLE(PAN_SCROLLING) if (m_panScrollInProgress) { m_frame->view()->removePanScrollIcon(); @@ -791,9 +799,9 @@ bool EventHandler::scrollOverflow(ScrollDirection direction, ScrollGranularity g node = m_mousePressNode.get(); if (node) { - RenderObject *r = node->renderer(); + RenderObject* r = node->renderer(); if (r && !r->isListBox()) - return r->scroll(direction, granularity); + return r->enclosingBox()->scroll(direction, granularity); } return false; @@ -1044,7 +1052,7 @@ bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent) if (mouseEvent.button() == MiddleButton && !mev.isOverLink()) { RenderObject* renderer = mev.targetNode()->renderer(); - while (renderer && !renderer->canBeProgramaticallyScrolled(false)) { + while (renderer && (!renderer->isBox() || !toRenderBox(renderer)->canBeProgramaticallyScrolled(false))) { if (!renderer->parent() && renderer->node() == renderer->document() && renderer->document()->ownerElement()) renderer = renderer->document()->ownerElement()->renderer(); else @@ -1524,7 +1532,7 @@ void EventHandler::updateMouseEventTargetNode(Node* targetNode, const PlatformMo } } -bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targetNode, bool cancelable, int clickCount, const PlatformMouseEvent& mouseEvent, bool setUnder) +bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targetNode, bool /*cancelable*/, int clickCount, const PlatformMouseEvent& mouseEvent, bool setUnder) { updateMouseEventTargetNode(targetNode, mouseEvent, setUnder); @@ -1584,12 +1592,14 @@ bool EventHandler::handleWheelEvent(PlatformWheelEvent& e) RenderObject* docRenderer = doc->renderer(); if (!docRenderer) return false; + + RefPtr<FrameView> protector(m_frame->view()); IntPoint vPoint = m_frame->view()->windowToContents(e.pos()); HitTestRequest request(true, false); HitTestResult result(vPoint); - doc->renderer()->layer()->hitTest(request, result); + doc->renderView()->layer()->hitTest(request, result); Node* node = result.innerNode(); if (node) { @@ -1635,8 +1645,10 @@ bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event) IntPoint viewportPos = v->windowToContents(event.pos()); MouseEventWithHitTestResults mev = doc->prepareMouseEvent(HitTestRequest(false, true), viewportPos, event); - // Context menu events shouldn't select text in GTK+ applications. -#if !PLATFORM(GTK) + // 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. + // See: https://bugs.webkit.org/show_bug.cgi?id=15279 +#if !PLATFORM(GTK) && !PLATFORM(CHROMIUM) if (!m_frame->selection()->contains(viewportPos) && // FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse. // If the selection is non-editable, we do word selection to make it easier to use the contextual menu items @@ -1705,7 +1717,7 @@ void EventHandler::hoverTimerFired(Timer<EventHandler>*) ASSERT(m_frame); ASSERT(m_frame->document()); - if (RenderObject* renderer = m_frame->contentRenderer()) { + if (RenderView* renderer = m_frame->contentRenderer()) { HitTestResult result(m_frame->view()->windowToContents(m_currentMousePosition)); renderer->layer()->hitTest(HitTestRequest(false, false, true), result); m_frame->document()->updateRendering(); @@ -1730,7 +1742,12 @@ static EventTargetNode* eventTargetNodeForDocument(Document* doc) bool EventHandler::handleAccessKey(const PlatformKeyboardEvent& evt) { - if ((evt.modifiers() & s_accessKeyModifiers) != s_accessKeyModifiers) + // FIXME: Ignoring the state of Shift key is what neither IE nor Firefox do. + // IE matches lower and upper case access keys regardless of Shift key state - but if both upper and + // lower case variants are present in a document, the correct element is matched based on Shift key state. + // Firefox only matches an access key if Shift is not pressed, and does that case-insensitively. + ASSERT(!(accessKeyModifiers() & PlatformKeyboardEvent::ShiftKey)); + if ((evt.modifiers() & ~PlatformKeyboardEvent::ShiftKey) != accessKeyModifiers()) return false; String key = evt.unmodifiedText(); Element* elem = m_frame->document()->getElementByAccessKey(key.lower()); @@ -1888,6 +1905,8 @@ void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event) m_frame->editor()->handleKeyboardEvent(event); if (event->defaultHandled()) return; + if (event->charCode() == ' ') + defaultSpaceEventHandler(event); } } @@ -2031,10 +2050,10 @@ bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event) // Check to see if the is a DOM based drag, if it is get the DOM specified drag // image and offset if (dragState().m_dragSrcIsDHTML) { - int srcX, srcY; if (RenderObject* renderer = dragState().m_dragSrc->renderer()) { - renderer->absolutePosition(srcX, srcY); - IntSize delta = m_mouseDownPos - IntPoint(srcX, srcY); + // FIXME: This doesn't work correctly with transforms. + FloatPoint absPos = renderer->localToAbsolute(); + IntSize delta = m_mouseDownPos - roundedIntPoint(absPos); dragState().m_dragClipboard->setDragImageElement(dragState().m_dragSrc.get(), IntPoint() + delta); } else { // The renderer has disappeared, this can happen if the onStartDrag handler has hidden @@ -2083,17 +2102,15 @@ cleanupDrag: return true; } -bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEvent, - bool isLineBreak, bool isBackTab) +bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEvent, bool isLineBreak, bool isBackTab) { - if (!m_frame) - return false; -#ifndef NDEBUG // Platforms should differentiate real commands like selectAll from text input in disguise (like insertNewline), // and avoid dispatching text input events from keydown default handlers. - if (underlyingEvent && underlyingEvent->isKeyboardEvent()) - ASSERT(static_cast<KeyboardEvent*>(underlyingEvent)->type() == eventNames().keypressEvent); -#endif + ASSERT(!underlyingEvent || !underlyingEvent->isKeyboardEvent() || static_cast<KeyboardEvent*>(underlyingEvent)->type() == eventNames().keypressEvent); + + if (!m_frame) + return false; + EventTarget* target; if (underlyingEvent) target = underlyingEvent->target(); @@ -2101,12 +2118,14 @@ bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEve target = eventTargetNodeForDocument(m_frame->document()); if (!target) return false; + RefPtr<TextEvent> event = TextEvent::create(m_frame->domWindow(), text); event->setUnderlyingEvent(underlyingEvent); event->setIsLineBreak(isLineBreak); event->setIsBackTab(isBackTab); ExceptionCode ec; - return target->dispatchEvent(event.release(), ec); + target->dispatchEvent(event, ec); + return event->defaultHandled(); } @@ -2146,6 +2165,36 @@ void EventHandler::defaultTextInputEventHandler(TextEvent* event) } } +#if PLATFORM(QT) || PLATFORM(MAC) + +// These two platforms handle the space event in the platform-specific WebKit code. +// Eventually it would be good to eliminate that and use the code here instead, but +// the Qt version is inside an ifdef and the Mac version has some extra behavior +// so we can't unify everything yet. +void EventHandler::defaultSpaceEventHandler(KeyboardEvent*) +{ +} + +#else + +void EventHandler::defaultSpaceEventHandler(KeyboardEvent* event) +{ + ScrollDirection direction = event->shiftKey() ? ScrollUp : ScrollDown; + if (scrollOverflow(direction, ScrollByPage)) { + event->setDefaultHandled(); + return; + } + + FrameView* view = m_frame->view(); + if (!view) + return; + + if (view->scroll(direction, ScrollByPage)) + event->setDefaultHandled(); +} + +#endif + void EventHandler::defaultTabEventHandler(KeyboardEvent* event) { // We should only advance focus on tabs if no special modifier keys are held down. diff --git a/WebCore/page/EventHandler.h b/WebCore/page/EventHandler.h index 8035494..944bbd3 100644 --- a/WebCore/page/EventHandler.h +++ b/WebCore/page/EventHandler.h @@ -148,7 +148,7 @@ public: bool needsKeyboardEventDisambiguationQuirks() const; - static unsigned accessKeyModifiers() { return s_accessKeyModifiers; } + static unsigned accessKeyModifiers(); bool handleAccessKey(const PlatformKeyboardEvent&); bool keyEvent(const PlatformKeyboardEvent&); void defaultKeyboardEventHandler(KeyboardEvent*); @@ -273,6 +273,7 @@ private: bool passMouseDownEventToWidget(Widget*); bool passWheelEventToWidget(PlatformWheelEvent&, Widget*); + void defaultSpaceEventHandler(KeyboardEvent*); void defaultTabEventHandler(KeyboardEvent*); void allowDHTMLDrag(bool& flagDHTML, bool& flagUA) const; @@ -339,14 +340,12 @@ private: RefPtr<HTMLFrameSetElement> m_frameSetBeingResized; - IntSize m_offsetFromResizeCorner; + IntSize m_offsetFromResizeCorner; // in the coords of m_resizeLayer IntPoint m_currentMousePosition; IntPoint m_mouseDownPos; // in our view's coords double m_mouseDownTimestamp; PlatformMouseEvent m_mouseDown; - - static unsigned s_accessKeyModifiers; unsigned m_pendingFrameUnloadEventCount; unsigned m_pendingFrameBeforeUnloadEventCount; diff --git a/WebCore/page/Frame.cpp b/WebCore/page/Frame.cpp index d474c3b..d4632e5 100644 --- a/WebCore/page/Frame.cpp +++ b/WebCore/page/Frame.cpp @@ -27,7 +27,6 @@ */ #include "config.h" #include "Frame.h" -#include "FramePrivate.h" #include "ApplyStyleCommand.h" #include "BeforeUnloadEvent.h" @@ -42,6 +41,7 @@ #include "EditorClient.h" #include "EventNames.h" #include "FocusController.h" +#include "FloatQuad.h" #include "FrameLoader.h" #include "FrameView.h" #include "GraphicsContext.h" @@ -66,7 +66,6 @@ #include "RenderTheme.h" #include "RenderView.h" #include "Settings.h" -#include "SystemTime.h" #include "TextIterator.h" #include "TextResourceDecoder.h" #include "XMLNames.h" @@ -75,6 +74,7 @@ #include "runtime_root.h" #include "visible_units.h" #include <wtf/RefCountedLeakCounter.h> +#include <wtf/StdLibExtras.h> #if FRAME_LOADS_USER_STYLESHEET #include "UserStyleSheetLoader.h" @@ -91,6 +91,10 @@ #include "WebViewCore.h" #endif +#if ENABLE(WML) +#include "WMLNames.h" +#endif + using namespace std; namespace WebCore { @@ -109,10 +113,33 @@ static inline Frame* parentFromOwnerElement(HTMLFrameOwnerElement* ownerElement) } Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* frameLoaderClient) - : d(new FramePrivate(page, parentFromOwnerElement(ownerElement), this, ownerElement, frameLoaderClient)) + : m_page(page) + , m_treeNode(this, parentFromOwnerElement(ownerElement)) + , m_loader(this, frameLoaderClient) + , m_ownerElement(ownerElement) + , m_script(this) + , m_selectionGranularity(CharacterGranularity) + , m_selectionController(this) + , m_caretBlinkTimer(this, &Frame::caretBlinkTimerFired) + , m_editor(this) + , m_eventHandler(this) + , m_animationController(this) + , m_lifeSupportTimer(this, &Frame::lifeSupportTimerFired) + , m_caretVisible(false) + , m_caretPaint(true) + , m_highlightTextMatches(false) + , m_inViewSourceMode(false) + , m_needsReapplyStyles(false) + , m_isDisconnected(false) + , m_excludeFromTextSearch(false) +#if FRAME_LOADS_USER_STYLESHEET + , m_userStyleSheetLoader(0) +#endif { + Frame* parent = parentFromOwnerElement(ownerElement); + m_zoomFactor = parent ? parent->m_zoomFactor : 1.0f; + AtomicString::init(); - EventNames::init(); HTMLNames::init(); QualifiedName::init(); MediaFeatureNames::init(); @@ -122,6 +149,10 @@ Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* XLinkNames::init(); #endif +#if ENABLE(WML) + WMLNames::init(); +#endif + XMLNames::init(); if (!ownerElement) @@ -146,76 +177,73 @@ Frame::~Frame() // FIXME: We should not be doing all this work inside the destructor - ASSERT(!d->m_lifeSupportTimer.isActive()); + ASSERT(!m_lifeSupportTimer.isActive()); #ifndef NDEBUG frameCounter.decrement(); #endif - if (d->m_script.haveWindowShell()) - d->m_script.windowShell()->disconnectFrame(); + if (m_script.haveWindowShell()) + m_script.windowShell()->disconnectFrame(); disconnectOwnerElement(); - if (d->m_domWindow) - d->m_domWindow->disconnectFrame(); + if (m_domWindow) + m_domWindow->disconnectFrame(); - HashSet<DOMWindow*>::iterator end = d->m_liveFormerWindows.end(); - for (HashSet<DOMWindow*>::iterator it = d->m_liveFormerWindows.begin(); it != end; ++it) + HashSet<DOMWindow*>::iterator end = m_liveFormerWindows.end(); + for (HashSet<DOMWindow*>::iterator it = m_liveFormerWindows.begin(); it != end; ++it) (*it)->disconnectFrame(); - if (d->m_view) { - d->m_view->hide(); - d->m_view->clearFrame(); + if (m_view) { + m_view->hide(); + m_view->clearFrame(); } - ASSERT(!d->m_lifeSupportTimer.isActive()); + ASSERT(!m_lifeSupportTimer.isActive()); #if FRAME_LOADS_USER_STYLESHEET - delete d->m_userStyleSheetLoader; + delete m_userStyleSheetLoader; #endif - - delete d; - d = 0; } void Frame::init() { - d->m_loader.init(); + m_loader.init(); } FrameLoader* Frame::loader() const { - return &d->m_loader; + return &m_loader; } FrameView* Frame::view() const { - return d->m_view.get(); + return m_view.get(); } void Frame::setView(FrameView* view) { #if PLATFORM(ANDROID) - if (!view && d->m_view) { + if (!view && m_view) { // FIXME(for Cary): This is moved from FrameAndroid destructor. Do we // need to call removeFrameGeneration per Frame or per FrameView? - android::WebViewCore::getWebViewCore(d->m_view.get())->removeFrameGeneration(this); + android::WebViewCore::getWebViewCore(m_view.get())->removeFrameGeneration(this); } #endif // Detach the document now, so any onUnload handlers get run - if // we wait until the view is destroyed, then things won't be // hooked up enough for some JavaScript calls to work. - if (!view && d->m_doc && d->m_doc->attached() && !d->m_doc->inPageCache()) { + if (!view && m_doc && m_doc->attached() && !m_doc->inPageCache()) { // FIXME: We don't call willRemove here. Why is that OK? - d->m_doc->detach(); - if (d->m_view) - d->m_view->unscheduleRelayout(); + m_doc->detach(); + if (m_view) + m_view->unscheduleRelayout(); } eventHandler()->clear(); - d->m_view = view; + m_view = view; // Only one form submission is allowed per view of a part. // Since this part may be getting reused as a result of being @@ -225,35 +253,35 @@ void Frame::setView(FrameView* view) ScriptController* Frame::script() { - return &d->m_script; + return &m_script; } Document* Frame::document() const { - return d->m_doc.get(); + return m_doc.get(); } void Frame::setDocument(PassRefPtr<Document> newDoc) { - if (d->m_doc && d->m_doc->attached() && !d->m_doc->inPageCache()) { + if (m_doc && m_doc->attached() && !m_doc->inPageCache()) { // FIXME: We don't call willRemove here. Why is that OK? - d->m_doc->detach(); + m_doc->detach(); } - d->m_doc = newDoc; - if (d->m_doc && selection()->isFocusedAndActive()) - setUseSecureKeyboardEntry(d->m_doc->useSecureKeyboardEntryWhenActive()); + m_doc = newDoc; + if (m_doc && selection()->isFocusedAndActive()) + setUseSecureKeyboardEntry(m_doc->useSecureKeyboardEntryWhenActive()); - if (d->m_doc && !d->m_doc->attached()) - d->m_doc->attach(); + if (m_doc && !m_doc->attached()) + m_doc->attach(); // Update the cached 'document' property, which is now stale. - d->m_script.updateDocument(); + m_script.updateDocument(); } Settings* Frame::settings() const { - return d->m_page ? d->m_page->settings() : 0; + return m_page ? m_page->settings() : 0; } String Frame::selectedText() const @@ -267,15 +295,24 @@ IntRect Frame::firstRectForRange(Range* range) const ExceptionCode ec = 0; ASSERT(range->startContainer(ec)); ASSERT(range->endContainer(ec)); + InlineBox* startInlineBox; int startCaretOffset; range->startPosition().getInlineBoxAndOffset(DOWNSTREAM, startInlineBox, startCaretOffset); - IntRect startCaretRect = range->startContainer(ec)->renderer()->caretRect(startInlineBox, startCaretOffset, &extraWidthToEndOfLine); + + RenderObject* startRenderer = range->startContainer(ec)->renderer(); + IntRect startCaretRect = startRenderer->localCaretRect(startInlineBox, startCaretOffset, &extraWidthToEndOfLine); + if (startCaretRect != IntRect()) + startCaretRect = startRenderer->localToAbsoluteQuad(FloatRect(startCaretRect)).enclosingBoundingBox(); InlineBox* endInlineBox; int endCaretOffset; range->endPosition().getInlineBoxAndOffset(UPSTREAM, endInlineBox, endCaretOffset); - IntRect endCaretRect = range->endContainer(ec)->renderer()->caretRect(endInlineBox, endCaretOffset); + + RenderObject* endRenderer = range->endContainer(ec)->renderer(); + IntRect endCaretRect = endRenderer->localCaretRect(endInlineBox, endCaretOffset); + if (endCaretRect != IntRect()) + endCaretRect = endRenderer->localToAbsoluteQuad(FloatRect(endCaretRect)).enclosingBoundingBox(); if (startCaretRect.y() == endCaretRect.y()) { // start and end are on the same line @@ -294,33 +331,33 @@ IntRect Frame::firstRectForRange(Range* range) const SelectionController* Frame::selection() const { - return &d->m_selectionController; + return &m_selectionController; } Editor* Frame::editor() const { - return &d->m_editor; + return &m_editor; } TextGranularity Frame::selectionGranularity() const { - return d->m_selectionGranularity; + return m_selectionGranularity; } -void Frame::setSelectionGranularity(TextGranularity granularity) const +void Frame::setSelectionGranularity(TextGranularity granularity) { - d->m_selectionGranularity = granularity; + m_selectionGranularity = granularity; } SelectionController* Frame::dragCaretController() const { - return d->m_page->dragCaretController(); + return m_page->dragCaretController(); } AnimationController* Frame::animation() const { - return &d->m_animationController; + return &m_animationController; } static RegularExpression* createRegExpForLabels(const Vector<String>& labels) @@ -328,7 +365,7 @@ static RegularExpression* createRegExpForLabels(const Vector<String>& labels) // REVIEW- version of this call in FrameMac.mm caches based on the NSArray ptrs being // the same across calls. We can't do that. - static RegularExpression wordRegExp = RegularExpression("\\w"); + DEFINE_STATIC_LOCAL(RegularExpression, wordRegExp, ("\\w", TextCaseSensitive)); String pattern("("); unsigned int numLabels = labels.size(); unsigned int i; @@ -338,8 +375,8 @@ static RegularExpression* createRegExpForLabels(const Vector<String>& labels) bool startsWithWordChar = false; bool endsWithWordChar = false; if (label.length() != 0) { - startsWithWordChar = wordRegExp.search(label.substring(0, 1)) >= 0; - endsWithWordChar = wordRegExp.search(label.substring(label.length() - 1, 1)) >= 0; + startsWithWordChar = wordRegExp.match(label.substring(0, 1)) >= 0; + endsWithWordChar = wordRegExp.match(label.substring(label.length() - 1, 1)) >= 0; } if (i != 0) @@ -356,7 +393,7 @@ static RegularExpression* createRegExpForLabels(const Vector<String>& labels) } } pattern.append(")"); - return new RegularExpression(pattern, false); + return new RegularExpression(pattern, TextCaseInsensitive); } String Frame::searchForLabelsAboveCell(RegularExpression* regExp, HTMLTableCellElement* cell) @@ -408,8 +445,7 @@ String Frame::searchForLabelsBeforeElement(const Vector<String>& labels, Element n = n->traversePreviousNode()) { if (n->hasTagName(formTag) - || (n->isHTMLElement() - && static_cast<HTMLElement*>(n)->isGenericFormElement())) + || (n->isHTMLElement() && static_cast<Element*>(n)->isFormControlElement())) { // We hit another form element or the start of the form - bail out break; @@ -448,7 +484,7 @@ String Frame::matchLabelsAgainstElement(const Vector<String>& labels, Element* e return String(); // Make numbers and _'s in field names behave like word boundaries, e.g., "address2" - replace(name, RegularExpression("\\d"), " "); + replace(name, RegularExpression("\\d", TextCaseSensitive), " "); name.replace('_', ' '); OwnPtr<RegularExpression> regExp(createRegExpForLabels(labels)); @@ -459,7 +495,7 @@ String Frame::matchLabelsAgainstElement(const Vector<String>& labels, Element* e int bestLength = -1; int start = 0; do { - pos = regExp->search(name, start); + pos = regExp->match(name, start); if (pos != -1) { length = regExp->matchedLength(); if (length >= bestLength) { @@ -477,7 +513,7 @@ String Frame::matchLabelsAgainstElement(const Vector<String>& labels, Element* e const Selection& Frame::mark() const { - return d->m_mark; + return m_mark; } void Frame::setMark(const Selection& s) @@ -487,7 +523,7 @@ void Frame::setMark(const Selection& s) ASSERT(!s.start().node() || s.start().node()->document() == document()); ASSERT(!s.end().node() || s.end().node()->document() == document()); - d->m_mark = s; + m_mark = s; } void Frame::notifyRendererOfSelectionChange(bool userTriggered) @@ -509,18 +545,18 @@ void Frame::invalidateSelection() void Frame::setCaretVisible(bool flag) { - if (d->m_caretVisible == flag) + if (m_caretVisible == flag) return; clearCaretRectIfNeeded(); - d->m_caretVisible = flag; + m_caretVisible = flag; selectionLayoutChanged(); } void Frame::clearCaretRectIfNeeded() { #if ENABLE(TEXT_CARET) - if (d->m_caretPaint) { - d->m_caretPaint = false; + if (m_caretPaint) { + m_caretPaint = false; selection()->invalidateCaretRect(); } #endif @@ -571,21 +607,23 @@ void Frame::selectionLayoutChanged() bool caretRectChanged = selection()->recomputeCaretRect(); #if ENABLE(TEXT_CARET) - bool shouldBlink = d->m_caretVisible + bool shouldBlink = m_caretVisible && selection()->isCaret() && selection()->isContentEditable(); shouldBlink = false; // If the caret moved, stop the blink timer so we can restart with a // black caret in the new location. if (caretRectChanged || !shouldBlink) - d->m_caretBlinkTimer.stop(); + m_caretBlinkTimer.stop(); // Start blinking with a black caret. Be sure not to restart if we're // already blinking in the right location. - if (shouldBlink && !d->m_caretBlinkTimer.isActive()) { - d->m_caretBlinkTimer.startRepeating(theme()->caretBlinkFrequency()); - if (!d->m_caretPaint) { - d->m_caretPaint = true; + if (shouldBlink && !m_caretBlinkTimer.isActive()) { + if (double blinkInterval = theme()->caretBlinkInterval()) + m_caretBlinkTimer.startRepeating(blinkInterval); + + if (!m_caretPaint) { + m_caretPaint = true; selection()->invalidateCaretRect(); } } @@ -594,14 +632,14 @@ void Frame::selectionLayoutChanged() return; #endif - RenderView* canvas = contentRenderer(); - if (!canvas) + RenderView* view = contentRenderer(); + if (!view) return; Selection selection = this->selection()->selection(); if (!selection.isRange()) - canvas->clearSelection(); + view->clearSelection(); else { // Use the rightmost candidate for the start of the selection, and the leftmost candidate for the end of the selection. // Example: foo <a>bar</a>. Imagine that a line wrap occurs after 'foo', and that 'bar' is selected. If we pass [foo, 3] @@ -619,7 +657,7 @@ void Frame::selectionLayoutChanged() if (startPos.isNotNull() && endPos.isNotNull() && selection.visibleStart() != selection.visibleEnd()) { RenderObject *startRenderer = startPos.node()->renderer(); RenderObject *endRenderer = endPos.node()->renderer(); - canvas->setSelection(startRenderer, startPos.offset(), endRenderer, endPos.offset()); + view->setSelection(startRenderer, startPos.offset(), endRenderer, endPos.offset()); } } } @@ -627,50 +665,50 @@ void Frame::selectionLayoutChanged() void Frame::caretBlinkTimerFired(Timer<Frame>*) { #if ENABLE(TEXT_CARET) - ASSERT(d->m_caretVisible); + ASSERT(m_caretVisible); ASSERT(selection()->isCaret()); - bool caretPaint = d->m_caretPaint; + bool caretPaint = m_caretPaint; if (selection()->isCaretBlinkingSuspended() && caretPaint) return; - d->m_caretPaint = !caretPaint; + m_caretPaint = !caretPaint; selection()->invalidateCaretRect(); #endif } -void Frame::paintCaret(GraphicsContext* p, const IntRect& rect) const +void Frame::paintCaret(GraphicsContext* p, int tx, int ty, const IntRect& clipRect) const { #if ENABLE(TEXT_CARET) - if (d->m_caretPaint && d->m_caretVisible) - selection()->paintCaret(p, rect); + if (m_caretPaint && m_caretVisible) + selection()->paintCaret(p, tx, ty, clipRect); #endif } -void Frame::paintDragCaret(GraphicsContext* p, const IntRect& rect) const +void Frame::paintDragCaret(GraphicsContext* p, int tx, int ty, const IntRect& clipRect) const { #if ENABLE(TEXT_CARET) - SelectionController* dragCaretController = d->m_page->dragCaretController(); + SelectionController* dragCaretController = m_page->dragCaretController(); ASSERT(dragCaretController->selection().isCaret()); if (dragCaretController->selection().start().node()->document()->frame() == this) - dragCaretController->paintCaret(p, rect); + dragCaretController->paintCaret(p, tx, ty, clipRect); #endif } float Frame::zoomFactor() const { - return d->m_zoomFactor; + return m_zoomFactor; } bool Frame::isZoomFactorTextOnly() const { - return d->m_page->settings()->zoomsTextOnly(); + return m_page->settings()->zoomsTextOnly(); } bool Frame::shouldApplyTextZoom() const { - if (d->m_zoomFactor == 1.0f || !isZoomFactorTextOnly()) + if (m_zoomFactor == 1.0f || !isZoomFactorTextOnly()) return false; #if ENABLE(SVG) - if (d->m_doc && d->m_doc->isSVGDocument()) + if (m_doc && m_doc->isSVGDocument()) return false; #endif return true; @@ -678,10 +716,10 @@ bool Frame::shouldApplyTextZoom() const bool Frame::shouldApplyPageZoom() const { - if (d->m_zoomFactor == 1.0f || isZoomFactorTextOnly()) + if (m_zoomFactor == 1.0f || isZoomFactorTextOnly()) return false; #if ENABLE(SVG) - if (d->m_doc && d->m_doc->isSVGDocument()) + if (m_doc && m_doc->isSVGDocument()) return false; #endif return true; @@ -689,44 +727,44 @@ bool Frame::shouldApplyPageZoom() const void Frame::setZoomFactor(float percent, bool isTextOnly) { - if (d->m_zoomFactor == percent && isZoomFactorTextOnly()) + if (m_zoomFactor == percent && isZoomFactorTextOnly() == isTextOnly) return; #if ENABLE(SVG) // SVG doesn't care if the zoom factor is text only. It will always apply a // zoom to the whole SVG. - if (d->m_doc && d->m_doc->isSVGDocument()) { - if (!static_cast<SVGDocument*>(d->m_doc.get())->zoomAndPanEnabled()) + if (m_doc && m_doc->isSVGDocument()) { + if (!static_cast<SVGDocument*>(m_doc.get())->zoomAndPanEnabled()) return; - d->m_zoomFactor = percent; - d->m_page->settings()->setZoomsTextOnly(true); // We do this to avoid doing any scaling of CSS pixels, since the SVG has its own notion of zoom. - if (d->m_doc->renderer()) - d->m_doc->renderer()->repaint(); + m_zoomFactor = percent; + m_page->settings()->setZoomsTextOnly(true); // We do this to avoid doing any scaling of CSS pixels, since the SVG has its own notion of zoom. + if (m_doc->renderer()) + m_doc->renderer()->repaint(); return; } #endif - d->m_zoomFactor = percent; - d->m_page->settings()->setZoomsTextOnly(isTextOnly); + m_zoomFactor = percent; + m_page->settings()->setZoomsTextOnly(isTextOnly); - if (d->m_doc) - d->m_doc->recalcStyle(Node::Force); + if (m_doc) + m_doc->recalcStyle(Node::Force); for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling()) - child->setZoomFactor(d->m_zoomFactor, isTextOnly); + child->setZoomFactor(m_zoomFactor, isTextOnly); - if (d->m_doc && d->m_doc->renderer() && d->m_doc->renderer()->needsLayout() && view()->didFirstLayout()) + if (m_doc && m_doc->renderer() && m_doc->renderer()->needsLayout() && view()->didFirstLayout()) view()->layout(); } void Frame::setPrinting(bool printing, float minPageWidth, float maxPageWidth, bool adjustViewSize) { - if (!d->m_doc) + if (!m_doc) return; - d->m_doc->setPrinting(printing); + m_doc->setPrinting(printing); view()->setMediaType(printing ? "print" : "screen"); - d->m_doc->updateStyleSelector(); + m_doc->updateStyleSelector(); forceLayoutWithPageWidthRange(minPageWidth, maxPageWidth, adjustViewSize); for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling()) @@ -735,58 +773,58 @@ void Frame::setPrinting(bool printing, float minPageWidth, float maxPageWidth, b void Frame::setJSStatusBarText(const String& text) { - d->m_kjsStatusBarText = text; - if (d->m_page) - d->m_page->chrome()->setStatusbarText(this, d->m_kjsStatusBarText); + m_kjsStatusBarText = text; + if (m_page) + m_page->chrome()->setStatusbarText(this, m_kjsStatusBarText); } void Frame::setJSDefaultStatusBarText(const String& text) { - d->m_kjsDefaultStatusBarText = text; - if (d->m_page) - d->m_page->chrome()->setStatusbarText(this, d->m_kjsDefaultStatusBarText); + m_kjsDefaultStatusBarText = text; + if (m_page) + m_page->chrome()->setStatusbarText(this, m_kjsDefaultStatusBarText); } String Frame::jsStatusBarText() const { - return d->m_kjsStatusBarText; + return m_kjsStatusBarText; } String Frame::jsDefaultStatusBarText() const { - return d->m_kjsDefaultStatusBarText; + return m_kjsDefaultStatusBarText; } void Frame::setNeedsReapplyStyles() { - if (d->m_needsReapplyStyles) + if (m_needsReapplyStyles) return; - d->m_needsReapplyStyles = true; + m_needsReapplyStyles = true; - // Invalidate the FrameView so that FrameView::layout will get called, - // which calls reapplyStyles. + // FrameView's "layout" timer includes reapplyStyles, so despite its + // name, it's what we want to call here. if (view()) - view()->invalidate(); + view()->scheduleRelayout(); } bool Frame::needsReapplyStyles() const { - return d->m_needsReapplyStyles; + return m_needsReapplyStyles; } void Frame::reapplyStyles() { - d->m_needsReapplyStyles = false; + m_needsReapplyStyles = false; // FIXME: This call doesn't really make sense in a method called // "reapplyStyles". We should probably eventually move it into its own // method. - if (d->m_doc) - d->m_doc->docLoader()->setAutoLoadImages(d->m_page && d->m_page->settings()->loadsImagesAutomatically()); + if (m_doc) + m_doc->docLoader()->setAutoLoadImages(m_page && m_page->settings()->loadsImagesAutomatically()); #if FRAME_LOADS_USER_STYLESHEET - const KURL userStyleSheetLocation = d->m_page ? d->m_page->settings()->userStyleSheetLocation() : KURL(); + const KURL userStyleSheetLocation = m_page ? m_page->settings()->userStyleSheetLocation() : KURL(); if (!userStyleSheetLocation.isEmpty()) setUserStyleSheetLocation(userStyleSheetLocation); else @@ -797,8 +835,8 @@ 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 (d->m_doc) - d->m_doc->updateStyleSelector(); + if (m_doc) + m_doc->updateStyleSelector(); } bool Frame::shouldChangeSelection(const Selection& newSelection) const @@ -819,11 +857,11 @@ bool Frame::shouldDeleteSelection(const Selection& selection) const bool Frame::isContentEditable() const { - if (d->m_editor.clientIsEditable()) + if (m_editor.clientIsEditable()) return true; - if (!d->m_doc) + if (!m_doc) return false; - return d->m_doc->inDesignMode(); + return m_doc->inDesignMode(); } #if !PLATFORM(MAC) @@ -837,22 +875,22 @@ void Frame::setUseSecureKeyboardEntry(bool) void Frame::updateSecureKeyboardEntryIfActive() { if (selection()->isFocusedAndActive()) - setUseSecureKeyboardEntry(d->m_doc->useSecureKeyboardEntryWhenActive()); + setUseSecureKeyboardEntry(m_doc->useSecureKeyboardEntryWhenActive()); } CSSMutableStyleDeclaration *Frame::typingStyle() const { - return d->m_typingStyle.get(); + return m_typingStyle.get(); } void Frame::setTypingStyle(CSSMutableStyleDeclaration *style) { - d->m_typingStyle = style; + m_typingStyle = style; } void Frame::clearTypingStyle() { - d->m_typingStyle = 0; + m_typingStyle = 0; } void Frame::computeAndSetTypingStyle(CSSStyleDeclaration *style, EditAction editingAction) @@ -869,9 +907,25 @@ void Frame::computeAndSetTypingStyle(CSSStyleDeclaration *style, EditAction edit mutableStyle = typingStyle(); } + RefPtr<CSSValue> unicodeBidi; + RefPtr<CSSValue> direction; + if (editingAction == EditActionSetWritingDirection) { + unicodeBidi = mutableStyle->getPropertyCSSValue(CSSPropertyUnicodeBidi); + direction = mutableStyle->getPropertyCSSValue(CSSPropertyDirection); + } + Node* node = selection()->selection().visibleStart().deepEquivalent().node(); computedStyle(node)->diff(mutableStyle.get()); - + + if (editingAction == EditActionSetWritingDirection && unicodeBidi) { + ASSERT(unicodeBidi->isPrimitiveValue()); + mutableStyle->setProperty(CSSPropertyUnicodeBidi, static_cast<CSSPrimitiveValue*>(unicodeBidi.get())->getIdent()); + if (direction) { + ASSERT(direction->isPrimitiveValue()); + mutableStyle->setProperty(CSSPropertyDirection, static_cast<CSSPrimitiveValue*>(direction.get())->getIdent()); + } + } + // Handle block styles, substracting these from the typing style. RefPtr<CSSMutableStyleDeclaration> blockStyle = mutableStyle->copyBlockProperties(); blockStyle->diff(mutableStyle.get()); @@ -879,7 +933,7 @@ void Frame::computeAndSetTypingStyle(CSSStyleDeclaration *style, EditAction edit applyCommand(ApplyStyleCommand::create(document(), blockStyle.get(), editingAction)); // Set the remaining style as the typing style. - d->m_typingStyle = mutableStyle.release(); + m_typingStyle = mutableStyle.release(); } String Frame::selectionStartStylePropertyValue(int stylePropertyID) const @@ -920,11 +974,11 @@ PassRefPtr<CSSComputedStyleDeclaration> Frame::selectionComputedStyle(Node*& nod RefPtr<Element> styleElement = elem; ExceptionCode ec = 0; - if (d->m_typingStyle) { + if (m_typingStyle) { styleElement = document()->createElementNS(xhtmlNamespaceURI, "span", ec); ASSERT(ec == 0); - styleElement->setAttribute(styleAttr, d->m_typingStyle->cssText().impl(), ec); + styleElement->setAttribute(styleAttr, m_typingStyle->cssText().impl(), ec); ASSERT(ec == 0); styleElement->appendChild(document()->createEditingTextNode(""), ec); @@ -990,10 +1044,10 @@ void Frame::textDidChangeInTextArea(Element* e) void Frame::applyEditingStyleToBodyElement() const { - if (!d->m_doc) + if (!m_doc) return; - RefPtr<NodeList> list = d->m_doc->getElementsByTagName("body"); + RefPtr<NodeList> list = m_doc->getElementsByTagName("body"); unsigned len = list->length(); for (unsigned i = 0; i < len; i++) { applyEditingStyleToElement(static_cast<Element*>(list->item(i))); @@ -1002,10 +1056,10 @@ void Frame::applyEditingStyleToBodyElement() const void Frame::removeEditingStyleFromBodyElement() const { - if (!d->m_doc) + if (!m_doc) return; - RefPtr<NodeList> list = d->m_doc->getElementsByTagName("body"); + RefPtr<NodeList> list = m_doc->getElementsByTagName("body"); unsigned len = list->length(); for (unsigned i = 0; i < len; i++) { removeEditingStyleFromElement(static_cast<Element*>(list->item(i))); @@ -1036,20 +1090,20 @@ void Frame::removeEditingStyleFromElement(Element*) const #ifndef NDEBUG static HashSet<Frame*>& keepAliveSet() { - static HashSet<Frame*> staticKeepAliveSet; + DEFINE_STATIC_LOCAL(HashSet<Frame*>, staticKeepAliveSet, ()); return staticKeepAliveSet; } #endif void Frame::keepAlive() { - if (d->m_lifeSupportTimer.isActive()) + if (m_lifeSupportTimer.isActive()) return; #ifndef NDEBUG keepAliveSet().add(this); #endif ref(); - d->m_lifeSupportTimer.startOneShot(0); + m_lifeSupportTimer.startOneShot(0); } #ifndef NDEBUG @@ -1058,7 +1112,7 @@ void Frame::cancelAllKeepAlive() HashSet<Frame*>::iterator end = keepAliveSet().end(); for (HashSet<Frame*>::iterator it = keepAliveSet().begin(); it != end; ++it) { Frame* frame = *it; - frame->d->m_lifeSupportTimer.stop(); + frame->m_lifeSupportTimer.stop(); frame->deref(); } keepAliveSet().clear(); @@ -1075,11 +1129,11 @@ void Frame::lifeSupportTimerFired(Timer<Frame>*) void Frame::clearDOMWindow() { - if (d->m_domWindow) { - d->m_liveFormerWindows.add(d->m_domWindow.get()); - d->m_domWindow->clear(); + if (m_domWindow) { + m_liveFormerWindows.add(m_domWindow.get()); + m_domWindow->clear(); } - d->m_domWindow = 0; + m_domWindow = 0; } RenderView* Frame::contentRenderer() const @@ -1096,12 +1150,12 @@ RenderView* Frame::contentRenderer() const HTMLFrameOwnerElement* Frame::ownerElement() const { - return d->m_ownerElement; + return m_ownerElement; } RenderPart* Frame::ownerRenderer() const { - HTMLFrameOwnerElement* ownerElement = d->m_ownerElement; + HTMLFrameOwnerElement* ownerElement = m_ownerElement; if (!ownerElement) return 0; RenderObject* object = ownerElement->renderer(); @@ -1109,7 +1163,7 @@ RenderPart* Frame::ownerRenderer() const return 0; // FIXME: If <object> is ever fixed to disassociate itself from frames // that it has started but canceled, then this can turn into an ASSERT - // since d->m_ownerElement would be 0 when the load is canceled. + // since m_ownerElement would be 0 when the load is canceled. // https://bugs.webkit.org/show_bug.cgi?id=18585 if (!object->isRenderPart()) return 0; @@ -1118,33 +1172,33 @@ RenderPart* Frame::ownerRenderer() const bool Frame::isDisconnected() const { - return d->m_isDisconnected; + return m_isDisconnected; } void Frame::setIsDisconnected(bool isDisconnected) { - d->m_isDisconnected = isDisconnected; + m_isDisconnected = isDisconnected; } bool Frame::excludeFromTextSearch() const { - return d->m_excludeFromTextSearch; + return m_excludeFromTextSearch; } void Frame::setExcludeFromTextSearch(bool exclude) { - d->m_excludeFromTextSearch = exclude; + m_excludeFromTextSearch = exclude; } // returns FloatRect because going through IntRect would truncate any floats -FloatRect Frame::selectionRect(bool clipToVisibleContent) const +FloatRect Frame::selectionBounds(bool clipToVisibleContent) const { RenderView* root = contentRenderer(); - FrameView* view = d->m_view.get(); + FrameView* view = m_view.get(); if (!root || !view) return IntRect(); - IntRect selectionRect = root->selectionRect(clipToVisibleContent); + IntRect selectionRect = root->selectionBounds(clipToVisibleContent); return clipToVisibleContent ? intersection(selectionRect, view->visibleContentRect()) : selectionRect; } @@ -1160,7 +1214,7 @@ void Frame::selectionTextRects(Vector<FloatRect>& rects, bool clipToVisibleConte selectedRange->addLineBoxRects(intRects, true); unsigned size = intRects.size(); - FloatRect visibleContentRect = d->m_view->visibleContentRect(); + FloatRect visibleContentRect = m_view->visibleContentRect(); for (unsigned i = 0; i < size; ++i) if (clipToVisibleContent) rects.append(intersection(intRects[i], visibleContentRect)); @@ -1171,7 +1225,7 @@ void Frame::selectionTextRects(Vector<FloatRect>& rects, bool clipToVisibleConte bool Frame::isFrameSet() const { - Document* document = d->m_doc.get(); + Document* document = m_doc.get(); if (!document || !document->isHTMLDocument()) return false; Node *body = static_cast<HTMLDocument*>(document)->body(); @@ -1185,7 +1239,7 @@ static HTMLFormElement *scanForForm(Node *start) for (n = start; n; n = n->traverseNextNode()) { if (n->hasTagName(formTag)) return static_cast<HTMLFormElement*>(n); - else if (n->isHTMLElement() && static_cast<HTMLElement*>(n)->isGenericFormElement()) + else if (n->isHTMLElement() && static_cast<Element*>(n)->isFormControlElement()) return static_cast<HTMLFormControlElement*>(n)->form(); else if (n->hasTagName(frameTag) || n->hasTagName(iframeTag)) { Node *childDoc = static_cast<HTMLFrameElementBase*>(n)->contentDocument(); @@ -1200,7 +1254,7 @@ static HTMLFormElement *scanForForm(Node *start) HTMLFormElement *Frame::currentForm() const { // start looking either at the active (first responder) node, or where the selection is - Node *start = d->m_doc ? d->m_doc->focusedNode() : 0; + Node *start = m_doc ? m_doc->focusedNode() : 0; if (!start) start = selection()->start().node(); @@ -1209,8 +1263,7 @@ HTMLFormElement *Frame::currentForm() const for (n = start; n; n = n->parentNode()) { if (n->hasTagName(formTag)) return static_cast<HTMLFormElement*>(n); - else if (n->isHTMLElement() - && static_cast<HTMLElement*>(n)->isGenericFormElement()) + else if (n->isHTMLElement() && static_cast<Element*>(n)->isFormControlElement()) return static_cast<HTMLFormControlElement*>(n)->form(); } @@ -1228,11 +1281,11 @@ void Frame::revealSelection(const RenderLayer::ScrollAlignment& alignment) const return; case Selection::CARET: - rect = selection()->caretRect(); + rect = selection()->absoluteCaretBounds(); break; case Selection::RANGE: - rect = enclosingIntRect(selectionRect(false)); + rect = enclosingIntRect(selectionBounds(false)); break; } @@ -1255,14 +1308,14 @@ void Frame::revealCaret(const RenderLayer::ScrollAlignment& alignment) const Position extent = selection()->extent(); if (extent.node() && extent.node()->renderer()) { - IntRect extentRect = VisiblePosition(extent).caretRect(); + 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) +void Frame::adjustPageHeight(float* newBottom, float oldTop, float oldBottom, float /*bottomLimit*/) { RenderView* root = contentRenderer(); if (root) { @@ -1294,7 +1347,7 @@ Frame* Frame::frameForWidget(const Widget* widget) void Frame::forceLayout(bool allowSubtree) { - FrameView *v = d->m_view.get(); + FrameView *v = m_view.get(); if (v) { v->layout(allowSubtree); // We cannot unschedule a pending relayout, since the force can be called with @@ -1343,7 +1396,7 @@ void Frame::sendResizeEvent() void Frame::sendScrollEvent() { - FrameView* v = d->m_view.get(); + FrameView* v = m_view.get(); if (!v) return; v->setWasScrolledByUser(true); @@ -1359,7 +1412,7 @@ void Frame::clearTimers(FrameView *view, Document *document) view->unscheduleRelayout(); if (view->frame()) { if (document && document->renderer() && document->renderer()->hasLayer()) - document->renderer()->layer()->suspendMarquees(); + document->renderView()->layer()->suspendMarquees(); view->frame()->animation()->suspendAnimations(document); view->frame()->eventHandler()->stopAutoscrollTimer(); } @@ -1368,7 +1421,7 @@ void Frame::clearTimers(FrameView *view, Document *document) void Frame::clearTimers() { - clearTimers(d->m_view.get(), document()); + clearTimers(m_view.get(), document()); } RenderStyle *Frame::styleForSelectionStart(Node *&nodeToRemove) const @@ -1387,14 +1440,14 @@ RenderStyle *Frame::styleForSelectionStart(Node *&nodeToRemove) const if (!node) return 0; - if (!d->m_typingStyle) + if (!m_typingStyle) return node->renderer()->style(); ExceptionCode ec = 0; RefPtr<Element> styleElement = document()->createElementNS(xhtmlNamespaceURI, "span", ec); ASSERT(ec == 0); - String styleText = d->m_typingStyle->cssText() + " display: inline"; + String styleText = m_typingStyle->cssText() + " display: inline"; styleElement->setAttribute(styleAttr, styleText.impl(), ec); ASSERT(ec == 0); @@ -1425,24 +1478,12 @@ void Frame::setSelectionFromNone() bool Frame::inViewSourceMode() const { - return d->m_inViewSourceMode; + return m_inViewSourceMode; } -void Frame::setInViewSourceMode(bool mode) const +void Frame::setInViewSourceMode(bool mode) { - d->m_inViewSourceMode = mode; -} - -UChar Frame::backslashAsCurrencySymbol() const -{ - Document *doc = document(); - if (!doc) - return '\\'; - TextResourceDecoder *decoder = doc->decoder(); - if (!decoder) - return '\\'; - - return decoder->encoding().backslashAsCurrencySymbol(); + m_inViewSourceMode = mode; } // Searches from the beginning of the document if nothing is selected. @@ -1577,13 +1618,13 @@ 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 && d->m_view && contentRenderer()) { + if (doc && m_view && contentRenderer()) { doc->updateLayout(); // Ensure layout is up to date. - IntRect visibleRect = d->m_view->visibleContentRect(); + IntRect visibleRect = m_view->visibleContentRect(); if (!visibleRect.isEmpty()) { GraphicsContext context((PlatformGraphicsContext*)0); context.setPaintingDisabled(true); - d->m_view->paintContents(&context, visibleRect); + m_view->paintContents(&context, visibleRect); } } @@ -1592,44 +1633,53 @@ unsigned Frame::markAllMatchesForText(const String& target, bool caseFlag, unsig bool Frame::markedTextMatchesAreHighlighted() const { - return d->m_highlightTextMatches; + return m_highlightTextMatches; } void Frame::setMarkedTextMatchesAreHighlighted(bool flag) { - if (flag == d->m_highlightTextMatches || !document()) + if (flag == m_highlightTextMatches || !document()) return; - d->m_highlightTextMatches = flag; + m_highlightTextMatches = flag; document()->repaintMarkers(DocumentMarker::TextMatch); } FrameTree* Frame::tree() const { - return &d->m_treeNode; + return &m_treeNode; +} + +void Frame::setDOMWindow(DOMWindow* domWindow) +{ + if (m_domWindow) { + m_liveFormerWindows.add(m_domWindow.get()); + m_domWindow->clear(); + } + m_domWindow = domWindow; } DOMWindow* Frame::domWindow() const { - if (!d->m_domWindow) - d->m_domWindow = DOMWindow::create(const_cast<Frame*>(this)); + if (!m_domWindow) + m_domWindow = DOMWindow::create(const_cast<Frame*>(this)); - return d->m_domWindow.get(); + return m_domWindow.get(); } void Frame::clearFormerDOMWindow(DOMWindow* window) { - d->m_liveFormerWindows.remove(window); + m_liveFormerWindows.remove(window); } Page* Frame::page() const { - return d->m_page; + return m_page; } EventHandler* Frame::eventHandler() const { - return &d->m_eventHandler; + return &m_eventHandler; } void Frame::pageDestroyed() @@ -1649,20 +1699,21 @@ void Frame::pageDestroyed() script()->windowShell()->disconnectFrame(); script()->clearScriptObjects(); + script()->updatePlatformScriptObjects(); - d->m_page = 0; + m_page = 0; } void Frame::disconnectOwnerElement() { - if (d->m_ownerElement) { + if (m_ownerElement) { if (Document* doc = document()) doc->clearAXObjectCache(); - d->m_ownerElement->m_contentFrame = 0; - if (d->m_page) - d->m_page->decrementFrameCount(); + m_ownerElement->m_contentFrame = 0; + if (m_page) + m_page->decrementFrameCount(); } - d->m_ownerElement = 0; + m_ownerElement = 0; } String Frame::documentTypeString() const @@ -1719,8 +1770,7 @@ bool Frame::shouldClose() if (beforeUnloadEvent->result().isNull()) return true; - String text = beforeUnloadEvent->result(); - text.replace('\\', backslashAsCurrencySymbol()); + String text = doc->displayStringModifiedByEncoding(beforeUnloadEvent->result()); return chrome->runBeforeUnloadConfirmPanel(text, this); } @@ -1811,37 +1861,5 @@ Document* Frame::documentAtPoint(const IntPoint& point) result = eventHandler()->hitTestResultAtPoint(pt, false); return result.innerNode() ? result.innerNode()->document() : 0; } - -FramePrivate::FramePrivate(Page* page, Frame* parent, Frame* thisFrame, HTMLFrameOwnerElement* ownerElement, - FrameLoaderClient* frameLoaderClient) - : m_page(page) - , m_treeNode(thisFrame, parent) - , m_loader(thisFrame, frameLoaderClient) - , m_ownerElement(ownerElement) - , m_script(thisFrame) - , m_zoomFactor(parent ? parent->d->m_zoomFactor : 1.0f) - , m_selectionGranularity(CharacterGranularity) - , m_selectionController(thisFrame) - , m_caretBlinkTimer(thisFrame, &Frame::caretBlinkTimerFired) - , m_editor(thisFrame) - , m_eventHandler(thisFrame) - , m_animationController(thisFrame) - , m_lifeSupportTimer(thisFrame, &Frame::lifeSupportTimerFired) - , m_caretVisible(false) - , m_caretPaint(true) - , m_highlightTextMatches(false) - , m_inViewSourceMode(false) - , m_needsReapplyStyles(false) - , m_isDisconnected(false) - , m_excludeFromTextSearch(false) -#if FRAME_LOADS_USER_STYLESHEET - , m_userStyleSheetLoader(0) -#endif -{ -} - -FramePrivate::~FramePrivate() -{ -} } // namespace WebCore diff --git a/WebCore/page/Frame.h b/WebCore/page/Frame.h index 8f50062..bebdc63 100644 --- a/WebCore/page/Frame.h +++ b/WebCore/page/Frame.h @@ -28,11 +28,23 @@ #ifndef Frame_h #define Frame_h +#include "AnimationController.h" #include "DragImage.h" #include "EditAction.h" +#include "Editor.h" +#include "EventHandler.h" +#include "FrameLoader.h" +#include "FrameTree.h" +#include "Range.h" #include "RenderLayer.h" +#include "ScriptController.h" +#include "SelectionController.h" #include "TextGranularity.h" +#if PLATFORM(WIN) +#include "FrameWin.h" +#endif + #if PLATFORM(MAC) #ifndef __OBJC__ class NSArray; @@ -43,6 +55,10 @@ typedef int NSWritingDirection; #endif #endif +#if PLATFORM(WIN) +typedef struct HBITMAP__* HBITMAP; +#endif + namespace WebCore { class Editor; @@ -60,6 +76,10 @@ class Selection; class SelectionController; class Widget; +#if FRAME_LOADS_USER_STYLESHEET + class UserStyleSheetLoader; +#endif + template <typename T> class Timer; class Frame : public RefCounted<Frame> { @@ -82,8 +102,10 @@ public: Document* document() const; FrameView* view() const; + void setDOMWindow(DOMWindow*); DOMWindow* domWindow() const; void clearFormerDOMWindow(DOMWindow*); + Editor* editor() const; EventHandler* eventHandler() const; FrameLoader* loader() const; @@ -104,8 +126,6 @@ public: private: Frame(Page*, HTMLFrameOwnerElement*, FrameLoaderClient*); - - FramePrivate* d; // === undecided, would like to consider moving to another class @@ -122,7 +142,7 @@ public: void setPrinting(bool printing, float minPageWidth, float maxPageWidth, bool adjustViewSize); bool inViewSourceMode() const; - void setInViewSourceMode(bool = true) const; + void setInViewSourceMode(bool = true); void keepAlive(); // Used to keep the frame alive when running a script that might destroy it. #ifndef NDEBUG @@ -134,9 +154,6 @@ public: void clearTimers(); static void clearTimers(FrameView*, Document*); - // Convenience, to avoid repeating the code to dig down to get this. - UChar backslashAsCurrencySymbol() const; - void setNeedsReapplyStyles(); bool needsReapplyStyles() const; void reapplyStyles(); @@ -147,6 +164,11 @@ public: // should move onto ScriptController void clearDOMWindow(); + String displayStringModifiedByEncoding(const String& str) const + { + return document() ? document()->displayStringModifiedByEncoding(str) : str; + } + private: void lifeSupportTimerFired(Timer<Frame>*); @@ -232,7 +254,7 @@ public: public: TextGranularity selectionGranularity() const; - void setSelectionGranularity(TextGranularity) const; + void setSelectionGranularity(TextGranularity); bool shouldChangeSelection(const Selection&) const; bool shouldDeleteSelection(const Selection&) const; @@ -244,8 +266,8 @@ public: void invalidateSelection(); void setCaretVisible(bool = true); - void paintCaret(GraphicsContext*, const IntRect&) const; - void paintDragCaret(GraphicsContext*, const IntRect&) const; + void paintCaret(GraphicsContext*, int tx, int ty, const IntRect& clipRect) const; + void paintDragCaret(GraphicsContext*, int tx, int ty, const IntRect& clipRect) const; bool isContentEditable() const; // if true, everything in frame is editable @@ -255,7 +277,7 @@ public: void setTypingStyle(CSSMutableStyleDeclaration*); void clearTypingStyle(); - FloatRect selectionRect(bool clipToVisibleContent = true) const; + FloatRect selectionBounds(bool clipToVisibleContent = true) const; void selectionTextRects(Vector<FloatRect>&, bool clipToVisibleContent = true) const; HTMLFormElement* currentForm() const; @@ -307,6 +329,59 @@ public: #endif +#if PLATFORM(WIN) + +public: + // FIXME - We should have a single version of nodeImage instead of using platform types. + HBITMAP nodeImage(Node*) const; + +#endif + +private: + Page* m_page; + mutable FrameTree m_treeNode; + mutable FrameLoader m_loader; + + mutable RefPtr<DOMWindow> m_domWindow; + HashSet<DOMWindow*> m_liveFormerWindows; + + HTMLFrameOwnerElement* m_ownerElement; + RefPtr<FrameView> m_view; + RefPtr<Document> m_doc; + + ScriptController m_script; + + String m_kjsStatusBarText; + String m_kjsDefaultStatusBarText; + + float m_zoomFactor; + + TextGranularity m_selectionGranularity; + + mutable SelectionController m_selectionController; + mutable Selection m_mark; + Timer<Frame> m_caretBlinkTimer; + mutable Editor m_editor; + mutable EventHandler m_eventHandler; + mutable AnimationController m_animationController; + + RefPtr<CSSMutableStyleDeclaration> m_typingStyle; + + Timer<Frame> m_lifeSupportTimer; + + bool m_caretVisible; + bool m_caretPaint; + + bool m_highlightTextMatches; + bool m_inViewSourceMode; + bool m_needsReapplyStyles; + bool m_isDisconnected; + bool m_excludeFromTextSearch; + +#if FRAME_LOADS_USER_STYLESHEET + UserStyleSheetLoader* m_userStyleSheetLoader; +#endif + }; } // namespace WebCore diff --git a/WebCore/page/FrameLoadRequest.h b/WebCore/page/FrameLoadRequest.h index bfb750c..0f92c45 100644 --- a/WebCore/page/FrameLoadRequest.h +++ b/WebCore/page/FrameLoadRequest.h @@ -33,16 +33,14 @@ namespace WebCore { struct FrameLoadRequest { public: FrameLoadRequest() - : m_lockHistory(false) #ifdef ANDROID_USER_GESTURE - , m_wasUserGesture(true) + : m_wasUserGesture(true) #endif { } FrameLoadRequest(const ResourceRequest& resourceRequest) : m_resourceRequest(resourceRequest) - , m_lockHistory(false) #ifdef ANDROID_USER_GESTURE , m_wasUserGesture(true) #endif @@ -52,7 +50,6 @@ namespace WebCore { FrameLoadRequest(const ResourceRequest& resourceRequest, const String& frameName) : m_resourceRequest(resourceRequest) , m_frameName(frameName) - , m_lockHistory(false) #ifdef ANDROID_USER_GESTURE , m_wasUserGesture(true) #endif @@ -67,9 +64,6 @@ namespace WebCore { const String& frameName() const { return m_frameName; } void setFrameName(const String& frameName) { m_frameName = frameName; } - bool lockHistory() const { return m_lockHistory; } - void setLockHistory(bool lock) { m_lockHistory = lock; } - #ifdef ANDROID_USER_GESTURE void setWasUserGesture(bool wasUserGesture) { m_wasUserGesture = wasUserGesture; } bool wasUserGesture() const { return m_wasUserGesture; } @@ -78,7 +72,6 @@ namespace WebCore { private: ResourceRequest m_resourceRequest; String m_frameName; - bool m_lockHistory; #ifdef ANDROID_USER_GESTURE bool m_wasUserGesture; #endif diff --git a/WebCore/page/FramePrivate.h b/WebCore/page/FramePrivate.h deleted file mode 100644 index 2f7c59a..0000000 --- a/WebCore/page/FramePrivate.h +++ /dev/null @@ -1,99 +0,0 @@ -/* Copyright (C) 1998, 1999 Torben Weis <weis@kde.org> - * 1999-2001 Lars Knoll <knoll@kde.org> - * 1999-2001 Antti Koivisto <koivisto@kde.org> - * 2000-2001 Simon Hausmann <hausmann@kde.org> - * 2000-2001 Dirk Mueller <mueller@kde.org> - * 2000 Stefan Schimanski <1Stein@gmx.de> - * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef FramePrivate_h -#define FramePrivate_h - -#include "AnimationController.h" -#include "Editor.h" -#include "EventHandler.h" -#include "FrameLoader.h" -#include "FrameTree.h" -#include "Range.h" -#include "SelectionController.h" -#include "StringHash.h" -#include "ScriptController.h" - -#if PLATFORM(WIN) -#include "FrameWin.h" -#endif - -namespace WebCore { - -#if FRAME_LOADS_USER_STYLESHEET - class UserStyleSheetLoader; -#endif - - class FramePrivate { - public: - FramePrivate(Page*, Frame* parent, Frame* thisFrame, HTMLFrameOwnerElement*, FrameLoaderClient*); - ~FramePrivate(); - - Page* m_page; - FrameTree m_treeNode; - FrameLoader m_loader; - RefPtr<DOMWindow> m_domWindow; - HashSet<DOMWindow*> m_liveFormerWindows; - - HTMLFrameOwnerElement* m_ownerElement; - RefPtr<FrameView> m_view; - RefPtr<Document> m_doc; - - ScriptController m_script; - - String m_kjsStatusBarText; - String m_kjsDefaultStatusBarText; - - float m_zoomFactor; - - TextGranularity m_selectionGranularity; - - SelectionController m_selectionController; - Selection m_mark; - Timer<Frame> m_caretBlinkTimer; - Editor m_editor; - EventHandler m_eventHandler; - AnimationController m_animationController; - - RefPtr<CSSMutableStyleDeclaration> m_typingStyle; - - Timer<Frame> m_lifeSupportTimer; - - bool m_caretVisible; - bool m_caretPaint; - - bool m_highlightTextMatches; - bool m_inViewSourceMode; - bool m_needsReapplyStyles; - bool m_isDisconnected; - bool m_excludeFromTextSearch; - -#if FRAME_LOADS_USER_STYLESHEET - UserStyleSheetLoader* m_userStyleSheetLoader; -#endif - }; -} - -#endif diff --git a/WebCore/page/FrameTree.h b/WebCore/page/FrameTree.h index 0952dcd..3b74d5d 100644 --- a/WebCore/page/FrameTree.h +++ b/WebCore/page/FrameTree.h @@ -21,10 +21,11 @@ #define FrameTree_h #include "AtomicString.h" -#include "Frame.h" namespace WebCore { + class Frame; + class FrameTree : Noncopyable { public: FrameTree(Frame* thisFrame, Frame* parentFrame) diff --git a/WebCore/page/FrameView.cpp b/WebCore/page/FrameView.cpp index 1d5ef9f..2eefd6c 100644 --- a/WebCore/page/FrameView.cpp +++ b/WebCore/page/FrameView.cpp @@ -34,6 +34,7 @@ #include "Frame.h" #include "FrameLoader.h" #include "FrameLoaderClient.h" +#include "FrameTree.h" #include "GraphicsContext.h" #include "HTMLDocument.h" #include "HTMLFrameElement.h" @@ -43,10 +44,11 @@ #include "Page.h" #include "RenderPart.h" #include "RenderPartObject.h" +#include "RenderScrollbar.h" #include "RenderTheme.h" #include "RenderView.h" #include "Settings.h" -#include "SystemTime.h" +#include <wtf/CurrentTime.h> #ifdef ANDROID_INSTRUMENT #include "FrameTree.h" @@ -64,110 +66,25 @@ struct ScheduledEvent { RefPtr<EventTargetNode> m_eventTarget; }; -class FrameViewPrivate { -public: - FrameViewPrivate(FrameView* view) - : m_slowRepaintObjectCount(0) - , m_layoutTimer(view, &FrameView::layoutTimerFired) - , m_layoutRoot(0) - , m_postLayoutTasksTimer(view, &FrameView::postLayoutTimerFired) - , m_mediaType("screen") - , m_enqueueEvents(0) - , m_overflowStatusDirty(true) - , m_viewportRenderer(0) - , m_wasScrolledByUser(false) - , m_inProgrammaticScroll(false) - , m_shouldUpdateWhileOffscreen(true) - { - m_isTransparent = false; - m_baseBackgroundColor = Color::white; - m_vmode = m_hmode = ScrollbarAuto; - m_needToInitScrollbars = true; - reset(); - } - void reset() - { - m_useSlowRepaints = false; - m_borderX = 30; - m_borderY = 30; - m_layoutTimer.stop(); - m_layoutRoot = 0; - m_delayedLayout = false; - m_doFullRepaint = true; - m_layoutSchedulingEnabled = true; - m_midLayout = false; - m_layoutCount = 0; - m_nestedLayoutCount = 0; - m_postLayoutTasksTimer.stop(); - m_firstLayout = true; - m_firstLayoutCallbackPending = false; - m_wasScrolledByUser = false; - m_lastLayoutSize = IntSize(); - m_lastZoomFactor = 1.0f; - m_deferringRepaints = 0; - m_repaintCount = 0; - m_repaintRect = IntRect(); - m_repaintRects.clear(); - m_paintRestriction = PaintRestrictionNone; - m_isPainting = false; - } - - bool m_doFullRepaint; - - ScrollbarMode m_vmode; - ScrollbarMode m_hmode; - bool m_useSlowRepaints; - unsigned m_slowRepaintObjectCount; - - int m_borderX, m_borderY; - - Timer<FrameView> m_layoutTimer; - bool m_delayedLayout; - RenderObject* m_layoutRoot; - - bool m_layoutSchedulingEnabled; - bool m_midLayout; - int m_layoutCount; - unsigned m_nestedLayoutCount; - Timer<FrameView> m_postLayoutTasksTimer; - bool m_firstLayoutCallbackPending; - - bool m_firstLayout; - bool m_needToInitScrollbars; - bool m_isTransparent; - Color m_baseBackgroundColor; - IntSize m_lastLayoutSize; - float m_lastZoomFactor; - - String m_mediaType; - - unsigned m_enqueueEvents; - Vector<ScheduledEvent*> m_scheduledEvents; - - bool m_overflowStatusDirty; - bool m_horizontalOverflow; - bool m_verticalOverflow; - RenderObject* m_viewportRenderer; - - bool m_wasScrolledByUser; - bool m_inProgrammaticScroll; - - unsigned m_deferringRepaints; - unsigned m_repaintCount; - IntRect m_repaintRect; - Vector<IntRect> m_repaintRects; - - bool m_shouldUpdateWhileOffscreen; - - RefPtr<Node> m_nodeToDraw; - PaintRestriction m_paintRestriction; - bool m_isPainting; -}; - FrameView::FrameView(Frame* frame) : m_refCount(1) , m_frame(frame) - , d(new FrameViewPrivate(this)) + , m_vmode(ScrollbarAuto) + , m_hmode(ScrollbarAuto) + , m_slowRepaintObjectCount(0) + , m_layoutTimer(this, &FrameView::layoutTimerFired) + , m_layoutRoot(0) + , m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired) + , m_needToInitScrollbars(true) + , m_isTransparent(false) + , m_baseBackgroundColor(Color::white) + , m_mediaType("screen") + , m_enqueueEvents(0) + , m_overflowStatusDirty(true) + , m_viewportRenderer(0) + , m_wasScrolledByUser(false) + , m_inProgrammaticScroll(false) + , m_shouldUpdateWhileOffscreen(true) { init(); show(); @@ -176,7 +93,22 @@ FrameView::FrameView(Frame* frame) FrameView::FrameView(Frame* frame, const IntSize& initialSize) : m_refCount(1) , m_frame(frame) - , d(new FrameViewPrivate(this)) + , m_vmode(ScrollbarAuto) + , m_hmode(ScrollbarAuto) + , m_slowRepaintObjectCount(0) + , m_layoutTimer(this, &FrameView::layoutTimerFired) + , m_layoutRoot(0) + , m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired) + , m_needToInitScrollbars(true) + , m_isTransparent(false) + , m_baseBackgroundColor(Color::white) + , m_mediaType("screen") + , m_enqueueEvents(0) + , m_overflowStatusDirty(true) + , m_viewportRenderer(0) + , m_wasScrolledByUser(false) + , m_inProgrammaticScroll(false) + , m_shouldUpdateWhileOffscreen(true) { init(); Widget::setFrameRect(IntRect(x(), y(), initialSize.width(), initialSize.height())); @@ -185,10 +117,10 @@ FrameView::FrameView(Frame* frame, const IntSize& initialSize) FrameView::~FrameView() { - if (d->m_postLayoutTasksTimer.isActive()) { - d->m_postLayoutTasksTimer.stop(); - d->m_scheduledEvents.clear(); - d->m_enqueueEvents = 0; + if (m_postLayoutTasksTimer.isActive()) { + m_postLayoutTasksTimer.stop(); + m_scheduledEvents.clear(); + m_enqueueEvents = 0; } resetScrollbars(); @@ -196,8 +128,8 @@ FrameView::~FrameView() setHasVerticalScrollbar(false); ASSERT(m_refCount == 0); - ASSERT(d->m_scheduledEvents.isEmpty()); - ASSERT(!d->m_enqueueEvents); + ASSERT(m_scheduledEvents.isEmpty()); + ASSERT(!m_enqueueEvents); if (m_frame) { ASSERT(m_frame->view() != this || !m_frame->document() || !m_frame->contentRenderer()); @@ -205,9 +137,35 @@ FrameView::~FrameView() if (renderer && renderer->widget() == this) renderer->setWidget(0); } +} - delete d; - d = 0; +void FrameView::reset() +{ + m_useSlowRepaints = false; + m_borderX = 30; + m_borderY = 30; + m_layoutTimer.stop(); + m_layoutRoot = 0; + m_delayedLayout = false; + m_doFullRepaint = true; + m_layoutSchedulingEnabled = true; + m_midLayout = false; + m_layoutCount = 0; + m_nestedLayoutCount = 0; + m_postLayoutTasksTimer.stop(); + m_firstLayout = true; + m_firstLayoutCallbackPending = false; + m_wasScrolledByUser = false; + m_lastLayoutSize = IntSize(); + m_lastZoomFactor = 1.0f; + m_deferringRepaints = 0; + m_repaintCount = 0; + m_repaintRect = IntRect(); + m_repaintRects.clear(); + m_paintRestriction = PaintRestrictionNone; + m_isPainting = false; + m_isVisuallyNonEmpty = false; + m_firstVisuallyNonEmptyLayoutCallbackPending = true; } bool FrameView::isFrameView() const @@ -223,14 +181,16 @@ void FrameView::clearFrame() void FrameView::resetScrollbars() { // Reset the document's scrollbars back to our defaults before we yield the floor. - d->m_firstLayout = true; + m_firstLayout = true; setScrollbarsSuppressed(true); - setScrollbarModes(d->m_hmode, d->m_vmode); + setScrollbarModes(m_hmode, m_vmode); setScrollbarsSuppressed(false); } void FrameView::init() { + reset(); + m_margins = IntSize(-1, -1); // undefined m_size = IntSize(); @@ -253,28 +213,34 @@ void FrameView::clear() { setCanBlitOnScroll(true); - d->reset(); + reset(); - if (m_frame) + if (m_frame) { if (RenderPart* renderer = m_frame->ownerRenderer()) renderer->viewCleared(); + } setScrollbarsSuppressed(true); } bool FrameView::didFirstLayout() const { - return !d->m_firstLayout; + return !m_firstLayout; } void FrameView::initScrollbars() { - if (!d->m_needToInitScrollbars) + if (!m_needToInitScrollbars) return; - d->m_needToInitScrollbars = false; - d->m_hmode = horizontalScrollbarMode(); - d->m_vmode = verticalScrollbarMode(); - setScrollbarModes(d->m_hmode, d->m_vmode); + m_needToInitScrollbars = false; + updateDefaultScrollbarState(); +} + +void FrameView::updateDefaultScrollbarState() +{ + m_hmode = horizontalScrollbarMode(); + m_vmode = verticalScrollbarMode(); + setScrollbarModes(m_hmode, m_vmode); } void FrameView::invalidateRect(const IntRect& rect) @@ -313,7 +279,44 @@ void FrameView::setMarginHeight(int h) void FrameView::setCanHaveScrollbars(bool canScroll) { ScrollView::setCanHaveScrollbars(canScroll); - scrollbarModes(d->m_hmode, d->m_vmode); + scrollbarModes(m_hmode, m_vmode); +} + +PassRefPtr<Scrollbar> FrameView::createScrollbar(ScrollbarOrientation orientation) +{ + // FIXME: We need to update the scrollbar dynamically as documents change (or as doc elements and bodies get discovered that have custom styles). + Document* doc = m_frame->document(); + if (!doc) + return ScrollView::createScrollbar(orientation); + + // Try the <body> element first as a scrollbar source. + Element* body = doc->body(); + if (body && body->renderer() && body->renderer()->style()->hasPseudoStyle(RenderStyle::SCROLLBAR)) + return RenderScrollbar::createCustomScrollbar(this, orientation, body->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)) + 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)) + return RenderScrollbar::createCustomScrollbar(this, orientation, frameRenderer); + + // Nobody set a custom style, so we just use a native scrollbar. + return ScrollView::createScrollbar(orientation); +} + +void FrameView::setContentsSize(const IntSize& size) +{ + ScrollView::setContentsSize(size); + + Page* page = frame() ? frame()->page() : 0; + if (!page) + return; + + page->chrome()->contentsSizeChanged(frame(), size); //notify only } void FrameView::adjustViewSize() @@ -361,31 +364,21 @@ void FrameView::applyOverflowToViewport(RenderObject* o, ScrollbarMode& hMode, S ; } - d->m_viewportRenderer = o; -} - -int FrameView::layoutCount() const -{ - return d->m_layoutCount; -} - -bool FrameView::needsFullRepaint() const -{ - return d->m_doFullRepaint; + m_viewportRenderer = o; } RenderObject* FrameView::layoutRoot(bool onlyDuringLayout) const { - return onlyDuringLayout && layoutPending() ? 0 : d->m_layoutRoot; + return onlyDuringLayout && layoutPending() ? 0 : m_layoutRoot; } void FrameView::layout(bool allowSubtree) { - if (d->m_midLayout) + if (m_midLayout) return; - d->m_layoutTimer.stop(); - d->m_delayedLayout = false; + m_layoutTimer.stop(); + m_delayedLayout = false; // Protect the view from being deleted during layout (in recalcStyle) RefPtr<FrameView> protector(this); @@ -393,7 +386,7 @@ void FrameView::layout(bool allowSubtree) if (!m_frame) { // FIXME: Do we need to set m_size.width here? // FIXME: Should we set m_size.height here too? - m_size.setWidth(visibleWidth()); + m_size.setWidth(layoutWidth()); return; } @@ -402,9 +395,9 @@ void FrameView::layout(bool allowSubtree) if (isPainting()) return; - if (!allowSubtree && d->m_layoutRoot) { - d->m_layoutRoot->markContainingBlocksForLayout(false); - d->m_layoutRoot = 0; + if (!allowSubtree && m_layoutRoot) { + m_layoutRoot->markContainingBlocksForLayout(false); + m_layoutRoot = 0; } ASSERT(m_frame->view() == this); @@ -417,16 +410,16 @@ void FrameView::layout(bool allowSubtree) Document* document = m_frame->document(); if (!document) { // FIXME: Should we set m_size.height here too? - m_size.setWidth(visibleWidth()); + m_size.setWidth(layoutWidth()); return; } - d->m_layoutSchedulingEnabled = false; + m_layoutSchedulingEnabled = false; - if (!d->m_nestedLayoutCount && d->m_postLayoutTasksTimer.isActive()) { + if (!m_nestedLayoutCount && m_postLayoutTasksTimer.isActive()) { // This is a new top-level layout. If there are any remaining tasks from the previous // layout, finish them now. - d->m_postLayoutTasksTimer.stop(); + m_postLayoutTasksTimer.stop(); performPostLayoutTasks(); } @@ -442,17 +435,17 @@ void FrameView::layout(bool allowSubtree) else if (document->hasChangedChild()) document->recalcStyle(); - bool subtree = d->m_layoutRoot; + bool subtree = m_layoutRoot; // If there is only one ref to this view left, then its going to be destroyed as soon as we exit, // so there's no point to continuing to layout if (protector->hasOneRef()) return; - RenderObject* root = subtree ? d->m_layoutRoot : document->renderer(); + RenderObject* root = subtree ? m_layoutRoot : document->renderer(); if (!root) { // FIXME: Do we need to set m_size here? - d->m_layoutSchedulingEnabled = true; + m_layoutSchedulingEnabled = true; return; } @@ -461,10 +454,10 @@ void FrameView::layout(bool allowSubtree) android::TimeCounter::start(android::TimeCounter::LayoutTimeCounter); #endif - d->m_nestedLayoutCount++; + m_nestedLayoutCount++; - ScrollbarMode hMode = d->m_hmode; - ScrollbarMode vMode = d->m_vmode; + ScrollbarMode hMode = m_hmode; + ScrollbarMode vMode = m_vmode; if (!subtree) { RenderObject* rootRenderer = document->documentElement() ? document->documentElement()->renderer() : 0; @@ -475,8 +468,8 @@ void FrameView::layout(bool allowSubtree) vMode = ScrollbarAlwaysOff; hMode = ScrollbarAlwaysOff; } else if (body->hasTagName(bodyTag)) { - if (!d->m_firstLayout && m_size.height() != visibleHeight() - && static_cast<RenderBox*>(body->renderer())->stretchesToViewHeight()) + if (!m_firstLayout && m_size.height() != layoutHeight() + && toRenderBox(body->renderer())->stretchesToViewHeight()) body->renderer()->setChildNeedsLayout(true); // It's sufficient to just check the X overflow, // since it's illegal to have visible in only one direction. @@ -486,25 +479,25 @@ void FrameView::layout(bool allowSubtree) } else if (rootRenderer) applyOverflowToViewport(rootRenderer, hMode, vMode); #ifdef INSTRUMENT_LAYOUT_SCHEDULING - if (d->m_firstLayout && !document->ownerElement()) + if (m_firstLayout && !document->ownerElement()) printf("Elapsed time before first layout: %d\n", document->elapsedTime()); #endif } - d->m_doFullRepaint = !subtree && (d->m_firstLayout || static_cast<RenderView*>(root)->printing()); + m_doFullRepaint = !subtree && (m_firstLayout || static_cast<RenderView*>(root)->printing()); if (!subtree) { // Now set our scrollbar state for the layout. ScrollbarMode currentHMode = horizontalScrollbarMode(); ScrollbarMode currentVMode = verticalScrollbarMode(); - if (d->m_firstLayout || (hMode != currentHMode || vMode != currentVMode)) { + if (m_firstLayout || (hMode != currentHMode || vMode != currentVMode)) { setScrollbarsSuppressed(true); - if (d->m_firstLayout) { - d->m_firstLayout = false; - d->m_firstLayoutCallbackPending = true; - d->m_lastLayoutSize = IntSize(width(), height()); - d->m_lastZoomFactor = root->style()->zoom(); + if (m_firstLayout) { + m_firstLayout = false; + m_firstLayoutCallbackPending = true; + m_lastLayoutSize = IntSize(width(), height()); + m_lastZoomFactor = root->style()->zoom(); // Set the initial vMode to AlwaysOn if we're auto. if (vMode == ScrollbarAuto) @@ -519,12 +512,12 @@ void FrameView::layout(bool allowSubtree) IntSize oldSize = m_size; - m_size = IntSize(visibleWidth(), visibleHeight()); + m_size = IntSize(layoutWidth(), layoutHeight()); if (oldSize != m_size) - d->m_doFullRepaint = true; + m_doFullRepaint = true; } - + RenderLayer* layer = root->enclosingLayer(); pauseScheduledEvents(); @@ -532,29 +525,29 @@ void FrameView::layout(bool allowSubtree) if (subtree) root->view()->pushLayoutState(root); - d->m_midLayout = true; + m_midLayout = true; beginDeferredRepaints(); root->layout(); endDeferredRepaints(); - d->m_midLayout = false; + m_midLayout = false; if (subtree) root->view()->popLayoutState(); - d->m_layoutRoot = 0; + m_layoutRoot = 0; m_frame->invalidateSelection(); - d->m_layoutSchedulingEnabled = true; + m_layoutSchedulingEnabled = true; if (!subtree && !static_cast<RenderView*>(root)->printing()) adjustViewSize(); // Now update the positions of all layers. beginDeferredRepaints(); - layer->updateLayerPositions(d->m_doFullRepaint); + layer->updateLayerPositions(m_doFullRepaint); endDeferredRepaints(); - d->m_layoutCount++; + m_layoutCount++; #if PLATFORM(MAC) if (AXObjectCache::accessibilityEnabled()) @@ -573,10 +566,10 @@ void FrameView::layout(bool allowSubtree) setCanBlitOnScroll(!useSlowRepaints()); if (document->hasListenerType(Document::OVERFLOWCHANGED_LISTENER)) - updateOverflowStatus(visibleWidth() < contentsWidth(), - visibleHeight() < contentsHeight()); + updateOverflowStatus(layoutWidth() < contentsWidth(), + layoutHeight() < contentsHeight()); - if (!d->m_postLayoutTasksTimer.isActive()) { + if (!m_postLayoutTasksTimer.isActive()) { // Calls resumeScheduledEvents() performPostLayoutTasks(); @@ -584,16 +577,16 @@ void FrameView::layout(bool allowSubtree) // Post-layout widget updates or an event handler made us need layout again. // Lay out again, but this time defer widget updates and event dispatch until after // we return. - d->m_postLayoutTasksTimer.startOneShot(0); + m_postLayoutTasksTimer.startOneShot(0); pauseScheduledEvents(); layout(); } } else { resumeScheduledEvents(); - ASSERT(d->m_enqueueEvents); + ASSERT(m_enqueueEvents); } - d->m_nestedLayoutCount--; + m_nestedLayoutCount--; } void FrameView::addWidgetToUpdate(RenderPartObject* object) @@ -614,7 +607,7 @@ void FrameView::removeWidgetToUpdate(RenderPartObject* object) void FrameView::setMediaType(const String& mediaType) { - d->m_mediaType = mediaType; + m_mediaType = mediaType; } String FrameView::mediaType() const @@ -623,33 +616,33 @@ String FrameView::mediaType() const String overrideType = m_frame->loader()->client()->overrideMediaType(); if (!overrideType.isNull()) return overrideType; - return d->m_mediaType; + return m_mediaType; } bool FrameView::useSlowRepaints() const { - return d->m_useSlowRepaints || d->m_slowRepaintObjectCount > 0; + return m_useSlowRepaints || m_slowRepaintObjectCount > 0; } void FrameView::setUseSlowRepaints() { - d->m_useSlowRepaints = true; + m_useSlowRepaints = true; setCanBlitOnScroll(false); } void FrameView::addSlowRepaintObject() { - if (!d->m_slowRepaintObjectCount) + if (!m_slowRepaintObjectCount) setCanBlitOnScroll(false); - d->m_slowRepaintObjectCount++; + m_slowRepaintObjectCount++; } void FrameView::removeSlowRepaintObject() { - ASSERT(d->m_slowRepaintObjectCount > 0); - d->m_slowRepaintObjectCount--; - if (!d->m_slowRepaintObjectCount) - setCanBlitOnScroll(!d->m_useSlowRepaints); + ASSERT(m_slowRepaintObjectCount > 0); + m_slowRepaintObjectCount--; + if (!m_slowRepaintObjectCount) + setCanBlitOnScroll(!m_useSlowRepaints); } void FrameView::restoreScrollbar() @@ -659,18 +652,18 @@ void FrameView::restoreScrollbar() void FrameView::scrollRectIntoViewRecursively(const IntRect& r) { - bool wasInProgrammaticScroll = d->m_inProgrammaticScroll; - d->m_inProgrammaticScroll = true; + bool wasInProgrammaticScroll = m_inProgrammaticScroll; + m_inProgrammaticScroll = true; ScrollView::scrollRectIntoViewRecursively(r); - d->m_inProgrammaticScroll = wasInProgrammaticScroll; + m_inProgrammaticScroll = wasInProgrammaticScroll; } void FrameView::setScrollPosition(const IntPoint& scrollPoint) { - bool wasInProgrammaticScroll = d->m_inProgrammaticScroll; - d->m_inProgrammaticScroll = true; + bool wasInProgrammaticScroll = m_inProgrammaticScroll; + m_inProgrammaticScroll = true; ScrollView::setScrollPosition(scrollPoint); - d->m_inProgrammaticScroll = wasInProgrammaticScroll; + m_inProgrammaticScroll = wasInProgrammaticScroll; } HostWindow* FrameView::hostWindow() const @@ -687,16 +680,16 @@ void FrameView::repaintContentRectangle(const IntRect& r, bool immediate) { ASSERT(!m_frame->document()->ownerElement()); - if (d->m_deferringRepaints && !immediate) { + if (m_deferringRepaints && !immediate) { IntRect visibleContent = visibleContentRect(); visibleContent.intersect(r); if (!visibleContent.isEmpty()) { - d->m_repaintCount++; - d->m_repaintRect.unite(r); - if (d->m_repaintCount == cRepaintRectUnionThreshold) - d->m_repaintRects.clear(); - else if (d->m_repaintCount < cRepaintRectUnionThreshold) - d->m_repaintRects.append(r); + 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 @@ -717,13 +710,13 @@ void FrameView::beginDeferredRepaints() if (page->mainFrame() != m_frame) return page->mainFrame()->view()->beginDeferredRepaints(); - d->m_deferringRepaints++; + m_deferringRepaints++; #ifdef ANDROID_FIX // This allows sub frames to accumulate deferred repaints - if (d->m_deferringRepaints == 1) { + if (m_deferringRepaints == 1) { #endif - d->m_repaintCount = 0; - d->m_repaintRect = IntRect(); - d->m_repaintRects.clear(); + m_repaintCount = 0; + m_repaintRect = IntRect(); + m_repaintRects.clear(); #ifdef ANDROID_FIX } #endif @@ -736,15 +729,15 @@ void FrameView::endDeferredRepaints() if (page->mainFrame() != m_frame) return page->mainFrame()->view()->endDeferredRepaints(); - ASSERT(d->m_deferringRepaints > 0); - if (--d->m_deferringRepaints == 0) { - if (d->m_repaintCount >= cRepaintRectUnionThreshold) - repaintContentRectangle(d->m_repaintRect, false); + ASSERT(m_deferringRepaints > 0); + if (--m_deferringRepaints == 0) { + if (m_repaintCount >= cRepaintRectUnionThreshold) + repaintContentRectangle(m_repaintRect, false); else { - unsigned size = d->m_repaintRects.size(); + unsigned size = m_repaintRects.size(); for (unsigned i = 0; i < size; i++) - repaintContentRectangle(d->m_repaintRects[i], false); - d->m_repaintRects.clear(); + repaintContentRectangle(m_repaintRects[i], false); + m_repaintRects.clear(); } } } @@ -763,13 +756,14 @@ void FrameView::scheduleRelayout() ASSERT(!m_frame->document() || !m_frame->document()->inPageCache()); ASSERT(m_frame->view() == this); - if (d->m_layoutRoot) { - d->m_layoutRoot->markContainingBlocksForLayout(false); - d->m_layoutRoot = 0; + if (m_layoutRoot) { + m_layoutRoot->markContainingBlocksForLayout(false); + m_layoutRoot = 0; } - if (!d->m_layoutSchedulingEnabled) + if (!m_layoutSchedulingEnabled) + return; + if (!needsLayout()) return; - if (!m_frame->document() || !m_frame->document()->shouldScheduleLayout()) return; @@ -783,19 +777,19 @@ void FrameView::scheduleRelayout() #else int delay = m_frame->document()->minimumLayoutDelay(); #endif - if (d->m_layoutTimer.isActive() && d->m_delayedLayout && !delay) + if (m_layoutTimer.isActive() && m_delayedLayout && !delay) unscheduleRelayout(); - if (d->m_layoutTimer.isActive()) + if (m_layoutTimer.isActive()) return; - d->m_delayedLayout = delay != 0; + m_delayedLayout = delay != 0; #ifdef INSTRUMENT_LAYOUT_SCHEDULING if (!m_frame->document()->ownerElement()) printf("Scheduling layout for %d\n", delay); #endif - d->m_layoutTimer.startOneShot(delay * 0.001); + m_layoutTimer.startOneShot(delay * 0.001); } static bool isObjectAncestorContainerOf(RenderObject* ancestor, RenderObject* descendant) @@ -811,7 +805,7 @@ void FrameView::scheduleRelayoutOfSubtree(RenderObject* relayoutRoot) { ASSERT(m_frame->view() == this); - if (!d->m_layoutSchedulingEnabled || (m_frame->contentRenderer() + if (!m_layoutSchedulingEnabled || (m_frame->contentRenderer() && m_frame->contentRenderer()->needsLayout())) { if (relayoutRoot) relayoutRoot->markContainingBlocksForLayout(false); @@ -819,19 +813,19 @@ void FrameView::scheduleRelayoutOfSubtree(RenderObject* relayoutRoot) } if (layoutPending()) { - if (d->m_layoutRoot != relayoutRoot) { - if (isObjectAncestorContainerOf(d->m_layoutRoot, relayoutRoot)) { + if (m_layoutRoot != relayoutRoot) { + if (isObjectAncestorContainerOf(m_layoutRoot, relayoutRoot)) { // Keep the current root - relayoutRoot->markContainingBlocksForLayout(false, d->m_layoutRoot); - } else if (d->m_layoutRoot && isObjectAncestorContainerOf(relayoutRoot, d->m_layoutRoot)) { + relayoutRoot->markContainingBlocksForLayout(false, m_layoutRoot); + } else if (m_layoutRoot && isObjectAncestorContainerOf(relayoutRoot, m_layoutRoot)) { // Re-root at relayoutRoot - d->m_layoutRoot->markContainingBlocksForLayout(false, relayoutRoot); - d->m_layoutRoot = relayoutRoot; + m_layoutRoot->markContainingBlocksForLayout(false, relayoutRoot); + m_layoutRoot = relayoutRoot; } else { // Just do a full relayout - if (d->m_layoutRoot) - d->m_layoutRoot->markContainingBlocksForLayout(false); - d->m_layoutRoot = 0; + if (m_layoutRoot) + m_layoutRoot->markContainingBlocksForLayout(false); + m_layoutRoot = 0; relayoutRoot->markContainingBlocksForLayout(false); } } @@ -841,27 +835,31 @@ void FrameView::scheduleRelayoutOfSubtree(RenderObject* relayoutRoot) #else int delay = m_frame->document()->minimumLayoutDelay(); #endif - d->m_layoutRoot = relayoutRoot; - d->m_delayedLayout = delay != 0; - d->m_layoutTimer.startOneShot(delay * 0.001); + m_layoutRoot = relayoutRoot; + m_delayedLayout = delay != 0; + m_layoutTimer.startOneShot(delay * 0.001); } } bool FrameView::layoutPending() const { - return d->m_layoutTimer.isActive(); + return m_layoutTimer.isActive(); } bool FrameView::needsLayout() const { - // It is possible that our document will not have a body yet. If this is the case, - // then we are not allowed to schedule layouts yet, so we won't be pending layout. + // This can return true in cases where the document does not have a body yet. + // Document::shouldScheduleLayout takes care of preventing us from scheduling + // layout in that case. if (!m_frame) return false; RenderView* root = m_frame->contentRenderer(); - Document * doc = m_frame->document(); - // doc->hasChangedChild() condition can occur when using WebKit ObjC interface - return layoutPending() || (root && root->needsLayout()) || d->m_layoutRoot || (doc && doc->hasChangedChild()) || m_frame->needsReapplyStyles(); + Document* document = m_frame->document(); + return layoutPending() + || (root && root->needsLayout()) + || m_layoutRoot + || (document && document->hasChangedChild()) // can occur when using WebKit ObjC interface + || m_frame->needsReapplyStyles(); } void FrameView::setNeedsLayout() @@ -873,7 +871,7 @@ void FrameView::setNeedsLayout() void FrameView::unscheduleRelayout() { - if (!d->m_layoutTimer.isActive()) + if (!m_layoutTimer.isActive()) return; #ifdef INSTRUMENT_LAYOUT_SCHEDULING @@ -881,45 +879,57 @@ void FrameView::unscheduleRelayout() printf("Layout timer unscheduled at %d\n", m_frame->document()->elapsedTime()); #endif - d->m_layoutTimer.stop(); - d->m_delayedLayout = false; + m_layoutTimer.stop(); + m_delayedLayout = false; } bool FrameView::isTransparent() const { - return d->m_isTransparent; + return m_isTransparent; } void FrameView::setTransparent(bool isTransparent) { - d->m_isTransparent = isTransparent; + m_isTransparent = isTransparent; } Color FrameView::baseBackgroundColor() const { - return d->m_baseBackgroundColor; + return m_baseBackgroundColor; } void FrameView::setBaseBackgroundColor(Color bc) { if (!bc.isValid()) bc = Color::white; - d->m_baseBackgroundColor = bc; + m_baseBackgroundColor = bc; +} + +void FrameView::updateBackgroundRecursively(const Color& backgroundColor, bool transparent) +{ + for (Frame* frame = m_frame.get(); frame; frame = frame->tree()->traverseNext(m_frame.get())) { + FrameView* view = frame->view(); + if (!view) + continue; + + view->setTransparent(transparent); + view->setBaseBackgroundColor(backgroundColor); + } } bool FrameView::shouldUpdateWhileOffscreen() const { - return d->m_shouldUpdateWhileOffscreen; + return m_shouldUpdateWhileOffscreen; } void FrameView::setShouldUpdateWhileOffscreen(bool shouldUpdateWhileOffscreen) { - d->m_shouldUpdateWhileOffscreen = shouldUpdateWhileOffscreen; + m_shouldUpdateWhileOffscreen = shouldUpdateWhileOffscreen; } void FrameView::scheduleEvent(PassRefPtr<Event> event, PassRefPtr<EventTargetNode> eventTarget) { - if (!d->m_enqueueEvents) { + if (!m_enqueueEvents) { ExceptionCode ec = 0; eventTarget->dispatchEvent(event, ec); return; @@ -928,34 +938,39 @@ void FrameView::scheduleEvent(PassRefPtr<Event> event, PassRefPtr<EventTargetNod ScheduledEvent* scheduledEvent = new ScheduledEvent; scheduledEvent->m_event = event; scheduledEvent->m_eventTarget = eventTarget; - d->m_scheduledEvents.append(scheduledEvent); + m_scheduledEvents.append(scheduledEvent); } void FrameView::pauseScheduledEvents() { - ASSERT(d->m_scheduledEvents.isEmpty() || d->m_enqueueEvents); - d->m_enqueueEvents++; + ASSERT(m_scheduledEvents.isEmpty() || m_enqueueEvents); + m_enqueueEvents++; } void FrameView::resumeScheduledEvents() { - d->m_enqueueEvents--; - if (!d->m_enqueueEvents) + m_enqueueEvents--; + if (!m_enqueueEvents) dispatchScheduledEvents(); - ASSERT(d->m_scheduledEvents.isEmpty() || d->m_enqueueEvents); + ASSERT(m_scheduledEvents.isEmpty() || m_enqueueEvents); } void FrameView::performPostLayoutTasks() { - if (d->m_firstLayoutCallbackPending) { - d->m_firstLayoutCallbackPending = false; + if (m_firstLayoutCallbackPending) { + m_firstLayoutCallbackPending = false; m_frame->loader()->didFirstLayout(); } - + + if (m_isVisuallyNonEmpty && m_firstVisuallyNonEmptyLayoutCallbackPending) { + m_firstVisuallyNonEmptyLayoutCallbackPending = false; + m_frame->loader()->didFirstVisuallyNonEmptyLayout(); + } + RenderView* root = m_frame->contentRenderer(); root->updateWidgetPositions(); - if (m_widgetUpdateSet && d->m_nestedLayoutCount <= 1) { + if (m_widgetUpdateSet && m_nestedLayoutCount <= 1) { Vector<RenderPartObject*> objectVector; copyToVector(*m_widgetUpdateSet, objectVector); size_t size = objectVector.size(); @@ -976,9 +991,9 @@ void FrameView::performPostLayoutTasks() if (!root->printing()) { IntSize currentSize = IntSize(width(), height()); float currentZoomFactor = root->style()->zoom(); - bool resized = !d->m_firstLayout && (currentSize != d->m_lastLayoutSize || currentZoomFactor != d->m_lastZoomFactor); - d->m_lastLayoutSize = currentSize; - d->m_lastZoomFactor = currentZoomFactor; + bool resized = !m_firstLayout && (currentSize != m_lastLayoutSize || currentZoomFactor != m_lastZoomFactor); + m_lastLayoutSize = currentSize; + m_lastZoomFactor = currentZoomFactor; if (resized) m_frame->sendResizeEvent(); } @@ -991,37 +1006,37 @@ void FrameView::postLayoutTimerFired(Timer<FrameView>*) void FrameView::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow) { - if (!d->m_viewportRenderer) + if (!m_viewportRenderer) return; - if (d->m_overflowStatusDirty) { - d->m_horizontalOverflow = horizontalOverflow; - d->m_verticalOverflow = verticalOverflow; - d->m_overflowStatusDirty = false; + if (m_overflowStatusDirty) { + m_horizontalOverflow = horizontalOverflow; + m_verticalOverflow = verticalOverflow; + m_overflowStatusDirty = false; return; } - bool horizontalOverflowChanged = (d->m_horizontalOverflow != horizontalOverflow); - bool verticalOverflowChanged = (d->m_verticalOverflow != verticalOverflow); + bool horizontalOverflowChanged = (m_horizontalOverflow != horizontalOverflow); + bool verticalOverflowChanged = (m_verticalOverflow != verticalOverflow); if (horizontalOverflowChanged || verticalOverflowChanged) { - d->m_horizontalOverflow = horizontalOverflow; - d->m_verticalOverflow = verticalOverflow; + m_horizontalOverflow = horizontalOverflow; + m_verticalOverflow = verticalOverflow; scheduleEvent(OverflowEvent::create(horizontalOverflowChanged, horizontalOverflow, verticalOverflowChanged, verticalOverflow), - EventTargetNodeCast(d->m_viewportRenderer->element())); + EventTargetNodeCast(m_viewportRenderer->element())); } } void FrameView::dispatchScheduledEvents() { - if (d->m_scheduledEvents.isEmpty()) + if (m_scheduledEvents.isEmpty()) return; - Vector<ScheduledEvent*> scheduledEventsCopy = d->m_scheduledEvents; - d->m_scheduledEvents.clear(); + Vector<ScheduledEvent*> scheduledEventsCopy = m_scheduledEvents; + m_scheduledEvents.clear(); Vector<ScheduledEvent*>::iterator end = scheduledEventsCopy.end(); for (Vector<ScheduledEvent*>::iterator it = scheduledEventsCopy.begin(); it != end; ++it) { @@ -1096,6 +1111,11 @@ void FrameView::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rec invalidateRect(dirtyRect); } +void FrameView::getTickmarks(Vector<IntRect>& tickmarks) const +{ + tickmarks = frame()->document()->renderedRectsForMarkers(DocumentMarker::TextMatch); +} + IntRect FrameView::windowResizerRect() const { Page* page = frame() ? frame()->page() : 0; @@ -1111,7 +1131,7 @@ void FrameView::updateDashboardRegions() if (!document->hasDashboardRegions()) return; Vector<DashboardRegionValue> newRegions; - document->renderer()->collectDashboardRegions(newRegions); + document->renderBox()->collectDashboardRegions(newRegions); if (newRegions == document->dashboardRegions()) return; document->setDashboardRegions(newRegions); @@ -1148,14 +1168,14 @@ void FrameView::updateControlTints() bool FrameView::wasScrolledByUser() const { - return d->m_wasScrolledByUser; + return m_wasScrolledByUser; } void FrameView::setWasScrolledByUser(bool wasScrolledByUser) { - if (d->m_inProgrammaticScroll) + if (m_inProgrammaticScroll) return; - d->m_wasScrolledByUser = wasScrolledByUser; + m_wasScrolledByUser = wasScrolledByUser; } void FrameView::paintContents(GraphicsContext* p, const IntRect& rect) @@ -1175,9 +1195,9 @@ void FrameView::paintContents(GraphicsContext* p, const IntRect& rect) fillWithRed = false; // Subframe, don't fill with red. else if (isTransparent()) fillWithRed = false; // Transparent, don't fill with red. - else if (d->m_paintRestriction == PaintRestrictionSelectionOnly || d->m_paintRestriction == PaintRestrictionSelectionOnlyBlackText) + else if (m_paintRestriction == PaintRestrictionSelectionOnly || m_paintRestriction == PaintRestrictionSelectionOnlyBlackText) fillWithRed = false; // Selections are transparent, don't fill with red. - else if (d->m_nodeToDraw) + else if (m_nodeToDraw) fillWithRed = false; // Element images are transparent, don't fill with red. else fillWithRed = true; @@ -1197,17 +1217,17 @@ void FrameView::paintContents(GraphicsContext* p, const IntRect& rect) } ASSERT(!needsLayout()); - ASSERT(!d->m_isPainting); + ASSERT(!m_isPainting); - d->m_isPainting = true; + m_isPainting = true; // m_nodeToDraw is used to draw only one element (and its descendants) - RenderObject* eltRenderer = d->m_nodeToDraw ? d->m_nodeToDraw->renderer() : 0; - if (d->m_paintRestriction == PaintRestrictionNone) + RenderObject* eltRenderer = m_nodeToDraw ? m_nodeToDraw->renderer() : 0; + if (m_paintRestriction == PaintRestrictionNone) document->invalidateRenderedRectsForMarkersInRect(rect); - contentRenderer->layer()->paint(p, rect, d->m_paintRestriction, eltRenderer); + contentRenderer->layer()->paint(p, rect, m_paintRestriction, eltRenderer); - d->m_isPainting = false; + m_isPainting = false; #if ENABLE(DASHBOARD_SUPPORT) // Regions may have changed as a result of the visibility/z-index of element changing. @@ -1221,17 +1241,17 @@ void FrameView::paintContents(GraphicsContext* p, const IntRect& rect) void FrameView::setPaintRestriction(PaintRestriction pr) { - d->m_paintRestriction = pr; + m_paintRestriction = pr; } bool FrameView::isPainting() const { - return d->m_isPainting; + return m_isPainting; } void FrameView::setNodeToDraw(Node* node) { - d->m_nodeToDraw = node; + m_nodeToDraw = node; } void FrameView::layoutIfNeededRecursive() @@ -1255,4 +1275,4 @@ void FrameView::layoutIfNeededRecursive() static_cast<FrameView*>(*current)->layoutIfNeededRecursive(); } -} +} // namespace WebCore diff --git a/WebCore/page/FrameView.h b/WebCore/page/FrameView.h index 84a829f..a1d514f 100644 --- a/WebCore/page/FrameView.h +++ b/WebCore/page/FrameView.h @@ -4,7 +4,7 @@ (C) 1998, 1999 Torben Weis (weis@kde.org) (C) 1999 Lars Knoll (knoll@kde.org) (C) 1999 Antti Koivisto (koivisto@kde.org) - Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. + Copyright (C) 2004, 2005, 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 @@ -39,11 +39,12 @@ class EventTargetNode; class Frame; class FrameViewPrivate; class IntRect; -class PlatformMouseEvent; class Node; +class PlatformMouseEvent; class RenderLayer; class RenderObject; class RenderPartObject; +class ScheduledEvent; class String; template <typename T> class Timer; @@ -75,6 +76,10 @@ public: virtual void setCanHaveScrollbars(bool); + virtual PassRefPtr<Scrollbar> createScrollbar(ScrollbarOrientation); + + virtual void setContentsSize(const IntSize&); + void layout(bool allowSubtree = true); bool didFirstLayout() const; void layoutTimerFired(Timer<FrameView>*); @@ -84,13 +89,13 @@ public: bool layoutPending() const; RenderObject* layoutRoot(bool onlyDuringLayout = false) const; - int layoutCount() const; + int layoutCount() const { return m_layoutCount; } // These two helper functions just pass through to the RenderView. bool needsLayout() const; void setNeedsLayout(); - bool needsFullRepaint() const; + bool needsFullRepaint() const { return m_doFullRepaint; } void resetScrollbars(); @@ -101,12 +106,14 @@ public: Color baseBackgroundColor() const; void setBaseBackgroundColor(Color); + void updateBackgroundRecursively(const Color&, bool); bool shouldUpdateWhileOffscreen() const; void setShouldUpdateWhileOffscreen(bool); void adjustViewSize(); void initScrollbars(); + void updateDefaultScrollbarState(); virtual IntRect windowClipRect(bool clipToContents = true) const; IntRect windowClipRectForLayer(const RenderLayer*, bool clipToLayerContents) const; @@ -114,7 +121,8 @@ public: virtual bool isActive() const; virtual void invalidateScrollbarRect(Scrollbar*, const IntRect&); virtual void valueChanged(Scrollbar*); - + virtual void getTickmarks(Vector<IntRect>&) const; + virtual IntRect windowResizerRect() const; virtual void scrollRectIntoViewRecursively(const IntRect&); @@ -158,7 +166,10 @@ public: void layoutIfNeededRecursive(); + void setIsVisuallyNonEmpty() { m_isVisuallyNonEmpty = true; } + private: + void reset(); void init(); virtual bool isFrameView() const; @@ -183,9 +194,62 @@ private: IntSize m_margins; OwnPtr<HashSet<RenderPartObject*> > m_widgetUpdateSet; RefPtr<Frame> m_frame; - FrameViewPrivate* d; + + bool m_doFullRepaint; + + ScrollbarMode m_vmode; + ScrollbarMode m_hmode; + bool m_useSlowRepaints; + unsigned m_slowRepaintObjectCount; + + int m_borderX, m_borderY; + + Timer<FrameView> m_layoutTimer; + bool m_delayedLayout; + RenderObject* m_layoutRoot; + + bool m_layoutSchedulingEnabled; + bool m_midLayout; + int m_layoutCount; + unsigned m_nestedLayoutCount; + Timer<FrameView> m_postLayoutTasksTimer; + bool m_firstLayoutCallbackPending; + + bool m_firstLayout; + bool m_needToInitScrollbars; + bool m_isTransparent; + Color m_baseBackgroundColor; + IntSize m_lastLayoutSize; + float m_lastZoomFactor; + + String m_mediaType; + + unsigned m_enqueueEvents; + Vector<ScheduledEvent*> m_scheduledEvents; + + bool m_overflowStatusDirty; + bool m_horizontalOverflow; + bool m_verticalOverflow; + RenderObject* m_viewportRenderer; + + bool m_wasScrolledByUser; + bool m_inProgrammaticScroll; + + unsigned m_deferringRepaints; + unsigned m_repaintCount; + IntRect m_repaintRect; + Vector<IntRect> m_repaintRects; + + bool m_shouldUpdateWhileOffscreen; + + RefPtr<Node> m_nodeToDraw; + PaintRestriction m_paintRestriction; + bool m_isPainting; + + bool m_isVisuallyNonEmpty; + bool m_firstVisuallyNonEmptyLayoutCallbackPending; }; -} +} // namespace WebCore -#endif +#endif // FrameView_h diff --git a/WebCore/page/Geolocation.cpp b/WebCore/page/Geolocation.cpp index a0c9694..f82e95d 100644 --- a/WebCore/page/Geolocation.cpp +++ b/WebCore/page/Geolocation.cpp @@ -47,7 +47,7 @@ void Geolocation::GeoNotifier::timerFired(Timer<GeoNotifier>*) m_timer.stop(); - RefPtr<PositionError> error = PositionError::create(PositionError::TIMEOUT_ERROR, "Timed out"); + RefPtr<PositionError> error = PositionError::create(PositionError::TIMEOUT, "Timed out"); m_errorCallback->handleEvent(error.get()); } @@ -73,7 +73,7 @@ void Geolocation::getCurrentPosition(PassRefPtr<PositionCallback> successCallbac if (!m_service->startUpdating(options)) { if (notifier->m_errorCallback) { - RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_ERROR, "Unable to Start"); + RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, "Unable to Start"); notifier->m_errorCallback->handleEvent(error.get()); } return; @@ -88,7 +88,7 @@ int Geolocation::watchPosition(PassRefPtr<PositionCallback> successCallback, Pas if (!m_service->startUpdating(options)) { if (notifier->m_errorCallback) { - RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_ERROR, "Unable to Start"); + RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, "Unable to Start"); notifier->m_errorCallback->handleEvent(error.get()); } return 0; diff --git a/WebCore/page/MouseEventWithHitTestResults.cpp b/WebCore/page/MouseEventWithHitTestResults.cpp index 0fc8c17..042269c 100644 --- a/WebCore/page/MouseEventWithHitTestResults.cpp +++ b/WebCore/page/MouseEventWithHitTestResults.cpp @@ -27,16 +27,6 @@ namespace WebCore { -static inline Element* targetElement(Node* node) -{ - if (!node) - return 0; - Node* parent = node->parent(); - if (!parent || !parent->isElementNode()) - return 0; - return static_cast<Element*>(parent); -} - MouseEventWithHitTestResults::MouseEventWithHitTestResults(const PlatformMouseEvent& event, const HitTestResult& hitTestResult) : m_event(event) , m_hitTestResult(hitTestResult) @@ -46,10 +36,12 @@ MouseEventWithHitTestResults::MouseEventWithHitTestResults(const PlatformMouseEv Node* MouseEventWithHitTestResults::targetNode() const { Node* node = m_hitTestResult.innerNode(); - if (node && node->inDocument()) + if (!node) + return 0; + if (node->inDocument()) return node; - Element* element = targetElement(node); + Element* element = node->parentElement(); if (element && element->inDocument()) return element; diff --git a/WebCore/page/Navigator.cpp b/WebCore/page/Navigator.cpp index 6045062..429ec00 100644 --- a/WebCore/page/Navigator.cpp +++ b/WebCore/page/Navigator.cpp @@ -30,7 +30,6 @@ #include "Geolocation.h" #include "Language.h" #include "MimeTypeArray.h" -#include "NetworkStateNotifier.h" #include "Page.h" #include "PlatformString.h" #include "PluginArray.h" @@ -38,37 +37,6 @@ #include "ScriptController.h" #include "Settings.h" -#ifndef WEBCORE_NAVIGATOR_PLATFORM -#if PLATFORM(MAC) && PLATFORM(PPC) -#define WEBCORE_NAVIGATOR_PLATFORM "MacPPC" -#elif PLATFORM(MAC) && PLATFORM(X86) -#define WEBCORE_NAVIGATOR_PLATFORM "MacIntel" -#elif PLATFORM(WIN_OS) -#define WEBCORE_NAVIGATOR_PLATFORM "Win32" -#elif PLATFORM(ANDROID) -#define WEBCORE_NAVIGATOR_PLATFORM "Android" -#else -#define WEBCORE_NAVIGATOR_PLATFORM "" -#endif -#endif // ifndef WEBCORE_NAVIGATOR_PLATFORM - -#ifndef WEBCORE_NAVIGATOR_PRODUCT -#define WEBCORE_NAVIGATOR_PRODUCT "Gecko" -#endif // ifndef WEBCORE_NAVIGATOR_PRODUCT - -#ifndef WEBCORE_NAVIGATOR_PRODUCT_SUB -#define WEBCORE_NAVIGATOR_PRODUCT_SUB "20030107" -#endif // ifndef WEBCORE_NAVIGATOR_PRODUCT_SUB - -#ifndef WEBCORE_NAVIGATOR_VENDOR -#define WEBCORE_NAVIGATOR_VENDOR "Apple Computer, Inc." -#endif // ifndef WEBCORE_NAVIGATOR_VENDOR - -#ifndef WEBCORE_NAVIGATOR_VENDOR_SUB -#define WEBCORE_NAVIGATOR_VENDOR_SUB "" -#endif // ifndef WEBCORE_NAVIGATOR_VENDOR_SUB - - namespace WebCore { Navigator::Navigator(Frame* frame) @@ -98,16 +66,6 @@ void Navigator::disconnectFrame() m_frame = 0; } -String Navigator::appCodeName() const -{ - return "Mozilla"; -} - -String Navigator::appName() const -{ - return "Netscape"; -} - // If this function returns true, we need to hide the substring "4." that would otherwise // appear in the appVersion string. This is to avoid problems with old versions of a // library called OpenCube QuickMenu, which as of this writing is still being used on @@ -129,9 +87,7 @@ String Navigator::appVersion() const { if (!m_frame) return String(); - // Version is everything in the user agent string past the "Mozilla/" prefix. - const String& userAgent = m_frame->loader()->userAgent(m_frame->document() ? m_frame->document()->url() : KURL()); - String appVersion = userAgent.substring(userAgent.find('/') + 1); + String appVersion = NavigatorBase::appVersion(); if (shouldHideFourDot(m_frame)) appVersion.replace("4.", "4_"); return appVersion; @@ -149,11 +105,6 @@ String Navigator::userAgent() const return m_frame->loader()->userAgent(m_frame->document() ? m_frame->document()->url() : KURL()); } -String Navigator::platform() const -{ - return WEBCORE_NAVIGATOR_PLATFORM; -} - PluginArray* Navigator::plugins() const { if (!m_plugins) @@ -168,26 +119,6 @@ MimeTypeArray* Navigator::mimeTypes() const return m_mimeTypes.get(); } -String Navigator::product() const -{ - return WEBCORE_NAVIGATOR_PRODUCT; -} - -String Navigator::productSub() const -{ - return WEBCORE_NAVIGATOR_PRODUCT_SUB; -} - -String Navigator::vendor() const -{ - return WEBCORE_NAVIGATOR_VENDOR; -} - -String Navigator::vendorSub() const -{ - return WEBCORE_NAVIGATOR_VENDOR_SUB; -} - bool Navigator::cookieEnabled() const { if (m_frame->page() && !m_frame->page()->cookieEnabled()) @@ -202,11 +133,6 @@ bool Navigator::javaEnabled() const return false; return m_frame->settings()->isJavaEnabled(); } - -bool Navigator::onLine() const -{ - return networkStateNotifier().onLine(); -} Geolocation* Navigator::geolocation() const { diff --git a/WebCore/page/Navigator.h b/WebCore/page/Navigator.h index ea5d780..d50721e 100644 --- a/WebCore/page/Navigator.h +++ b/WebCore/page/Navigator.h @@ -20,6 +20,7 @@ #ifndef Navigator_h #define Navigator_h +#include "NavigatorBase.h" #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> #include <wtf/RefPtr.h> @@ -33,7 +34,7 @@ namespace WebCore { class PluginArray; class String; - class Navigator : public RefCounted<Navigator> { + class Navigator : public NavigatorBase, public RefCounted<Navigator> { public: static PassRefPtr<Navigator> create(Frame* frame) { return adoptRef(new Navigator(frame)); } ~Navigator(); @@ -41,22 +42,15 @@ namespace WebCore { void disconnectFrame(); Frame* frame() const { return m_frame; } - String appCodeName() const; - String appName() const; String appVersion() const; String language() const; - String userAgent() const; - String platform() const; PluginArray* plugins() const; MimeTypeArray* mimeTypes() const; - String product() const; - String productSub() const; - String vendor() const; - String vendorSub() const; bool cookieEnabled() const; bool javaEnabled() const; - bool onLine() const; + virtual String userAgent() const; + Geolocation* geolocation() const; // This is used for GC marking. Geolocation* optionalGeolocation() const { return m_geolocation.get(); } diff --git a/WebCore/page/NavigatorBase.cpp b/WebCore/page/NavigatorBase.cpp new file mode 100644 index 0000000..27c9fdd --- /dev/null +++ b/WebCore/page/NavigatorBase.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "config.h" +#include "NavigatorBase.h" + +#include "NetworkStateNotifier.h" +#include "PlatformString.h" + +#ifndef WEBCORE_NAVIGATOR_PLATFORM +#if PLATFORM(MAC) && PLATFORM(PPC) +#define WEBCORE_NAVIGATOR_PLATFORM "MacPPC" +#elif PLATFORM(MAC) && PLATFORM(X86) +#define WEBCORE_NAVIGATOR_PLATFORM "MacIntel" +#elif PLATFORM(WIN_OS) +#define WEBCORE_NAVIGATOR_PLATFORM "Win32" +#else +#define WEBCORE_NAVIGATOR_PLATFORM "" +#endif +#endif // ifndef WEBCORE_NAVIGATOR_PLATFORM + +#ifndef WEBCORE_NAVIGATOR_PRODUCT +#define WEBCORE_NAVIGATOR_PRODUCT "Gecko" +#endif // ifndef WEBCORE_NAVIGATOR_PRODUCT + +#ifndef WEBCORE_NAVIGATOR_PRODUCT_SUB +#define WEBCORE_NAVIGATOR_PRODUCT_SUB "20030107" +#endif // ifndef WEBCORE_NAVIGATOR_PRODUCT_SUB + +#ifndef WEBCORE_NAVIGATOR_VENDOR +#define WEBCORE_NAVIGATOR_VENDOR "Apple Computer, Inc." +#endif // ifndef WEBCORE_NAVIGATOR_VENDOR + +#ifndef WEBCORE_NAVIGATOR_VENDOR_SUB +#define WEBCORE_NAVIGATOR_VENDOR_SUB "" +#endif // ifndef WEBCORE_NAVIGATOR_VENDOR_SUB + + +namespace WebCore { + +NavigatorBase::~NavigatorBase() +{ +} + +String NavigatorBase::appName() const +{ + return "Netscape"; +} + +String NavigatorBase::appVersion() const +{ + // Version is everything in the user agent string past the "Mozilla/" prefix. + const String& agent = userAgent(); + return agent.substring(agent.find('/') + 1); +} + +String NavigatorBase::platform() const +{ + return WEBCORE_NAVIGATOR_PLATFORM; +} + +String NavigatorBase::appCodeName() const +{ + return "Mozilla"; +} + +String NavigatorBase::product() const +{ + return WEBCORE_NAVIGATOR_PRODUCT; +} + +String NavigatorBase::productSub() const +{ + return WEBCORE_NAVIGATOR_PRODUCT_SUB; +} + +String NavigatorBase::vendor() const +{ + return WEBCORE_NAVIGATOR_VENDOR; +} + +String NavigatorBase::vendorSub() const +{ + return WEBCORE_NAVIGATOR_VENDOR_SUB; +} + +bool NavigatorBase::onLine() const +{ + return networkStateNotifier().onLine(); +} + +} // namespace WebCore diff --git a/WebCore/page/NavigatorBase.h b/WebCore/page/NavigatorBase.h new file mode 100644 index 0000000..4c09f47 --- /dev/null +++ b/WebCore/page/NavigatorBase.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef NavigatorBase_h +#define NavigatorBase_h + +namespace WebCore { + + class String; + + class NavigatorBase { + public: + String appName() const; + String appVersion() const; + virtual String userAgent() const = 0; + String platform() const; + + String appCodeName() const; + String product() const; + String productSub() const; + String vendor() const; + String vendorSub() const; + + bool onLine() const; + + protected: + virtual ~NavigatorBase(); + }; + +} // namespace WebCore + +#endif // NavigatorBase_h diff --git a/WebCore/page/Page.cpp b/WebCore/page/Page.cpp index 3c573d6..460183a 100644 --- a/WebCore/page/Page.cpp +++ b/WebCore/page/Page.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2006, 2007, 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -50,10 +51,9 @@ #include "TextResourceDecoder.h" #include "Widget.h" #include "ScriptController.h" -#include <kjs/collector.h> -#include <runtime/JSLock.h> #include <wtf/HashMap.h> #include <wtf/RefCountedLeakCounter.h> +#include <wtf/StdLibExtras.h> #if ENABLE(DOM_STORAGE) #include "LocalStorage.h" @@ -65,6 +65,10 @@ #include "JavaScriptDebugServer.h" #endif +#if ENABLE(WML) +#include "WMLPageState.h" +#endif + namespace WebCore { static HashSet<Page*>* allPages; @@ -100,7 +104,7 @@ static void networkStateChanged() eventTarget->dispatchEventForType(eventName, false, false); } } - + Page::Page(ChromeClient* chromeClient, ContextMenuClient* contextMenuClient, EditorClient* editorClient, DragClient* dragClient, InspectorClient* inspectorClient) : m_chrome(new Chrome(this, chromeClient)) , m_dragCaretController(new SelectionController(0, true)) @@ -117,6 +121,8 @@ Page::Page(ChromeClient* chromeClient, ContextMenuClient* contextMenuClient, Edi , m_defersLoading(false) , m_inLowQualityInterpolationMode(false) , m_cookieEnabled(true) + , m_areMemoryCacheClientCallsEnabled(true) + , m_mediaVolume(1) , m_parentInspectorController(0) , m_didLoadUserStyleSheet(false) , m_userStyleSheetModificationTime(0) @@ -213,6 +219,11 @@ void Page::goToItem(HistoryItem* item, FrameLoadType type) m_mainFrame->loader()->goToItem(item, type); } +void Page::setGlobalHistoryItem(HistoryItem* item) +{ + m_globalHistoryItem = item; +} + void Page::setGroupName(const String& name) { if (m_group && !m_group->name().isEmpty()) { @@ -232,7 +243,7 @@ void Page::setGroupName(const String& name) const String& Page::groupName() const { - static String nullString; + DEFINE_STATIC_LOCAL(String, nullString, ()); return m_group ? m_group->name() : nullString; } @@ -281,6 +292,8 @@ void Page::refreshPlugins(bool reload) PluginData* Page::pluginData() const { + if (!settings()->arePluginsEnabled()) + return 0; if (!m_pluginData) m_pluginData = PluginData::create(this); return m_pluginData.get(); @@ -381,6 +394,21 @@ void Page::setInLowQualityImageInterpolationMode(bool mode) m_inLowQualityInterpolationMode = mode; } +void Page::setMediaVolume(float volume) +{ + if (volume < 0 || volume > 1) + return; + + if (m_mediaVolume == volume) + return; + + m_mediaVolume = volume; + for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) { + if (frame->document()) + frame->document()->mediaVolumeDidChange(); + } +} + void Page::userStyleSheetLocationChanged() { #if !FRAME_LOADS_USER_STYLESHEET @@ -469,7 +497,7 @@ void Page::allVisitedStateChanged(PageGroup* group) } } -void Page::visitedStateChanged(PageGroup* group, unsigned visitedLinkHash) +void Page::visitedStateChanged(PageGroup* group, LinkHash visitedLinkHash) { ASSERT(group); ASSERT(allPages); @@ -561,6 +589,15 @@ void Page::changePendingBeforeUnloadEventCount(int delta) return; } +#if ENABLE(WML) +WMLPageState* Page::wmlPageState() +{ + if (!m_wmlPageState) + m_wmlPageState.set(new WMLPageState(this)); + return m_wmlPageState.get(); +} +#endif + void Page::setCustomHTMLTokenizerTimeDelay(double customHTMLTokenizerTimeDelay) { if (customHTMLTokenizerTimeDelay < 0) { @@ -579,4 +616,17 @@ void Page::setCustomHTMLTokenizerChunkSize(int customHTMLTokenizerChunkSize) m_customHTMLTokenizerChunkSize = customHTMLTokenizerChunkSize; } +void Page::setMemoryCacheClientCallsEnabled(bool enabled) +{ + if (m_areMemoryCacheClientCallsEnabled == enabled) + return; + + m_areMemoryCacheClientCallsEnabled = enabled; + if (!enabled) + return; + + for (RefPtr<Frame> frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) + frame->loader()->tellClientAboutPastMemoryCacheLoads(); +} + } // namespace WebCore diff --git a/WebCore/page/Page.h b/WebCore/page/Page.h index 9c00ba7..aea16a2 100644 --- a/WebCore/page/Page.h +++ b/WebCore/page/Page.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -24,12 +25,14 @@ #include "Chrome.h" #include "ContextMenuController.h" #include "FrameLoaderTypes.h" +#include "LinkHash.h" #include "PlatformString.h" +#include <wtf/HashSet.h> +#include <wtf/OwnPtr.h> + #if PLATFORM(MAC) #include "SchedulePair.h" #endif -#include <wtf/HashSet.h> -#include <wtf/OwnPtr.h> #if PLATFORM(WIN) || (PLATFORM(WX) && PLATFORM(WIN_OS)) || (PLATFORM(QT) && defined(Q_WS_WIN)) typedef struct HINSTANCE__* HINSTANCE; @@ -63,8 +66,10 @@ namespace WebCore { class SessionStorage; #endif class Settings; +#if ENABLE(WML) + class WMLPageState; +#endif - enum TextCaseSensitivity { TextCaseSensitive, TextCaseInsensitive }; enum FindDirection { FindDirectionForward, FindDirectionBackward }; class Page : Noncopyable { @@ -91,7 +96,10 @@ namespace WebCore { bool goBack(); bool goForward(); void goToItem(HistoryItem*, FrameLoadType); - + + HistoryItem* globalHistoryItem() const { return m_globalHistoryItem.get(); } + void setGlobalHistoryItem(HistoryItem*); + void setGroupName(const String&); const String& groupName() const; @@ -142,6 +150,9 @@ namespace WebCore { bool cookieEnabled() const { return m_cookieEnabled; } void setCookieEnabled(bool enabled) { m_cookieEnabled = enabled; } + float mediaVolume() const { return m_mediaVolume; } + void setMediaVolume(float volume); + void userStyleSheetLocationChanged(); const String& userStyleSheet() const; @@ -163,13 +174,17 @@ namespace WebCore { static void removeAllVisitedLinks(); static void allVisitedStateChanged(PageGroup*); - static void visitedStateChanged(PageGroup*, unsigned visitedHash); + static void visitedStateChanged(PageGroup*, LinkHash visitedHash); #if ENABLE(DOM_STORAGE) SessionStorage* sessionStorage(bool optionalCreate = true); void setSessionStorage(PassRefPtr<SessionStorage>); #endif +#if ENABLE(WML) + WMLPageState* wmlPageState(); +#endif + void setCustomHTMLTokenizerTimeDelay(double); bool hasCustomHTMLTokenizerTimeDelay() const { return m_customHTMLTokenizerTimeDelay != -1; } double customHTMLTokenizerTimeDelay() const { ASSERT(m_customHTMLTokenizerTimeDelay != -1); return m_customHTMLTokenizerTimeDelay; } @@ -178,6 +193,9 @@ namespace WebCore { bool hasCustomHTMLTokenizerChunkSize() const { return m_customHTMLTokenizerChunkSize != -1; } int customHTMLTokenizerChunkSize() const { ASSERT(m_customHTMLTokenizerChunkSize != -1); return m_customHTMLTokenizerChunkSize; } + void setMemoryCacheClientCallsEnabled(bool); + bool areMemoryCacheClientCallsEnabled() const { return m_areMemoryCacheClientCallsEnabled; } + private: void initGroup(); @@ -193,6 +211,8 @@ namespace WebCore { RefPtr<BackForwardList> m_backForwardList; RefPtr<Frame> m_mainFrame; + RefPtr<HistoryItem> m_globalHistoryItem; + mutable RefPtr<PluginData> m_pluginData; EditorClient* m_editorClient; @@ -205,6 +225,8 @@ namespace WebCore { bool m_inLowQualityInterpolationMode; bool m_cookieEnabled; + bool m_areMemoryCacheClientCallsEnabled; + float m_mediaVolume; InspectorController* m_parentInspectorController; @@ -227,9 +249,14 @@ namespace WebCore { #if ENABLE(DOM_STORAGE) RefPtr<SessionStorage> m_sessionStorage; #endif + #if PLATFORM(WIN) || (PLATFORM(WX) && defined(__WXMSW__)) || (PLATFORM(QT) && defined(Q_WS_WIN)) static HINSTANCE s_instanceHandle; #endif + +#if ENABLE(WML) + OwnPtr<WMLPageState> m_wmlPageState; +#endif }; } // namespace WebCore diff --git a/WebCore/page/PageGroup.cpp b/WebCore/page/PageGroup.cpp index 6b72be2..f0951eb 100644 --- a/WebCore/page/PageGroup.cpp +++ b/WebCore/page/PageGroup.cpp @@ -36,6 +36,10 @@ #include "StorageArea.h" #endif +#if PLATFORM(CHROMIUM) +#include "ChromiumBridge.h" +#endif + namespace WebCore { static unsigned getUniqueIdentifier() @@ -117,23 +121,29 @@ void PageGroup::removePage(Page* page) m_pages.remove(page); } -bool PageGroup::isLinkVisited(unsigned visitedLinkHash) +bool PageGroup::isLinkVisited(LinkHash visitedLinkHash) { +#if PLATFORM(CHROMIUM) + // Use Chromium's built-in visited link database. + return ChromiumBridge::isLinkVisited(visitedLinkHash); +#else if (!m_visitedLinksPopulated) { m_visitedLinksPopulated = true; ASSERT(!m_pages.isEmpty()); (*m_pages.begin())->chrome()->client()->populateVisitedLinks(); } return m_visitedLinkHashes.contains(visitedLinkHash); +#endif } -inline void PageGroup::addVisitedLink(unsigned stringHash) +inline void PageGroup::addVisitedLink(LinkHash hash) { ASSERT(shouldTrackVisitedLinks); - unsigned visitedLinkHash = AlreadyHashed::avoidDeletedValue(stringHash); - if (!m_visitedLinkHashes.add(visitedLinkHash).second) +#if !PLATFORM(CHROMIUM) + if (!m_visitedLinkHashes.add(hash).second) return; - Page::visitedStateChanged(this, visitedLinkHash); +#endif + Page::visitedStateChanged(this, hash); } void PageGroup::addVisitedLink(const KURL& url) @@ -141,14 +151,14 @@ void PageGroup::addVisitedLink(const KURL& url) if (!shouldTrackVisitedLinks) return; ASSERT(!url.isEmpty()); - addVisitedLink(url.string().impl()->hash()); + addVisitedLink(visitedLinkHash(url.string().characters(), url.string().length())); } void PageGroup::addVisitedLink(const UChar* characters, size_t length) { if (!shouldTrackVisitedLinks) return; - addVisitedLink(StringImpl::computeHash(characters, length)); + addVisitedLink(visitedLinkHash(characters, length)); } void PageGroup::removeVisitedLinks() diff --git a/WebCore/page/PageGroup.h b/WebCore/page/PageGroup.h index b25892d..097fb87 100644 --- a/WebCore/page/PageGroup.h +++ b/WebCore/page/PageGroup.h @@ -28,6 +28,7 @@ #include <wtf/HashSet.h> #include <wtf/Noncopyable.h> +#include "LinkHash.h" #include "StringHash.h" namespace WebCore { @@ -49,7 +50,7 @@ namespace WebCore { void addPage(Page*); void removePage(Page*); - bool isLinkVisited(unsigned visitedLinkHash); + bool isLinkVisited(LinkHash); void addVisitedLink(const KURL&); void addVisitedLink(const UChar*, size_t); @@ -66,12 +67,13 @@ namespace WebCore { #endif private: - void addVisitedLink(unsigned stringHash); + void addVisitedLink(LinkHash stringHash); String m_name; HashSet<Page*> m_pages; - HashSet<unsigned, AlreadyHashed> m_visitedLinkHashes; + + HashSet<LinkHash, LinkHashHash> m_visitedLinkHashes; bool m_visitedLinksPopulated; unsigned m_identifier; diff --git a/WebCore/page/PositionError.h b/WebCore/page/PositionError.h index 1d68bde..1d31f3b 100644 --- a/WebCore/page/PositionError.h +++ b/WebCore/page/PositionError.h @@ -35,11 +35,10 @@ namespace WebCore { class PositionError : public RefCounted<PositionError> { public: enum ErrorCode { - PERMISSION_ERROR = 1, - LOCATION_PROVIDER_ERROR, - POSITION_NOT_FOUND_ERROR, - TIMEOUT_ERROR, - UNKNOWN_ERROR + UNKNOWN_ERROR = 0, + PERMISSION_DENIED = 1, + POSITION_UNAVAILABLE = 2, + TIMEOUT = 3 }; static PassRefPtr<PositionError> create(ErrorCode code, const String& message) { return adoptRef(new PositionError(code, message)); } diff --git a/WebCore/page/PositionError.idl b/WebCore/page/PositionError.idl index 8c8c335..cb2ef5e 100644 --- a/WebCore/page/PositionError.idl +++ b/WebCore/page/PositionError.idl @@ -28,8 +28,13 @@ module core { interface [ GenerateConstructor ] PositionError { - readonly attribute long code; + readonly attribute unsigned short code; readonly attribute DOMString message; + + const unsigned short UNKNOWN_ERROR = 0; + const unsigned short PERMISSION_DENIED = 1; + const unsigned short POSITION_UNAVAILABLE = 2; + const unsigned short TIMEOUT = 3; }; } diff --git a/WebCore/page/SecurityOrigin.cpp b/WebCore/page/SecurityOrigin.cpp index 6de7508..fd8144f 100644 --- a/WebCore/page/SecurityOrigin.cpp +++ b/WebCore/page/SecurityOrigin.cpp @@ -33,6 +33,7 @@ #include "FrameLoader.h" #include "KURL.h" #include "PlatformString.h" +#include <wtf/StdLibExtras.h> namespace WebCore { @@ -41,7 +42,8 @@ static bool isDefaultPortForProtocol(unsigned short port, const String& protocol if (protocol.isEmpty()) return false; - static HashMap<String, unsigned> defaultPorts; + typedef HashMap<String, unsigned> DefaultPortsMap; + DEFINE_STATIC_LOCAL(DefaultPortsMap, defaultPorts, ()); if (defaultPorts.isEmpty()) { defaultPorts.set("http", 80); defaultPorts.set("https", 443); @@ -94,6 +96,8 @@ bool SecurityOrigin::isEmpty() const PassRefPtr<SecurityOrigin> SecurityOrigin::create(const KURL& url) { + if (!url.isValid()) + return adoptRef(new SecurityOrigin(KURL())); return adoptRef(new SecurityOrigin(url)); } @@ -222,7 +226,7 @@ String SecurityOrigin::toString() const PassRefPtr<SecurityOrigin> SecurityOrigin::createFromString(const String& originString) { - return SecurityOrigin::create(KURL(originString)); + return SecurityOrigin::create(KURL(KURL(), originString)); } static const char SeparatorCharacter = '_'; @@ -260,7 +264,7 @@ PassRefPtr<SecurityOrigin> SecurityOrigin::createFromDatabaseIdentifier(const St String SecurityOrigin::databaseIdentifier() const { - static String separatorString = String(&SeparatorCharacter, 1); + DEFINE_STATIC_LOCAL(String, separatorString, (&SeparatorCharacter, 1)); return m_protocol + separatorString + m_host + separatorString + String::number(m_port); } diff --git a/WebCore/page/Settings.cpp b/WebCore/page/Settings.cpp index b9b3925..8c9bb44 100644 --- a/WebCore/page/Settings.cpp +++ b/WebCore/page/Settings.cpp @@ -33,10 +33,6 @@ #include "PageCache.h" #include <limits> -#if ENABLE(DATABASE) -#include "DatabaseTracker.h" -#endif - namespace WebCore { static void setNeedsReapplyStylesInAllFrames(Page* page) @@ -55,6 +51,7 @@ Settings::Settings(Page* page) , m_layoutAlgorithm(kLayoutFitColumnToScreen) #endif , m_editableLinkBehavior(EditableLinkDefaultBehavior) + , m_textDirectionSubmenuInclusionBehavior(TextDirectionSubmenuAutomaticallyIncluded) , m_minimumFontSize(0) , m_minimumLogicalFontSize(0) , m_defaultFontSize(0) @@ -72,6 +69,8 @@ Settings::Settings(Page* page) , m_loadsImagesAutomatically(false) , m_privateBrowsingEnabled(false) , m_arePluginsEnabled(false) + , m_databasesEnabled(false) + , m_localStorageEnabled(false) , m_isJavaScriptEnabled(false) , m_javaScriptCanOpenWindowsAutomatically(false) , m_shouldPrintBackgrounds(false) @@ -98,6 +97,7 @@ Settings::Settings(Page* page) , m_zoomsTextOnly(false) , m_enforceCSSMIMETypeInStrictMode(true) , m_maximumDecodedImageSize(std::numeric_limits<size_t>::max()) + , m_needsIChatMemoryCacheCallsQuirk(false) { // A Frame may not have been created yet, so we initialize the AtomicString // hash before trying to use it. @@ -231,6 +231,16 @@ void Settings::setPluginsPath(const String& pluginsPath) } #endif +void Settings::setDatabasesEnabled(bool databasesEnabled) +{ + m_databasesEnabled = databasesEnabled; +} + +void Settings::setLocalStorageEnabled(bool localStorageEnabled) +{ + m_localStorageEnabled = localStorageEnabled; +} + void Settings::setPrivateBrowsingEnabled(bool privateBrowsingEnabled) { m_privateBrowsingEnabled = privateBrowsingEnabled; @@ -276,6 +286,11 @@ void Settings::setEditableLinkBehavior(EditableLinkBehavior editableLinkBehavior m_editableLinkBehavior = editableLinkBehavior; } +void Settings::setTextDirectionSubmenuInclusionBehavior(TextDirectionSubmenuInclusionBehavior behavior) +{ + m_textDirectionSubmenuInclusionBehavior = behavior; +} + #if ENABLE(DASHBOARD_SUPPORT) void Settings::setUsesDashboardBackwardCompatibilityMode(bool usesDashboardBackwardCompatibilityMode) { @@ -509,4 +524,9 @@ void Settings::setShouldPaintNativeControls(bool shouldPaintNativeControls) } #endif +void Settings::setNeedsIChatMemoryCacheCallsQuirk(bool needsIChatMemoryCacheCallsQuirk) +{ + m_needsIChatMemoryCacheCallsQuirk = needsIChatMemoryCacheCallsQuirk; +} + } // namespace WebCore diff --git a/WebCore/page/Settings.h b/WebCore/page/Settings.h index 8acc998..b9b888f 100644 --- a/WebCore/page/Settings.h +++ b/WebCore/page/Settings.h @@ -43,6 +43,12 @@ namespace WebCore { EditableLinkNeverLive }; + enum TextDirectionSubmenuInclusionBehavior { + TextDirectionSubmenuNeverIncluded, + TextDirectionSubmenuAutomaticallyIncluded, + TextDirectionSubmenuAlwaysIncluded + }; + class Settings { public: Settings(Page*); @@ -120,6 +126,12 @@ namespace WebCore { const String& pluginsPath() const { return m_pluginsPath; } #endif + void setDatabasesEnabled(bool); + bool databasesEnabled() const { return m_databasesEnabled; } + + void setLocalStorageEnabled(bool); + bool localStorageEnabled() const { return m_localStorageEnabled; } + void setPrivateBrowsingEnabled(bool); bool privateBrowsingEnabled() const { return m_privateBrowsingEnabled; } @@ -137,7 +149,10 @@ namespace WebCore { void setEditableLinkBehavior(EditableLinkBehavior); EditableLinkBehavior editableLinkBehavior() const { return m_editableLinkBehavior; } - + + void setTextDirectionSubmenuInclusionBehavior(TextDirectionSubmenuInclusionBehavior); + TextDirectionSubmenuInclusionBehavior textDirectionSubmenuInclusionBehavior() const { return m_textDirectionSubmenuInclusionBehavior; } + #if ENABLE(DASHBOARD_SUPPORT) void setUsesDashboardBackwardCompatibilityMode(bool); bool usesDashboardBackwardCompatibilityMode() const { return m_usesDashboardBackwardCompatibilityMode; } @@ -230,6 +245,9 @@ namespace WebCore { static bool shouldPaintNativeControls() { return gShouldPaintNativeControls; } #endif + void setNeedsIChatMemoryCacheCallsQuirk(bool); + bool needsIChatMemoryCacheCallsQuirk() const { return m_needsIChatMemoryCacheCallsQuirk; } + private: Page* m_page; @@ -250,6 +268,7 @@ namespace WebCore { LayoutAlgorithm m_layoutAlgorithm; #endif EditableLinkBehavior m_editableLinkBehavior; + TextDirectionSubmenuInclusionBehavior m_textDirectionSubmenuInclusionBehavior; int m_minimumFontSize; int m_minimumLogicalFontSize; int m_defaultFontSize; @@ -289,6 +308,8 @@ namespace WebCore { bool m_loadsImagesAutomatically : 1; bool m_privateBrowsingEnabled : 1; bool m_arePluginsEnabled : 1; + bool m_databasesEnabled : 1; + bool m_localStorageEnabled : 1; bool m_isJavaScriptEnabled : 1; bool m_javaScriptCanOpenWindowsAutomatically : 1; bool m_shouldPrintBackgrounds : 1; @@ -315,6 +336,7 @@ namespace WebCore { bool m_zoomsTextOnly : 1; bool m_enforceCSSMIMETypeInStrictMode : 1; size_t m_maximumDecodedImageSize; + bool m_needsIChatMemoryCacheCallsQuirk : 1; #if USE(SAFARI_THEME) static bool gShouldPaintNativeControls; diff --git a/WebCore/page/WorkerNavigator.cpp b/WebCore/page/WorkerNavigator.cpp new file mode 100644 index 0000000..339f107 --- /dev/null +++ b/WebCore/page/WorkerNavigator.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "config.h" + +#if ENABLE(WORKERS) + +#include "WorkerNavigator.h" + +namespace WebCore { + +WorkerNavigator::WorkerNavigator(const String& userAgent) + : m_userAgent(userAgent) +{ +} + +WorkerNavigator::~WorkerNavigator() +{ +} + +String WorkerNavigator::userAgent() const +{ + return m_userAgent; +} + +} // namespace WebCore + +#endif // ENABLE(WORKERS) diff --git a/WebCore/page/WorkerNavigator.h b/WebCore/page/WorkerNavigator.h new file mode 100644 index 0000000..8ca2fd9 --- /dev/null +++ b/WebCore/page/WorkerNavigator.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef WorkerNavigator_h +#define WorkerNavigator_h + +#if ENABLE(WORKERS) + +#include "NavigatorBase.h" +#include "PlatformString.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + + class WorkerNavigator : public NavigatorBase, public RefCounted<WorkerNavigator> { + public: + static PassRefPtr<WorkerNavigator> create(const String& userAgent) { return adoptRef(new WorkerNavigator(userAgent)); } + virtual ~WorkerNavigator(); + + virtual String userAgent() const; + + private: + WorkerNavigator(const String&); + + String m_userAgent; + }; + +} // namespace WebCore + +#endif // ENABLE(WORKERS) + +#endif // WorkerNavigator_h diff --git a/WebCore/page/WorkerNavigator.idl b/WebCore/page/WorkerNavigator.idl new file mode 100644 index 0000000..195f0bc --- /dev/null +++ b/WebCore/page/WorkerNavigator.idl @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module threads { + + interface [ + Conditional=WORKERS, + NoStaticTables + ] WorkerNavigator { + readonly attribute DOMString appName; + readonly attribute DOMString appVersion; + readonly attribute DOMString platform; + readonly attribute DOMString userAgent; + + readonly attribute boolean onLine; + }; + +} diff --git a/WebCore/page/android/DragControllerAndroid.cpp b/WebCore/page/android/DragControllerAndroid.cpp index ae87f02..7a52b56 100644 --- a/WebCore/page/android/DragControllerAndroid.cpp +++ b/WebCore/page/android/DragControllerAndroid.cpp @@ -46,6 +46,10 @@ DragOperation DragController::dragOperation(DragData* dragData) return DragOperationNone; } +void DragController::cleanupAfterSystemDrag() +{ +} + const float DragController::DragImageAlpha = 1.0f; static IntSize dummy; const IntSize& DragController::maxDragImageSize() { return dummy; } diff --git a/WebCore/page/android/EventHandlerAndroid.cpp b/WebCore/page/android/EventHandlerAndroid.cpp index 62ccd2e..df73fe0 100644 --- a/WebCore/page/android/EventHandlerAndroid.cpp +++ b/WebCore/page/android/EventHandlerAndroid.cpp @@ -39,8 +39,6 @@ namespace WebCore { -unsigned EventHandler::s_accessKeyModifiers = PlatformKeyboardEvent::AltKey; - bool EventHandler::tabsToAllControls(KeyboardEvent* ) const { return true; @@ -124,6 +122,11 @@ PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const return PassRefPtr<Clipboard>(0); } +unsigned EventHandler::accessKeyModifiers() +{ + return PlatformKeyboardEvent::AltKey; +} + const double EventHandler::TextDragDelay = 0.0; } // namespace WebCore diff --git a/WebCore/page/android/InspectorControllerAndroid.cpp b/WebCore/page/android/InspectorControllerAndroid.cpp index 4f55ec4..d6222d7 100644 --- a/WebCore/page/android/InspectorControllerAndroid.cpp +++ b/WebCore/page/android/InspectorControllerAndroid.cpp @@ -78,10 +78,10 @@ void InspectorController::willSendRequest(DocumentLoader*, unsigned long, Resour void InspectorController::didReceiveResponse(DocumentLoader*, unsigned long, ResourceResponse const&) {} void InspectorController::didReceiveContentLength(DocumentLoader*, unsigned long, int) {} void InspectorController::didFinishLoading(DocumentLoader*, unsigned long) {} -void InspectorController::didLoadResourceFromMemoryCache(DocumentLoader*, ResourceRequest const&, ResourceResponse const&, int) {} +void InspectorController::didLoadResourceFromMemoryCache(DocumentLoader*, const CachedResource*) {} void InspectorController::frameDetachedFromParent(Frame*) {} -void InspectorController::addMessageToConsole(MessageSource, MessageLevel, JSC::ExecState*, JSC::ArgList const&, unsigned int, String const&) {} +void InspectorController::addMessageToConsole(MessageSource, MessageLevel, ScriptCallStack*) {} void InspectorController::addMessageToConsole(MessageSource, MessageLevel, const String& message, unsigned lineNumber, const String& sourceID) {} #if ENABLE(DATABASE) void InspectorController::didOpenDatabase(Database*, String const&, String const&, String const&) {} @@ -91,14 +91,14 @@ void InspectorController::inspect(Node*) {} bool InspectorController::windowVisible() { return false; } void InspectorController::addProfile(PassRefPtr<JSC::Profile>, unsigned int, const JSC::UString&) {} void InspectorController::inspectedPageDestroyed() {} -void InspectorController::resourceRetrievedByXMLHttpRequest(unsigned long identifier, JSC::UString& sourceString) {} +void InspectorController::resourceRetrievedByXMLHttpRequest(unsigned long identifier, const JSC::UString& sourceString) {} void InspectorController::inspectedWindowScriptObjectCleared(Frame* frame) {} -void InspectorController::startGroup(MessageSource source, JSC::ExecState* exec, const JSC::ArgList& arguments, unsigned lineNumber, const String& sourceURL) {} +void InspectorController::startGroup(MessageSource source, ScriptCallStack* callFrame) {} void InspectorController::endGroup(MessageSource source, unsigned lineNumber, const String& sourceURL) {} -void InspectorController::startTiming(const JSC::UString& title) {} -bool InspectorController::stopTiming(const JSC::UString& title, double& elapsed) { return false; } -void InspectorController::count(const JSC::UString& title, unsigned lineNumber, const String& sourceID) {} +void InspectorController::startTiming(const String& title) {} +bool InspectorController::stopTiming(const String& title, double& elapsed) { return false; } +void InspectorController::count(const String& title, unsigned lineNumber, const String& sourceID) {} void InspectorController::mouseDidMoveOverElement(const HitTestResult&, unsigned modifierFlags) {} void InspectorController::handleMousePressOnNode(Node*) {} diff --git a/WebCore/page/animation/AnimationBase.cpp b/WebCore/page/animation/AnimationBase.cpp index fc28469..3e43f66 100644 --- a/WebCore/page/animation/AnimationBase.cpp +++ b/WebCore/page/animation/AnimationBase.cpp @@ -30,6 +30,8 @@ #include "AnimationBase.h" #include "AnimationController.h" +#include "CSSMutableStyleDeclaration.h" +#include "CSSPropertyLonghand.h" #include "CSSPropertyNames.h" #include "CString.h" #include "CompositeAnimation.h" @@ -43,13 +45,10 @@ #include "MatrixTransformOperation.h" #include "RenderObject.h" #include "RenderStyle.h" -#include "SystemTime.h" #include "UnitBezier.h" namespace WebCore { -static const double cAnimationTimerDelay = 0.025; - // The epsilon value we pass to UnitBezier::solve given that the animation is going to run over |dur| seconds. The longer the // animation, the more precision we need in the timing function result to avoid ugly discontinuities. static inline double solveEpsilon(double duration) @@ -65,35 +64,34 @@ static inline double solveCubicBezierFunction(double p1x, double p1y, double p2x return bezier.solve(t, solveEpsilon(duration)); } -void AnimationTimerCallback::timerFired(Timer<AnimationTimerBase>*) -{ - m_anim->animationTimerCallbackFired(m_eventType, m_elapsedTime); -} - -static inline int blendFunc(const AnimationBase* anim, int from, int to, double progress) +static inline int blendFunc(const AnimationBase*, int from, int to, double progress) { return int(from + (to - from) * progress); } -static inline double blendFunc(const AnimationBase* anim, double from, double to, double progress) +static inline double blendFunc(const AnimationBase*, double from, double to, double progress) { return from + (to - from) * progress; } -static inline float blendFunc(const AnimationBase* anim, float from, float to, double progress) +static inline float blendFunc(const AnimationBase*, float from, float to, double progress) { return narrowPrecisionToFloat(from + (to - from) * progress); } static inline Color blendFunc(const AnimationBase* anim, const Color& from, const Color& to, double progress) -{ +{ + // We need to preserve the state of the valid flag at the end of the animation + if (progress == 1 && !to.isValid()) + return Color(); + return Color(blendFunc(anim, from.red(), to.red(), progress), blendFunc(anim, from.green(), to.green(), progress), blendFunc(anim, from.blue(), to.blue(), progress), blendFunc(anim, from.alpha(), to.alpha(), progress)); } -static inline Length blendFunc(const AnimationBase* anim, const Length& from, const Length& to, double progress) +static inline Length blendFunc(const AnimationBase*, const Length& from, const Length& to, double progress) { return to.blend(from, progress); } @@ -136,9 +134,9 @@ static inline TransformOperations blendFunc(const AnimationBase* anim, const Tra } } else { // Convert the TransformOperations into matrices - IntSize size = anim->renderer()->borderBox().size(); - AffineTransform fromT; - AffineTransform toT; + IntSize size = anim->renderer()->isBox() ? toRenderBox(anim->renderer())->borderBoxRect().size() : IntSize(); + TransformationMatrix fromT; + TransformationMatrix toT; from.apply(size, fromT); to.apply(size, toT); @@ -162,6 +160,11 @@ static inline EVisibility blendFunc(const AnimationBase* anim, EVisibility from, return result > 0. ? VISIBLE : (to != VISIBLE ? to : from); } +class PropertyWrapperBase; + +static void addShorthandProperties(); +static PropertyWrapperBase* wrapperForProperty(int propertyID); + class PropertyWrapperBase { public: PropertyWrapperBase(int prop) @@ -170,6 +173,8 @@ public: } virtual ~PropertyWrapperBase() { } + + virtual bool isShorthandWrapper() const { return false; } virtual bool equals(const RenderStyle* a, const RenderStyle* b) const = 0; virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const = 0; @@ -296,9 +301,48 @@ private: void (RenderStyle::*m_setter)(const Color&); }; +class ShorthandPropertyWrapper : public PropertyWrapperBase { +public: + ShorthandPropertyWrapper(int property, const CSSPropertyLonghand& longhand) + : PropertyWrapperBase(property) + { + for (unsigned i = 0; i < longhand.length(); ++i) { + PropertyWrapperBase* wrapper = wrapperForProperty(longhand.properties()[i]); + if (wrapper) + m_propertyWrappers.append(wrapper); + } + } + + virtual bool isShorthandWrapper() const { return true; } + + virtual bool equals(const RenderStyle* a, const RenderStyle* b) const + { + Vector<PropertyWrapperBase*>::const_iterator end = m_propertyWrappers.end(); + for (Vector<PropertyWrapperBase*>::const_iterator it = m_propertyWrappers.begin(); it != end; ++it) { + if (!(*it)->equals(a, b)) + return false; + } + return true; + } + + virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const + { + Vector<PropertyWrapperBase*>::const_iterator end = m_propertyWrappers.end(); + for (Vector<PropertyWrapperBase*>::const_iterator it = m_propertyWrappers.begin(); it != end; ++it) + (*it)->blend(anim, dst, a, b, progress); + } + +private: + Vector<PropertyWrapperBase*> m_propertyWrappers; +}; + + static Vector<PropertyWrapperBase*>* gPropertyWrappers = 0; static int gPropertyWrapperMap[numCSSProperties]; +static const int cInvalidPropertyWrapperIndex = -1; + + static void ensurePropertyMap() { // FIXME: This data is never destroyed. Maybe we should ref count it and toss it when the last AnimationController is destroyed? @@ -368,37 +412,122 @@ static void ensurePropertyMap() gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyStrokeOpacity, &RenderStyle::strokeOpacity, &RenderStyle::setStrokeOpacity)); #endif + // TODO: + // + // CSSPropertyBackground, CSSPropertyBackgroundPosition + // CSSPropertyMinWidth, CSSPropertyMaxWidth, CSSPropertyMinHeight, CSSPropertyMaxHeight + // CSSPropertyTextIndent + // CSSPropertyVerticalAlign + // CSSPropertyWebkitBackgroundOrigin + // CSSPropertyWebkitBackgroundSize + // CSSPropertyWebkitMaskPosition + // CSSPropertyWebkitMaskOrigin + // CSSPropertyWebkitMaskSize + // + // Compound properties that have components that should be animatable: + // + // CSSPropertyWebkitColumns + // CSSPropertyWebkitMask + // CSSPropertyWebkitBoxReflect + // Make sure unused slots have a value - for (unsigned int i = 0; i < (unsigned int) numCSSProperties; ++i) - gPropertyWrapperMap[i] = CSSPropertyInvalid; + for (unsigned int i = 0; i < static_cast<unsigned int>(numCSSProperties); ++i) + gPropertyWrapperMap[i] = cInvalidPropertyWrapperIndex; + // First we put the non-shorthand property wrappers into the map, so the shorthand-building + // code can find them. size_t n = gPropertyWrappers->size(); for (unsigned int i = 0; i < n; ++i) { ASSERT((*gPropertyWrappers)[i]->property() - firstCSSProperty < numCSSProperties); gPropertyWrapperMap[(*gPropertyWrappers)[i]->property() - firstCSSProperty] = i; } + + // Now add the shorthand wrappers. + addShorthandProperties(); } } +static void addPropertyWrapper(int propertyID, PropertyWrapperBase* wrapper) +{ + int propIndex = propertyID - firstCSSProperty; + + ASSERT(gPropertyWrapperMap[propIndex] == cInvalidPropertyWrapperIndex); + + unsigned wrapperIndex = gPropertyWrappers->size(); + gPropertyWrappers->append(wrapper); + gPropertyWrapperMap[propIndex] = wrapperIndex; +} + +static void addShorthandProperties() +{ + static const int animatableShorthandProperties[] = { + CSSPropertyBackground, // for background-color + CSSPropertyBorderTop, CSSPropertyBorderRight, CSSPropertyBorderBottom, CSSPropertyBorderLeft, + CSSPropertyBorderColor, + CSSPropertyBorderWidth, + CSSPropertyBorder, + CSSPropertyBorderSpacing, + CSSPropertyMargin, + CSSPropertyOutline, + CSSPropertyPadding, + CSSPropertyWebkitTextStroke, + CSSPropertyWebkitColumnRule, + CSSPropertyWebkitBorderRadius, + CSSPropertyWebkitTransformOrigin + }; + + for (unsigned i = 0; i < sizeof(animatableShorthandProperties) / sizeof(animatableShorthandProperties[0]); ++i) { + int propertyID = animatableShorthandProperties[i]; + CSSPropertyLonghand longhand = longhandForProperty(propertyID); + if (longhand.length() > 0) + addPropertyWrapper(propertyID, new ShorthandPropertyWrapper(propertyID, longhand)); + } + + // 'font' is not in the shorthand map. + static const int animatableFontProperties[] = { + CSSPropertyFontSize, + CSSPropertyFontWeight + }; + + CSSPropertyLonghand fontLonghand(animatableFontProperties, sizeof(animatableFontProperties) / sizeof(animatableFontProperties[0])); + addPropertyWrapper(CSSPropertyFont, new ShorthandPropertyWrapper(CSSPropertyFont, fontLonghand)); +} + +static PropertyWrapperBase* wrapperForProperty(int propertyID) +{ + int propIndex = propertyID - firstCSSProperty; + if (propIndex >= 0 && propIndex < numCSSProperties) { + int wrapperIndex = gPropertyWrapperMap[propIndex]; + if (wrapperIndex >= 0) + return (*gPropertyWrappers)[wrapperIndex]; + } + return 0; +} + AnimationBase::AnimationBase(const Animation* transition, RenderObject* renderer, CompositeAnimation* compAnim) : m_animState(AnimationStateNew) - , m_iteration(0) , m_isAnimating(false) , m_waitedForResponse(false) , m_startTime(0) , m_pauseTime(-1) + , m_requestedStartTime(0) , m_object(renderer) - , m_animationTimerCallback(const_cast<AnimationBase*>(this)) , m_animation(const_cast<Animation*>(transition)) , m_compAnim(compAnim) , m_transformFunctionListValid(false) + , m_nextIterationDuration(-1) + , m_next(0) { + // Compute the total duration + m_totalDuration = -1; + if (m_animation->iterationCount() > 0) + m_totalDuration = m_animation->duration() * m_animation->iterationCount(); } AnimationBase::~AnimationBase() { if (m_animState == AnimationStateStartWaitStyleAvailable) - m_compAnim->setWaitingForStyleAvailable(false); + m_compAnim->removeFromStyleAvailableWaitList(this); } bool AnimationBase::propertiesEqual(int prop, const RenderStyle* a, const RenderStyle* b) @@ -407,27 +536,28 @@ bool AnimationBase::propertiesEqual(int prop, const RenderStyle* a, const Render if (prop == cAnimateAll) { size_t n = gPropertyWrappers->size(); for (unsigned int i = 0; i < n; ++i) { - if (!(*gPropertyWrappers)[i]->equals(a, b)) + PropertyWrapperBase* wrapper = (*gPropertyWrappers)[i]; + // No point comparing shorthand wrappers for 'all'. + if (!wrapper->isShorthandWrapper() && !wrapper->equals(a, b)) return false; } } else { - int propIndex = prop - firstCSSProperty; - - if (propIndex >= 0 && propIndex < numCSSProperties) { - int i = gPropertyWrapperMap[propIndex]; - return i >= 0 ? (*gPropertyWrappers)[i]->equals(a, b) : true; - } + PropertyWrapperBase* wrapper = wrapperForProperty(prop); + if (wrapper) + return wrapper->equals(a, b); } return true; } -int AnimationBase::getPropertyAtIndex(int i) +int AnimationBase::getPropertyAtIndex(int i, bool& isShorthand) { ensurePropertyMap(); if (i < 0 || i >= static_cast<int>(gPropertyWrappers->size())) return CSSPropertyInvalid; - return (*gPropertyWrappers)[i]->property(); + PropertyWrapperBase* wrapper = (*gPropertyWrappers)[i]; + isShorthand = wrapper->isShorthandWrapper(); + return wrapper->property(); } int AnimationBase::getNumProperties() @@ -440,31 +570,12 @@ int AnimationBase::getNumProperties() bool AnimationBase::blendProperties(const AnimationBase* anim, int prop, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) { ASSERT(prop != cAnimateAll); - // FIXME: Why can this happen? - - ensurePropertyMap(); - if (prop == cAnimateAll) { - bool needsTimer = false; - size_t n = gPropertyWrappers->size(); - for (unsigned int i = 0; i < n; ++i) { - PropertyWrapperBase* wrapper = (*gPropertyWrappers)[i]; - if (!wrapper->equals(a, b)) { - wrapper->blend(anim, dst, a, b, progress); - needsTimer = true; - } - } - return needsTimer; - } - - int propIndex = prop - firstCSSProperty; - if (propIndex >= 0 && propIndex < numCSSProperties) { - int i = gPropertyWrapperMap[propIndex]; - if (i >= 0) { - PropertyWrapperBase* wrapper = (*gPropertyWrappers)[i]; - wrapper->blend(anim, dst, a, b, progress); - return true; - } + ensurePropertyMap(); + PropertyWrapperBase* wrapper = wrapperForProperty(prop); + if (wrapper) { + wrapper->blend(anim, dst, a, b, progress); + return true; } return false; @@ -473,7 +584,8 @@ bool AnimationBase::blendProperties(const AnimationBase* anim, int prop, RenderS void AnimationBase::setChanged(Node* node) { ASSERT(!node || (node->document() && !node->document()->inPageCache())); - node->setChanged(AnimationStyleChange); + if (node) + node->setChanged(AnimationStyleChange); } double AnimationBase::duration() const @@ -483,7 +595,7 @@ double AnimationBase::duration() const bool AnimationBase::playStatePlaying() const { - return m_animation && m_animation->playState() == AnimPlayStatePlaying; + return m_animation->playState() == AnimPlayStatePlaying; } bool AnimationBase::animationsMatch(const Animation* anim) const @@ -496,22 +608,25 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) // If we get AnimationStateInputRestartAnimation then we force a new animation, regardless of state. if (input == AnimationStateInputMakeNew) { if (m_animState == AnimationStateStartWaitStyleAvailable) - m_compAnim->setWaitingForStyleAvailable(false); + m_compAnim->removeFromStyleAvailableWaitList(this); m_animState = AnimationStateNew; m_startTime = 0; m_pauseTime = -1; + m_requestedStartTime = 0; + m_nextIterationDuration = -1; m_waitedForResponse = false; endAnimation(false); return; } if (input == AnimationStateInputRestartAnimation) { - cancelTimers(); if (m_animState == AnimationStateStartWaitStyleAvailable) - m_compAnim->setWaitingForStyleAvailable(false); + m_compAnim->removeFromStyleAvailableWaitList(this); m_animState = AnimationStateNew; m_startTime = 0; m_pauseTime = -1; + m_requestedStartTime = 0; + m_nextIterationDuration = -1; endAnimation(false); if (!paused()) @@ -520,9 +635,8 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) } if (input == AnimationStateInputEndAnimation) { - cancelTimers(); if (m_animState == AnimationStateStartWaitStyleAvailable) - m_compAnim->setWaitingForStyleAvailable(false); + m_compAnim->removeFromStyleAvailableWaitList(this); m_animState = AnimationStateDone; endAnimation(true); return; @@ -533,7 +647,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) // If we are in AnimationStateStartWaitResponse, the animation will get canceled before // we get a response, so move to the next state. endAnimation(false); - updateStateMachine(AnimationStateInputStartTimeSet, currentTime()); + updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUpdateTime()); } return; } @@ -551,10 +665,9 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) case AnimationStateNew: ASSERT(input == AnimationStateInputStartAnimation || input == AnimationStateInputPlayStateRunnning || input == AnimationStateInputPlayStatePaused); if (input == AnimationStateInputStartAnimation || input == AnimationStateInputPlayStateRunnning) { - // Set the start timer to the initial delay (0 if no delay) m_waitedForResponse = false; + m_requestedStartTime = beginAnimationUpdateTime(); m_animState = AnimationStateStartWaitTimer; - m_animationTimerCallback.startTimer(m_animation->delay(), eventNames().webkitAnimationStartEvent, m_animation->delay()); } break; case AnimationStateStartWaitTimer: @@ -564,48 +677,36 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) ASSERT(param >= 0); // Start timer has fired, tell the animation to start and wait for it to respond with start time m_animState = AnimationStateStartWaitStyleAvailable; - m_compAnim->setWaitingForStyleAvailable(true); + m_compAnim->addToStyleAvailableWaitList(this); // Trigger a render so we can start the animation - setChanged(m_object->element()); - m_object->animation()->startUpdateRenderingDispatcher(); + if (m_object) + m_object->animation()->addNodeChangeToDispatch(m_object->element()); } else { ASSERT(!paused()); // We're waiting for the start timer to fire and we got a pause. Cancel the timer, pause and wait - m_pauseTime = currentTime(); - cancelTimers(); + m_pauseTime = beginAnimationUpdateTime(); m_animState = AnimationStatePausedWaitTimer; } break; case AnimationStateStartWaitStyleAvailable: ASSERT(input == AnimationStateInputStyleAvailable || input == AnimationStateInputPlayStatePaused); - m_compAnim->setWaitingForStyleAvailable(false); - - if (input == AnimationStateInputStyleAvailable) { - // Start timer has fired, tell the animation to start and wait for it to respond with start time - m_animState = AnimationStateStartWaitResponse; + // Start timer has fired, tell the animation to start and wait for it to respond with start time + m_animState = AnimationStateStartWaitResponse; - overrideAnimations(); + overrideAnimations(); - // Send start event, if needed - onAnimationStart(0); // The elapsedTime is always 0 here + // Send start event, if needed + onAnimationStart(0); // The elapsedTime is always 0 here - // Start the animation - if (overridden() || !startAnimation(0)) { - // We're not going to get a startTime callback, so fire the start time here - m_animState = AnimationStateStartWaitResponse; - updateStateMachine(AnimationStateInputStartTimeSet, currentTime()); - } else - m_waitedForResponse = true; - } else { - ASSERT(!paused()); - // We're waiting for the a notification that the style has been setup. If we're asked to wait - // at this point, the style must have been processed, so we can deal with this like we would - // for WAIT_RESPONSE, except that we don't need to do an endAnimation(). - m_pauseTime = 0; + // Start the animation + if (overridden() || !startAnimation(0)) { + // We're not going to get a startTime callback, so fire the start time here m_animState = AnimationStateStartWaitResponse; - } + updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUpdateTime()); + } else + m_waitedForResponse = true; break; case AnimationStateStartWaitResponse: ASSERT(input == AnimationStateInputStartTimeSet || input == AnimationStateInputPlayStatePaused); @@ -616,16 +717,16 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) if (m_startTime <= 0) m_startTime = param; - // Decide when the end or loop event needs to fire - primeEventTimers(); + // Decide whether to go into looping or ending state + goIntoEndingOrLoopingState(); - // Trigger a render so we can start the animation - setChanged(m_object->element()); - m_object->animation()->startUpdateRenderingDispatcher(); + // Dispatch updateRendering so we can start the animation + if (m_object) + m_object->animation()->addNodeChangeToDispatch(m_object->element()); } else { // We are pausing while waiting for a start response. Cancel the animation and wait. When // we unpause, we will act as though the start timer just fired - m_pauseTime = 0; + m_pauseTime = -1; endAnimation(false); m_animState = AnimationStatePausedWaitResponse; } @@ -637,11 +738,12 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) ASSERT(param >= 0); // Loop timer fired, loop again or end. onAnimationIteration(param); - primeEventTimers(); + + // Decide whether to go into looping or ending state + goIntoEndingOrLoopingState(); } else { // We are pausing while running. Cancel the animation and wait - m_pauseTime = currentTime(); - cancelTimers(); + m_pauseTime = beginAnimationUpdateTime(); endAnimation(false); m_animState = AnimationStatePausedRun; } @@ -654,17 +756,17 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) // End timer fired, finish up onAnimationEnd(param); - resumeOverriddenAnimations(); - - // Fire off another style change so we can set the final value - setChanged(m_object->element()); m_animState = AnimationStateDone; - m_object->animation()->startUpdateRenderingDispatcher(); - // |this| may be deleted here when we've been called from timerFired() + + if (m_object) { + resumeOverriddenAnimations(); + + // Fire off another style change so we can set the final value + m_object->animation()->addNodeChangeToDispatch(m_object->element()); + } } else { // We are pausing while running. Cancel the animation and wait - m_pauseTime = currentTime(); - cancelTimers(); + m_pauseTime = beginAnimationUpdateTime(); endAnimation(false); m_animState = AnimationStatePausedRun; } @@ -674,7 +776,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) ASSERT(input == AnimationStateInputPlayStateRunnning); ASSERT(paused()); // Update the times - m_startTime += currentTime() - m_pauseTime; + m_startTime += beginAnimationUpdateTime() - m_pauseTime; m_pauseTime = -1; // we were waiting for the start timer to fire, go back and wait again @@ -691,7 +793,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) ASSERT(paused()); // Update the times if (m_animState == AnimationStatePausedRun) - m_startTime += currentTime() - m_pauseTime; + m_startTime += beginAnimationUpdateTime() - m_pauseTime; else m_startTime = 0; m_pauseTime = -1; @@ -702,7 +804,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) // Start the animation if (overridden() || !startAnimation(m_startTime)) { // We're not going to get a startTime callback, so fire the start time here - updateStateMachine(AnimationStateInputStartTimeSet, currentTime()); + updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUpdateTime()); } else m_waitedForResponse = true; break; @@ -710,21 +812,53 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) // We're done. Stay in this state until we are deleted break; } - // |this| may be deleted here if we came out of AnimationStateEnding when we've been called from timerFired() } -void AnimationBase::animationTimerCallbackFired(const AtomicString& eventType, double elapsedTime) +void AnimationBase::fireAnimationEventsIfNeeded() { - ASSERT(m_object->document() && !m_object->document()->inPageCache()); + // If we are waiting for the delay time to expire and it has, go to the next state + if (m_animState != AnimationStateStartWaitTimer && m_animState != AnimationStateLooping && m_animState != AnimationStateEnding) + return; - // FIXME: use an enum - if (eventType == eventNames().webkitAnimationStartEvent) - updateStateMachine(AnimationStateInputStartTimerFired, elapsedTime); - else if (eventType == eventNames().webkitAnimationIterationEvent) - updateStateMachine(AnimationStateInputLoopTimerFired, elapsedTime); - else if (eventType == eventNames().webkitAnimationEndEvent) { - updateStateMachine(AnimationStateInputEndTimerFired, elapsedTime); - // |this| may be deleted here + // We have to make sure to keep a ref to the this pointer, because it could get destroyed + // during an animation callback that might get called. Since the owner is a CompositeAnimation + // and it ref counts this object, we will keep a ref to that instead. That way the AnimationBase + // can still access the resources of its CompositeAnimation as needed. + RefPtr<AnimationBase> protector(this); + RefPtr<CompositeAnimation> compProtector(m_compAnim); + + // Check for start timeout + if (m_animState == AnimationStateStartWaitTimer) { + if (beginAnimationUpdateTime() - m_requestedStartTime >= m_animation->delay()) + updateStateMachine(AnimationStateInputStartTimerFired, 0); + return; + } + + double elapsedDuration = beginAnimationUpdateTime() - m_startTime; + ASSERT(elapsedDuration >= 0); + + // Check for end timeout + if (m_totalDuration >= 0 && elapsedDuration >= m_totalDuration) { + // Fire an end event + updateStateMachine(AnimationStateInputEndTimerFired, m_totalDuration); + } + else { + // Check for iteration timeout + if (m_nextIterationDuration < 0) { + // Hasn't been set yet, set it + double durationLeft = m_animation->duration() - fmod(elapsedDuration, m_animation->duration()); + m_nextIterationDuration = elapsedDuration + durationLeft; + } + + if (elapsedDuration >= m_nextIterationDuration) { + // Set to the next iteration + double previous = m_nextIterationDuration; + double durationLeft = m_animation->duration() - fmod(elapsedDuration, m_animation->duration()); + m_nextIterationDuration = elapsedDuration + durationLeft; + + // Send the event + updateStateMachine(AnimationStateInputLoopTimerFired, previous); + } } } @@ -734,14 +868,28 @@ void AnimationBase::updatePlayState(bool run) updateStateMachine(run ? AnimationStateInputPlayStateRunnning : AnimationStateInputPlayStatePaused, -1); } +double AnimationBase::willNeedService() const +{ + // Returns the time at which next service is required. -1 means no service is required. 0 means + // service is required now, and > 0 means service is required that many seconds in the future. + if (paused() || isNew()) + return -1; + + if (m_animState == AnimationStateStartWaitTimer) { + double timeFromNow = m_animation->delay() - (beginAnimationUpdateTime() - m_requestedStartTime); + return (float) ((timeFromNow > 0) ? timeFromNow : 0); + } + + // In all other cases, we need service right away. + return 0; +} + double AnimationBase::progress(double scale, double offset, const TimingFunction* tf) const { if (preActive()) return 0; - double elapsedTime = running() ? (currentTime() - m_startTime) : (m_pauseTime - m_startTime); - if (running() && elapsedTime < 0) - return 0; + double elapsedTime = getElapsedTime(); double dur = m_animation->duration(); if (m_animation->iterationCount() > 0) @@ -778,38 +926,53 @@ double AnimationBase::progress(double scale, double offset, const TimingFunction return result; } -void AnimationBase::primeEventTimers() +void AnimationBase::goIntoEndingOrLoopingState() { // Decide when the end or loop event needs to fire - double ct = currentTime(); - const double elapsedDuration = ct - m_startTime; - ASSERT(elapsedDuration >= 0); - double totalDuration = -1; if (m_animation->iterationCount() > 0) totalDuration = m_animation->duration() * m_animation->iterationCount(); + const double elapsedDuration = beginAnimationUpdateTime() - m_startTime; + ASSERT(elapsedDuration >= 0); double durationLeft = 0; double nextIterationTime = totalDuration; + if (totalDuration < 0 || elapsedDuration < totalDuration) { durationLeft = m_animation->duration() - fmod(elapsedDuration, m_animation->duration()); nextIterationTime = elapsedDuration + durationLeft; } - // At this point, we may have 0 durationLeft, if we've gotten the event late and we are already - // past totalDuration. In this case we still fire an end timer before processing the end. - // This defers the call to sendAnimationEvents to avoid re-entrant calls that destroy - // the RenderObject, and therefore |this| before we're done with it. if (totalDuration < 0 || nextIterationTime < totalDuration) { - // We are not at the end yet, send a loop event + // We are not at the end yet ASSERT(nextIterationTime > 0); m_animState = AnimationStateLooping; - m_animationTimerCallback.startTimer(durationLeft, eventNames().webkitAnimationIterationEvent, nextIterationTime); } else { - // We are at the end, send an end event + // We are at the end m_animState = AnimationStateEnding; - m_animationTimerCallback.startTimer(durationLeft, eventNames().webkitAnimationEndEvent, nextIterationTime); } } +void AnimationBase::pauseAtTime(double t) +{ + updatePlayState(false); + m_pauseTime = m_startTime + t - m_animation->delay(); +} + +double AnimationBase::beginAnimationUpdateTime() const +{ + return m_compAnim->animationController()->beginAnimationUpdateTime(); +} + +double AnimationBase::getElapsedTime() const +{ + if (paused()) + return m_pauseTime - m_startTime; + if (m_startTime <= 0) + return 0; + if (postActive()) + return 1; + return beginAnimationUpdateTime() - m_startTime; +} + } // namespace WebCore diff --git a/WebCore/page/animation/AnimationBase.h b/WebCore/page/animation/AnimationBase.h index 925c0d5..ce16f93 100644 --- a/WebCore/page/animation/AnimationBase.h +++ b/WebCore/page/animation/AnimationBase.h @@ -30,7 +30,6 @@ #define AnimationBase_h #include "AtomicString.h" -#include "Timer.h" #include <wtf/HashMap.h> namespace WebCore { @@ -45,60 +44,6 @@ class RenderObject; class RenderStyle; class TimingFunction; -class AnimationTimerBase { -public: - AnimationTimerBase(AnimationBase* anim) - : m_timer(this, &AnimationTimerBase::timerFired) - , m_anim(anim) - { - m_timer.startOneShot(0); - } - - virtual ~AnimationTimerBase() { } - - void startTimer(double timeout = 0) - { - m_timer.startOneShot(timeout); - } - - void cancelTimer() - { - m_timer.stop(); - } - - virtual void timerFired(Timer<AnimationTimerBase>*) = 0; - -private: - Timer<AnimationTimerBase> m_timer; - -protected: - AnimationBase* m_anim; -}; - -class AnimationTimerCallback : public AnimationTimerBase { -public: - AnimationTimerCallback(AnimationBase* anim) - : AnimationTimerBase(anim) - , m_elapsedTime(0) - { - } - - virtual ~AnimationTimerCallback() { } - - virtual void timerFired(Timer<AnimationTimerBase>*); - - void startTimer(double timeout, const AtomicString& eventType, double elapsedTime) - { - m_eventType = eventType; - m_elapsedTime = elapsedTime; - AnimationTimerBase::startTimer(timeout); - } - -private: - AtomicString m_eventType; - double m_elapsedTime; -}; - class AnimationBase : public RefCounted<AnimationBase> { friend class CompositeAnimationPrivate; @@ -107,14 +52,10 @@ public: virtual ~AnimationBase(); RenderObject* renderer() const { return m_object; } - double startTime() const { return m_startTime; } + void clearRenderer() { m_object = 0; } + double duration() const; - void cancelTimers() - { - m_animationTimerCallback.cancelTimer(); - } - // Animations and Transitions go through the states below. When entering the STARTED state // the animation is started. This may or may not require deferred response from the animator. // If so, we stay in this state until that response is received (and it returns the start time). @@ -176,16 +117,16 @@ 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; } - bool isAnimating() const { return m_isAnimating; } + double willNeedService() const; double progress(double scale, double offset, const TimingFunction*) const; - virtual void animate(CompositeAnimation*, RenderObject*, const RenderStyle* currentStyle, - const RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle) { } + virtual void animate(CompositeAnimation*, RenderObject*, const RenderStyle* /*currentStyle*/, + const RenderStyle* /*targetStyle*/, RefPtr<RenderStyle>& /*animatedStyle*/) { } virtual bool shouldFireEvents() const { return false; } - void animationTimerCallbackFired(const AtomicString& eventType, double elapsedTime); + void fireAnimationEventsIfNeeded(); bool animationsMatch(const Animation*) const; @@ -198,7 +139,7 @@ public: virtual bool overridden() const { return false; } // Does this animation/transition involve the given property? - virtual bool affectsProperty(int property) const { return false; } + virtual bool affectsProperty(int /*property*/) const { return false; } bool isAnimatingProperty(int property, bool isRunningNow) const { if (isRunningNow) @@ -209,6 +150,21 @@ public: bool isTransformFunctionListValid() const { return m_transformFunctionListValid; } + void pauseAtTime(double t); + + double beginAnimationUpdateTime() const; + + double getElapsedTime() const; + + AnimationBase* next() const { return m_next; } + void setNext(AnimationBase* animation) { m_next = animation; } + + void styleAvailable() + { + ASSERT(waitingForStyleAvailable()); + updateStateMachine(AnimationBase::AnimationStateInputStyleAvailable, -1); + } + protected: virtual void overrideAnimations() { } virtual void resumeOverriddenAnimations() { } @@ -216,16 +172,16 @@ protected: CompositeAnimation* compositeAnimation() { return m_compAnim; } // These are called when the corresponding timer fires so subclasses can do any extra work - virtual void onAnimationStart(double elapsedTime) { } - virtual void onAnimationIteration(double elapsedTime) { } - virtual void onAnimationEnd(double elapsedTime) { } - virtual bool startAnimation(double beginTime) { return false; } - virtual void endAnimation(bool reset) { } + virtual void onAnimationStart(double /*elapsedTime*/) { } + virtual void onAnimationIteration(double /*elapsedTime*/) { } + virtual void onAnimationEnd(double /*elapsedTime*/) { } + virtual bool startAnimation(double /*beginTime*/) { return false; } + virtual void endAnimation(bool /*reset*/) { } - void primeEventTimers(); + void goIntoEndingOrLoopingState(); static bool propertiesEqual(int prop, const RenderStyle* a, const RenderStyle* b); - static int getPropertyAtIndex(int); + static int getPropertyAtIndex(int, bool& isShorthand); static int getNumProperties(); // Return true if we need to start software animation timers @@ -233,20 +189,21 @@ protected: static void setChanged(Node*); -protected: AnimState m_animState; - int m_iteration; bool m_isAnimating; // transition/animation requires continual timer firing bool m_waitedForResponse; double m_startTime; double m_pauseTime; + double m_requestedStartTime; RenderObject* m_object; - AnimationTimerCallback m_animationTimerCallback; RefPtr<Animation> m_animation; CompositeAnimation* m_compAnim; bool m_transformFunctionListValid; + double m_totalDuration, m_nextIterationDuration; + + AnimationBase* m_next; }; } // namespace WebCore diff --git a/WebCore/page/animation/AnimationController.cpp b/WebCore/page/animation/AnimationController.cpp index d449afe..f85e6c1 100644 --- a/WebCore/page/animation/AnimationController.cpp +++ b/WebCore/page/animation/AnimationController.cpp @@ -28,27 +28,34 @@ #include "config.h" #include "AnimationController.h" +#include "AnimationBase.h" #include "CompositeAnimation.h" +#include "CSSParser.h" +#include "EventNames.h" #include "Frame.h" #include "Timer.h" +#include <wtf/CurrentTime.h> namespace WebCore { static const double cAnimationTimerDelay = 0.025; +static const double cBeginAnimationUpdateTimeNotSet = -1; class AnimationControllerPrivate { public: AnimationControllerPrivate(Frame*); ~AnimationControllerPrivate(); - CompositeAnimation* accessCompositeAnimation(RenderObject*); + PassRefPtr<CompositeAnimation> accessCompositeAnimation(RenderObject*); bool clear(RenderObject*); void animationTimerFired(Timer<AnimationControllerPrivate>*); - void updateAnimationTimer(); + 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(); } @@ -59,32 +66,65 @@ public: 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*, CompositeAnimation*> RenderObjectAnimationMap; + 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) , m_frame(frame) + , m_beginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet) + , m_styleAvailableWaiters(0) + , m_lastStyleAvailableWaiter(0) { } AnimationControllerPrivate::~AnimationControllerPrivate() { - deleteAllValues(m_compositeAnimations); } -CompositeAnimation* AnimationControllerPrivate::accessCompositeAnimation(RenderObject* renderer) +PassRefPtr<CompositeAnimation> AnimationControllerPrivate::accessCompositeAnimation(RenderObject* renderer) { - CompositeAnimation* animation = m_compositeAnimations.get(renderer); + RefPtr<CompositeAnimation> animation = m_compositeAnimations.get(renderer); if (!animation) { - animation = new CompositeAnimation(m_frame->animation()); + animation = CompositeAnimation::create(m_frame->animation()); m_compositeAnimations.set(renderer, animation); } return animation; @@ -94,44 +134,81 @@ bool AnimationControllerPrivate::clear(RenderObject* renderer) { // Return false if we didn't do anything OR we are suspended (so we don't try to // do a setChanged() when suspended). - CompositeAnimation* animation = m_compositeAnimations.take(renderer); + PassRefPtr<CompositeAnimation> animation = m_compositeAnimations.take(renderer); if (!animation) return false; - animation->resetTransitions(renderer); - bool wasSuspended = animation->isSuspended(); - delete animation; - return !wasSuspended; + animation->clearRenderer(); + return animation->isSuspended(); } -void AnimationControllerPrivate::styleAvailable() +void AnimationControllerPrivate::updateAnimationTimer(bool callSetChanged/* = false*/) { - RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end(); - for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) - it->second->styleAvailable(); -} - -void AnimationControllerPrivate::updateAnimationTimer() -{ - bool isAnimating = false; + double needsService = -1; + bool calledSetChanged = false; RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end(); for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) { - CompositeAnimation* compAnim = it->second; - if (!compAnim->isSuspended() && compAnim->isAnimating()) { - isAnimating = true; - break; + RefPtr<CompositeAnimation> compAnim = it->second; + if (!compAnim->isSuspended() && compAnim->hasAnimations()) { + double t = compAnim->willNeedService(); + if (t != -1 && (t < needsService || needsService == -1)) + needsService = t; + if (needsService == 0) { + if (callSetChanged) { + Node* node = it->first->element(); + ASSERT(!node || (node->document() && !node->document()->inPageCache())); + node->setChanged(AnimationStyleChange); + calledSetChanged = true; + } + else + break; + } } } - if (isAnimating) { - if (!m_animationTimer.isActive()) + if (calledSetChanged) + m_frame->document()->updateRendering(); + + // If we want service immediately, we start a repeating timer to reduce the overhead of starting + if (needsService == 0) { + if (!m_animationTimer.isActive() || m_animationTimer.repeatInterval() == 0) m_animationTimer.startRepeating(cAnimationTimerDelay); - } else if (m_animationTimer.isActive()) + return; + } + + // If we don't need service, we want to make sure the timer is no longer running + if (needsService < 0) { + if (m_animationTimer.isActive()) + m_animationTimer.stop(); + return; + } + + // Otherwise, we want to start a one-shot timer so we get here again + if (m_animationTimer.isActive()) m_animationTimer.stop(); + m_animationTimer.startOneShot(needsService); } void AnimationControllerPrivate::updateRenderingDispatcherFired(Timer<AnimationControllerPrivate>*) { + // fire all the events + Vector<EventToDispatch>::const_iterator eventsToDispatchEnd = m_eventsToDispatch.end(); + for (Vector<EventToDispatch>::const_iterator it = m_eventsToDispatch.begin(); it != eventsToDispatchEnd; ++it) { + if (it->eventType == eventNames().webkitTransitionEndEvent) + it->element->dispatchWebKitTransitionEvent(it->eventType,it->name, it->elapsedTime); + else + it->element->dispatchWebKitAnimationEvent(it->eventType,it->name, it->elapsedTime); + } + + m_eventsToDispatch.clear(); + + // call setChanged on all the elements + Vector<RefPtr<Node> >::const_iterator nodeChangesToDispatchEnd = m_nodeChangesToDispatch.end(); + for (Vector<RefPtr<Node> >::const_iterator it = m_nodeChangesToDispatch.begin(); it != nodeChangesToDispatchEnd; ++it) + (*it)->setChanged(AnimationStyleChange); + + m_nodeChangesToDispatch.clear(); + if (m_frame && m_frame->document()) m_frame->document()->updateRendering(); } @@ -142,32 +219,38 @@ void AnimationControllerPrivate::startUpdateRenderingDispatcher() m_updateRenderingDispatcher.startOneShot(0); } -void AnimationControllerPrivate::animationTimerFired(Timer<AnimationControllerPrivate>* timer) +void AnimationControllerPrivate::addEventToDispatch(PassRefPtr<Element> element, const AtomicString& eventType, const String& name, double elapsedTime) { - // When the timer fires, all we do is call setChanged on all DOM nodes with running animations and then do an immediate - // updateRendering. It will then call back to us with new information. - bool isAnimating = false; - RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end(); - for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) { - CompositeAnimation* compAnim = it->second; - if (!compAnim->isSuspended() && compAnim->isAnimating()) { - isAnimating = true; - compAnim->setAnimating(false); - - Node* node = it->first->element(); - ASSERT(!node || (node->document() && !node->document()->inPageCache())); - node->setChanged(AnimationStyleChange); - } - } + m_eventsToDispatch.grow(m_eventsToDispatch.size()+1); + EventToDispatch& event = m_eventsToDispatch[m_eventsToDispatch.size()-1]; + event.element = element; + event.eventType = eventType; + event.name = name; + event.elapsedTime = elapsedTime; + + startUpdateRenderingDispatcher(); +} + +void AnimationControllerPrivate::addNodeChangeToDispatch(PassRefPtr<Node> node) +{ + m_nodeChangesToDispatch.append(node); + startUpdateRenderingDispatcher(); +} - m_frame->document()->updateRendering(); +void AnimationControllerPrivate::animationTimerFired(Timer<AnimationControllerPrivate>*) +{ + // Make sure animationUpdateTime is updated, so that it is current even if no + // styleChange has happened (e.g. hardware animations) + setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet); - updateAnimationTimer(); + // When the timer fires, all we do is call setChanged on all DOM nodes with running animations and then do an immediate + // updateRendering. It will then call back to us with new information. + updateAnimationTimer(true); } bool AnimationControllerPrivate::isAnimatingPropertyOnRenderer(RenderObject* renderer, int property, bool isRunningNow) const { - CompositeAnimation* animation = m_compositeAnimations.get(renderer); + RefPtr<CompositeAnimation> animation = m_compositeAnimations.get(renderer); if (!animation) return false; @@ -179,7 +262,7 @@ void AnimationControllerPrivate::suspendAnimations(Document* document) RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end(); for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) { RenderObject* renderer = it->first; - CompositeAnimation* compAnim = it->second; + RefPtr<CompositeAnimation> compAnim = it->second; if (renderer->document() == document) compAnim->suspendAnimations(); } @@ -192,7 +275,7 @@ void AnimationControllerPrivate::resumeAnimations(Document* document) RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end(); for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) { RenderObject* renderer = it->first; - CompositeAnimation* compAnim = it->second; + RefPtr<CompositeAnimation> compAnim = it->second; if (renderer->document() == document) compAnim->resumeAnimations(); } @@ -200,9 +283,96 @@ void AnimationControllerPrivate::resumeAnimations(Document* document) updateAnimationTimer(); } +bool AnimationControllerPrivate::pauseAnimationAtTime(RenderObject* renderer, const String& name, double t) +{ + if (!renderer) + return false; + + RefPtr<CompositeAnimation> compAnim = accessCompositeAnimation(renderer); + if (!compAnim) + return false; + + if (compAnim->pauseAnimationAtTime(name, t)) { + renderer->node()->setChanged(AnimationStyleChange); + return true; + } + + return false; +} + +bool AnimationControllerPrivate::pauseTransitionAtTime(RenderObject* renderer, const String& property, double t) +{ + if (!renderer) + return false; + + RefPtr<CompositeAnimation> compAnim = accessCompositeAnimation(renderer); + if (!compAnim) + return false; + + if (compAnim->pauseTransitionAtTime(cssPropertyID(property), t)) { + renderer->node()->setChanged(AnimationStyleChange); + return true; + } + + return false; +} + +unsigned AnimationControllerPrivate::numberOfActiveAnimations() const +{ + unsigned count = 0; + + RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end(); + for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) { + CompositeAnimation* compAnim = it->second.get(); + count += compAnim->numberOfActiveAnimations(); + } + + return count; +} + +void AnimationControllerPrivate::addToStyleAvailableWaitList(AnimationBase* animation) +{ + ASSERT(!animation->next()); + + if (m_styleAvailableWaiters) + m_lastStyleAvailableWaiter->setNext(animation); + else + m_styleAvailableWaiters = animation; + + m_lastStyleAvailableWaiter = animation; + animation->setNext(0); +} + +void AnimationControllerPrivate::removeFromStyleAvailableWaitList(AnimationBase* animationToRemove) +{ + AnimationBase* prevAnimation = 0; + for (AnimationBase* animation = m_styleAvailableWaiters; animation; animation = animation->next()) { + if (animation == animationToRemove) { + if (prevAnimation) + prevAnimation->setNext(animation->next()); + else + m_styleAvailableWaiters = animation->next(); + + if (m_lastStyleAvailableWaiter == animation) + m_lastStyleAvailableWaiter = prevAnimation; + + animationToRemove->setNext(0); + } + } +} + +void AnimationControllerPrivate::styleAvailable() +{ + // Go through list of waiters and send them on their way + for (AnimationBase* animation = m_styleAvailableWaiters; animation; animation = animation->next()) + animation->styleAvailable(); + + m_styleAvailableWaiters = 0; + m_lastStyleAvailableWaiter = 0; +} + AnimationController::AnimationController(Frame* frame) : m_data(new AnimationControllerPrivate(frame)) - , m_numStyleAvailableWaiters(0) { } @@ -224,7 +394,7 @@ void AnimationController::cancelAnimations(RenderObject* renderer) } PassRefPtr<RenderStyle> AnimationController::updateAnimations(RenderObject* renderer, RenderStyle* newStyle) -{ +{ // Don't do anything if we're in the cache if (!renderer->document() || renderer->document()->inPageCache()) return newStyle; @@ -240,7 +410,7 @@ PassRefPtr<RenderStyle> AnimationController::updateAnimations(RenderObject* rend // a new style. ASSERT(renderer->element()); // FIXME: We do not animate generated content yet. - CompositeAnimation* rendererAnimations = m_data->accessCompositeAnimation(renderer); + RefPtr<CompositeAnimation> rendererAnimations = m_data->accessCompositeAnimation(renderer); RefPtr<RenderStyle> blendedStyle = rendererAnimations->animate(renderer, oldStyle, newStyle); m_data->updateAnimationTimer(); @@ -257,16 +427,31 @@ PassRefPtr<RenderStyle> AnimationController::updateAnimations(RenderObject* rend void AnimationController::setAnimationStartTime(RenderObject* renderer, double t) { - CompositeAnimation* rendererAnimations = m_data->accessCompositeAnimation(renderer); + RefPtr<CompositeAnimation> rendererAnimations = m_data->accessCompositeAnimation(renderer); rendererAnimations->setAnimationStartTime(t); } void AnimationController::setTransitionStartTime(RenderObject* renderer, int property, double t) { - CompositeAnimation* rendererAnimations = m_data->accessCompositeAnimation(renderer); + RefPtr<CompositeAnimation> rendererAnimations = m_data->accessCompositeAnimation(renderer); rendererAnimations->setTransitionStartTime(property, t); } +bool AnimationController::pauseAnimationAtTime(RenderObject* renderer, const String& name, double t) +{ + return m_data->pauseAnimationAtTime(renderer, name, t); +} + +unsigned AnimationController::numberOfActiveAnimations() const +{ + return m_data->numberOfActiveAnimations(); +} + +bool AnimationController::pauseTransitionAtTime(RenderObject* renderer, const String& property, double t) +{ + return m_data->pauseTransitionAtTime(renderer, property, t); +} + bool AnimationController::isAnimatingPropertyOnRenderer(RenderObject* renderer, int property, bool isRunningNow) const { return m_data->isAnimatingPropertyOnRenderer(renderer, property, isRunningNow); @@ -287,12 +472,41 @@ void AnimationController::startUpdateRenderingDispatcher() m_data->startUpdateRenderingDispatcher(); } -void AnimationController::styleAvailable() +void AnimationController::addEventToDispatch(PassRefPtr<Element> element, const AtomicString& eventType, const String& name, double elapsedTime) { - if (!m_numStyleAvailableWaiters) - return; + 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); +} + +void AnimationController::endAnimationUpdate() +{ m_data->styleAvailable(); } +void AnimationController::addToStyleAvailableWaitList(AnimationBase* animation) +{ + m_data->addToStyleAvailableWaitList(animation); +} + +void AnimationController::removeFromStyleAvailableWaitList(AnimationBase* animation) +{ + m_data->removeFromStyleAvailableWaitList(animation); +} + } // namespace WebCore diff --git a/WebCore/page/animation/AnimationController.h b/WebCore/page/animation/AnimationController.h index bc13a2a..13ea1bd 100644 --- a/WebCore/page/animation/AnimationController.h +++ b/WebCore/page/animation/AnimationController.h @@ -33,11 +33,16 @@ namespace WebCore { +class AnimationBase; class AnimationControllerPrivate; +class AtomicString; class Document; +class Element; class Frame; +class Node; class RenderObject; class RenderStyle; +class String; class AnimationController { public: @@ -50,27 +55,29 @@ public: void setAnimationStartTime(RenderObject*, double t); void setTransitionStartTime(RenderObject*, int property, double t); + bool pauseAnimationAtTime(RenderObject*, const String& name, double t); // To be used only for testing + bool pauseTransitionAtTime(RenderObject*, const String& property, double t); // To be used only for testing + unsigned numberOfActiveAnimations() const; // To be used only for testing + bool isAnimatingPropertyOnRenderer(RenderObject*, int property, bool isRunningNow) const; void suspendAnimations(Document*); void resumeAnimations(Document*); - void updateAnimationTimer(); void startUpdateRenderingDispatcher(); + void addEventToDispatch(PassRefPtr<Element>, const AtomicString& eventType, const String& name, double elapsedTime); + void addNodeChangeToDispatch(PassRefPtr<Node>); - void styleAvailable(); + void addToStyleAvailableWaitList(AnimationBase*); + void removeFromStyleAvailableWaitList(AnimationBase*); - void setWaitingForStyleAvailable(bool waiting) - { - if (waiting) - m_numStyleAvailableWaiters++; - else - m_numStyleAvailableWaiters--; - } + double beginAnimationUpdateTime(); + + void beginAnimationUpdate(); + void endAnimationUpdate(); private: AnimationControllerPrivate* m_data; - unsigned m_numStyleAvailableWaiters; }; } // namespace WebCore diff --git a/WebCore/page/animation/CompositeAnimation.cpp b/WebCore/page/animation/CompositeAnimation.cpp index 2ae68d9..bf61b78 100644 --- a/WebCore/page/animation/CompositeAnimation.cpp +++ b/WebCore/page/animation/CompositeAnimation.cpp @@ -50,15 +50,16 @@ public: ~CompositeAnimationPrivate(); + void clearRenderer(); + PassRefPtr<RenderStyle> animate(RenderObject*, RenderStyle* currentStyle, RenderStyle* targetStyle); + AnimationController* animationController() { return m_animationController; } + void setAnimating(bool); - bool isAnimating() const; + double willNeedService() const; - const KeyframeAnimation* getAnimationForProperty(int property) const; - - void resetTransitions(RenderObject*); - void resetAnimations(RenderObject*); + PassRefPtr<KeyframeAnimation> getAnimationForProperty(int property); void cleanupFinishedAnimations(RenderObject*); @@ -72,11 +73,16 @@ public: void overrideImplicitAnimations(int property); void resumeOverriddenImplicitAnimations(int property); - void styleAvailable(); + bool hasAnimations() const { return !m_transitions.isEmpty() || !m_keyframeAnimations.isEmpty(); } bool isAnimatingProperty(int property, bool isRunningNow) const; - void setWaitingForStyleAvailable(bool); + void addToStyleAvailableWaitList(AnimationBase*); + void removeFromStyleAvailableWaitList(AnimationBase*); + + bool pauseAnimationAtTime(const AtomicString& name, double t); + bool pauseTransitionAtTime(int property, double t); + unsigned numberOfActiveAnimations() const; protected: void updateTransitions(RenderObject*, RenderStyle* currentStyle, RenderStyle* targetStyle); @@ -96,9 +102,30 @@ private: CompositeAnimationPrivate::~CompositeAnimationPrivate() { + // Toss the refs to all animations m_transitions.clear(); m_keyframeAnimations.clear(); } + +void CompositeAnimationPrivate::clearRenderer() +{ + if (!m_transitions.isEmpty()) { + // Clear the renderers from all running animations, in case we are in the middle of + // an animation callback (see https://bugs.webkit.org/show_bug.cgi?id=22052) + CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end(); + for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) { + ImplicitAnimation* transition = it->second.get(); + transition->clearRenderer(); + } + } + if (!m_keyframeAnimations.isEmpty()) { + AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end(); + for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) { + KeyframeAnimation* anim = it->second.get(); + anim->clearRenderer(); + } + } +} void CompositeAnimationPrivate::updateTransitions(RenderObject* renderer, RenderStyle* currentStyle, RenderStyle* targetStyle) { @@ -122,17 +149,20 @@ void CompositeAnimationPrivate::updateTransitions(RenderObject* renderer, Render // through the loop. for (int propertyIndex = 0; propertyIndex < AnimationBase::getNumProperties(); ++propertyIndex) { if (all) { - // Get the next property - prop = AnimationBase::getPropertyAtIndex(propertyIndex); + // Get the next property which is not a shorthand. + bool isShorthand; + prop = AnimationBase::getPropertyAtIndex(propertyIndex, isShorthand); + if (isShorthand) + continue; } // ImplicitAnimations are always hashed by actual properties, never cAnimateAll - ASSERT(prop > firstCSSProperty && prop < (firstCSSProperty + numCSSProperties)); + ASSERT(prop >= firstCSSProperty && prop < (firstCSSProperty + numCSSProperties)); // If there is a running animation for this property, the transition is overridden // and we have to use the unanimatedStyle from the animation. We do the test // against the unanimated style here, but we "override" the transition later. - const KeyframeAnimation* keyframeAnim = getAnimationForProperty(prop); + RefPtr<KeyframeAnimation> keyframeAnim = getAnimationForProperty(prop); RenderStyle* fromStyle = keyframeAnim ? keyframeAnim->unanimatedStyle() : currentStyle; // See if there is a current transition for this prop @@ -140,14 +170,12 @@ void CompositeAnimationPrivate::updateTransitions(RenderObject* renderer, Render bool equal = true; if (implAnim) { - // This implAnim might not be an already running transition. It might be - // newly added to the list in a previous iteration. This would happen if - // you have both an explicit transition-property and 'all' in the same - // list. In this case, the latter one overrides the earlier one, so we - // behave as though this is a running animation being replaced. - if (!isActiveTransition) - m_transitions.remove(prop); - else if (!implAnim->isTargetPropertyEqual(prop, targetStyle)) { + // This implAnim might not be an already running transition. It might be + // newly added to the list in a previous iteration. This would happen if + // you have both an explicit transition-property and 'all' in the same + // list. In this case, the latter one overrides the earlier one, so we + // behave as though this is a running animation being replaced. + if (!implAnim->isTargetPropertyEqual(prop, targetStyle)) { m_transitions.remove(prop); equal = false; } @@ -239,10 +267,12 @@ PassRefPtr<RenderStyle> CompositeAnimationPrivate::animate(RenderObject* rendere if (currentStyle) { // Now that we have transition objects ready, let them know about the new goal state. We want them // to fill in a RenderStyle*& only if needed. - CSSPropertyTransitionsMap::const_iterator end = m_transitions.end(); - for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) { - if (ImplicitAnimation* anim = it->second.get()) - anim->animate(m_compositeAnimation, renderer, currentStyle, targetStyle, resultStyle); + if (!m_transitions.isEmpty()) { + CSSPropertyTransitionsMap::const_iterator end = m_transitions.end(); + for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) { + if (ImplicitAnimation* anim = it->second.get()) + anim->animate(m_compositeAnimation, renderer, currentStyle, targetStyle, resultStyle); + } } } @@ -269,123 +299,139 @@ PassRefPtr<RenderStyle> CompositeAnimationPrivate::animate(RenderObject* rendere // "animating" means that something is running that requires the timer to keep firing void CompositeAnimationPrivate::setAnimating(bool animating) { - CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end(); - for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) { - ImplicitAnimation* transition = it->second.get(); - transition->setAnimating(animating); + if (!m_transitions.isEmpty()) { + CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end(); + for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) { + ImplicitAnimation* transition = it->second.get(); + transition->setAnimating(animating); + } } - - AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end(); - for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) { - KeyframeAnimation* anim = it->second.get(); - anim->setAnimating(animating); + if (!m_keyframeAnimations.isEmpty()) { + AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end(); + for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) { + KeyframeAnimation* anim = it->second.get(); + anim->setAnimating(animating); + } } } -bool CompositeAnimationPrivate::isAnimating() const +double CompositeAnimationPrivate::willNeedService() const { - CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end(); - for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) { - ImplicitAnimation* transition = it->second.get(); - if (transition && transition->isAnimating() && transition->running()) - return true; + // Returns the time at which next service is required. -1 means no service is required. 0 means + // service is required now, and > 0 means service is required that many seconds in the future. + double minT = -1; + + if (!m_transitions.isEmpty()) { + CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end(); + for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) { + ImplicitAnimation* transition = it->second.get(); + double t = transition ? transition->willNeedService() : -1; + if (t < minT || minT == -1) + minT = t; + if (minT == 0) + return 0; + } } - - AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end(); - for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) { - KeyframeAnimation* anim = it->second.get(); - if (anim && !anim->paused() && anim->isAnimating() && anim->active()) - return true; + if (!m_keyframeAnimations.isEmpty()) { + AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end(); + for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) { + KeyframeAnimation* animation = it->second.get(); + double t = animation ? animation->willNeedService() : -1; + if (t < minT || minT == -1) + minT = t; + if (minT == 0) + return 0; + } } - return false; + return minT; } -const KeyframeAnimation* CompositeAnimationPrivate::getAnimationForProperty(int property) const +PassRefPtr<KeyframeAnimation> CompositeAnimationPrivate::getAnimationForProperty(int property) { - const KeyframeAnimation* retval = 0; + RefPtr<KeyframeAnimation> retval; // We want to send back the last animation with the property if there are multiples. // So we need to iterate through all animations - AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end(); - for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) { - const KeyframeAnimation* anim = it->second.get(); - if (anim->hasAnimationForProperty(property)) - retval = anim; + if (!m_keyframeAnimations.isEmpty()) { + AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end(); + for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) { + RefPtr<KeyframeAnimation> anim = it->second; + if (anim->hasAnimationForProperty(property)) + retval = anim; + } } return retval; } -void CompositeAnimationPrivate::resetTransitions(RenderObject* renderer) -{ - m_transitions.clear(); -} - -void CompositeAnimationPrivate::resetAnimations(RenderObject*) -{ - m_keyframeAnimations.clear(); -} - -void CompositeAnimationPrivate::cleanupFinishedAnimations(RenderObject* renderer) +void CompositeAnimationPrivate::cleanupFinishedAnimations(RenderObject*) { if (isSuspended()) return; // Make a list of transitions to be deleted Vector<int> finishedTransitions; - CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end(); + if (!m_transitions.isEmpty()) { + CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end(); - for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) { - ImplicitAnimation* anim = it->second.get(); - if (!anim) - continue; - if (anim->postActive()) - finishedTransitions.append(anim->animatingProperty()); + for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) { + ImplicitAnimation* anim = it->second.get(); + if (!anim) + continue; + if (anim->postActive()) + finishedTransitions.append(anim->animatingProperty()); + } + + // Delete them + size_t finishedTransitionCount = finishedTransitions.size(); + for (size_t i = 0; i < finishedTransitionCount; ++i) + m_transitions.remove(finishedTransitions[i]); } - // Delete them - size_t finishedTransitionCount = finishedTransitions.size(); - for (size_t i = 0; i < finishedTransitionCount; ++i) - m_transitions.remove(finishedTransitions[i]); - // Make a list of animations to be deleted Vector<AtomicStringImpl*> finishedAnimations; - AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end(); + if (!m_keyframeAnimations.isEmpty()) { + AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end(); - for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) { - KeyframeAnimation* anim = it->second.get(); - if (!anim) - continue; - if (anim->postActive()) - finishedAnimations.append(anim->name().impl()); - } + for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) { + KeyframeAnimation* anim = it->second.get(); + if (!anim) + continue; + if (anim->postActive()) + finishedAnimations.append(anim->name().impl()); + } - // Delete them - size_t finishedAnimationCount = finishedAnimations.size(); - for (size_t i = 0; i < finishedAnimationCount; ++i) - m_keyframeAnimations.remove(finishedAnimations[i]); + // Delete them + size_t finishedAnimationCount = finishedAnimations.size(); + for (size_t i = 0; i < finishedAnimationCount; ++i) + m_keyframeAnimations.remove(finishedAnimations[i]); + } } void CompositeAnimationPrivate::setAnimationStartTime(double t) { // Set start time on all animations waiting for it - AnimationNameMap::const_iterator end = m_keyframeAnimations.end(); - for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != end; ++it) { - KeyframeAnimation* anim = it->second.get(); - if (anim && anim->waitingForStartTime()) - anim->updateStateMachine(AnimationBase::AnimationStateInputStartTimeSet, t); + 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 - 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); + 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); + } } } @@ -396,17 +442,20 @@ void CompositeAnimationPrivate::suspendAnimations() m_isSuspended = true; - AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end(); - for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) { - if (KeyframeAnimation* anim = it->second.get()) - anim->updatePlayState(false); + if (!m_keyframeAnimations.isEmpty()) { + AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end(); + for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) { + if (KeyframeAnimation* anim = it->second.get()) + anim->updatePlayState(false); + } } - - CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end(); - for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) { - ImplicitAnimation* anim = it->second.get(); - if (anim && anim->hasStyle()) - anim->updatePlayState(false); + if (!m_transitions.isEmpty()) { + CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end(); + for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) { + ImplicitAnimation* anim = it->second.get(); + if (anim && anim->hasStyle()) + anim->updatePlayState(false); + } } } @@ -417,98 +466,139 @@ void CompositeAnimationPrivate::resumeAnimations() m_isSuspended = false; - AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end(); - for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) { - KeyframeAnimation* anim = it->second.get(); - if (anim && anim->playStatePlaying()) - anim->updatePlayState(true); + if (!m_keyframeAnimations.isEmpty()) { + AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end(); + for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) { + KeyframeAnimation* anim = it->second.get(); + if (anim && anim->playStatePlaying()) + anim->updatePlayState(true); + } } - CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end(); - for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) { - ImplicitAnimation* anim = it->second.get(); - if (anim && anim->hasStyle()) - anim->updatePlayState(true); + if (!m_transitions.isEmpty()) { + CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end(); + for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) { + ImplicitAnimation* anim = it->second.get(); + if (anim && anim->hasStyle()) + anim->updatePlayState(true); + } } } void CompositeAnimationPrivate::overrideImplicitAnimations(int property) { CSSPropertyTransitionsMap::const_iterator end = m_transitions.end(); - for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) { - ImplicitAnimation* anim = it->second.get(); - if (anim && anim->animatingProperty() == property) - anim->setOverridden(true); + if (!m_transitions.isEmpty()) { + for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) { + ImplicitAnimation* anim = it->second.get(); + if (anim && anim->animatingProperty() == property) + anim->setOverridden(true); + } } } void CompositeAnimationPrivate::resumeOverriddenImplicitAnimations(int property) { - CSSPropertyTransitionsMap::const_iterator end = m_transitions.end(); - for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) { - ImplicitAnimation* anim = it->second.get(); - if (anim && anim->animatingProperty() == property) - anim->setOverridden(false); + 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->animatingProperty() == property) + anim->setOverridden(false); + } + } +} + +bool CompositeAnimationPrivate::isAnimatingProperty(int property, bool isRunningNow) const +{ + if (!m_keyframeAnimations.isEmpty()) { + AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end(); + for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) { + KeyframeAnimation* anim = it->second.get(); + if (anim && anim->isAnimatingProperty(property, isRunningNow)) + return true; + } + } + + if (!m_transitions.isEmpty()) { + CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end(); + for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) { + ImplicitAnimation* anim = it->second.get(); + if (anim && anim->isAnimatingProperty(property, isRunningNow)) + return true; + } } + return false; } -static inline bool compareAnimationIndices(RefPtr<KeyframeAnimation> a, const RefPtr<KeyframeAnimation> b) +void CompositeAnimationPrivate::addToStyleAvailableWaitList(AnimationBase* animation) { - return a->index() < b->index(); + m_animationController->addToStyleAvailableWaitList(animation); } -void CompositeAnimationPrivate::styleAvailable() +void CompositeAnimationPrivate::removeFromStyleAvailableWaitList(AnimationBase* animation) { - if (m_numStyleAvailableWaiters == 0) - return; + m_animationController->removeFromStyleAvailableWaitList(animation); +} - // We have to go through animations in the order in which they appear in - // the style, because order matters for additivity. - Vector<RefPtr<KeyframeAnimation> > animations(m_keyframeAnimations.size()); - copyValuesToVector(m_keyframeAnimations, animations); +bool CompositeAnimationPrivate::pauseAnimationAtTime(const AtomicString& name, double t) +{ + if (!name) + return false; - if (animations.size() > 1) - std::stable_sort(animations.begin(), animations.end(), compareAnimationIndices); + RefPtr<KeyframeAnimation> keyframeAnim = m_keyframeAnimations.get(name.impl()); + if (!keyframeAnim || !keyframeAnim->running()) + return false; - for (size_t i = 0; i < animations.size(); ++i) { - KeyframeAnimation* anim = animations[i].get(); - if (anim && anim->waitingForStyleAvailable()) - anim->updateStateMachine(AnimationBase::AnimationStateInputStyleAvailable, -1); + int count = keyframeAnim->m_animation->iterationCount(); + if ((t >= 0.0) && (!count || (t <= count * keyframeAnim->duration()))) { + keyframeAnim->pauseAtTime(t); + return true; } - CSSPropertyTransitionsMap::const_iterator end = m_transitions.end(); - for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) { - ImplicitAnimation* anim = it->second.get(); - if (anim && anim->waitingForStyleAvailable()) - anim->updateStateMachine(AnimationBase::AnimationStateInputStyleAvailable, -1); - } + return false; } -bool CompositeAnimationPrivate::isAnimatingProperty(int property, bool isRunningNow) const +bool CompositeAnimationPrivate::pauseTransitionAtTime(int property, double t) { - AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end(); - for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) { - KeyframeAnimation* anim = it->second.get(); - if (anim && anim->isAnimatingProperty(property, isRunningNow)) - return true; - } + if ((property < firstCSSProperty) || (property >= firstCSSProperty + numCSSProperties)) + return false; + + ImplicitAnimation* implAnim = m_transitions.get(property).get(); + if (!implAnim || !implAnim->running()) + return false; - CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end(); - for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) { - ImplicitAnimation* anim = it->second.get(); - if (anim && anim->isAnimatingProperty(property, isRunningNow)) - return true; + if ((t >= 0.0) && (t <= implAnim->duration())) { + implAnim->pauseAtTime(t); + return true; } + return false; } -void CompositeAnimationPrivate::setWaitingForStyleAvailable(bool waiting) +unsigned CompositeAnimationPrivate::numberOfActiveAnimations() const { - if (waiting) - m_numStyleAvailableWaiters++; - else - m_numStyleAvailableWaiters--; - m_animationController->setWaitingForStyleAvailable(waiting); + unsigned count = 0; + + if (!m_keyframeAnimations.isEmpty()) { + AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end(); + for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) { + KeyframeAnimation* anim = it->second.get(); + if (anim->running()) + ++count; + } + } + + if (!m_transitions.isEmpty()) { + CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end(); + for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) { + ImplicitAnimation* anim = it->second.get(); + if (anim->running()) + ++count; + } + } + + return count; } CompositeAnimation::CompositeAnimation(AnimationController* animationController) @@ -521,24 +611,34 @@ CompositeAnimation::~CompositeAnimation() delete m_data; } +AnimationController* CompositeAnimation::animationController() +{ + return m_data->animationController(); +} + +void CompositeAnimation::clearRenderer() +{ + m_data->clearRenderer(); +} + PassRefPtr<RenderStyle> CompositeAnimation::animate(RenderObject* renderer, RenderStyle* currentStyle, RenderStyle* targetStyle) { return m_data->animate(renderer, currentStyle, targetStyle); } -bool CompositeAnimation::isAnimating() const +double CompositeAnimation::willNeedService() const { - return m_data->isAnimating(); + return m_data->willNeedService(); } -void CompositeAnimation::setWaitingForStyleAvailable(bool b) +void CompositeAnimation::addToStyleAvailableWaitList(AnimationBase* animation) { - m_data->setWaitingForStyleAvailable(b); + m_data->addToStyleAvailableWaitList(animation); } -void CompositeAnimation::resetTransitions(RenderObject* renderer) +void CompositeAnimation::removeFromStyleAvailableWaitList(AnimationBase* animation) { - m_data->resetTransitions(renderer); + m_data->removeFromStyleAvailableWaitList(animation); } void CompositeAnimation::suspendAnimations() @@ -556,9 +656,9 @@ bool CompositeAnimation::isSuspended() const return m_data->isSuspended(); } -void CompositeAnimation::styleAvailable() +bool CompositeAnimation::hasAnimations() const { - m_data->styleAvailable(); + return m_data->hasAnimations(); } void CompositeAnimation::setAnimating(bool b) @@ -571,6 +671,11 @@ bool CompositeAnimation::isAnimatingProperty(int property, bool isRunningNow) co return m_data->isAnimatingProperty(property, isRunningNow); } +PassRefPtr<KeyframeAnimation> CompositeAnimation::getAnimationForProperty(int property) +{ + return m_data->getAnimationForProperty(property); +} + void CompositeAnimation::setAnimationStartTime(double t) { m_data->setAnimationStartTime(t); @@ -591,4 +696,19 @@ void CompositeAnimation::resumeOverriddenImplicitAnimations(int property) m_data->resumeOverriddenImplicitAnimations(property); } +bool CompositeAnimation::pauseAnimationAtTime(const AtomicString& name, double t) +{ + return m_data->pauseAnimationAtTime(name, t); +} + +bool CompositeAnimation::pauseTransitionAtTime(int property, double t) +{ + return m_data->pauseTransitionAtTime(property, t); +} + +unsigned CompositeAnimation::numberOfActiveAnimations() const +{ + return m_data->numberOfActiveAnimations(); +} + } // namespace WebCore diff --git a/WebCore/page/animation/CompositeAnimation.h b/WebCore/page/animation/CompositeAnimation.h index 13f1179..3517b34 100644 --- a/WebCore/page/animation/CompositeAnimation.h +++ b/WebCore/page/animation/CompositeAnimation.h @@ -37,30 +37,41 @@ namespace WebCore { class CompositeAnimationPrivate; +class AnimationBase; class AnimationController; +class KeyframeAnimation; class RenderObject; class RenderStyle; // A CompositeAnimation represents a collection of animations that are running // on a single RenderObject, such as a number of properties transitioning at once. -class CompositeAnimation : public Noncopyable { +class CompositeAnimation : public RefCounted<CompositeAnimation> { public: - CompositeAnimation(AnimationController* animationController); + static PassRefPtr<CompositeAnimation> create(AnimationController* animationController) + { + return adoptRef(new CompositeAnimation(animationController)); + }; + ~CompositeAnimation(); + + void clearRenderer(); PassRefPtr<RenderStyle> animate(RenderObject*, RenderStyle* currentStyle, RenderStyle* targetStyle); - bool isAnimating() const; - - void setWaitingForStyleAvailable(bool); - void resetTransitions(RenderObject*); + double willNeedService() const; + + AnimationController* animationController(); void suspendAnimations(); void resumeAnimations(); bool isSuspended() const; + + bool hasAnimations() const; - void styleAvailable(); void setAnimating(bool); bool isAnimatingProperty(int property, bool isRunningNow) const; + + PassRefPtr<KeyframeAnimation> getAnimationForProperty(int property); + void setAnimationStartTime(double t); void setTransitionStartTime(int property, double t); @@ -68,7 +79,16 @@ public: void overrideImplicitAnimations(int property); void resumeOverriddenImplicitAnimations(int property); + bool pauseAnimationAtTime(const AtomicString& name, double t); + bool pauseTransitionAtTime(int property, double t); + unsigned numberOfActiveAnimations() const; + + void addToStyleAvailableWaitList(AnimationBase*); + void removeFromStyleAvailableWaitList(AnimationBase*); + private: + CompositeAnimation(AnimationController* animationController); + CompositeAnimationPrivate* m_data; }; diff --git a/WebCore/page/animation/ImplicitAnimation.cpp b/WebCore/page/animation/ImplicitAnimation.cpp index 4d470e4..f984909 100644 --- a/WebCore/page/animation/ImplicitAnimation.cpp +++ b/WebCore/page/animation/ImplicitAnimation.cpp @@ -27,9 +27,13 @@ */ #include "config.h" + +#include "AnimationController.h" +#include "CompositeAnimation.h" #include "CSSPropertyNames.h" #include "EventNames.h" #include "ImplicitAnimation.h" +#include "KeyframeAnimation.h" #include "RenderObject.h" namespace WebCore { @@ -56,12 +60,8 @@ bool ImplicitAnimation::shouldSendEventForListener(Document::ListenerType inList return m_object->document()->hasListenerType(inListenerType); } -void ImplicitAnimation::animate(CompositeAnimation* animation, RenderObject* renderer, RenderStyle* currentStyle, - RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle) +void ImplicitAnimation::animate(CompositeAnimation*, RenderObject*, RenderStyle*, RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle) { - if (paused()) - return; - // If we get this far and the animation is done, it means we are cleaning up a just finished animation. // So just return. Everything is already all cleaned up. if (postActive()) @@ -78,10 +78,22 @@ void ImplicitAnimation::animate(CompositeAnimation* animation, RenderObject* ren if (blendProperties(this, m_animatingProperty, animatedStyle.get(), m_fromStyle.get(), m_toStyle.get(), progress(1, 0, 0))) setAnimating(); + + // Fire the start timeout if needed + fireAnimationEventsIfNeeded(); } void ImplicitAnimation::onAnimationEnd(double elapsedTime) { + // If we have a keyframe animation on this property, this transition is being overridden. The keyframe + // animation keeps an unanimated style in case a transition starts while the keyframe animation is + // running. But now that the transition has completed, we need to update this style with its new + // destination. If we didn't, the next time through we would think a transition had started + // (comparing the old unanimated style with the new final style of the transition). + RefPtr<KeyframeAnimation> keyframeAnim = m_compAnim->getAnimationForProperty(m_animatingProperty); + if (keyframeAnim) + keyframeAnim->setUnanimatedStyle(m_toStyle); + if (!sendTransitionEvent(eventNames().webkitTransitionEndEvent, elapsedTime)) { // We didn't dispatch an event, which would call endAnimation(), so we'll just call it here. endAnimation(true); @@ -107,14 +119,11 @@ bool ImplicitAnimation::sendTransitionEvent(const AtomicString& eventType, doubl if (!element) return false; - // Keep a reference to this ImplicitAnimation so it doesn't go away in the handler - RefPtr<ImplicitAnimation> retainer(this); - - // Call the event handler - element->dispatchWebKitTransitionEvent(eventType, propertyName, elapsedTime); + // Schedule event handling + m_object->animation()->addEventToDispatch(element, eventType, propertyName, elapsedTime); // Restore the original (unanimated) style - if (eventType == eventNames().webkitAnimationEndEvent && element->renderer()) + if (eventType == eventNames().webkitTransitionEndEvent && element->renderer()) setChanged(element.get()); return true; // Did dispatch an event diff --git a/WebCore/page/animation/ImplicitAnimation.h b/WebCore/page/animation/ImplicitAnimation.h index 7c9d50f..cf98bba 100644 --- a/WebCore/page/animation/ImplicitAnimation.h +++ b/WebCore/page/animation/ImplicitAnimation.h @@ -54,8 +54,6 @@ public: void setOverridden(bool); virtual bool overridden() const { return m_overridden; } - virtual bool shouldFireEvents() const { return true; } - virtual bool affectsProperty(int) const; bool hasStyle() const { return m_fromStyle && m_toStyle; } diff --git a/WebCore/page/animation/KeyframeAnimation.cpp b/WebCore/page/animation/KeyframeAnimation.cpp index 69fdd11..2efa578 100644 --- a/WebCore/page/animation/KeyframeAnimation.cpp +++ b/WebCore/page/animation/KeyframeAnimation.cpp @@ -29,12 +29,12 @@ #include "config.h" #include "KeyframeAnimation.h" +#include "AnimationController.h" #include "CSSPropertyNames.h" #include "CSSStyleSelector.h" #include "CompositeAnimation.h" #include "EventNames.h" #include "RenderObject.h" -#include "SystemTime.h" namespace WebCore { @@ -59,9 +59,11 @@ KeyframeAnimation::~KeyframeAnimation() updateStateMachine(AnimationStateInputEndAnimation, -1); } -void KeyframeAnimation::animate(CompositeAnimation* animation, RenderObject* renderer, const RenderStyle* currentStyle, - const RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle) +void KeyframeAnimation::animate(CompositeAnimation*, RenderObject*, const RenderStyle*, const RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle) { + // Fire the start timeout if needed + fireAnimationEventsIfNeeded(); + // If we have not yet started, we will not have a valid start time, so just start the animation if needed. if (isNew() && m_animation->playState() == AnimPlayStatePlaying) updateStateMachine(AnimationStateInputStartAnimation, -1); @@ -84,9 +86,7 @@ void KeyframeAnimation::animate(CompositeAnimation* animation, RenderObject* ren // We should cache the last pair or something. // Find the first key - double elapsedTime = (m_startTime > 0) ? ((!paused() ? currentTime() : m_pauseTime) - m_startTime) : 0; - if (elapsedTime < 0) - elapsedTime = 0; + double elapsedTime = getElapsedTime(); double t = m_animation->duration() ? (elapsedTime / m_animation->duration()) : 1; int i = static_cast<int>(t); @@ -200,11 +200,8 @@ bool KeyframeAnimation::sendAnimationEvent(const AtomicString& eventType, double if (!element) return false; - // Keep a reference to this ImplicitAnimation so it doesn't go away in the handler - RefPtr<KeyframeAnimation> retainer(this); - - // Call the event handler - element->dispatchWebKitAnimationEvent(eventType, m_keyframes.animationName(), elapsedTime); + // Schedule event handling + m_object->animation()->addEventToDispatch(element, eventType, m_keyframes.animationName(), elapsedTime); // Restore the original (unanimated) style if (eventType == eventNames().webkitAnimationEndEvent && element->renderer()) diff --git a/WebCore/page/animation/KeyframeAnimation.h b/WebCore/page/animation/KeyframeAnimation.h index 55b429a..5c3176c 100644 --- a/WebCore/page/animation/KeyframeAnimation.h +++ b/WebCore/page/animation/KeyframeAnimation.h @@ -51,10 +51,9 @@ public: int index() const { return m_index; } void setIndex(int i) { m_index = i; } - virtual bool shouldFireEvents() const { return true; } - bool hasAnimationForProperty(int property) const; + void setUnanimatedStyle(PassRefPtr<RenderStyle> style) { m_unanimatedStyle = style; } RenderStyle* unanimatedStyle() const { return m_unanimatedStyle.get(); } protected: diff --git a/WebCore/page/chromium/AXObjectCacheChromium.cpp b/WebCore/page/chromium/AXObjectCacheChromium.cpp new file mode 100644 index 0000000..bbaf21d --- /dev/null +++ b/WebCore/page/chromium/AXObjectCacheChromium.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2008 Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "AXObjectCache.h" + +#include "AccessibilityObject.h" + +namespace WebCore { + +void AXObjectCache::detachWrapper(AccessibilityObject* obj) +{ + // In Chromium, AccessibilityObjects are wrapped lazily. + if (AccessibilityObjectWrapper* wrapper = obj->wrapper()) + wrapper->detach(); +} + +void AXObjectCache::attachWrapper(AccessibilityObject*) +{ + // In Chromium, AccessibilityObjects are wrapped lazily. +} + +void AXObjectCache::postNotification(RenderObject*, const String&) +{ +} + +void AXObjectCache::postNotificationToElement(RenderObject*, const String&) +{ +} + +void AXObjectCache::handleFocusedUIElementChanged() +{ +} + +} // namespace WebCore diff --git a/WebCore/page/PositionOptions.idl b/WebCore/page/chromium/AccessibilityObjectChromium.cpp index 29253df..650fb3a 100644 --- a/WebCore/page/PositionOptions.idl +++ b/WebCore/page/chromium/AccessibilityObjectChromium.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2008 Google Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,13 +24,14 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -module core { +#include "config.h" +#include "AccessibilityObject.h" - interface [ - GenerateConstructor - ] PositionOptions { - attribute boolean enableHighAccuracy; - attribute unsigned long timeout; - }; +namespace WebCore { +bool AccessibilityObject::accessibilityIgnoreAttachment() const +{ + return false; } + +} // namespace WebCore diff --git a/WebCore/page/chromium/AccessibilityObjectWrapper.h b/WebCore/page/chromium/AccessibilityObjectWrapper.h new file mode 100644 index 0000000..9920e4d --- /dev/null +++ b/WebCore/page/chromium/AccessibilityObjectWrapper.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2008 Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef AccessibilityObjectWrapper_h +#define AccessibilityObjectWrapper_h + +namespace WebCore { + + class AccessibilityObject; + class AccessibilityObjectWrapper : public RefCounted<AccessibilityObjectWrapper> { + public: + virtual ~AccessibilityObjectWrapper() {} + virtual void detach() = 0; + bool attached() const { return m_object; } + AccessibilityObject* accessibilityObject() const { return m_object; } + + protected: + AccessibilityObjectWrapper(AccessibilityObject* obj) + : RefCounted<AccessibilityObjectWrapper>(0), m_object(obj) { } + AccessibilityObjectWrapper() : m_object(0) { } + + AccessibilityObject* m_object; + }; + +} // namespace WebCore + +#endif diff --git a/WebCore/page/chromium/ChromeClientChromium.h b/WebCore/page/chromium/ChromeClientChromium.h new file mode 100644 index 0000000..5821dff --- /dev/null +++ b/WebCore/page/chromium/ChromeClientChromium.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2008, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ChromeClientChromium_h +#define ChromeClientChromium_h + +#include "ChromeClient.h" +#include <wtf/Forward.h> + +namespace WebCore { + class FramelessScrollView; + class IntRect; + + // Contains Chromium-specific extensions to the ChromeClient. Only put + // things here that don't make sense for other ports. + class ChromeClientChromium : public ChromeClient { + public: + // Notifies the client of a new popup widget. The client should place + // and size the widget with the given bounds, relative to the screen. + virtual void popupOpened(FramelessScrollView* popupView, const IntRect& bounds, bool focusOnShow) = 0; + }; + +} // namespace WebCore + +#endif diff --git a/WebCore/page/chromium/DragControllerChromium.cpp b/WebCore/page/chromium/DragControllerChromium.cpp new file mode 100644 index 0000000..18688fd --- /dev/null +++ b/WebCore/page/chromium/DragControllerChromium.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2008 Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "DragController.h" + +#include "DragData.h" +#include "SelectionController.h" +#include <wtf/RefPtr.h> + +#if PLATFORM(WIN_OS) +#include <windows.h> +#endif + +namespace WebCore { + +const int DragController::LinkDragBorderInset = 2; +const int DragController::MaxOriginalImageArea = 1500 * 1500; +const int DragController::DragIconRightInset = 7; +const int DragController::DragIconBottomInset = 3; + +const float DragController::DragImageAlpha = 0.75f; + +DragOperation DragController::dragOperation(DragData* dragData) +{ + // FIXME: To match the MacOS behaviour we should return DragOperationNone + // if we are a modal window, we are the drag source, or the window is an + // attached sheet If this can be determined from within WebCore + // operationForDrag can be pulled into WebCore itself + ASSERT(dragData); + return dragData->containsURL() && !m_didInitiateDrag ? DragOperationCopy : DragOperationNone; +} + +bool DragController::isCopyKeyDown() +{ + // FIXME: This should not be OS specific. Delegate to the embedder instead. +#if PLATFORM(WIN_OS) + return ::GetAsyncKeyState(VK_CONTROL); +#else + return false; +#endif +} + +const IntSize& DragController::maxDragImageSize() +{ + static const IntSize maxDragImageSize(200, 200); + return maxDragImageSize; +} + +void DragController::cleanupAfterSystemDrag() +{ +} + +} // namespace WebCore diff --git a/WebCore/page/chromium/EventHandlerChromium.cpp b/WebCore/page/chromium/EventHandlerChromium.cpp new file mode 100644 index 0000000..883bece --- /dev/null +++ b/WebCore/page/chromium/EventHandlerChromium.cpp @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008 Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "EventHandler.h" + +#include "ChromiumDataObject.h" +#include "ClipboardChromium.h" +#include "Cursor.h" +#include "FloatPoint.h" +#include "FocusController.h" +#include "FrameView.h" +#include "Frame.h" +#include "HitTestRequest.h" +#include "HitTestResult.h" +#include "MouseEventWithHitTestResults.h" +#include "NotImplemented.h" +#include "Page.h" +#include "PlatformKeyboardEvent.h" +#include "PlatformWheelEvent.h" +#include "RenderWidget.h" +#include "SelectionController.h" + +namespace WebCore { + +#if PLATFORM(DARWIN) +const double EventHandler::TextDragDelay = 0.15; +#else +const double EventHandler::TextDragDelay = 0.0; +#endif + +bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe) +{ + // If we're clicking into a frame that is selected, the frame will appear + // greyed out even though we're clicking on the selection. This looks + // really strange (having the whole frame be greyed out), so we deselect the + // selection. + IntPoint p = m_frame->view()->windowToContents(mev.event().pos()); + if (m_frame->selection()->contains(p)) { + VisiblePosition visiblePos( + mev.targetNode()->renderer()->positionForPoint(mev.localPoint())); + Selection newSelection(visiblePos); + if (m_frame->shouldChangeSelection(newSelection)) + m_frame->selection()->setSelection(newSelection); + } + + subframe->eventHandler()->handleMousePressEvent(mev.event()); + return true; +} + +bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe, HitTestResult* hoveredNode) +{ + if (m_mouseDownMayStartDrag && !m_mouseDownWasInSubframe) + return false; + subframe->eventHandler()->handleMouseMoveEvent(mev.event(), hoveredNode); + return true; +} + +bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe) +{ + subframe->eventHandler()->handleMouseReleaseEvent(mev.event()); + return true; +} + +bool EventHandler::passWheelEventToWidget(PlatformWheelEvent& wheelEvent, Widget* widget) +{ + // We can sometimes get a null widget! EventHandlerMac handles a null + // widget by returning false, so we do the same. + if (!widget) + return false; + + // If not a FrameView, then probably a plugin widget. Those will receive + // the event via an EventTargetNode dispatch when this returns false. + if (!widget->isFrameView()) + return false; + + return static_cast<FrameView*>(widget)->frame()->eventHandler()->handleWheelEvent(wheelEvent); +} + +bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults& event) +{ + // Figure out which view to send the event to. + if (!event.targetNode() || !event.targetNode()->renderer() || !event.targetNode()->renderer()->isWidget()) + return false; + + return passMouseDownEventToWidget(static_cast<RenderWidget*>(event.targetNode()->renderer())->widget()); +} + +bool EventHandler::passMouseDownEventToWidget(Widget* widget) +{ + notImplemented(); + return false; +} + +bool EventHandler::tabsToAllControls(KeyboardEvent*) const +{ + return true; +} + +bool EventHandler::eventActivatedView(const PlatformMouseEvent& event) const +{ + // FIXME: EventHandlerWin.cpp does the following: + // return event.activatedWebView(); + return false; +} + +PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const +{ + RefPtr<ChromiumDataObject> dataObject = ChromiumDataObject::create(); + return ClipboardChromium::create(true, dataObject.get(), ClipboardWritable); +} + +void EventHandler::focusDocumentView() +{ + Page* page = m_frame->page(); + if (!page) + return; + page->focusController()->setFocusedFrame(m_frame); +} + +bool EventHandler::passWidgetMouseDownEventToWidget(RenderWidget* renderWidget) +{ + return passMouseDownEventToWidget(renderWidget->widget()); +} + +unsigned EventHandler::accessKeyModifiers() +{ + return PlatformKeyboardEvent::AltKey; +} + +} // namespace WebCore diff --git a/WebCore/page/chromium/FrameChromium.cpp b/WebCore/page/chromium/FrameChromium.cpp new file mode 100644 index 0000000..1e4ed16 --- /dev/null +++ b/WebCore/page/chromium/FrameChromium.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008 Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FrameChromium.h" + +#include "Document.h" +#include "FloatRect.h" +#include "RenderView.h" +#include "Settings.h" + +using std::min; + +namespace WebCore { + +void computePageRectsForFrame(Frame* frame, const IntRect& printRect, float headerHeight, float footerHeight, float userScaleFactor, Vector<IntRect>& pages, int& outPageHeight) +{ + ASSERT(frame); + + pages.clear(); + outPageHeight = 0; + + if (!frame->document() || !frame->view() || !frame->document()->renderer()) + return; + + RenderView* root = static_cast<RenderView*>(frame->document()->renderer()); + + if (!root) { + LOG_ERROR("document to be printed has no renderer"); + return; + } + + if (userScaleFactor <= 0) { + LOG_ERROR("userScaleFactor has bad value %.2f", userScaleFactor); + return; + } + + float ratio = static_cast<float>(printRect.height()) / static_cast<float>(printRect.width()); + + float pageWidth = static_cast<float>(root->docWidth()); + float pageHeight = pageWidth * ratio; + outPageHeight = static_cast<int>(pageHeight); // this is the height of the page adjusted by margins + pageHeight -= (headerHeight + footerHeight); + + if (pageHeight <= 0) { + LOG_ERROR("pageHeight has bad value %.2f", pageHeight); + return; + } + + float currPageHeight = pageHeight / userScaleFactor; + float docHeight = root->layer()->height(); + float currPageWidth = pageWidth / userScaleFactor; + + + // always return at least one page, since empty files should print a blank page + float printedPagesHeight = 0.0f; + do { + float proposedBottom = min(docHeight, printedPagesHeight + pageHeight); + frame->adjustPageHeight(&proposedBottom, printedPagesHeight, proposedBottom, printedPagesHeight); + currPageHeight = max(1.0f, proposedBottom - printedPagesHeight); + + pages.append(IntRect(0, printedPagesHeight, currPageWidth, currPageHeight)); + printedPagesHeight += currPageHeight; + } while (printedPagesHeight < docHeight); +} + +DragImageRef Frame::dragImageForSelection() +{ + if (selection()->isRange()) + return 0; // FIXME: implement me! + + return 0; +} + +} // namespace WebCore diff --git a/WebCore/page/chromium/FrameChromium.h b/WebCore/page/chromium/FrameChromium.h new file mode 100644 index 0000000..faa78e7 --- /dev/null +++ b/WebCore/page/chromium/FrameChromium.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2008 Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FrameChromium_h +#define FrameChromium_h + +#include "Frame.h" + +namespace WebCore { + + // printRect is only used for the width/height ratio. Their absolute values aren't used. + void computePageRectsForFrame(Frame*, const IntRect& printRect, float headerHeight, float footerHeight, float userScaleFactor, Vector<IntRect>& pages, int& pageHeight); + +} + +#endif diff --git a/WebCore/page/gtk/AccessibilityObjectAtk.cpp b/WebCore/page/gtk/AccessibilityObjectAtk.cpp index b755645..1710027 100644 --- a/WebCore/page/gtk/AccessibilityObjectAtk.cpp +++ b/WebCore/page/gtk/AccessibilityObjectAtk.cpp @@ -20,6 +20,8 @@ #include "config.h" #include "AccessibilityObject.h" +#if HAVE(ACCESSIBILITY) + namespace WebCore { bool AccessibilityObject::accessibilityIgnoreAttachment() const @@ -28,3 +30,5 @@ bool AccessibilityObject::accessibilityIgnoreAttachment() const } } // namespace WebCore + +#endif // HAVE(ACCESSIBILITY) diff --git a/WebCore/page/gtk/AccessibilityObjectWrapperAtk.cpp b/WebCore/page/gtk/AccessibilityObjectWrapperAtk.cpp index b46fb60..c1a405e 100644 --- a/WebCore/page/gtk/AccessibilityObjectWrapperAtk.cpp +++ b/WebCore/page/gtk/AccessibilityObjectWrapperAtk.cpp @@ -20,6 +20,8 @@ #include "config.h" #include "AccessibilityObjectWrapperAtk.h" +#if HAVE(ACCESSIBILITY) + #include "AXObjectCache.h" #include "AccessibilityListBox.h" #include "AccessibilityRenderObject.h" @@ -674,3 +676,5 @@ void AccessibilityObject::setWrapper(AccessibilityObjectWrapper* wrapper) } } // namespace WebCore + +#endif // HAVE(ACCESSIBILITY) diff --git a/WebCore/page/gtk/DragControllerGtk.cpp b/WebCore/page/gtk/DragControllerGtk.cpp index 62f4421..9e17255 100644 --- a/WebCore/page/gtk/DragControllerGtk.cpp +++ b/WebCore/page/gtk/DragControllerGtk.cpp @@ -63,4 +63,8 @@ const IntSize& DragController::maxDragImageSize() return maxDragImageSize; } +void DragController::cleanupAfterSystemDrag() +{ +} + } diff --git a/WebCore/page/gtk/EventHandlerGtk.cpp b/WebCore/page/gtk/EventHandlerGtk.cpp index bb650b4..7692dae 100644 --- a/WebCore/page/gtk/EventHandlerGtk.cpp +++ b/WebCore/page/gtk/EventHandlerGtk.cpp @@ -42,8 +42,6 @@ namespace WebCore { -unsigned EventHandler::s_accessKeyModifiers = PlatformKeyboardEvent::AltKey; - const double EventHandler::TextDragDelay = 0.0; bool EventHandler::tabsToAllControls(KeyboardEvent* event) const @@ -120,4 +118,9 @@ bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& return true; } +unsigned EventHandler::accessKeyModifiers() +{ + return PlatformKeyboardEvent::AltKey; +} + } diff --git a/WebCore/page/mac/AXObjectCacheMac.mm b/WebCore/page/mac/AXObjectCacheMac.mm index 10ae1cc..d5ce8f3 100644 --- a/WebCore/page/mac/AXObjectCacheMac.mm +++ b/WebCore/page/mac/AXObjectCacheMac.mm @@ -26,6 +26,8 @@ #import "config.h" #import "AXObjectCache.h" +#if HAVE(ACCESSIBILITY) + #import "AccessibilityObject.h" #import "AccessibilityObjectWrapper.h" #import "RenderObject.h" @@ -85,3 +87,5 @@ void AXObjectCache::handleFocusedUIElementChanged() } } + +#endif // HAVE(ACCESSIBILITY) diff --git a/WebCore/page/mac/AccessibilityObjectMac.mm b/WebCore/page/mac/AccessibilityObjectMac.mm index 872e108..8f47af0 100644 --- a/WebCore/page/mac/AccessibilityObjectMac.mm +++ b/WebCore/page/mac/AccessibilityObjectMac.mm @@ -26,6 +26,8 @@ #import "config.h" #import "AccessibilityObject.h" +#if HAVE(ACCESSIBILITY) + #import "AccessibilityObjectWrapper.h" namespace WebCore { @@ -36,3 +38,5 @@ bool AccessibilityObject::accessibilityIgnoreAttachment() const } } // WebCore + +#endif // HAVE(ACCESSIBILITY) diff --git a/WebCore/page/mac/AccessibilityObjectWrapper.mm b/WebCore/page/mac/AccessibilityObjectWrapper.mm index 2104ca9..1e28f00 100644 --- a/WebCore/page/mac/AccessibilityObjectWrapper.mm +++ b/WebCore/page/mac/AccessibilityObjectWrapper.mm @@ -29,6 +29,8 @@ #import "config.h" #import "AccessibilityObjectWrapper.h" +#if HAVE(ACCESSIBILITY) + #import "AXObjectCache.h" #import "AccessibilityListBox.h" #import "AccessibilityList.h" @@ -56,6 +58,7 @@ #import "WebCoreViewFactory.h" #import "htmlediting.h" #import "visible_units.h" +#import <runtime/InitializeThreading.h> using namespace WebCore; using namespace HTMLNames; @@ -99,6 +102,15 @@ using namespace std; #define NSAccessibilityDefinitionListSubrole @"AXDefinitionList" #endif +// Miscellaneous +#ifndef NSAccessibilityBlockQuoteLevelAttribute +#define NSAccessibilityBlockQuoteLevelAttribute @"AXBlockQuoteLevel" +#endif + +#ifndef NSAccessibilityAccessKeyAttribute +#define NSAccessibilityAccessKeyAttribute @"AXAccessKey" +#endif + #ifdef BUILDING_ON_TIGER typedef unsigned NSUInteger; #endif @@ -113,12 +125,13 @@ typedef unsigned NSUInteger; @implementation AccessibilityObjectWrapper -#ifndef BUILDING_ON_TIGER + (void)initialize { + JSC::initializeThreading(); +#ifndef BUILDING_ON_TIGER WebCoreObjCFinalizeOnMainThread(self); -} #endif +} - (id)initWithAccessibilityObject:(AccessibilityObject*)axObject { @@ -265,15 +278,16 @@ static CGColorRef CreateCGColorIfDifferent(NSColor* nsColor, CGColorRef existing [rgbColor getRed:&components[0] green:&components[1] blue:&components[2] alpha:&components[3]]; // create a new CGColorRef to return - CGColorSpaceRef cgColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); + CGColorSpaceRef cgColorSpace = CGColorSpaceCreateDeviceRGB(); CGColorRef cgColor = CGColorCreate(cgColorSpace, components); CGColorSpaceRelease(cgColorSpace); - CFMakeCollectable(cgColor); // check for match with existing color - if (existingColor && CGColorEqualToColor(cgColor, existingColor)) - cgColor = nil; - + if (existingColor && CGColorEqualToColor(cgColor, existingColor)) { + CGColorRelease(cgColor); + cgColor = 0; + } + return cgColor; } @@ -356,6 +370,9 @@ static void AXAttributeStringSetStyle(NSMutableAttributedString* attrString, Ren static int blockquoteLevel(RenderObject* renderer) { + if (!renderer) + return 0; + int result = 0; for (Node* node = renderer->element(); node; node = node->parent()) { if (node->hasTagName(blockquoteTag)) @@ -370,9 +387,9 @@ static void AXAttributeStringSetBlockquoteLevel(NSMutableAttributedString* attrS int quoteLevel = blockquoteLevel(renderer); if (quoteLevel) - [attrString addAttribute:@"AXBlockQuoteLevel" value:[NSNumber numberWithInt:quoteLevel] range:range]; + [attrString addAttribute:NSAccessibilityBlockQuoteLevelAttribute value:[NSNumber numberWithInt:quoteLevel] range:range]; else - [attrString removeAttribute:@"AXBlockQuoteLevel" range:range]; + [attrString removeAttribute:NSAccessibilityBlockQuoteLevelAttribute range:range]; } static void AXAttributeStringSetSpelling(NSMutableAttributedString* attrString, Node* node, int offset, NSRange range) @@ -404,7 +421,7 @@ static void AXAttributeStringSetSpelling(NSMutableAttributedString* attrString, } } -static void AXAttributeStringSetHeadingLevel(AccessibilityObject* object, NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range) +static void AXAttributeStringSetHeadingLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range) { int parentHeadingLevel = AccessibilityRenderObject::headingLevel(renderer->parent()->element()); @@ -458,7 +475,7 @@ static void AXAttributeStringSetElement(NSMutableAttributedString* attrString, N [attrString removeAttribute:attribute range:range]; } -static void AXAttributedStringAppendText(AccessibilityObject* object, NSMutableAttributedString* attrString, Node* node, int offset, const UChar* chars, int length) +static void AXAttributedStringAppendText(NSMutableAttributedString* attrString, Node* node, int offset, const UChar* chars, int length) { // skip invisible text if (!node->renderer()) @@ -480,7 +497,7 @@ static void AXAttributedStringAppendText(AccessibilityObject* object, NSMutableA // set new attributes AXAttributeStringSetStyle(attrString, node->renderer(), attrStringRange); - AXAttributeStringSetHeadingLevel(object, attrString, node->renderer(), attrStringRange); + AXAttributeStringSetHeadingLevel(attrString, node->renderer(), attrStringRange); AXAttributeStringSetBlockquoteLevel(attrString, node->renderer(), attrStringRange); AXAttributeStringSetElement(attrString, NSAccessibilityLinkTextAttribute, AXLinkElementForNode(node), attrStringRange); @@ -530,7 +547,7 @@ static NSString* nsStringForReplacedNode(Node* replacedNode) // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX) if (it.length() != 0) { - AXAttributedStringAppendText(m_object, attrString, node, offset, it.characters(), it.length()); + AXAttributedStringAppendText(attrString, node, offset, it.characters(), it.length()); } else { Node* replacedNode = node->childNode(offset); NSString *attachmentString = nsStringForReplacedNode(replacedNode); @@ -563,6 +580,8 @@ static WebCoreTextMarkerRange* textMarkerRangeFromVisiblePositions(VisiblePositi - (NSArray*)accessibilityActionNames { + m_object->updateBackingStore(); + static NSArray* actionElementActions = [[NSArray alloc] initWithObjects: NSAccessibilityPressAction, NSAccessibilityShowMenuAction, nil]; static NSArray* defaultElementActions = [[NSArray alloc] initWithObjects: NSAccessibilityShowMenuAction, nil]; static NSArray* menuElementActions = [[NSArray alloc] initWithObjects: NSAccessibilityCancelAction, NSAccessibilityPressAction, nil]; @@ -582,6 +601,8 @@ static WebCoreTextMarkerRange* textMarkerRangeFromVisiblePositions(VisiblePositi - (NSArray*)accessibilityAttributeNames { + m_object->updateBackingStore(); + if (m_object->isAttachment()) return [[self attachmentView] accessibilityAttributeNames]; @@ -601,6 +622,8 @@ static WebCoreTextMarkerRange* textMarkerRangeFromVisiblePositions(VisiblePositi static NSArray* tableRowAttrs = nil; static NSArray* tableColAttrs = nil; static NSArray* tableCellAttrs = nil; + static NSArray* groupAttrs = nil; + static NSArray* inputImageAttrs = nil; NSMutableArray* tempArray; if (attributes == nil) { attributes = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute, @@ -623,7 +646,7 @@ static WebCoreTextMarkerRange* textMarkerRangeFromVisiblePositions(VisiblePositi @"AXVisited", NSAccessibilityLinkedUIElementsAttribute, NSAccessibilitySelectedAttribute, - @"AXBlockQuoteLevel", + NSAccessibilityBlockQuoteLevelAttribute, NSAccessibilityTopLevelUIElementAttribute, nil]; } @@ -640,6 +663,7 @@ static WebCoreTextMarkerRange* textMarkerRangeFromVisiblePositions(VisiblePositi if (anchorAttrs == nil) { tempArray = [[NSMutableArray alloc] initWithArray:attributes]; [tempArray addObject:NSAccessibilityURLAttribute]; + [tempArray addObject:NSAccessibilityAccessKeyAttribute]; anchorAttrs = [[NSArray alloc] initWithArray:tempArray]; [tempArray release]; } @@ -660,6 +684,7 @@ static WebCoreTextMarkerRange* textMarkerRangeFromVisiblePositions(VisiblePositi [tempArray addObject:NSAccessibilityVisibleCharacterRangeAttribute]; [tempArray addObject:NSAccessibilityInsertionPointLineNumberAttribute]; [tempArray addObject:NSAccessibilityTitleUIElementAttribute]; + [tempArray addObject:NSAccessibilityAccessKeyAttribute]; textAttrs = [[NSArray alloc] initWithArray:tempArray]; [tempArray release]; } @@ -669,6 +694,7 @@ static WebCoreTextMarkerRange* textMarkerRangeFromVisiblePositions(VisiblePositi [tempArray addObject:NSAccessibilityVisibleChildrenAttribute]; [tempArray addObject:NSAccessibilityOrientationAttribute]; [tempArray addObject:NSAccessibilityTitleUIElementAttribute]; + [tempArray addObject:NSAccessibilityAccessKeyAttribute]; listBoxAttrs = [[NSArray alloc] initWithArray:tempArray]; [tempArray release]; } @@ -728,6 +754,7 @@ static WebCoreTextMarkerRange* textMarkerRangeFromVisiblePositions(VisiblePositi if (controlAttrs == nil) { tempArray = [[NSMutableArray alloc] initWithArray:attributes]; [tempArray addObject:NSAccessibilityTitleUIElementAttribute]; + [tempArray addObject:NSAccessibilityAccessKeyAttribute]; controlAttrs = [[NSArray alloc] initWithArray:tempArray]; [tempArray release]; } @@ -766,6 +793,19 @@ static WebCoreTextMarkerRange* textMarkerRangeFromVisiblePositions(VisiblePositi tableCellAttrs = [[NSArray alloc] initWithArray:tempArray]; [tempArray release]; } + if (groupAttrs == nil) { + tempArray = [[NSMutableArray alloc] initWithArray:attributes]; + [tempArray addObject:NSAccessibilityTitleUIElementAttribute]; + groupAttrs = [[NSArray alloc] initWithArray:tempArray]; + [tempArray release]; + } + if (inputImageAttrs == nil) { + tempArray = [[NSMutableArray alloc] initWithArray:controlAttrs]; + [tempArray addObject:NSAccessibilityURLAttribute]; + [tempArray addObject:NSAccessibilityAccessKeyAttribute]; + inputImageAttrs = [[NSArray alloc] initWithArray:tempArray]; + [tempArray release]; + } if (m_object->isPasswordField()) return attributes; @@ -794,9 +834,15 @@ static WebCoreTextMarkerRange* textMarkerRangeFromVisiblePositions(VisiblePositi if (m_object->isProgressIndicator() || m_object->isSlider()) return rangeAttrs; + if (m_object->isInputImage()) + return inputImageAttrs; + if (m_object->isControl()) return controlAttrs; + if (m_object->isGroup()) + return groupAttrs; + if (m_object->isMenu()) return menuAttrs; if (m_object->isMenuBar()) @@ -819,7 +865,7 @@ static WebCoreTextMarkerRange* textMarkerRangeFromVisiblePositions(VisiblePositi Widget* widget = m_object->widget(); if (!widget) return nil; - return [(widget->getOuterView()) accessibilityAttributeValue: NSAccessibilityChildrenAttribute]; + return [(widget->platformWidget()) accessibilityAttributeValue: NSAccessibilityChildrenAttribute]; } static void convertToVector(NSArray* array, AccessibilityObject::AccessibilityChildrenVector& vector) @@ -1082,6 +1128,8 @@ static NSString* roleValueToNSString(AccessibilityRole value) if (!m_object) return nil; + m_object->updateBackingStore(); + if ([attributeName isEqualToString: NSAccessibilityRoleAttribute]) return [self role]; @@ -1246,6 +1294,13 @@ static NSString* roleValueToNSString(AccessibilityRole value) return nil; } + if ([attributeName isEqualToString:NSAccessibilityAccessKeyAttribute]) { + AtomicString accessKey = m_object->accessKey(); + if (accessKey.isNull()) + return nil; + return accessKey; + } + if (m_object->isDataTable()) { // TODO: distinguish between visible and non-visible rows if ([attributeName isEqualToString:NSAccessibilityRowsAttribute] || @@ -1341,8 +1396,15 @@ static NSString* roleValueToNSString(AccessibilityRole value) if ([attributeName isEqualToString: @"AXEndTextMarker"]) return textMarkerForVisiblePosition(endOfDocument(renderer->document())); - if ([attributeName isEqualToString: @"AXBlockQuoteLevel"]) + if ([attributeName isEqualToString:NSAccessibilityBlockQuoteLevelAttribute]) return [NSNumber numberWithInt:blockquoteLevel(renderer)]; + } else { + if ([attributeName isEqualToString:NSAccessibilityBlockQuoteLevelAttribute]) { + AccessibilityObject* parent = m_object->parentObjectUnignored(); + if (!parent) + return [NSNumber numberWithInt:0]; + return [parent->wrapper() accessibilityAttributeValue:NSAccessibilityBlockQuoteLevelAttribute]; + } } if ([attributeName isEqualToString: NSAccessibilityLinkedUIElementsAttribute]) { @@ -1374,6 +1436,8 @@ static NSString* roleValueToNSString(AccessibilityRole value) - (id)accessibilityFocusedUIElement { + m_object->updateBackingStore(); + RefPtr<AccessibilityObject> focusedObj = m_object->focusedUIElement(); if (!focusedObj) @@ -1384,6 +1448,8 @@ static NSString* roleValueToNSString(AccessibilityRole value) - (id)accessibilityHitTest:(NSPoint)point { + m_object->updateBackingStore(); + RefPtr<AccessibilityObject> axObject = m_object->doAccessibilityHitTest(IntPoint(point)); if (axObject) return NSAccessibilityUnignoredAncestor(axObject->wrapper()); @@ -1392,6 +1458,8 @@ static NSString* roleValueToNSString(AccessibilityRole value) - (BOOL)accessibilityIsAttributeSettable:(NSString*)attributeName { + m_object->updateBackingStore(); + if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"]) return YES; @@ -1426,6 +1494,8 @@ static NSString* roleValueToNSString(AccessibilityRole value) // Registering an object is also required for observing notifications. Only registered objects can be observed. - (BOOL)accessibilityIsIgnored { + m_object->updateBackingStore(); + if (m_object->isAttachment()) return [[self attachmentView] accessibilityIsIgnored]; return m_object->accessibilityIsIgnored(); @@ -1433,6 +1503,8 @@ static NSString* roleValueToNSString(AccessibilityRole value) - (NSArray* )accessibilityParameterizedAttributeNames { + m_object->updateBackingStore(); + if (m_object->isAttachment()) return nil; @@ -1513,6 +1585,8 @@ static NSString* roleValueToNSString(AccessibilityRole value) - (void)accessibilityPerformPressAction { + m_object->updateBackingStore(); + if (m_object->isAttachment()) [[self attachmentView] accessibilityPerformAction:NSAccessibilityPressAction]; @@ -1557,6 +1631,8 @@ static NSString* roleValueToNSString(AccessibilityRole value) - (void)accessibilityPerformAction:(NSString*)action { + m_object->updateBackingStore(); + if ([action isEqualToString:NSAccessibilityPressAction]) [self accessibilityPerformPressAction]; @@ -1566,6 +1642,8 @@ static NSString* roleValueToNSString(AccessibilityRole value) - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attributeName { + m_object->updateBackingStore(); + WebCoreTextMarkerRange* textMarkerRange = nil; NSNumber* number = nil; NSString* string = nil; @@ -1688,6 +1766,8 @@ static RenderObject* rendererForView(NSView* view) if (!m_object || !attribute || !parameter) return nil; + m_object->updateBackingStore(); + // common parameter type check/casting. Nil checks in handlers catch wrong type case. // NOTE: This assumes nil is not a valid parameter, because it is indistinguishable from // a parameter of the wrong type. @@ -1933,6 +2013,8 @@ static RenderObject* rendererForView(NSView* view) // API that AppKit uses for faster access - (NSUInteger)accessibilityIndexOfChild:(id)child { + m_object->updateBackingStore(); + const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children(); if (children.isEmpty()) @@ -1949,6 +2031,8 @@ static RenderObject* rendererForView(NSView* view) - (NSUInteger)accessibilityArrayAttributeCount:(NSString *)attribute { + m_object->updateBackingStore(); + if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) { const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children(); if (children.isEmpty()) @@ -1962,6 +2046,8 @@ static RenderObject* rendererForView(NSView* view) - (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount { + m_object->updateBackingStore(); + if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) { if (m_object->children().isEmpty()) { NSArray *children = [self renderWidgetChildren]; @@ -1994,3 +2080,5 @@ static RenderObject* rendererForView(NSView* view) } @end + +#endif // HAVE(ACCESSIBILITY) diff --git a/WebCore/page/mac/DragControllerMac.mm b/WebCore/page/mac/DragControllerMac.mm index 2ab9d41..86d8f66 100644 --- a/WebCore/page/mac/DragControllerMac.mm +++ b/WebCore/page/mac/DragControllerMac.mm @@ -66,4 +66,13 @@ const IntSize& DragController::maxDragImageSize() return maxDragImageSize; } +void DragController::cleanupAfterSystemDrag() +{ + // Drag has ended, dragEnded *should* have been called, however it is possible + // for the UIDelegate to take over the drag, and fail to send the appropriate + // drag termination event. As dragEnded just resets drag variables, we just + // call it anyway to be on the safe side + dragEnded(); +} + } diff --git a/WebCore/page/mac/EventHandlerMac.mm b/WebCore/page/mac/EventHandlerMac.mm index 562c1dd..5d09843 100644 --- a/WebCore/page/mac/EventHandlerMac.mm +++ b/WebCore/page/mac/EventHandlerMac.mm @@ -26,6 +26,7 @@ #include "config.h" #include "EventHandler.h" +#include "AXObjectCache.h" #include "BlockExceptions.h" #include "ChromeClient.h" #include "ClipboardMac.h" @@ -42,16 +43,15 @@ #include "RenderWidget.h" #include "Scrollbar.h" #include "Settings.h" +#include <wtf/StdLibExtras.h> namespace WebCore { -unsigned EventHandler::s_accessKeyModifiers = PlatformKeyboardEvent::CtrlKey | PlatformKeyboardEvent::AltKey; - const double EventHandler::TextDragDelay = 0.15; static RetainPtr<NSEvent>& currentEvent() { - static RetainPtr<NSEvent> event; + DEFINE_STATIC_LOCAL(RetainPtr<NSEvent>, event, ()); return event; } @@ -643,4 +643,15 @@ bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& return passSubframeEventToSubframe(mev, subframe); } +unsigned EventHandler::accessKeyModifiers() +{ + // Control+Option key combinations are usually unused on Mac OS X, but not when VoiceOver is enabled. + // So, we use Control in this case, even though it conflicts with Emacs-style key bindings. + // See <https://bugs.webkit.org/show_bug.cgi?id=21107> for more detail. + if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled()) + return PlatformKeyboardEvent::CtrlKey; + + return PlatformKeyboardEvent::CtrlKey | PlatformKeyboardEvent::AltKey; +} + } diff --git a/WebCore/page/mac/FrameMac.mm b/WebCore/page/mac/FrameMac.mm index 66e2d04..84d7549 100644 --- a/WebCore/page/mac/FrameMac.mm +++ b/WebCore/page/mac/FrameMac.mm @@ -36,7 +36,6 @@ #import "EditorClient.h" #import "Event.h" #import "FrameLoaderClient.h" -#import "FramePrivate.h" #import "FrameView.h" #import "GraphicsContext.h" #import "HTMLNames.h" @@ -59,6 +58,7 @@ #import <Carbon/Carbon.h> #import <runtime/JSLock.h> +#import <wtf/StdLibExtras.h> #if ENABLE(DASHBOARD_SUPPORT) #import "WebDashboardRegion.h" @@ -78,7 +78,7 @@ using namespace HTMLNames; // Either get cached regexp or build one that matches any of the labels. // The regexp we build is of the form: (STR1|STR2|STRN) -RegularExpression* regExpForLabels(NSArray* labels) +static RegularExpression* regExpForLabels(NSArray* labels) { // All the ObjC calls in this method are simple array and string // calls which we can assume do not raise exceptions @@ -88,8 +88,8 @@ RegularExpression* regExpForLabels(NSArray* labels) // that the app will use is equal to the number of locales is used in searching. static const unsigned int regExpCacheSize = 4; static NSMutableArray* regExpLabels = nil; - static Vector<RegularExpression*> regExps; - static RegularExpression wordRegExp = RegularExpression("\\w"); + DEFINE_STATIC_LOCAL(Vector<RegularExpression*>, regExps, ()); + DEFINE_STATIC_LOCAL(RegularExpression, wordRegExp, ("\\w", TextCaseSensitive)); RegularExpression* result; if (!regExpLabels) @@ -107,8 +107,8 @@ RegularExpression* regExpForLabels(NSArray* labels) bool startsWithWordChar = false; bool endsWithWordChar = false; if (label.length() != 0) { - startsWithWordChar = wordRegExp.search(label.substring(0, 1)) >= 0; - endsWithWordChar = wordRegExp.search(label.substring(label.length() - 1, 1)) >= 0; + startsWithWordChar = wordRegExp.match(label.substring(0, 1)) >= 0; + endsWithWordChar = wordRegExp.match(label.substring(label.length() - 1, 1)) >= 0; } if (i != 0) @@ -123,7 +123,7 @@ RegularExpression* regExpForLabels(NSArray* labels) pattern.append("\\b"); } pattern.append(")"); - result = new RegularExpression(pattern, false); + result = new RegularExpression(pattern, TextCaseInsensitive); } // add regexp to the cache, making sure it is at the front for LRU ordering @@ -196,8 +196,7 @@ NSString* Frame::searchForLabelsBeforeElement(NSArray* labels, Element* element) n = n->traversePreviousNode()) { if (n->hasTagName(formTag) - || (n->isHTMLElement() - && static_cast<HTMLElement*>(n)->isGenericFormElement())) + || (n->isHTMLElement() && static_cast<Element*>(n)->isFormControlElement())) { // We hit another form element or the start of the form - bail out break; @@ -240,7 +239,7 @@ NSString* Frame::matchLabelsAgainstElement(NSArray* labels, Element* element) return nil; // Make numbers and _'s in field names behave like word boundaries, e.g., "address2" - replace(name, RegularExpression("\\d"), " "); + replace(name, RegularExpression("\\d", TextCaseSensitive), " "); name.replace('_', ' '); RegularExpression* regExp = regExpForLabels(labels); @@ -251,7 +250,7 @@ NSString* Frame::matchLabelsAgainstElement(NSArray* labels, Element* element) int bestLength = -1; int start = 0; do { - pos = regExp->search(name, start); + pos = regExp->match(name, start); if (pos != -1) { length = regExp->matchedLength(); if (length >= bestLength) { @@ -269,7 +268,7 @@ NSString* Frame::matchLabelsAgainstElement(NSArray* labels, Element* element) NSImage* Frame::imageFromRect(NSRect rect) const { - NSView* view = d->m_view->documentView(); + NSView* view = m_view->documentView(); if (!view) return nil; if (![view respondsToSelector:@selector(drawSingleRect:)]) @@ -314,10 +313,10 @@ NSImage* Frame::imageFromRect(NSRect rect) const NSImage* Frame::selectionImage(bool forceBlackText) const { - d->m_view->setPaintRestriction(forceBlackText ? PaintRestrictionSelectionOnlyBlackText : PaintRestrictionSelectionOnly); - d->m_doc->updateLayout(); - NSImage* result = imageFromRect(selectionRect()); - d->m_view->setPaintRestriction(PaintRestrictionNone); + m_view->setPaintRestriction(forceBlackText ? PaintRestrictionSelectionOnlyBlackText : PaintRestrictionSelectionOnly); + m_doc->updateLayout(); + NSImage* result = imageFromRect(selectionBounds()); + m_view->setPaintRestriction(PaintRestrictionNone); return result; } @@ -328,16 +327,16 @@ NSImage* Frame::snapshotDragImage(Node* node, NSRect* imageRect, NSRect* element return nil; renderer->updateDragState(true); // mark dragged nodes (so they pick up the right CSS) - d->m_doc->updateLayout(); // forces style recalc - needed since changing the drag state might + m_doc->updateLayout(); // forces style recalc - needed since changing the drag state might // imply new styles, plus JS could have changed other things IntRect topLevelRect; NSRect paintingRect = renderer->paintingRootRect(topLevelRect); - d->m_view->setNodeToDraw(node); // invoke special sub-tree drawing mode + m_view->setNodeToDraw(node); // invoke special sub-tree drawing mode NSImage* result = imageFromRect(paintingRect); renderer->updateDragState(false); - d->m_doc->updateLayout(); - d->m_view->setNodeToDraw(0); + m_doc->updateLayout(); + m_view->setNodeToDraw(0); if (elementRect) *elementRect = topLevelRect; @@ -352,14 +351,14 @@ NSImage* Frame::nodeImage(Node* node) const if (!renderer) return nil; - d->m_doc->updateLayout(); // forces style recalc + m_doc->updateLayout(); // forces style recalc IntRect topLevelRect; NSRect paintingRect = renderer->paintingRootRect(topLevelRect); - d->m_view->setNodeToDraw(node); // invoke special sub-tree drawing mode + m_view->setNodeToDraw(node); // invoke special sub-tree drawing mode NSImage* result = imageFromRect(paintingRect); - d->m_view->setNodeToDraw(0); + m_view->setNodeToDraw(0); return result; } @@ -536,18 +535,18 @@ DragImageRef Frame::dragImageForSelection() void Frame::setUserStyleSheetLocation(const KURL& url) { - delete d->m_userStyleSheetLoader; - d->m_userStyleSheetLoader = 0; - if (d->m_doc && d->m_doc->docLoader()) - d->m_userStyleSheetLoader = new UserStyleSheetLoader(d->m_doc, url.string()); + delete m_userStyleSheetLoader; + m_userStyleSheetLoader = 0; + if (m_doc && m_doc->docLoader()) + m_userStyleSheetLoader = new UserStyleSheetLoader(m_doc, url.string()); } void Frame::setUserStyleSheet(const String& styleSheet) { - delete d->m_userStyleSheetLoader; - d->m_userStyleSheetLoader = 0; - if (d->m_doc) - d->m_doc->setUserStyleSheet(styleSheet); + delete m_userStyleSheetLoader; + m_userStyleSheetLoader = 0; + if (m_doc) + m_doc->setUserStyleSheet(styleSheet); } } // namespace WebCore diff --git a/WebCore/page/mac/WebCoreViewFactory.h b/WebCore/page/mac/WebCoreViewFactory.h index 4caef54..883d586 100644 --- a/WebCore/page/mac/WebCoreViewFactory.h +++ b/WebCore/page/mac/WebCoreViewFactory.h @@ -79,6 +79,7 @@ - (NSString *)contextMenuItemTagStartSpeaking; - (NSString *)contextMenuItemTagStopSpeaking; - (NSString *)contextMenuItemTagWritingDirectionMenu; +- (NSString *)contextMenuItemTagTextDirectionMenu; - (NSString *)contextMenuItemTagDefaultDirection; - (NSString *)contextMenuItemTagLeftToRight; - (NSString *)contextMenuItemTagRightToLeft; @@ -103,6 +104,7 @@ - (WebCoreTextMarker *)endOfTextMarkerRange:(WebCoreTextMarkerRange *)range; - (void)accessibilityHandleFocusChanged; +- (CGRect)accessibilityConvertScreenRect:(CGRect)bounds; - (AXUIElementRef)AXUIElementForElement:(id)element; - (void)unregisterUniqueIdForUIElement:(id)element; diff --git a/WebCore/page/mac/WebDashboardRegion.m b/WebCore/page/mac/WebDashboardRegion.m index d2eb07f..a6b9872 100644 --- a/WebCore/page/mac/WebDashboardRegion.m +++ b/WebCore/page/mac/WebDashboardRegion.m @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2004 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -22,11 +22,16 @@ * (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" + +#import "config.h" #import "WebDashboardRegion.h" +#import <wtf/UnusedParam.h> + #if ENABLE(DASHBOARD_SUPPORT) + @implementation WebDashboardRegion + - initWithRect:(NSRect)r clip:(NSRect)c type:(WebDashboardRegionType)t { self = [super init]; @@ -36,8 +41,10 @@ return self; } -- (id)copyWithZone:(NSZone *)zone +- (id)copyWithZone:(NSZone *)unusedZone { + UNUSED_PARAM(unusedZone); + return [self retain]; } @@ -56,22 +63,32 @@ return type; } +static const char* typeName(WebDashboardRegionType type) +{ + switch (type) { + case WebDashboardRegionTypeNone: + return "None"; + case WebDashboardRegionTypeCircle: + return "Circle"; + case WebDashboardRegionTypeRectangle: + return "Rectangle"; + case WebDashboardRegionTypeScrollerRectangle: + return "ScrollerRectangle"; + } + return "Unknown"; +} + - (NSString *)description { - return [NSString stringWithFormat:@"rect:%@ clip:%@ type:%s", - NSStringFromRect(rect), - NSStringFromRect(clip), - type == WebDashboardRegionTypeNone ? "None" : - (type == WebDashboardRegionTypeCircle ? "Circle" : - (type == WebDashboardRegionTypeRectangle ? "Rectangle" : - (type == WebDashboardRegionTypeScrollerRectangle ? "ScrollerRectangle" : - "Unknown")))]; + return [NSString stringWithFormat:@"rect:%@ clip:%@ type:%s", NSStringFromRect(rect), NSStringFromRect(clip), typeName(type)]; } +// FIXME: Overriding isEqual: without overriding hash will cause trouble if this ever goes into a NSSet or is the key in an NSDictionary. - (BOOL)isEqual:(id)other { - return NSEqualRects (rect, [other dashboardRegionRect]) && NSEqualRects (clip, [other dashboardRegionClip]) && type == [other dashboardRegionType]; + return NSEqualRects(rect, [other dashboardRegionRect]) && NSEqualRects(clip, [other dashboardRegionClip]) && type == [other dashboardRegionType]; } @end + #endif diff --git a/WebCore/page/qt/AccessibilityObjectQt.cpp b/WebCore/page/qt/AccessibilityObjectQt.cpp index b755645..1710027 100644 --- a/WebCore/page/qt/AccessibilityObjectQt.cpp +++ b/WebCore/page/qt/AccessibilityObjectQt.cpp @@ -20,6 +20,8 @@ #include "config.h" #include "AccessibilityObject.h" +#if HAVE(ACCESSIBILITY) + namespace WebCore { bool AccessibilityObject::accessibilityIgnoreAttachment() const @@ -28,3 +30,5 @@ bool AccessibilityObject::accessibilityIgnoreAttachment() const } } // namespace WebCore + +#endif // HAVE(ACCESSIBILITY) diff --git a/WebCore/page/qt/DragControllerQt.cpp b/WebCore/page/qt/DragControllerQt.cpp index 62372d0..1fe56b4 100644 --- a/WebCore/page/qt/DragControllerQt.cpp +++ b/WebCore/page/qt/DragControllerQt.cpp @@ -65,4 +65,8 @@ const IntSize& DragController::maxDragImageSize() return maxDragImageSize; } +void DragController::cleanupAfterSystemDrag() +{ +} + } diff --git a/WebCore/page/qt/EventHandlerQt.cpp b/WebCore/page/qt/EventHandlerQt.cpp index 421caaf..3425289 100644 --- a/WebCore/page/qt/EventHandlerQt.cpp +++ b/WebCore/page/qt/EventHandlerQt.cpp @@ -56,8 +56,6 @@ QT_END_NAMESPACE namespace WebCore { -unsigned EventHandler::s_accessKeyModifiers = PlatformKeyboardEvent::CtrlKey; - const double EventHandler::TextDragDelay = 0.0; static bool isKeyboardOptionTab(KeyboardEvent* event) @@ -132,4 +130,9 @@ bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& return true; } +unsigned EventHandler::accessKeyModifiers() +{ + return PlatformKeyboardEvent::CtrlKey; +} + } diff --git a/WebCore/page/qt/FrameQt.cpp b/WebCore/page/qt/FrameQt.cpp index 1bbbff5..388bf66 100644 --- a/WebCore/page/qt/FrameQt.cpp +++ b/WebCore/page/qt/FrameQt.cpp @@ -23,7 +23,7 @@ #include "config.h" #include "Frame.h" -#include "FramePrivate.h" + #include "UserStyleSheetLoader.h" namespace WebCore { @@ -35,18 +35,18 @@ DragImageRef Frame::dragImageForSelection() void Frame::setUserStyleSheetLocation(const KURL& url) { - delete d->m_userStyleSheetLoader; - d->m_userStyleSheetLoader = 0; - if (d->m_doc && d->m_doc->docLoader()) - d->m_userStyleSheetLoader = new UserStyleSheetLoader(d->m_doc, url.string()); + delete m_userStyleSheetLoader; + m_userStyleSheetLoader = 0; + if (m_doc && m_doc->docLoader()) + m_userStyleSheetLoader = new UserStyleSheetLoader(m_doc, url.string()); } void Frame::setUserStyleSheet(const String& styleSheet) { - delete d->m_userStyleSheetLoader; - d->m_userStyleSheetLoader = 0; - if (d->m_doc) - d->m_doc->setUserStyleSheet(styleSheet); + delete m_userStyleSheetLoader; + m_userStyleSheetLoader = 0; + if (m_doc) + m_doc->setUserStyleSheet(styleSheet); } } diff --git a/WebCore/page/win/AccessibilityObjectWin.cpp b/WebCore/page/win/AccessibilityObjectWin.cpp index e309ac8..0a386c7 100644 --- a/WebCore/page/win/AccessibilityObjectWin.cpp +++ b/WebCore/page/win/AccessibilityObjectWin.cpp @@ -23,10 +23,11 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - #include "config.h" #include "AccessibilityObject.h" +#if HAVE(ACCESSIBILITY) + namespace WebCore { bool AccessibilityObject::accessibilityIgnoreAttachment() const @@ -35,3 +36,5 @@ bool AccessibilityObject::accessibilityIgnoreAttachment() const } } // namespace WebCore + +#endif // HAVE(ACCESSIBILITY) diff --git a/WebCore/page/win/DragControllerWin.cpp b/WebCore/page/win/DragControllerWin.cpp index 41f3008..dca8ea2 100644 --- a/WebCore/page/win/DragControllerWin.cpp +++ b/WebCore/page/win/DragControllerWin.cpp @@ -61,4 +61,8 @@ const IntSize& DragController::maxDragImageSize() return maxDragImageSize; } +void DragController::cleanupAfterSystemDrag() +{ +} + } diff --git a/WebCore/page/win/EventHandlerWin.cpp b/WebCore/page/win/EventHandlerWin.cpp index bfd2b02..88bc373 100644 --- a/WebCore/page/win/EventHandlerWin.cpp +++ b/WebCore/page/win/EventHandlerWin.cpp @@ -45,8 +45,6 @@ namespace WebCore { -unsigned EventHandler::s_accessKeyModifiers = PlatformKeyboardEvent::AltKey; - const double EventHandler::TextDragDelay = 0.0; bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe) @@ -108,4 +106,9 @@ bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestR return false; } +unsigned EventHandler::accessKeyModifiers() +{ + return PlatformKeyboardEvent::AltKey; +} + } diff --git a/WebCore/page/win/FrameCGWin.cpp b/WebCore/page/win/FrameCGWin.cpp index ad22967..8b0408d 100644 --- a/WebCore/page/win/FrameCGWin.cpp +++ b/WebCore/page/win/FrameCGWin.cpp @@ -44,18 +44,13 @@ static void drawRectIntoContext(IntRect rect, FrameView* view, GraphicsContext* rect.move(-offset.width(), -offset.height()); rect = view->convertToContainingWindow(rect); - gc->concatCTM(AffineTransform().translate(-rect.x(), -rect.y())); + gc->concatCTM(TransformationMatrix().translate(-rect.x(), -rect.y())); view->paint(gc, rect); } -HBITMAP imageFromSelection(Frame* frame, bool forceBlackText) +static HBITMAP imageFromRect(const Frame* frame, IntRect& ir) { - frame->view()->setPaintRestriction(forceBlackText ? PaintRestrictionSelectionOnlyBlackText : PaintRestrictionSelectionOnly); - FloatRect fr = frame->selectionRect(); - IntRect ir(static_cast<int>(fr.x()), static_cast<int>(fr.y()), - static_cast<int>(fr.width()), static_cast<int>(fr.height())); - void* bits; HDC hdc = CreateCompatibleDC(0); int w = ir.width(); @@ -72,16 +67,44 @@ HBITMAP imageFromSelection(Frame* frame, bool forceBlackText) GraphicsContext gc(context); - frame->document()->updateLayout(); drawRectIntoContext(ir, frame->view(), &gc); CGContextRelease(context); SelectObject(hdc, hbmpOld); DeleteDC(hdc); + return hbmp; +} + +HBITMAP imageFromSelection(Frame* frame, bool forceBlackText) +{ + frame->document()->updateLayout(); + + frame->view()->setPaintRestriction(forceBlackText ? PaintRestrictionSelectionOnlyBlackText : PaintRestrictionSelectionOnly); + FloatRect fr = frame->selectionBounds(); + IntRect ir(static_cast<int>(fr.x()), static_cast<int>(fr.y()), + static_cast<int>(fr.width()), static_cast<int>(fr.height())); + HBITMAP image = imageFromRect(frame, ir); frame->view()->setPaintRestriction(PaintRestrictionNone); + return image; +} - return hbmp; +HBITMAP Frame::nodeImage(Node* node) const +{ + RenderObject* renderer = node->renderer(); + if (!renderer) + return 0; + + IntRect topLevelRect; + IntRect paintingRect = renderer->paintingRootRect(topLevelRect); + + document()->updateLayout(); + + m_view->setNodeToDraw(node); // invoke special sub-tree drawing mode + HBITMAP result = imageFromRect(this, paintingRect); + m_view->setNodeToDraw(0); + + return result; } } // namespace WebCore diff --git a/WebCore/page/win/FrameCairoWin.cpp b/WebCore/page/win/FrameCairoWin.cpp index a645a10..f5b832e 100644 --- a/WebCore/page/win/FrameCairoWin.cpp +++ b/WebCore/page/win/FrameCairoWin.cpp @@ -39,4 +39,10 @@ HBITMAP imageFromSelection(Frame* frame, bool forceBlackText) return 0; } +HBITMAP Frame::nodeImage(Node*) const +{ + notImplemented(); + return 0; +} + } // namespace WebCore diff --git a/WebCore/page/win/FrameWin.cpp b/WebCore/page/win/FrameWin.cpp index 536f5d8..fef1ffa 100644 --- a/WebCore/page/win/FrameWin.cpp +++ b/WebCore/page/win/FrameWin.cpp @@ -27,10 +27,9 @@ #include "runtime.h" #include "FrameWin.h" -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include "FloatRect.h" #include "Document.h" -#include "FramePrivate.h" #include "RenderView.h" #include "Settings.h" diff --git a/WebCore/page/wx/AccessibilityObjectWx.cpp b/WebCore/page/wx/AccessibilityObjectWx.cpp index b755645..1710027 100644 --- a/WebCore/page/wx/AccessibilityObjectWx.cpp +++ b/WebCore/page/wx/AccessibilityObjectWx.cpp @@ -20,6 +20,8 @@ #include "config.h" #include "AccessibilityObject.h" +#if HAVE(ACCESSIBILITY) + namespace WebCore { bool AccessibilityObject::accessibilityIgnoreAttachment() const @@ -28,3 +30,5 @@ bool AccessibilityObject::accessibilityIgnoreAttachment() const } } // namespace WebCore + +#endif // HAVE(ACCESSIBILITY) diff --git a/WebCore/page/wx/DragControllerWx.cpp b/WebCore/page/wx/DragControllerWx.cpp index 659364f..c288a01 100644 --- a/WebCore/page/wx/DragControllerWx.cpp +++ b/WebCore/page/wx/DragControllerWx.cpp @@ -65,4 +65,8 @@ const IntSize& DragController::maxDragImageSize() return maxDragImageSize; } +void DragController::cleanupAfterSystemDrag() +{ +} + } diff --git a/WebCore/page/wx/EventHandlerWx.cpp b/WebCore/page/wx/EventHandlerWx.cpp index ce4473f..a0d8b23 100644 --- a/WebCore/page/wx/EventHandlerWx.cpp +++ b/WebCore/page/wx/EventHandlerWx.cpp @@ -39,8 +39,6 @@ namespace WebCore { -unsigned EventHandler::s_accessKeyModifiers = PlatformKeyboardEvent::AltKey; - const double EventHandler::TextDragDelay = 0.0; bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe) @@ -91,4 +89,9 @@ PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const return ClipboardWx::create(ClipboardWritable, true); } +unsigned EventHandler::accessKeyModifiers() +{ + return PlatformKeyboardEvent::AltKey; +} + } |