diff options
99 files changed, 1492 insertions, 1193 deletions
diff --git a/ThirdPartyProject.prop b/ThirdPartyProject.prop index 4efb8e4..7d97ec6 100644 --- a/ThirdPartyProject.prop +++ b/ThirdPartyProject.prop @@ -11,4 +11,4 @@ homepage=http\://webkit.org/ # Currently we track the Chromium 9.0.597 release branch: # http://trac.webkit.org/browser/branches/chromium/597 # which is WebKit r72805 + stability cherry picks. -webkit.chromiumRelease=http\://src.chromium.org/svn/releases/9.0.597.83/DEPS +webkit.chromiumRelease=http\://src.chromium.org/svn/releases/9.0.597.106/DEPS diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog index ae5f73f..2749f26 100644 --- a/WebCore/ChangeLog +++ b/WebCore/ChangeLog @@ -1,3 +1,234 @@ +2011-01-30 Kenichi Ishibashi <bashi@google.com> + + Reviewed by Kent Tamura. + + Dangling form associated elements should not be registered on the document + https://bugs.webkit.org/show_bug.cgi?id=53223 + + Adds insertedIntoDocument() and remvoedFromDocument() to + FormAssociatedElement class to register the element on the document + if and only if it actually inserted into (removed from) the document. + + Test: fast/forms/dangling-form-element-crash.html + + * html/FormAssociatedElement.cpp: + (WebCore::FormAssociatedElement::insertedIntoDocument): Added. + (WebCore::FormAssociatedElement::removedFromDocument): Ditto. + (WebCore::FormAssociatedElement::insertedIntoTree): Don't register + the element to a document. + (WebCore::FormAssociatedElement::removedFromTree): Don't unregister + the element from a document. + * html/FormAssociatedElement.h: + * html/HTMLFormControlElement.cpp: + (WebCore::HTMLFormControlElement::insertedIntoDocument): Added. + (WebCore::HTMLFormControlElement::removedFromDocument): Ditto. + * html/HTMLFormControlElement.h: + * html/HTMLObjectElement.cpp: + (WebCore::HTMLObjectElement::insertedIntoDocument): Calls + FormAssociatedElement::insertedIntoDocument(). + (WebCore::HTMLObjectElement::removedFromDocument): Calls + FormAssociatedElement::removedFromDocument(). + +2011-02-08 Zhenyao Mo <zmo@google.com> + + Reviewed by Kenneth Russell. + + drawElements should check if a buffer is bound to ELEMENT_ARRAY_BUFFER + https://bugs.webkit.org/show_bug.cgi?id=54017 + + * html/canvas/WebGLRenderingContext.cpp: + (WebCore::WebGLRenderingContext::drawElements): + +2011-02-02 Chris Evans <cevans@chromium.org> + + Reviewed by Darin Fisher. + + window.find() can fail when switching case sensitivity + https://bugs.webkit.org/show_bug.cgi?id=53654 + + Reset the pattern to a safe one when done, to avoid usearch_reset() + indirectly touching the old, stale text pointer. + + Test: fast/text/find-window.html + + * editing/TextIterator.cpp: + (WebCore::SearchBuffer::~SearchBuffer): leave a safe pattern buffer when done. + +2011-02-03 Justin Schuh <jschuh@chromium.org> + + Reviewed by Dirk Schulze. + + startAnimations should use a local, RefCounted Vector. + https://bugs.webkit.org/show_bug.cgi?id=53458 + + Test: svg/custom/use-animation-in-fill.html + + * svg/SVGDocumentExtensions.cpp: + (WebCore::SVGDocumentExtensions::startAnimations): + +2011-02-03 Abhishek Arya <inferno@chromium.org> + + Reviewed by James Robinson. + + Enforce more limits on root inline boxes height calculations. + https://bugs.webkit.org/show_bug.cgi?id=53729 + + Test: fast/overflow/overflow-height-float-not-removed-crash.html + + * rendering/RenderBlock.cpp: + (WebCore::RenderBlock::removeFloatingObject): prevent logicalBottom to + become negative when logicalTop is INT_MAX. + (WebCore::RenderBlock::markLinesDirtyInBlockRange): when logicalBottom + is INT_MAX, we should dirty everything. So, we bail out to make + afterLowest equal to the lastRootBox() or lowestDirstLine. + +2011-01-26 Emil A Eklund <eae@chromium.org> + + Reviewed by Alexey Proskuryakov. + + Remove cached document reference from CSSStyleSheet and XSLStyleSheet. + https://bugs.webkit.org/show_bug.cgi?id=52084 + + Test: fast/dom/css-delete-doc.html + + * css/CSSMediaRule.cpp: + (WebCore::CSSMediaRule::insertRule): + (WebCore::CSSMediaRule::deleteRule): + * css/CSSStyleSheet.cpp: + (WebCore::CSSStyleSheet::CSSStyleSheet): + (WebCore::CSSStyleSheet::document): + * css/CSSStyleSheet.h: + * xml/XSLStyleSheet.h: + (WebCore::XSLStyleSheet::parentStyleSheet): + * xml/XSLStyleSheetLibxslt.cpp: + (WebCore::XSLStyleSheet::XSLStyleSheet): + (WebCore::XSLStyleSheet::cachedResourceLoader): + (WebCore::XSLStyleSheet::setParentStyleSheet): + (WebCore::XSLStyleSheet::ownerDocument): + * xml/XSLStyleSheetQt.cpp: + (WebCore::XSLStyleSheet::XSLStyleSheet): + (WebCore::XSLStyleSheet::cachedResourceLoader): + (WebCore::XSLStyleSheet::ownerDocument): + +2011-01-27 Abhishek Arya <inferno@chromium.org> + + Reviewed by Dave Hyatt. + + If beforeChild is wrapped in an anonymous table section, we need to + go the parent to find it and use it before adding childs to table. + https://bugs.webkit.org/show_bug.cgi?id=53276 + + We need to make sure that beforeChild's parent is "this" before calling + RenderBox::addChild. The previous condition in while is too restrictive + and fails to calculate the right beforeChild value when its display + style is table caption. + Test: fast/table/before-child-non-table-section-add-table-crash.html + + * rendering/RenderTable.cpp: + (WebCore::RenderTable::addChild): + +2011-02-01 Abhishek Arya <inferno@chromium.org> + + Reviewed by Dan Bernstein. + + Do not add a node in the document's stylesheet candidate node list if the + node is already removed from document. + https://bugs.webkit.org/show_bug.cgi?id=53441 + + Test: fast/css/stylesheet-candidate-nodes-crash.xhtml + + * dom/Document.cpp: + (WebCore::Document::addStyleSheetCandidateNode): + +2011-01-31 Abhishek Arya <inferno@chromium.org> + + Reviewed by Dimitri Glazkov. + + Check the textarea node still exists in document before casting + it to HTMLTextAreaElement. + https://bugs.webkit.org/show_bug.cgi?id=53429 + + Test: fast/forms/textarea-node-removed-from-document-crash.html + + * rendering/RenderTextControlMultiLine.cpp: + (WebCore::RenderTextControlMultiLine::~RenderTextControlMultiLine): + +2011-02-02 Jian Li <jianli@chromium.org> + + Reviewed by Kenneth Russell. + + [V8] Accessing DataView with index of -1 returns 0, doesn't throw + https://bugs.webkit.org/show_bug.cgi?id=53559 + + Added test cases to cover this in fast/canvas/webgl/data-view-test.html. + + * html/canvas/DataView.h: + (WebCore::DataView::beyondRange): + +2011-02-06 Andreas Kling <kling@webkit.org> + + Reviewed by Dirk Schulze. + + Fix potential buffer overrun in SVGTextRunWalker::walk() + https://bugs.webkit.org/show_bug.cgi?id=53870 + + A new String was created from a UChar* with a 'length' argument + that could be greater than the number of UChars available. + + * svg/SVGFont.cpp: + (WebCore::SVGTextRunWalker::walk): + +2011-02-02 Cris Neckar <cdn@chromium.org> + + Reviewed by James Robinson. + + Refcount domwindows when dispatching device orientation events. + https://bugs.webkit.org/show_bug.cgi?id=53623 + + Test: fast/events/device-orientation-crash.html + + * dom/DeviceMotionController.cpp: + (WebCore::DeviceMotionController::timerFired): + (WebCore::DeviceMotionController::didChangeDeviceMotion): + * dom/DeviceMotionController.h: + * dom/DeviceOrientationController.cpp: + (WebCore::DeviceOrientationController::timerFired): + (WebCore::DeviceOrientationController::didChangeDeviceOrientation): + * dom/DeviceOrientationController.h: + +2011-01-27 Abhishek Arya <inferno@chromium.org> + + Reviewed by Dan Bernstein. + + Recalc table sections if needed before calculating the first line + box baseline. + https://bugs.webkit.org/show_bug.cgi?id=53265 + + When we try to calculate the baseline position of a table cell, + we recurse through all the child sibling boxes (when children are + non inline) and add their first linebox baseline values. If one of + the children is a table with pending section recalc, we will access + wrong table section values. We recalc table sections if it is needed. + + Test: fast/table/recalc-section-first-body-crash-main.html + + * rendering/RenderTable.cpp: + (WebCore::RenderTable::firstLineBoxBaseline): + +2011-01-27 Cris Neckar <cdn@chromium.org> + + Reviewed by Dimitri Glazkov. + + Clear the parent on a css keyframe's m_style when removing it from the stylesheet. + https://bugs.webkit.org/show_bug.cgi?id=52320 + + Test: fast/css/css-keyframe-style-crash.html + + * css/CSSRuleList.cpp: + (WebCore::CSSRuleList::deleteRule): + * css/WebKitCSSKeyframesRule.cpp: + (WebCore::WebKitCSSKeyframesRule::~WebKitCSSKeyframesRule): + 2011-01-20 Xiaomei Ji <xji@chromium.org> Reviewed by Dan Bernstein. diff --git a/WebCore/bindings/v8/V8NPUtils.cpp b/WebCore/bindings/v8/V8NPUtils.cpp index 8fa19d7..cb752be 100644 --- a/WebCore/bindings/v8/V8NPUtils.cpp +++ b/WebCore/bindings/v8/V8NPUtils.cpp @@ -65,8 +65,10 @@ void convertV8ObjectToNPVariant(v8::Local<v8::Value> object, NPObject* owner, NP VOID_TO_NPVARIANT(*result); else if (object->IsString()) { v8::String::Utf8Value utf8(object); - char* utf8_chars = strdup(*utf8); - STRINGN_TO_NPVARIANT(utf8_chars, utf8.length(), *result); + int length = utf8.length() + 1; + char* utf8Chars = reinterpret_cast<char*>(malloc(length)); + memcpy(utf8Chars, *utf8, length); + STRINGN_TO_NPVARIANT(utf8Chars, utf8.length(), *result); } else if (object->IsObject()) { DOMWindow* window = V8Proxy::retrieveWindow(V8Proxy::currentContext()); NPObject* npobject = npCreateV8ScriptObject(0, v8::Handle<v8::Object>::Cast(object), window); diff --git a/WebCore/config.h b/WebCore/config.h index 7174c4b..6117fef 100644 --- a/WebCore/config.h +++ b/WebCore/config.h @@ -160,7 +160,7 @@ #define ANDROID_META_SUPPORT // Converts ListBoxes to dropdown popup lists. -#define ANDROID_LISTBOX_USES_MENU_LIST +#define ENABLE_NO_LISTBOX_RENDERING 1 #define ANDROID_MULTIPLE_WINDOWS #define ANDROID_CSS_RING diff --git a/WebCore/css/CSSFontFaceSource.cpp b/WebCore/css/CSSFontFaceSource.cpp index 30a0072..d5dc6ec 100644 --- a/WebCore/css/CSSFontFaceSource.cpp +++ b/WebCore/css/CSSFontFaceSource.cpp @@ -168,7 +168,7 @@ SimpleFontData* CSSFontFaceSource::getFontData(const FontDescription& fontDescri #if ENABLE(SVG_FONTS) // In-Document SVG Fonts if (m_svgFontFaceElement) - fontData.set(new SimpleFontData(adoptPtr(new SVGFontData(m_svgFontFaceElement)), fontDescription.computedPixelSize(), syntheticBold, syntheticItalic)); + fontData.set(new SimpleFontData(adoptPtr(new SVGFontData(m_svgFontFaceElement.get())), fontDescription.computedPixelSize(), syntheticBold, syntheticItalic)); #endif } } else { @@ -190,6 +190,16 @@ SimpleFontData* CSSFontFaceSource::getFontData(const FontDescription& fontDescri } #if ENABLE(SVG_FONTS) +SVGFontFaceElement* CSSFontFaceSource::svgFontFaceElement() const +{ + return m_svgFontFaceElement.get(); +} + +void CSSFontFaceSource::setSVGFontFaceElement(PassRefPtr<SVGFontFaceElement> element) +{ + m_svgFontFaceElement = element; +} + bool CSSFontFaceSource::isSVGFontFaceSource() const { return m_svgFontFaceElement || (m_font && m_font->isSVGFont()); diff --git a/WebCore/css/CSSFontFaceSource.h b/WebCore/css/CSSFontFaceSource.h index e2057cc..a5c3e61 100644 --- a/WebCore/css/CSSFontFaceSource.h +++ b/WebCore/css/CSSFontFaceSource.h @@ -63,8 +63,8 @@ public: void pruneTable(); #if ENABLE(SVG_FONTS) - SVGFontFaceElement* svgFontFaceElement() const { return m_svgFontFaceElement; } - void setSVGFontFaceElement(SVGFontFaceElement* element) { m_svgFontFaceElement = element; } + SVGFontFaceElement* svgFontFaceElement() const; + void setSVGFontFaceElement(PassRefPtr<SVGFontFaceElement>); bool isSVGFontFaceSource() const; #endif @@ -75,7 +75,7 @@ private: HashMap<unsigned, SimpleFontData*> m_fontDataTable; // The hash key is composed of size synthetic styles. #if ENABLE(SVG_FONTS) - SVGFontFaceElement* m_svgFontFaceElement; + RefPtr<SVGFontFaceElement> m_svgFontFaceElement; RefPtr<SVGFontElement> m_externalSVGFontElement; #endif }; diff --git a/WebCore/css/CSSMediaRule.cpp b/WebCore/css/CSSMediaRule.cpp index 6348762..46dc780 100644 --- a/WebCore/css/CSSMediaRule.cpp +++ b/WebCore/css/CSSMediaRule.cpp @@ -88,8 +88,8 @@ unsigned CSSMediaRule::insertRule(const String& rule, unsigned index, ExceptionC newRule->setParent(this); unsigned returnedIndex = m_lstCSSRules->insertRule(newRule.get(), index); - // stylesheet() can only return 0 for computed style declarations. - stylesheet()->styleSheetChanged(); + if (stylesheet()) + stylesheet()->styleSheetChanged(); return returnedIndex; } @@ -105,8 +105,8 @@ void CSSMediaRule::deleteRule(unsigned index, ExceptionCode& ec) m_lstCSSRules->deleteRule(index); - // stylesheet() can only return 0 for computed style declarations. - stylesheet()->styleSheetChanged(); + if (stylesheet()) + stylesheet()->styleSheetChanged(); } String CSSMediaRule::cssText() const diff --git a/WebCore/css/CSSRuleList.cpp b/WebCore/css/CSSRuleList.cpp index 0a312af..da65632 100644 --- a/WebCore/css/CSSRuleList.cpp +++ b/WebCore/css/CSSRuleList.cpp @@ -22,8 +22,10 @@ #include "config.h" #include "CSSRuleList.h" +#include "CSSMutableStyleDeclaration.h" #include "CSSRule.h" #include "StyleList.h" +#include "WebKitCSSKeyframeRule.h" namespace WebCore { @@ -76,6 +78,11 @@ void CSSRuleList::deleteRule(unsigned index) return; } + if (m_lstCSSRules[index]->isKeyframeRule()) { + if (CSSMutableStyleDeclaration* style = static_cast<WebKitCSSKeyframeRule*>(m_lstCSSRules[index].get())->style()) + style->setParent(0); + } + m_lstCSSRules[index]->setParent(0); m_lstCSSRules.remove(index); } diff --git a/WebCore/css/CSSStyleSheet.cpp b/WebCore/css/CSSStyleSheet.cpp index d5487a1..16c2ba8 100644 --- a/WebCore/css/CSSStyleSheet.cpp +++ b/WebCore/css/CSSStyleSheet.cpp @@ -53,7 +53,6 @@ static bool isAcceptableCSSStyleSheetParent(Node* parentNode) CSSStyleSheet::CSSStyleSheet(CSSStyleSheet* parentSheet, const String& href, const KURL& baseURL, const String& charset) : StyleSheet(parentSheet, href, baseURL) - , m_document(parentSheet ? parentSheet->document() : 0) , m_charset(charset) , m_loadCompleted(false) , m_strictParsing(!parentSheet || parentSheet->useStrictParsing()) @@ -64,7 +63,6 @@ CSSStyleSheet::CSSStyleSheet(CSSStyleSheet* parentSheet, const String& href, con CSSStyleSheet::CSSStyleSheet(Node* parentNode, const String& href, const KURL& baseURL, const String& charset) : StyleSheet(parentNode, href, baseURL) - , m_document(parentNode->document()) , m_charset(charset) , m_loadCompleted(false) , m_strictParsing(false) @@ -82,7 +80,6 @@ CSSStyleSheet::CSSStyleSheet(CSSRule* ownerRule, const String& href, const KURL& , m_hasSyntacticallyValidCSSHeader(true) { CSSStyleSheet* parentSheet = ownerRule ? ownerRule->parentStyleSheet() : 0; - m_document = parentSheet ? parentSheet->document() : 0; m_isUserStyleSheet = parentSheet ? parentSheet->isUserStyleSheet() : false; } @@ -233,6 +230,24 @@ void CSSStyleSheet::checkLoaded() m_loadCompleted = ownerNode() ? ownerNode()->sheetLoaded() : true; } +Document* CSSStyleSheet::document() +{ + StyleBase* styleObject = this; + while (styleObject) { + if (styleObject->isCSSStyleSheet()) { + Node* ownerNode = static_cast<CSSStyleSheet*>(styleObject)->ownerNode(); + if (ownerNode) + return ownerNode->document(); + } + if (styleObject->isRule()) + styleObject = static_cast<CSSRule*>(styleObject)->parentStyleSheet(); + else + styleObject = styleObject->parent(); + } + + return 0; +} + void CSSStyleSheet::styleSheetChanged() { StyleBase* root = this; diff --git a/WebCore/css/CSSStyleSheet.h b/WebCore/css/CSSStyleSheet.h index 725518f..062886a 100644 --- a/WebCore/css/CSSStyleSheet.h +++ b/WebCore/css/CSSStyleSheet.h @@ -87,7 +87,7 @@ public: virtual void checkLoaded(); - Document* document() { return m_document; } + Document* document(); const String& charset() const { return m_charset; } @@ -112,7 +112,6 @@ private: virtual bool isCSSStyleSheet() const { return true; } virtual String type() const { return "text/css"; } - Document* m_document; OwnPtr<CSSNamespace> m_namespaces; String m_charset; bool m_loadCompleted : 1; diff --git a/WebCore/css/WebKitCSSKeyframesRule.cpp b/WebCore/css/WebKitCSSKeyframesRule.cpp index 23f9f34..bf0c463 100644 --- a/WebCore/css/WebKitCSSKeyframesRule.cpp +++ b/WebCore/css/WebKitCSSKeyframesRule.cpp @@ -24,12 +24,13 @@ */ #include "config.h" +#include "WebKitCSSKeyframesRule.h" +#include "CSSMutableStyleDeclaration.h" #include "CSSParser.h" -#include "WebKitCSSKeyframesRule.h" -#include "WebKitCSSKeyframeRule.h" #include "CSSRuleList.h" #include "StyleSheet.h" +#include "WebKitCSSKeyframeRule.h" namespace WebCore { @@ -45,8 +46,13 @@ WebKitCSSKeyframesRule::~WebKitCSSKeyframesRule() if (length == 0) return; - for (int i = 0; i < length; i++) + for (int i = 0; i < length; i++) { + if (m_lstCSSRules->item(i)->isKeyframeRule()) { + if (CSSMutableStyleDeclaration* style = static_cast<WebKitCSSKeyframeRule*>(m_lstCSSRules->item(i))->style()) + style->setParent(0); + } m_lstCSSRules->item(i)->setParent(0); + } } String WebKitCSSKeyframesRule::name() const diff --git a/WebCore/dom/DeviceMotionController.cpp b/WebCore/dom/DeviceMotionController.cpp index 3385167..28e201e 100644 --- a/WebCore/dom/DeviceMotionController.cpp +++ b/WebCore/dom/DeviceMotionController.cpp @@ -54,7 +54,7 @@ void DeviceMotionController::timerFired(Timer<DeviceMotionController>* timer) RefPtr<DeviceMotionData> deviceMotionData = m_client ? m_client->currentDeviceMotion() : DeviceMotionData::create(); RefPtr<DeviceMotionEvent> event = DeviceMotionEvent::create(eventNames().devicemotionEvent, deviceMotionData.get()); - Vector<DOMWindow*> listenersVector; + Vector<RefPtr<DOMWindow> > listenersVector; copyToVector(m_newListeners, listenersVector); m_newListeners.clear(); for (size_t i = 0; i < listenersVector.size(); ++i) @@ -100,7 +100,7 @@ void DeviceMotionController::removeAllListeners(DOMWindow* window) void DeviceMotionController::didChangeDeviceMotion(DeviceMotionData* deviceMotionData) { RefPtr<DeviceMotionEvent> event = DeviceMotionEvent::create(eventNames().devicemotionEvent, deviceMotionData); - Vector<DOMWindow*> listenersVector; + Vector<RefPtr<DOMWindow> > listenersVector; copyToVector(m_listeners, listenersVector); for (size_t i = 0; i < listenersVector.size(); ++i) listenersVector[i]->dispatchEvent(event); diff --git a/WebCore/dom/DeviceMotionController.h b/WebCore/dom/DeviceMotionController.h index 70c948e..80c9d94 100644 --- a/WebCore/dom/DeviceMotionController.h +++ b/WebCore/dom/DeviceMotionController.h @@ -52,9 +52,9 @@ private: void timerFired(Timer<DeviceMotionController>*); DeviceMotionClient* m_client; - typedef HashCountedSet<DOMWindow*> ListenersCountedSet; + typedef HashCountedSet<RefPtr<DOMWindow> > ListenersCountedSet; ListenersCountedSet m_listeners; - typedef HashSet<DOMWindow*> ListenersSet; + typedef HashSet<RefPtr<DOMWindow> > ListenersSet; ListenersSet m_newListeners; Timer<DeviceMotionController> m_timer; }; diff --git a/WebCore/dom/DeviceOrientationController.cpp b/WebCore/dom/DeviceOrientationController.cpp index 60fcf13..da42bec 100644 --- a/WebCore/dom/DeviceOrientationController.cpp +++ b/WebCore/dom/DeviceOrientationController.cpp @@ -54,7 +54,7 @@ void DeviceOrientationController::timerFired(Timer<DeviceOrientationController>* RefPtr<DeviceOrientation> orientation = m_client->lastOrientation(); RefPtr<DeviceOrientationEvent> event = DeviceOrientationEvent::create(eventNames().deviceorientationEvent, orientation.get()); - Vector<DOMWindow*> listenersVector; + Vector<RefPtr<DOMWindow> > listenersVector; copyToVector(m_newListeners, listenersVector); m_newListeners.clear(); for (size_t i = 0; i < listenersVector.size(); ++i) @@ -102,7 +102,7 @@ void DeviceOrientationController::removeAllListeners(DOMWindow* window) void DeviceOrientationController::didChangeDeviceOrientation(DeviceOrientation* orientation) { RefPtr<DeviceOrientationEvent> event = DeviceOrientationEvent::create(eventNames().deviceorientationEvent, orientation); - Vector<DOMWindow*> listenersVector; + Vector<RefPtr<DOMWindow> > listenersVector; copyToVector(m_listeners, listenersVector); for (size_t i = 0; i < listenersVector.size(); ++i) listenersVector[i]->dispatchEvent(event); diff --git a/WebCore/dom/DeviceOrientationController.h b/WebCore/dom/DeviceOrientationController.h index 4fa9006..5e06771 100644 --- a/WebCore/dom/DeviceOrientationController.h +++ b/WebCore/dom/DeviceOrientationController.h @@ -55,9 +55,9 @@ private: Page* m_page; DeviceOrientationClient* m_client; - typedef HashCountedSet<DOMWindow*> ListenersCountedSet; + typedef HashCountedSet<RefPtr<DOMWindow> > ListenersCountedSet; ListenersCountedSet m_listeners; - typedef HashSet<DOMWindow*> ListenersSet; + typedef HashSet<RefPtr<DOMWindow> > ListenersSet; ListenersSet m_newListeners; Timer<DeviceOrientationController> m_timer; }; diff --git a/WebCore/dom/Document.cpp b/WebCore/dom/Document.cpp index 400d917..f01ae32 100644 --- a/WebCore/dom/Document.cpp +++ b/WebCore/dom/Document.cpp @@ -2990,6 +2990,9 @@ void Document::styleSelectorChanged(StyleSelectorUpdateFlag updateFlag) void Document::addStyleSheetCandidateNode(Node* node, bool createdByParser) { + if (!node->inDocument()) + return; + // Until the <body> exists, we have no choice but to compare document positions, // since styles outside of the body and head continue to be shunted into the head // (and thus can shift to end up before dynamically added DOM content that is also diff --git a/WebCore/editing/TextIterator.cpp b/WebCore/editing/TextIterator.cpp index 2ea16fb..182742e 100644 --- a/WebCore/editing/TextIterator.cpp +++ b/WebCore/editing/TextIterator.cpp @@ -1869,6 +1869,11 @@ inline SearchBuffer::SearchBuffer(const String& target, bool isCaseSensitive) inline SearchBuffer::~SearchBuffer() { + // Leave the static object pointing to a valid string. + UErrorCode status = U_ZERO_ERROR; + usearch_setPattern(WebCore::searcher(), &newlineCharacter, 1, &status); + ASSERT(status == U_ZERO_ERROR); + unlockSearcher(); } diff --git a/WebCore/history/HistoryItem.cpp b/WebCore/history/HistoryItem.cpp index 34b54a1..2c1ffb3 100644 --- a/WebCore/history/HistoryItem.cpp +++ b/WebCore/history/HistoryItem.cpp @@ -60,6 +60,8 @@ HistoryItem::HistoryItem() , m_visitCount(0) , m_itemSequenceNumber(generateSequenceNumber()) , m_documentSequenceNumber(generateSequenceNumber()) + , m_next(0) + , m_prev(0) { } @@ -74,6 +76,8 @@ HistoryItem::HistoryItem(const String& urlString, const String& title, double ti , m_visitCount(0) , m_itemSequenceNumber(generateSequenceNumber()) , m_documentSequenceNumber(generateSequenceNumber()) + , m_next(0) + , m_prev(0) { iconDatabase()->retainIconForPageURL(m_urlString); } @@ -90,6 +94,8 @@ HistoryItem::HistoryItem(const String& urlString, const String& title, const Str , m_visitCount(0) , m_itemSequenceNumber(generateSequenceNumber()) , m_documentSequenceNumber(generateSequenceNumber()) + , m_next(0) + , m_prev(0) { iconDatabase()->retainIconForPageURL(m_urlString); } @@ -107,6 +113,8 @@ HistoryItem::HistoryItem(const KURL& url, const String& target, const String& pa , m_visitCount(0) , m_itemSequenceNumber(generateSequenceNumber()) , m_documentSequenceNumber(generateSequenceNumber()) + , m_next(0) + , m_prev(0) { iconDatabase()->retainIconForPageURL(m_urlString); } @@ -159,6 +167,38 @@ PassRefPtr<HistoryItem> HistoryItem::copy() const return adoptRef(new HistoryItem(*this)); } +void HistoryItem::reset() +{ + iconDatabase()->releaseIconForPageURL(m_urlString); + + m_urlString = String(); + m_originalURLString = String(); + m_referrer = String(); + m_target = String(); + m_parent = String(); + m_title = String(); + m_displayTitle = String(); + + m_lastVisitedTime = 0; + m_lastVisitWasHTTPNonGet = false; + + m_lastVisitWasFailure = false; + m_isTargetItem = false; + m_visitCount = 0; + m_dailyVisitCounts.clear(); + m_weeklyVisitCounts.clear(); + + m_redirectURLs.clear(); + + m_itemSequenceNumber = generateSequenceNumber(); + + m_stateObject = 0; + m_documentSequenceNumber = generateSequenceNumber(); + + m_formData = 0; + m_formContentType = String(); +} + const String& HistoryItem::urlString() const { return m_urlString; diff --git a/WebCore/history/HistoryItem.h b/WebCore/history/HistoryItem.h index ef9ac23..285f3d7 100644 --- a/WebCore/history/HistoryItem.h +++ b/WebCore/history/HistoryItem.h @@ -88,6 +88,9 @@ public: PassRefPtr<HistoryItem> copy() const; + // Resets the HistoryItem to its initial state, as returned by create(). + void reset(); + const String& originalURLString() const; const String& urlString() const; const String& title() const; @@ -141,7 +144,7 @@ public: void setDocumentSequenceNumber(long long number) { m_documentSequenceNumber = number; } long long documentSequenceNumber() const { return m_documentSequenceNumber; } - + void setFormInfoFromRequest(const ResourceRequest&); void setFormData(PassRefPtr<FormData>); void setFormContentType(const String&); @@ -251,11 +254,19 @@ private: OwnPtr<Vector<String> > m_redirectURLs; + // If two HistoryItems have the same item sequence number, then they are + // clones of one another. Traversing history from one such HistoryItem to + // another is a no-op. HistoryItem clones are created for parent and + // sibling frames when only a subframe navigates. long long m_itemSequenceNumber; + // If two HistoryItems have the same document sequence number, then they + // refer to the same instance of a document. Traversing history from one + // such HistoryItem to another preserves the document. + long long m_documentSequenceNumber; + // Support for HTML5 History RefPtr<SerializedScriptValue> m_stateObject; - long long m_documentSequenceNumber; // info used to repost form data RefPtr<FormData> m_formData; diff --git a/WebCore/html/HTMLFormControlElement.cpp b/WebCore/html/HTMLFormControlElement.cpp index daf4b93..88b47ac 100644 --- a/WebCore/html/HTMLFormControlElement.cpp +++ b/WebCore/html/HTMLFormControlElement.cpp @@ -162,7 +162,6 @@ void HTMLFormControlElement::willMoveToNewOwnerDocument() void HTMLFormControlElement::insertedIntoTree(bool deep) { if (fastHasAttribute(formAttr)) { - document()->registerFormElementWithFormAttribute(this); Element* element = document()->getElementById(fastGetAttribute(formAttr)); if (element && element->hasTagName(formTag)) { if (m_form) @@ -196,9 +195,6 @@ static inline Node* findRoot(Node* n) void HTMLFormControlElement::removedFromTree(bool deep) { - if (fastHasAttribute(formAttr)) - document()->unregisterFormElementWithFormAttribute(this); - // If the form and element are both in the same tree, preserve the connection to the form. // Otherwise, null out our form and remove ourselves from the form's list of elements. if (m_form && findRoot(this) != findRoot(m_form)) { @@ -209,6 +205,20 @@ void HTMLFormControlElement::removedFromTree(bool deep) HTMLElement::removedFromTree(deep); } +void HTMLFormControlElement::insertedIntoDocument() +{ + if (fastHasAttribute(formAttr)) + document()->registerFormElementWithFormAttribute(this); + HTMLElement::insertedIntoDocument(); +} + +void HTMLFormControlElement::removedFromDocument() +{ + if (fastHasAttribute(formAttr)) + document()->unregisterFormElementWithFormAttribute(this); + HTMLElement::removedFromDocument(); +} + const AtomicString& HTMLFormControlElement::formControlName() const { const AtomicString& name = fastGetAttribute(nameAttr); diff --git a/WebCore/html/HTMLFormControlElement.h b/WebCore/html/HTMLFormControlElement.h index c5ed013..f006e65 100644 --- a/WebCore/html/HTMLFormControlElement.h +++ b/WebCore/html/HTMLFormControlElement.h @@ -109,6 +109,8 @@ protected: virtual void attach(); virtual void insertedIntoTree(bool deep); virtual void removedFromTree(bool deep); + virtual void insertedIntoDocument(); + virtual void removedFromDocument(); virtual void willMoveToNewOwnerDocument(); virtual bool isKeyboardFocusable(KeyboardEvent*) const; diff --git a/WebCore/html/HTMLOptionElement.h b/WebCore/html/HTMLOptionElement.h index deac66a..c1791d7 100644 --- a/WebCore/html/HTMLOptionElement.h +++ b/WebCore/html/HTMLOptionElement.h @@ -27,13 +27,6 @@ #include "HTMLFormControlElement.h" #include "OptionElement.h" -#if PLATFORM(ANDROID) -namespace android { -class WebViewCore; -class ListBoxReply; -}; -#endif - namespace WebCore { class HTMLSelectElement; @@ -41,11 +34,6 @@ class HTMLSelectElement; class HTMLOptionElement : public HTMLFormControlElement, public OptionElement { friend class HTMLSelectElement; friend class RenderMenuList; -#if PLATFORM(ANDROID) - friend class RenderThemeAndroid; - friend class android::WebViewCore; - friend class android::ListBoxReply; -#endif public: static PassRefPtr<HTMLOptionElement> create(Document*, HTMLFormElement*); diff --git a/WebCore/html/canvas/DataView.h b/WebCore/html/canvas/DataView.h index 0681341..1c76c28 100755 --- a/WebCore/html/canvas/DataView.h +++ b/WebCore/html/canvas/DataView.h @@ -75,7 +75,7 @@ private: DataView(PassRefPtr<ArrayBuffer>, unsigned byteOffset, unsigned byteLength); template<typename T> - inline bool beyondRange(unsigned byteOffset) const { return byteOffset + sizeof(T) > m_byteLength; } + inline bool beyondRange(unsigned byteOffset) const { return byteOffset >= m_byteLength || byteOffset + sizeof(T) > m_byteLength; } template<typename T> T getData(unsigned byteOffset, bool littleEndian, ExceptionCode&) const; diff --git a/WebCore/html/canvas/WebGLRenderingContext.cpp b/WebCore/html/canvas/WebGLRenderingContext.cpp index 3dd1453..237d80c 100644 --- a/WebCore/html/canvas/WebGLRenderingContext.cpp +++ b/WebCore/html/canvas/WebGLRenderingContext.cpp @@ -1146,6 +1146,11 @@ void WebGLRenderingContext::drawElements(unsigned long mode, long count, unsigne if (!count) return; + if (!m_boundElementArrayBuffer) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); + return; + } + long numElements = 0; if (!isErrorGeneratedOnOutOfBoundsAccesses()) { // Ensure we have a valid rendering state diff --git a/WebCore/loader/HistoryController.cpp b/WebCore/loader/HistoryController.cpp index ff733a9..0919a59 100644 --- a/WebCore/loader/HistoryController.cpp +++ b/WebCore/loader/HistoryController.cpp @@ -248,6 +248,10 @@ void HistoryController::updateForBackForwardNavigation() // Must grab the current scroll position before disturbing it if (!m_frameLoadComplete) saveScrollPositionAndViewStateToItem(m_previousItem.get()); + + // When traversing history, we may end up redirecting to a different URL + // this time (e.g., due to cookies). See http://webkit.org/b/49654. + updateCurrentItem(); } void HistoryController::updateForReload() @@ -262,11 +266,11 @@ void HistoryController::updateForReload() if (m_frame->loader()->loadType() == FrameLoadTypeReload || m_frame->loader()->loadType() == FrameLoadTypeReloadFromOrigin) saveScrollPositionAndViewStateToItem(m_currentItem.get()); - - // Sometimes loading a page again leads to a different result because of cookies. Bugzilla 4072 - if (m_frame->loader()->documentLoader()->unreachableURL().isEmpty()) - m_currentItem->setURL(m_frame->loader()->documentLoader()->requestURL()); } + + // When reloading the page, we may end up redirecting to a different URL + // this time (e.g., due to cookies). See http://webkit.org/b/4072. + updateCurrentItem(); } // There are 3 things you might think of as "history", all of which are handled by these functions. @@ -298,9 +302,9 @@ void HistoryController::updateForStandardLoad(HistoryUpdateType updateType) if (Page* page = m_frame->page()) page->setGlobalHistoryItem(needPrivacy ? 0 : page->backForward()->currentItem()); } - } else if (frameLoader->documentLoader()->unreachableURL().isEmpty() && m_currentItem) { - m_currentItem->setURL(frameLoader->documentLoader()->url()); - m_currentItem->setFormInfoFromRequest(frameLoader->documentLoader()->request()); + } else { + // The client redirect replaces the current history item. + updateCurrentItem(); } if (!historyURL.isEmpty() && !needPrivacy) { @@ -337,14 +341,12 @@ void HistoryController::updateForRedirectWithLockedBackForwardList() page->setGlobalHistoryItem(needPrivacy ? 0 : page->backForward()->currentItem()); } } - if (m_currentItem) { - m_currentItem->setURL(m_frame->loader()->documentLoader()->url()); - m_currentItem->setFormInfoFromRequest(m_frame->loader()->documentLoader()->request()); - } + // The client redirect replaces the current history item. + updateCurrentItem(); } else { Frame* parentFrame = m_frame->tree()->parent(); if (parentFrame && parentFrame->loader()->history()->m_currentItem) - parentFrame->loader()->history()->m_currentItem->setChildItem(createItem(true)); + parentFrame->loader()->history()->m_currentItem->setChildItem(createItem()); } if (!historyURL.isEmpty() && !needPrivacy) { @@ -453,12 +455,13 @@ void HistoryController::setProvisionalItem(HistoryItem* item) m_provisionalItem = item; } -PassRefPtr<HistoryItem> HistoryController::createItem(bool useOriginal) +void HistoryController::initializeItem(HistoryItem* item) { DocumentLoader* documentLoader = m_frame->loader()->documentLoader(); - - KURL unreachableURL = documentLoader ? documentLoader->unreachableURL() : KURL(); - + ASSERT(documentLoader); + + KURL unreachableURL = documentLoader->unreachableURL(); + KURL url; KURL originalURL; @@ -466,15 +469,10 @@ PassRefPtr<HistoryItem> HistoryController::createItem(bool useOriginal) url = unreachableURL; originalURL = unreachableURL; } else { - originalURL = documentLoader ? documentLoader->originalURL() : KURL(); - if (useOriginal) - url = originalURL; - else if (documentLoader) - url = documentLoader->requestURL(); + url = documentLoader->url(); + originalURL = documentLoader->originalURL(); } - LOG(History, "WebCoreHistory: Creating item for %s", url.string().ascii().data()); - // Frames that have never successfully loaded any content // may have no URL at all. Currently our history code can't // deal with such things, so we nip that in the bud here. @@ -487,21 +485,25 @@ PassRefPtr<HistoryItem> HistoryController::createItem(bool useOriginal) Frame* parentFrame = m_frame->tree()->parent(); String parent = parentFrame ? parentFrame->tree()->uniqueName() : ""; - String title = documentLoader ? documentLoader->title() : ""; + String title = documentLoader->title(); - RefPtr<HistoryItem> item = HistoryItem::create(url, m_frame->tree()->uniqueName(), parent, title); + item->setURL(url); + item->setTarget(m_frame->tree()->uniqueName()); + item->setParent(parent); + item->setTitle(title); item->setOriginalURLString(originalURL.string()); - if (!unreachableURL.isEmpty() || !documentLoader || documentLoader->response().httpStatusCode() >= 400) + if (!unreachableURL.isEmpty() || documentLoader->response().httpStatusCode() >= 400) item->setLastVisitWasFailure(true); // Save form state if this is a POST - if (documentLoader) { - if (useOriginal) - item->setFormInfoFromRequest(documentLoader->originalRequest()); - else - item->setFormInfoFromRequest(documentLoader->request()); - } + item->setFormInfoFromRequest(documentLoader->request()); +} + +PassRefPtr<HistoryItem> HistoryController::createItem() +{ + RefPtr<HistoryItem> item = HistoryItem::create(); + initializeItem(item.get()); // Set the item for which we will save document state m_frameLoadComplete = false; @@ -513,7 +515,7 @@ PassRefPtr<HistoryItem> HistoryController::createItem(bool useOriginal) PassRefPtr<HistoryItem> HistoryController::createItemTree(Frame* targetFrame, bool clipAtTarget) { - RefPtr<HistoryItem> bfItem = createItem(m_frame->tree()->parent() ? true : false); + RefPtr<HistoryItem> bfItem = createItem(); if (!m_frameLoadComplete) saveScrollPositionAndViewStateToItem(m_previousItem.get()); @@ -647,6 +649,31 @@ void HistoryController::updateBackForwardListClippedAtTarget(bool doClip) page->backForward()->addItem(topItem.release()); } +void HistoryController::updateCurrentItem() +{ + if (!m_currentItem) + return; + + DocumentLoader* documentLoader = m_frame->loader()->documentLoader(); + + if (!documentLoader->unreachableURL().isEmpty()) + return; + + if (m_currentItem->url() != documentLoader->url()) { + // We ended up on a completely different URL this time, so the HistoryItem + // needs to be re-initialized. Preserve the isTargetItem flag as it is a + // property of how this HistoryItem was originally created and is not + // dependent on the document. + bool isTargetItem = m_currentItem->isTargetItem(); + m_currentItem->reset(); + initializeItem(m_currentItem.get()); + m_currentItem->setIsTargetItem(isTargetItem); + } else { + // Even if the final URL didn't change, the form data may have changed. + m_currentItem->setFormInfoFromRequest(documentLoader->request()); + } +} + void HistoryController::pushState(PassRefPtr<SerializedScriptValue> stateObject, const String& title, const String& urlString) { if (!m_currentItem) diff --git a/WebCore/loader/HistoryController.h b/WebCore/loader/HistoryController.h index 1bf5072..01f093c 100644 --- a/WebCore/loader/HistoryController.h +++ b/WebCore/loader/HistoryController.h @@ -84,12 +84,14 @@ public: void replaceState(PassRefPtr<SerializedScriptValue>, const String& title, const String& url); private: - PassRefPtr<HistoryItem> createItem(bool useOriginal); + void initializeItem(HistoryItem*); + PassRefPtr<HistoryItem> createItem(); PassRefPtr<HistoryItem> createItemTree(Frame* targetFrame, bool clipAtTarget); void recursiveGoToItem(HistoryItem*, HistoryItem*, FrameLoadType); bool currentFramesMatchItem(HistoryItem*) const; void updateBackForwardListClippedAtTarget(bool doClip); + void updateCurrentItem(); Frame* m_frame; diff --git a/WebCore/page/DOMWindow.cpp b/WebCore/page/DOMWindow.cpp index 22e1355..17b4c3d 100644 --- a/WebCore/page/DOMWindow.cpp +++ b/WebCore/page/DOMWindow.cpp @@ -867,7 +867,7 @@ void DOMWindow::blur() page->chrome()->unfocus(); } -void DOMWindow::close() +void DOMWindow::close(ScriptExecutionContext* context) { if (!m_frame) return; @@ -879,6 +879,16 @@ void DOMWindow::close() if (m_frame != page->mainFrame()) return; + if (context) { + ASSERT(WTF::isMainThread()); + Frame* activeFrame = static_cast<Document*>(context)->frame(); + if (!activeFrame) + return; + + if (!activeFrame->loader()->shouldAllowNavigation(m_frame)) + return; + } + Settings* settings = m_frame->settings(); bool allowScriptsToCloseWindows = settings && settings->allowScriptsToCloseWindows(); diff --git a/WebCore/page/DOMWindow.h b/WebCore/page/DOMWindow.h index 68b21ff..d0a6cce 100644 --- a/WebCore/page/DOMWindow.h +++ b/WebCore/page/DOMWindow.h @@ -147,7 +147,7 @@ namespace WebCore { void focus(); void blur(); - void close(); + void close(ScriptExecutionContext* = 0); void print(); void stop(); diff --git a/WebCore/page/DOMWindow.idl b/WebCore/page/DOMWindow.idl index 602289b..fe12287 100644 --- a/WebCore/page/DOMWindow.idl +++ b/WebCore/page/DOMWindow.idl @@ -65,7 +65,7 @@ module window { [DoNotCheckDomainSecurity] void focus(); [DoNotCheckDomainSecurity] void blur(); - [DoNotCheckDomainSecurity] void close(); + [DoNotCheckDomainSecurity, CallWith=ScriptExecutionContext] void close(); void print(); void stop(); diff --git a/WebCore/page/FrameView.cpp b/WebCore/page/FrameView.cpp index 5314a32..1f03599 100644 --- a/WebCore/page/FrameView.cpp +++ b/WebCore/page/FrameView.cpp @@ -1067,6 +1067,29 @@ void FrameView::removeFixedObject() updateCanBlitOnScrollRecursively(); } +#if PLATFORM(ANDROID) +// When the screen size change, fixed positioned element should be updated. +void FrameView::updatePositionedObjects() +{ + RenderBlock::PositionedObjectsListHashSet* positionedObjects = 0; + if (RenderView* root = m_frame->contentRenderer()) + positionedObjects = root->positionedObjects(); + + if (!positionedObjects || positionedObjects->isEmpty()) + return; + + RenderBlock::PositionedObjectsListHashSet::const_iterator end = positionedObjects->end(); + for (RenderBlock::PositionedObjectsListHashSet::const_iterator it = positionedObjects->begin(); it != end; ++it) { + RenderBox* renderBox = *it; + if (renderBox->style()->position() != FixedPosition) + continue; + + renderBox->computeLogicalWidth(); + renderBox->computeLogicalHeight(); + } +} +#endif + bool FrameView::scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect) { const size_t fixedObjectThreshold = 5; diff --git a/WebCore/page/FrameView.h b/WebCore/page/FrameView.h index 1b5b322..4135045 100644 --- a/WebCore/page/FrameView.h +++ b/WebCore/page/FrameView.h @@ -97,6 +97,10 @@ public: bool needsFullRepaint() const { return m_doFullRepaint; } +#if PLATFORM(ANDROID) + void updatePositionedObjects(); +#endif + #if USE(ACCELERATED_COMPOSITING) void updateCompositingLayers(); diff --git a/WebCore/page/History.cpp b/WebCore/page/History.cpp index 95b1350..f0a75fe 100644 --- a/WebCore/page/History.cpp +++ b/WebCore/page/History.cpp @@ -27,6 +27,7 @@ #include "History.h" #include "BackForwardController.h" +#include "Document.h" #include "ExceptionCode.h" #include "Frame.h" #include "FrameLoader.h" @@ -62,22 +63,44 @@ unsigned History::length() const void History::back() { - if (!m_frame) - return; - m_frame->navigationScheduler()->scheduleHistoryNavigation(-1); + go(-1); +} + +void History::back(ScriptExecutionContext* context) +{ + go(context, -1); } void History::forward() { + go(1); +} + +void History::forward(ScriptExecutionContext* context) +{ + go(context, 1); +} + +void History::go(int distance) +{ if (!m_frame) return; - m_frame->navigationScheduler()->scheduleHistoryNavigation(1); + m_frame->navigationScheduler()->scheduleHistoryNavigation(distance); } -void History::go(int distance) +void History::go(ScriptExecutionContext* context, int distance) { if (!m_frame) return; + + ASSERT(WTF::isMainThread()); + Frame* activeFrame = static_cast<Document*>(context)->frame(); + if (!activeFrame) + return; + + if (!activeFrame->loader()->shouldAllowNavigation(m_frame)) + return; + m_frame->navigationScheduler()->scheduleHistoryNavigation(distance); } diff --git a/WebCore/page/History.h b/WebCore/page/History.h index e885847..9ec1914 100644 --- a/WebCore/page/History.h +++ b/WebCore/page/History.h @@ -34,6 +34,7 @@ namespace WebCore { class Frame; +class ScriptExecutionContext; class SerializedScriptValue; typedef int ExceptionCode; @@ -49,6 +50,10 @@ public: void forward(); void go(int distance); + void back(ScriptExecutionContext*); + void forward(ScriptExecutionContext*); + void go(ScriptExecutionContext*, int distance); + enum StateObjectType { StateObjectPush, StateObjectReplace diff --git a/WebCore/page/History.idl b/WebCore/page/History.idl index d1be5ae..d8eac60 100644 --- a/WebCore/page/History.idl +++ b/WebCore/page/History.idl @@ -37,9 +37,9 @@ module window { ] History { readonly attribute unsigned long length; - [DoNotCheckDomainSecurity] void back(); - [DoNotCheckDomainSecurity] void forward(); - [DoNotCheckDomainSecurity] void go(in long distance); + [DoNotCheckDomainSecurity, CallWith=ScriptExecutionContext] void back(); + [DoNotCheckDomainSecurity, CallWith=ScriptExecutionContext] void forward(); + [DoNotCheckDomainSecurity, CallWith=ScriptExecutionContext] void go(in long distance); [Custom, EnabledAtRuntime] void pushState(in any data, in DOMString title, in optional DOMString url) raises(DOMException); diff --git a/WebCore/page/animation/AnimationController.cpp b/WebCore/page/animation/AnimationController.cpp index e8e990c..613aee6 100644 --- a/WebCore/page/animation/AnimationController.cpp +++ b/WebCore/page/animation/AnimationController.cpp @@ -145,16 +145,16 @@ void AnimationControllerPrivate::fireEventsAndUpdateStyle() bool updateStyle = !m_eventsToDispatch.isEmpty() || !m_nodeChangesToDispatch.isEmpty(); // fire all the events - Vector<EventToDispatch>::const_iterator eventsToDispatchEnd = m_eventsToDispatch.end(); - for (Vector<EventToDispatch>::const_iterator it = m_eventsToDispatch.begin(); it != eventsToDispatchEnd; ++it) { + Vector<EventToDispatch> eventsToDispatch = m_eventsToDispatch; + m_eventsToDispatch.clear(); + Vector<EventToDispatch>::const_iterator eventsToDispatchEnd = eventsToDispatch.end(); + for (Vector<EventToDispatch>::const_iterator it = eventsToDispatch.begin(); it != eventsToDispatchEnd; ++it) { if (it->eventType == eventNames().webkitTransitionEndEvent) it->element->dispatchEvent(WebKitTransitionEvent::create(it->eventType, it->name, it->elapsedTime)); else it->element->dispatchEvent(WebKitAnimationEvent::create(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) diff --git a/WebCore/platform/android/PlatformBridge.h b/WebCore/platform/android/PlatformBridge.h index 3f559d5..faa823e 100644 --- a/WebCore/platform/android/PlatformBridge.h +++ b/WebCore/platform/android/PlatformBridge.h @@ -149,8 +149,8 @@ public: static int memoryUsageMB(); static int actualMemoryUsageMB(); - static int visibleScreenWidth(const FrameView*); - static int visibleScreenHeight(const FrameView*); + static int screenWidthInDocCoord(const FrameView*); + static int screenHeightInDocCoord(const FrameView*); }; } diff --git a/WebCore/platform/android/PopupMenuAndroid.cpp b/WebCore/platform/android/PopupMenuAndroid.cpp index 2bae724..f4c351f 100644 --- a/WebCore/platform/android/PopupMenuAndroid.cpp +++ b/WebCore/platform/android/PopupMenuAndroid.cpp @@ -31,7 +31,7 @@ class PopupReply : public android::WebCoreReply { public: - PopupReply(const IntRect& rect, android::WebViewCore* view, PopupMenuClient* client) + PopupReply(const IntRect& rect, android::WebViewCore* view, ListPopupMenuClient* client) : m_rect(rect) , m_viewImpl(view) , m_popupClient(client) @@ -53,9 +53,23 @@ public: m_viewImpl->contentInvalidate(m_rect); } - virtual void replyIntArray(const int*, int) { - // Should never be called. - SkASSERT(false); + virtual void replyIntArray(const int* values, int count) + { + if (m_popupClient) { + m_popupClient->popupDidHide(); + if (0 == count) { + m_popupClient->valueChanged(-1, true); + } else { + for (int i = 0; i < count; i++) { + m_popupClient->listBoxSelectItem(values[i], + i != 0 /* allowMultiplySelection */, + false /* shift */, + i == count - 1 /* fireOnChangeNow */); + } + } + } + if (m_viewImpl) + m_viewImpl->contentInvalidate(m_rect); } void disconnectClient() @@ -67,12 +81,12 @@ private: IntRect m_rect; // FIXME: Do not need this if we handle ChromeClientAndroid::formStateDidChange android::WebViewCore* m_viewImpl; - PopupMenuClient* m_popupClient; + ListPopupMenuClient* m_popupClient; }; namespace WebCore { -PopupMenuAndroid::PopupMenuAndroid(PopupMenuClient* menuList) +PopupMenuAndroid::PopupMenuAndroid(ListPopupMenuClient* menuList) : m_popupClient(menuList) , m_reply(0) { @@ -91,8 +105,7 @@ void PopupMenuAndroid::disconnectClient() m_reply = 0; } } -// Copied from WebViewCore.cpp. Once we move ListBox handling to this class, -// we can remove the one in WebViewCore.cpp. + // Convert a WTF::String into an array of characters where the first // character represents the length, for easy conversion to java. static uint16_t* stringConverter(const WTF::String& text) @@ -122,9 +135,7 @@ void PopupMenuAndroid::show(const IntRect& rect, FrameView* frameView, int) SkTDArray<int> enabledArray; SkTDArray<int> selectedArray; int size = m_popupClient->listSize(); - // If we use this for ListBoxes in addition to MenuLists, we will need to - // account for 'multiple' - bool multiple = false; + bool multiple = m_popupClient->multiple(); for (int i = 0; i < size; i++) { *names.append() = stringConverter(m_popupClient->itemText(i)); if (m_popupClient->itemIsSeparator(i)) { diff --git a/WebCore/platform/android/PopupMenuAndroid.h b/WebCore/platform/android/PopupMenuAndroid.h index 48bce44..6c2c015 100644 --- a/WebCore/platform/android/PopupMenuAndroid.h +++ b/WebCore/platform/android/PopupMenuAndroid.h @@ -34,18 +34,18 @@ class PopupReply; namespace WebCore { class FrameView; -class PopupMenuClient; +class ListPopupMenuClient; class PopupMenuAndroid : public PopupMenu { public: - PopupMenuAndroid(PopupMenuClient*); + PopupMenuAndroid(ListPopupMenuClient*); virtual ~PopupMenuAndroid(); virtual void show(const IntRect&, FrameView*, int); virtual void hide() { } virtual void updateFromElement() { } virtual void disconnectClient(); private: - PopupMenuClient* m_popupClient; + ListPopupMenuClient* m_popupClient; PopupReply* m_reply; }; diff --git a/WebCore/platform/android/RenderThemeAndroid.cpp b/WebCore/platform/android/RenderThemeAndroid.cpp index 87e7a6d..66f034d 100644 --- a/WebCore/platform/android/RenderThemeAndroid.cpp +++ b/WebCore/platform/android/RenderThemeAndroid.cpp @@ -52,9 +52,15 @@ namespace WebCore { // dropdowns, we want a much smaller height, which encompasses the text. const int listboxPadding = 5; -// This is the color of selection in a textfield. It was obtained by checking -// the color of selection in TextViews in the system. -const RGBA32 selectionColor = makeRGB(255, 146, 0); +// This is the color of selection in a textfield. It was computed from +// frameworks/base/core/res/res/values/colors.xml, which uses #9983CC39 +// (decimal a = 153, r = 131, g = 204, b = 57) +// for all four highlighted text values. Blending this with white yields: +// R = (131 * 153 + 255 * (255 - 153)) / 255 -> 180.6 +// G = (204 * 153 + 255 * (255 - 153)) / 255 -> 224.4 +// B = ( 57 * 153 + 255 * (255 - 153)) / 255 -> 136.2 + +const RGBA32 selectionColor = makeRGB(181, 224, 136); static SkCanvas* getCanvasFromInfo(const PaintInfo& info) { @@ -351,57 +357,9 @@ void RenderThemeAndroid::adjustTextAreaStyle(CSSStyleSelector*, RenderStyle* sty bool RenderThemeAndroid::paintTextArea(RenderObject* obj, const PaintInfo& info, const IntRect& rect) { - if (!obj->isListBox()) - return true; - - paintCombo(obj, info, rect); - RenderStyle* style = obj->style(); - if (style) - style->setColor(Color::transparent); - Node* node = obj->node(); - if (!node || !node->hasTagName(HTMLNames::selectTag)) - return true; - - HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node); - // The first item may be visible. Make sure it does not draw. - // If it has a style, it overrides the RenderListBox's style, so we - // need to make sure both are set to transparent. - node = select->item(0); - if (node) { - RenderObject* renderer = node->renderer(); - if (renderer) { - RenderStyle* renderStyle = renderer->style(); - if (renderStyle) - renderStyle->setColor(Color::transparent); - } - } - // Find the first selected option, and draw its text. - // FIXME: In a later change, if there is more than one item selected, - // draw a string that says "X items" like iPhone Safari does - int index = select->selectedIndex(); - node = select->item(index); - if (!node || !node->hasTagName(HTMLNames::optionTag)) - return true; - - HTMLOptionElement* option = static_cast<HTMLOptionElement*>(node); - String label = option->textIndentedToRespectGroupLabel(); - SkRect r(rect); - - SkPaint paint; - paint.setAntiAlias(true); - paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); - // Values for text size and positioning determined by trial and error - paint.setTextSize(r.height() - SkIntToScalar(6)); - - SkCanvas* canvas = getCanvasFromInfo(info); - int saveCount = canvas->save(); - r.fRight -= SkIntToScalar(RenderSkinCombo::extraWidth()); - canvas->clipRect(r); - canvas->drawText(label.characters(), label.length() << 1, - r.fLeft + SkIntToScalar(5), r.fBottom - SkIntToScalar(5), paint); - canvas->restoreToCount(saveCount); - - return true; + if (obj->isMenuList()) + paintCombo(obj, info, rect); + return true; } void RenderThemeAndroid::adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle* style, Element*) const @@ -414,16 +372,7 @@ bool RenderThemeAndroid::paintSearchField(RenderObject*, const PaintInfo&, const return true; } -void RenderThemeAndroid::adjustListboxStyle(CSSStyleSelector*, RenderStyle* style, Element*) const -{ - style->setPaddingRight(Length(RenderSkinCombo::extraWidth(), Fixed)); - style->setMaxHeight(Length(style->fontSize() + listboxPadding, Fixed)); - // Make webkit draw invisible, since it will simply draw the first element - style->setColor(Color::transparent); - addIntrinsicMargins(style); -} - -static void adjustMenuListStyleCommon(RenderStyle* style, Element* e) +static void adjustMenuListStyleCommon(RenderStyle* style) { // Added to make room for our arrow and make the touch target less cramped. style->setPaddingLeft(Length(RenderSkinCombo::padding(), Fixed)); @@ -432,9 +381,14 @@ static void adjustMenuListStyleCommon(RenderStyle* style, Element* e) style->setPaddingRight(Length(RenderSkinCombo::extraWidth(), Fixed)); } +void RenderThemeAndroid::adjustListboxStyle(CSSStyleSelector*, RenderStyle* style, Element*) const +{ + adjustMenuListButtonStyle(0, style, 0); +} + void RenderThemeAndroid::adjustMenuListStyle(CSSStyleSelector*, RenderStyle* style, Element* e) const { - adjustMenuListStyleCommon(style, e); + adjustMenuListStyleCommon(style); addIntrinsicMargins(style); } @@ -450,7 +404,8 @@ bool RenderThemeAndroid::paintMenuList(RenderObject* obj, const PaintInfo& info, return paintCombo(obj, info, rect); } -void RenderThemeAndroid::adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle* style, Element* e) const +void RenderThemeAndroid::adjustMenuListButtonStyle(CSSStyleSelector*, + RenderStyle* style, Element*) const { // Copied from RenderThemeSafari. const float baseFontSize = 11.0f; @@ -468,7 +423,7 @@ void RenderThemeAndroid::adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyl const int padding = 4; style->setPaddingTop(Length(padding, Fixed)); style->setPaddingLeft(Length(padding, Fixed)); - adjustMenuListStyleCommon(style, e); + adjustMenuListStyleCommon(style); } bool RenderThemeAndroid::paintMenuListButton(RenderObject* obj, const PaintInfo& info, const IntRect& rect) diff --git a/WebCore/platform/graphics/android/BaseLayerAndroid.cpp b/WebCore/platform/graphics/android/BaseLayerAndroid.cpp index 3483e44..584add1 100644 --- a/WebCore/platform/graphics/android/BaseLayerAndroid.cpp +++ b/WebCore/platform/graphics/android/BaseLayerAndroid.cpp @@ -116,12 +116,11 @@ void BaseLayerAndroid::drawCanvas(SkCanvas* canvas) } #if USE(ACCELERATED_COMPOSITING) -bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale) +bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale, double currentTime) { if (!m_glWebViewState) return false; - double currentTime = WTF::currentTime(); bool goingDown = m_previousVisible.fTop - viewport.fTop <= 0; bool goingLeft = m_previousVisible.fLeft - viewport.fLeft >= 0; @@ -282,7 +281,8 @@ bool BaseLayerAndroid::drawGL(IntRect& viewRect, SkRect& visibleRect, shader->setViewport(visibleRect); shader->resetBlending(); - ret = drawBasePictureInGL(visibleRect, scale); + double currentTime = WTF::currentTime(); + ret = drawBasePictureInGL(visibleRect, scale, currentTime); if (countChildren() >= 1) { LayerAndroid* compositedRoot = static_cast<LayerAndroid*>(getChild(0)); @@ -311,7 +311,7 @@ bool BaseLayerAndroid::drawGL(IntRect& viewRect, SkRect& visibleRect, scale = m_glWebViewState->futureScale(); } compositedRoot->setScale(scale); - compositedRoot->computeTextureSize(); + compositedRoot->computeTextureSize(currentTime); compositedRoot->reserveGLTextures(); #ifdef DEBUG @@ -337,12 +337,6 @@ bool BaseLayerAndroid::drawGL(IntRect& viewRect, SkRect& visibleRect, glBindBuffer(GL_ARRAY_BUFFER, 0); m_previousVisible = visibleRect; -#ifdef DEBUG_COUNT - XLOG("GLWebViewState(%d) DoubleBufferedTexture(%d) BaseTile(%d) TileSet(%d) TiledPage(%d)", - GLWebViewState::count(), DoubleBufferedTexture::count(), - BaseTile::count(), TileSet::count(), TiledPage::count()); -#endif // DEBUG_COUNT - #endif // USE(ACCELERATED_COMPOSITING) #ifdef DEBUG ClassTracker::instance()->show(); diff --git a/WebCore/platform/graphics/android/BaseLayerAndroid.h b/WebCore/platform/graphics/android/BaseLayerAndroid.h index c57b13d..cb1caef 100644 --- a/WebCore/platform/graphics/android/BaseLayerAndroid.h +++ b/WebCore/platform/graphics/android/BaseLayerAndroid.h @@ -59,7 +59,7 @@ public: void swapExtra(BaseLayerAndroid* base) { m_extra.swap(base->m_extra); } private: #if USE(ACCELERATED_COMPOSITING) - bool drawBasePictureInGL(SkRect& viewport, float scale); + bool drawBasePictureInGL(SkRect& viewport, float scale, double currentTime); GLWebViewState* m_glWebViewState; android::Mutex m_drawLock; diff --git a/WebCore/platform/graphics/android/BaseTile.cpp b/WebCore/platform/graphics/android/BaseTile.cpp index acb500d..bfd5118 100644 --- a/WebCore/platform/graphics/android/BaseTile.cpp +++ b/WebCore/platform/graphics/android/BaseTile.cpp @@ -265,18 +265,18 @@ void BaseTile::paintBitmap() canvas->restore(); -#ifdef DEBUG - SkPaint paint; - paint.setARGB(128, 255, 0, 0); - paint.setStrokeWidth(3); - canvas->drawLine(0, 0, tileWidth, tileHeight, paint); - paint.setARGB(128, 0, 255, 0); - canvas->drawLine(0, tileHeight, tileWidth, 0, paint); - paint.setARGB(128, 0, 0, 255); - canvas->drawLine(0, 0, tileWidth, 0, paint); - canvas->drawLine(tileWidth, 0, tileWidth, tileHeight, paint); - drawTileInfo(canvas, texture, x, y, scale); -#endif + if (TilesManager::instance()->getShowVisualIndicator()) { + SkPaint paint; + paint.setARGB(128, 255, 0, 0); + paint.setStrokeWidth(3); + canvas->drawLine(0, 0, tileWidth, tileHeight, paint); + paint.setARGB(128, 0, 255, 0); + canvas->drawLine(0, tileHeight, tileWidth, 0, paint); + paint.setARGB(128, 0, 0, 255); + canvas->drawLine(0, 0, tileWidth, 0, paint); + canvas->drawLine(tileWidth, 0, tileWidth, tileHeight, paint); + drawTileInfo(canvas, texture, x, y, scale); + } texture->setTile(x, y); texture->producerUpdate(textureInfo); diff --git a/WebCore/platform/graphics/android/GLWebViewState.cpp b/WebCore/platform/graphics/android/GLWebViewState.cpp index eef32e8..3d2f6c8 100644 --- a/WebCore/platform/graphics/android/GLWebViewState.cpp +++ b/WebCore/platform/graphics/android/GLWebViewState.cpp @@ -93,7 +93,8 @@ GLWebViewState::~GLWebViewState() #endif } -void GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, const IntRect& rect) +void GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, const IntRect& rect, + bool showVisualIndicator) { android::Mutex::Autolock lock(m_baseLayerLock); if (!layer) { @@ -114,6 +115,8 @@ void GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, const IntRect& rect) m_currentBaseLayer = layer; } inval(rect); + + TilesManager::instance()->setShowVisualIndicator(showVisualIndicator); } void GLWebViewState::unlockBaseLayerUpdate() { @@ -128,7 +131,7 @@ void GLWebViewState::unlockBaseLayerUpdate() { } void GLWebViewState::setExtra(BaseLayerAndroid* layer, SkPicture& picture, - const IntRect& rect) + const IntRect& rect, bool allowSame) { android::Mutex::Autolock lock(m_baseLayerLock); if (!m_baseLayerUpdate) @@ -136,7 +139,7 @@ void GLWebViewState::setExtra(BaseLayerAndroid* layer, SkPicture& picture, layer->setExtra(picture); - if (m_lastInval == rect) + if (!allowSame && m_lastInval == rect) return; if (!rect.isEmpty()) diff --git a/WebCore/platform/graphics/android/GLWebViewState.h b/WebCore/platform/graphics/android/GLWebViewState.h index 4b71d86..d265b41 100644 --- a/WebCore/platform/graphics/android/GLWebViewState.h +++ b/WebCore/platform/graphics/android/GLWebViewState.h @@ -168,8 +168,8 @@ public: void resetTransitionTime() { m_transitionTime = -1; } unsigned int paintBaseLayerContent(SkCanvas* canvas); - void setBaseLayer(BaseLayerAndroid* layer, const IntRect& rect); - void setExtra(BaseLayerAndroid*, SkPicture&, const IntRect&); + void setBaseLayer(BaseLayerAndroid* layer, const IntRect& rect, bool showVisualIndicator); + void setExtra(BaseLayerAndroid*, SkPicture&, const IntRect&, bool allowSame); void scheduleUpdate(const double& currentTime, const SkIRect& viewport, float scale); TiledPage* sibling(TiledPage* page); @@ -205,12 +205,12 @@ public: return false; } - void setBackgroundColor(SkColor color) { m_backgroundColor = color; } - SkColor getBackgroundColor() { return m_backgroundColor; } - bool drawGL(IntRect& rect, SkRect& viewport, float scale, SkColor color = SK_ColorWHITE); + void setBackgroundColor(SkColor color) { m_backgroundColor = color; } + SkColor getBackgroundColor() { return m_backgroundColor; } + private: void inval(const IntRect& rect); // caller must hold m_baseLayerLock diff --git a/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp b/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp index e887964..ccc872a 100644 --- a/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp +++ b/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp @@ -271,7 +271,17 @@ void GraphicsLayerAndroid::setPosition(const FloatPoint& point) if (point == m_position) return; - GraphicsLayer::setPosition(point); + FloatPoint pos(point); +#if ENABLE(ANDROID_OVERFLOW_SCROLL) + // Add the scroll position back in. When scrolling a layer, all the children + // are positioned based on the content scroll. Adding the scroll position + // back in allows the children to draw based on 0,0. + RenderLayer* layer = renderLayerFromClient(m_client); + if (layer && layer->parent() && layer->parent()->hasOverflowScroll()) + pos += layer->parent()->scrolledContentOffset(); +#endif + + GraphicsLayer::setPosition(pos); #ifdef LAYER_DEBUG_2 LOG("(%x) setPosition(%.2f,%.2f) pos(%.2f, %.2f) anchor(%.2f,%.2f) size(%.2f, %.2f)", @@ -279,7 +289,7 @@ void GraphicsLayerAndroid::setPosition(const FloatPoint& point) m_anchorPoint.x(), m_anchorPoint.y(), m_size.width(), m_size.height()); #endif updateFixedPosition(); - m_contentLayer->setPosition(point.x(), point.y()); + m_contentLayer->setPosition(pos.x(), pos.y()); askForSync(); } @@ -368,31 +378,6 @@ void GraphicsLayerAndroid::setDrawsContent(bool drawsContent) if (m_contentLayer->isRootLayer()) return; if (m_drawsContent) { -#if ENABLE(ANDROID_OVERFLOW_SCROLL) - RenderLayer* layer = renderLayerFromClient(m_client); - if (layer) { - if (layer->hasOverflowScroll() && !m_foregroundLayer) { - m_foregroundLayer = new ScrollableLayerAndroid(); - m_foregroundClipLayer = new LayerAndroid(false); - m_foregroundClipLayer->setMasksToBounds(true); - - m_foregroundClipLayer->addChild(m_foregroundLayer); - m_contentLayer->addChild(m_foregroundClipLayer); - } else if (layer->isRootLayer() - && layer->renderer()->frame()->ownerRenderer()) { - // We have to do another check for scrollable content since an - // iframe might be compositing for other reasons. - FrameView* view = layer->renderer()->frame()->view(); - if (view->hasOverflowScroll()) { - // Replace the content layer with a scrollable layer. - LayerAndroid* layer = new ScrollableLayerAndroid(*m_contentLayer); - m_contentLayer->unref(); - m_contentLayer = layer; - } - } - } -#endif - m_haveContents = true; setNeedsDisplay(); } @@ -478,6 +463,77 @@ private: GraphicsLayerPaintingPhase m_originalPhase; }; +void GraphicsLayerAndroid::updateScrollingLayers() +{ +#if ENABLE(ANDROID_OVERFLOW_SCROLL) + RenderLayer* layer = renderLayerFromClient(m_client); + if (!layer || !m_haveContents) + return; + bool hasOverflowScroll = m_foregroundLayer || m_contentLayer->contentIsScrollable(); + bool layerNeedsOverflow = layer->hasOverflowScroll(); + bool iframeNeedsOverflow = layer->isRootLayer() && + layer->renderer()->frame()->ownerRenderer() && + layer->renderer()->frame()->view()->hasOverflowScroll(); + + if (hasOverflowScroll && (layerNeedsOverflow || iframeNeedsOverflow)) { + // Already has overflow layers. + return; + } + if (!hasOverflowScroll && !layerNeedsOverflow && !iframeNeedsOverflow) { + // Does not need overflow layers. + return; + } + if (layerNeedsOverflow || iframeNeedsOverflow) { + ASSERT(!hasOverflowScroll); + if (layerNeedsOverflow) { + ASSERT(!m_foregroundLayer && !m_foregroundClipLayer); + m_foregroundLayer = new ScrollableLayerAndroid(); + m_foregroundClipLayer = new LayerAndroid(false); + m_foregroundClipLayer->setMasksToBounds(true); + m_foregroundClipLayer->addChild(m_foregroundLayer); + m_contentLayer->addChild(m_foregroundClipLayer); + } else { + ASSERT(iframeNeedsOverflow && !m_contentLayer->contentIsScrollable()); + // No need to copy the children as they will be removed and synced. + m_contentLayer->removeChildren(); + // Replace the content layer with a scrollable layer. + LayerAndroid* layer = new ScrollableLayerAndroid(*m_contentLayer); + m_contentLayer->unref(); + m_contentLayer = layer; + if (m_parent) { + // The content layer has changed so the parent needs to sync + // children. + static_cast<GraphicsLayerAndroid*>(m_parent)->m_needsSyncChildren = true; + } + } + // Need to rebuild our children based on the new structure. + m_needsSyncChildren = true; + } else { + ASSERT(hasOverflowScroll && !layerNeedsOverflow && !iframeNeedsOverflow); + ASSERT(m_contentLayer); + // Remove the foreground layers. + if (m_foregroundLayer) { + m_foregroundLayer->unref(); + m_foregroundLayer = 0; + m_foregroundClipLayer->unref(); + m_foregroundClipLayer = 0; + } + // No need to copy over children. + m_contentLayer->removeChildren(); + LayerAndroid* layer = new LayerAndroid(*m_contentLayer); + m_contentLayer->unref(); + m_contentLayer = layer; + if (m_parent) { + // The content layer has changed so the parent needs to sync + // children. + static_cast<GraphicsLayerAndroid*>(m_parent)->m_needsSyncChildren = true; + } + // Children are all re-parented. + m_needsSyncChildren = true; + } +#endif +} + bool GraphicsLayerAndroid::repaint() { LOG("(%x) repaint(), gPaused(%d) m_needsRepaint(%d) m_haveContents(%d) ", @@ -506,8 +562,13 @@ bool GraphicsLayerAndroid::repaint() m_foregroundLayer->setSize(contentsRect.width(), contentsRect.height()); // Paint everything else into the main recording canvas. phase.clear(GraphicsLayerPaintBackground); - if (!paintContext(m_foregroundLayer->recordContext(), contentsRect)) - return false; + + // Paint at 0,0. + IntSize scroll = layer->scrolledContentOffset(); + layer->scrollToOffset(0, 0, true, false); + // At this point, it doesn't matter if painting failed. + (void) paintContext(m_foregroundLayer->recordContext(), contentsRect); + layer->scrollToOffset(scroll.width(), scroll.height(), true, false); // Construct the clip layer for masking the contents. IntRect clip = layer->renderer()->absoluteBoundingBoxRect(); @@ -830,10 +891,16 @@ void GraphicsLayerAndroid::syncChildren() { if (m_needsSyncChildren) { m_contentLayer->removeChildren(); - if (m_foregroundClipLayer) + LayerAndroid* layer = m_contentLayer; + if (m_foregroundClipLayer) { m_contentLayer->addChild(m_foregroundClipLayer); + // Use the scrollable content layer as the parent of the children so + // that they move with the content. + layer = m_foregroundLayer; + layer->removeChildren(); + } for (unsigned int i = 0; i < m_children.size(); i++) - m_contentLayer->addChild(m_children[i]->platformLayer()); + layer->addChild(m_children[i]->platformLayer()); m_needsSyncChildren = false; } } @@ -857,6 +924,7 @@ void GraphicsLayerAndroid::syncCompositingState() for (unsigned int i = 0; i < m_children.size(); i++) m_children[i]->syncCompositingState(); + updateScrollingLayers(); syncChildren(); syncMask(); diff --git a/WebCore/platform/graphics/android/GraphicsLayerAndroid.h b/WebCore/platform/graphics/android/GraphicsLayerAndroid.h index ce6bac1..da247ca 100644 --- a/WebCore/platform/graphics/android/GraphicsLayerAndroid.h +++ b/WebCore/platform/graphics/android/GraphicsLayerAndroid.h @@ -127,6 +127,7 @@ private: void syncMask(); void updateFixedPosition(); + void updateScrollingLayers(); // with SkPicture, we always repaint the entire layer's content. bool repaint(); diff --git a/WebCore/platform/graphics/android/LayerAndroid.cpp b/WebCore/platform/graphics/android/LayerAndroid.cpp index 7e998c1..35979f6 100644 --- a/WebCore/platform/graphics/android/LayerAndroid.cpp +++ b/WebCore/platform/graphics/android/LayerAndroid.cpp @@ -75,7 +75,8 @@ LayerAndroid::LayerAndroid(bool isRootLayer) : SkLayer(), m_reservedTexture(0), m_pictureUsed(0), m_requestSent(false), - m_scale(1) + m_scale(1), + m_lastComputeTextureSize(0) { m_backgroundColor = 0; @@ -123,6 +124,7 @@ LayerAndroid::LayerAndroid(const LayerAndroid& layer) : SkLayer(layer), m_dirty = layer.m_dirty; m_pictureUsed = layer.m_pictureUsed; m_scale = layer.m_scale; + m_lastComputeTextureSize = 0; for (int i = 0; i < layer.countChildren(); i++) addChild(layer.getChild(i)->copy())->unref(); @@ -147,7 +149,8 @@ LayerAndroid::LayerAndroid(SkPicture* picture) : SkLayer(), m_drawingTexture(0), m_reservedTexture(0), m_requestSent(false), - m_scale(1) + m_scale(1), + m_lastComputeTextureSize(0) { m_backgroundColor = 0; m_dirty = false; @@ -651,8 +654,12 @@ static inline bool compareLayerFullSize(const LayerAndroid* a, const LayerAndroi return sizeA > sizeB; } -void LayerAndroid::computeTextureSize() +void LayerAndroid::computeTextureSize(double time) { + if (m_lastComputeTextureSize + s_computeTextureDelay > time) + return; + m_lastComputeTextureSize = time; + // First, we collect the layers, computing m_layerTextureRect // as being clipped against the viewport Vector <LayerAndroid*> layers; @@ -985,25 +992,25 @@ void LayerAndroid::contentDraw(SkCanvas* canvas) canvas->drawPicture(*m_extra); m_atomicSync.unlock(); -#ifdef LAYER_DEBUG - float w = getSize().width(); - float h = getSize().height(); - SkPaint paint; - paint.setARGB(128, 255, 0, 0); - canvas->drawLine(0, 0, w, h, paint); - canvas->drawLine(0, h, w, 0, paint); - paint.setARGB(128, 0, 255, 0); - canvas->drawLine(0, 0, 0, h, paint); - canvas->drawLine(0, h, w, h, paint); - canvas->drawLine(w, h, w, 0, paint); - canvas->drawLine(w, 0, 0, 0, paint); - - if (m_isFixed) { - SkPaint paint; - paint.setARGB(80, 255, 0, 0); - canvas->drawRect(m_fixedRect, paint); + if (TilesManager::instance()->getShowVisualIndicator()) { + float w = getSize().width(); + float h = getSize().height(); + SkPaint paint; + paint.setARGB(128, 255, 0, 0); + canvas->drawLine(0, 0, w, h, paint); + canvas->drawLine(0, h, w, 0, paint); + paint.setARGB(128, 0, 255, 0); + canvas->drawLine(0, 0, 0, h, paint); + canvas->drawLine(0, h, w, h, paint); + canvas->drawLine(w, h, w, 0, paint); + canvas->drawLine(w, 0, 0, 0, paint); + + if (m_isFixed) { + SkPaint paint; + paint.setARGB(80, 255, 0, 0); + canvas->drawRect(m_fixedRect, paint); + } } -#endif } void LayerAndroid::onDraw(SkCanvas* canvas, SkScalar opacity) diff --git a/WebCore/platform/graphics/android/LayerAndroid.h b/WebCore/platform/graphics/android/LayerAndroid.h index 2cb56c1..0d5a878 100644 --- a/WebCore/platform/graphics/android/LayerAndroid.h +++ b/WebCore/platform/graphics/android/LayerAndroid.h @@ -111,7 +111,7 @@ public: void showLayers(int indent = 0); // Texture size functions - void computeTextureSize(); + void computeTextureSize(double time); void collect(Vector<LayerAndroid*>& layers, int& size); int clippedTextureSize() const; @@ -325,6 +325,10 @@ private: float m_scale; + // We try to not always compute the texture size, as this is quite heavy + static const double s_computeTextureDelay = 0.2; // 200 ms + double m_lastComputeTextureSize; + // This mutex serves two purposes. (1) It ensures that certain operations // happen atomically and (2) it makes sure those operations are synchronized // across all threads and cores. diff --git a/WebCore/platform/graphics/android/TilesManager.cpp b/WebCore/platform/graphics/android/TilesManager.cpp index 8bea60c..16fb782 100644 --- a/WebCore/platform/graphics/android/TilesManager.cpp +++ b/WebCore/platform/graphics/android/TilesManager.cpp @@ -89,6 +89,7 @@ TilesManager::TilesManager() , m_maxTextureCount(0) , m_expandedTileBounds(false) , m_generatorReady(false) + , m_showVisualIndicator(false) { XLOG("TilesManager ctor"); m_textures.reserveCapacity(MAX_TEXTURE_ALLOCATION); diff --git a/WebCore/platform/graphics/android/TilesManager.h b/WebCore/platform/graphics/android/TilesManager.h index 29b7fc1..107b121 100644 --- a/WebCore/platform/graphics/android/TilesManager.h +++ b/WebCore/platform/graphics/android/TilesManager.h @@ -108,6 +108,14 @@ public: m_expandedTileBounds = enabled; } + bool getShowVisualIndicator() { + return m_showVisualIndicator; + } + + void setShowVisualIndicator(bool showVisualIndicator) { + m_showVisualIndicator = showVisualIndicator; + } + private: TilesManager(); @@ -129,6 +137,8 @@ private: bool m_generatorReady; + bool m_showVisualIndicator; + sp<TexturesGenerator> m_pixmapsGenerationThread; android::Mutex m_texturesLock; diff --git a/WebCore/platform/graphics/android/android_graphics.cpp b/WebCore/platform/graphics/android/android_graphics.cpp index c046858..e50cfec 100644 --- a/WebCore/platform/graphics/android/android_graphics.cpp +++ b/WebCore/platform/graphics/android/android_graphics.cpp @@ -109,14 +109,8 @@ void CursorRing::draw(SkCanvas* canvas, LayerAndroid* layer, IntRect* inval) inval->unite(m_lastBounds); } -bool CursorRing::setup() +void CursorRing::setIsButton(const CachedNode* node) { - m_node->localCursorRings(m_frame, &m_rings); - if (!m_rings.size()) { - DBG_NAV_LOG("!rings.size()"); - m_viewImpl->m_hasCursorBounds = false; - return false; - } m_isButton = false; m_viewImpl->gButtonMutex.lock(); // If this is a button drawn by us (rather than webkit) do not draw the @@ -124,7 +118,7 @@ bool CursorRing::setup() // Should be in sync with recordButtons, since that will be called // before this. if (m_viewImpl->m_buttons.size() > 0) { - WebCore::Node* cursorPointer = (WebCore::Node*) m_node->nodePointer(); + WebCore::Node* cursorPointer = (WebCore::Node*) node->nodePointer(); Container* end = m_viewImpl->m_buttons.end(); for (Container* ptr = m_viewImpl->m_buttons.begin(); ptr != end; ptr++) { if (ptr->matches(cursorPointer)) { @@ -134,6 +128,17 @@ bool CursorRing::setup() } } m_viewImpl->gButtonMutex.unlock(); +} + +bool CursorRing::setup() +{ + m_node->localCursorRings(m_frame, &m_rings); + if (!m_rings.size()) { + DBG_NAV_LOG("!rings.size()"); + m_viewImpl->m_hasCursorBounds = false; + return false; + } + setIsButton(m_node); m_bounds = m_node->localBounds(m_frame); m_viewImpl->updateCursorBounds(m_root, m_frame, m_node); diff --git a/WebCore/platform/graphics/android/android_graphics.h b/WebCore/platform/graphics/android/android_graphics.h index 9f52a27..be309a6 100644 --- a/WebCore/platform/graphics/android/android_graphics.h +++ b/WebCore/platform/graphics/android/android_graphics.h @@ -54,6 +54,7 @@ public: CursorRing(WebViewCore* core) : m_viewImpl(core) {} virtual ~CursorRing() {} virtual void draw(SkCanvas* , LayerAndroid* , IntRect* ); + void setIsButton(const CachedNode* ); bool setup(); private: friend class WebView; diff --git a/WebCore/rendering/RenderBlock.cpp b/WebCore/rendering/RenderBlock.cpp index 4609f1b..22e8afb 100644 --- a/WebCore/rendering/RenderBlock.cpp +++ b/WebCore/rendering/RenderBlock.cpp @@ -117,6 +117,7 @@ RenderBlock::RenderBlock(Node* node) , m_continuation(0) , m_rareData(0) , m_lineHeight(-1) + , m_beingDestroyed(false) { setChildrenInline(true); } @@ -151,6 +152,9 @@ RenderBlock::~RenderBlock() void RenderBlock::destroy() { + // Mark as being destroyed to avoid trouble with merges in removeChild(). + m_beingDestroyed = true; + // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise. children()->destroyLeftoverChildren(); @@ -930,8 +934,8 @@ static bool canMergeContiguousAnonymousBlocks(RenderObject* oldChild, RenderObje if (oldChild->documentBeingDestroyed() || oldChild->isInline() || oldChild->virtualContinuation()) return false; - if ((prev && (!prev->isAnonymousBlock() || toRenderBlock(prev)->continuation())) - || (next && (!next->isAnonymousBlock() || toRenderBlock(next)->continuation()))) + if ((prev && (!prev->isAnonymousBlock() || toRenderBlock(prev)->continuation() || toRenderBlock(prev)->beingDestroyed())) + || (next && (!next->isAnonymousBlock() || toRenderBlock(next)->continuation() || toRenderBlock(next)->beingDestroyed()))) return false; // FIXME: This check isn't required when inline run-ins can't be split into continuations. @@ -1007,10 +1011,6 @@ void RenderBlock::removeChild(RenderObject* oldChild) nextBlock->deleteLineBoxTree(); nextBlock->destroy(); next = 0; - - // FIXME: Revert the continuation change done above. - if (oldChildBlock) - oldChildBlock->setContinuation(0); } } @@ -3033,7 +3033,7 @@ void RenderBlock::removeFloatingObject(RenderBox* o) // Special-case zero- and less-than-zero-height floats: those don't touch // the line that they're on, but it still needs to be dirtied. This is // accomplished by pretending they have a height of 1. - logicalBottom = max(logicalBottom, logicalTop + 1); + logicalBottom = max(logicalBottom, logicalTop == numeric_limits<int>::max() ? logicalTop : logicalTop + 1); markLinesDirtyInBlockRange(0, logicalBottom); } m_floatingObjects->removeRef(it.current()); @@ -3807,7 +3807,7 @@ void RenderBlock::markLinesDirtyInBlockRange(int logicalTop, int logicalBottom, RootInlineBox* lowestDirtyLine = lastRootBox(); RootInlineBox* afterLowest = lowestDirtyLine; - while (lowestDirtyLine && lowestDirtyLine->blockLogicalHeight() >= logicalBottom) { + while (lowestDirtyLine && lowestDirtyLine->blockLogicalHeight() >= logicalBottom && logicalBottom < numeric_limits<int>::max()) { afterLowest = lowestDirtyLine; lowestDirtyLine = lowestDirtyLine->prevRootBox(); } diff --git a/WebCore/rendering/RenderBlock.h b/WebCore/rendering/RenderBlock.h index 5153218..cc06954 100644 --- a/WebCore/rendering/RenderBlock.h +++ b/WebCore/rendering/RenderBlock.h @@ -55,6 +55,7 @@ public: RenderObjectChildList* children() { return &m_children; } virtual void destroy(); + bool beingDestroyed() const { return m_beingDestroyed; } // These two functions are overridden for inline-block. virtual int lineHeight(bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const; @@ -717,7 +718,8 @@ private: RenderObjectChildList m_children; RenderLineBoxList m_lineBoxes; // All of the root line boxes created for this block flow. For example, <div>Hello<br>world.</div> will have two total lines for the <div>. - mutable int m_lineHeight; + mutable int m_lineHeight : 31; + bool m_beingDestroyed : 1; // RenderRubyBase objects need to be able to split and merge, moving their children around // (calling moveChildTo, moveAllChildrenTo, and makeChildrenNonInline). diff --git a/WebCore/rendering/RenderBox.cpp b/WebCore/rendering/RenderBox.cpp index fe78fd5..140d326 100644 --- a/WebCore/rendering/RenderBox.cpp +++ b/WebCore/rendering/RenderBox.cpp @@ -39,7 +39,9 @@ #include "FloatQuad.h" #include "Frame.h" #include "Page.h" +#if PLATFORM(ANDROID) #include "PlatformBridge.h" +#endif #include "RenderArena.h" #include "RenderFlexibleBox.h" #include "RenderInline.h" @@ -225,26 +227,30 @@ void RenderBox::removeFloatingOrPositionedChildFromBlockLists() return; if (isFloating()) { - RenderBlock* outermostBlock = containingBlock(); - for (RenderBlock* p = outermostBlock; p && !p->isRenderView(); p = p->containingBlock()) { - if (p->containsFloat(this)) - outermostBlock = p; + RenderBlock* parentBlock = 0; + for (RenderObject* curr = parent(); curr && !curr->isRenderView(); curr = curr->parent()) { + if (curr->isRenderBlock()) { + RenderBlock* currBlock = toRenderBlock(curr); + if (currBlock->containsFloat(this)) + parentBlock = currBlock; + else + break; + } } - if (outermostBlock) { - RenderObject* parent = outermostBlock->parent(); + if (parentBlock) { + RenderObject* parent = parentBlock->parent(); if (parent && parent->isFlexibleBox()) - outermostBlock = toRenderBlock(parent); + parentBlock = toRenderBlock(parent); - outermostBlock->markAllDescendantsWithFloatsForLayout(this, false); + parentBlock->markAllDescendantsWithFloatsForLayout(this, false); } } if (isPositioned()) { - RenderObject* p; - for (p = parent(); p; p = p->parent()) { - if (p->isRenderBlock()) - toRenderBlock(p)->removePositionedObject(this); + for (RenderObject* curr = parent(); curr; curr = curr->parent()) { + if (curr->isRenderBlock()) + toRenderBlock(curr)->removePositionedObject(this); } } } @@ -2078,13 +2084,14 @@ void RenderBox::computeBlockDirectionMargins(RenderBlock* containingBlock) int RenderBox::containingBlockWidthForPositioned(const RenderBoxModelObject* containingBlock) const { +#if PLATFORM(ANDROID) // Fixed element's position should be decided by the visible screen size. // That is in the doc coordindate. if (style()->position() == FixedPosition && containingBlock->isRenderView()) { const RenderView* view = toRenderView(containingBlock); - return PlatformBridge::visibleScreenWidth(view->frameView()); + return PlatformBridge::screenWidthInDocCoord(view->frameView()); } - +#endif if (containingBlock->isBox()) { const RenderBox* containingBlockBox = toRenderBox(containingBlock); return containingBlockBox->width() - containingBlockBox->borderLeft() - containingBlockBox->borderRight() - containingBlockBox->verticalScrollbarWidth(); @@ -2114,14 +2121,15 @@ int RenderBox::containingBlockWidthForPositioned(const RenderBoxModelObject* con } int RenderBox::containingBlockHeightForPositioned(const RenderBoxModelObject* containingBlock) const -{ +{ +#if PLATFORM(ANDROID) // Fixed element's position should be decided by the visible screen size. // That is in the doc coordindate. if (style()->position() == FixedPosition && containingBlock->isRenderView()) { const RenderView* view = toRenderView(containingBlock); - return PlatformBridge::visibleScreenHeight(view->frameView()); + return PlatformBridge::screenHeightInDocCoord(view->frameView()); } - +#endif int heightResult = 0; if (containingBlock->isBox()) heightResult = toRenderBox(containingBlock)->height(); diff --git a/WebCore/rendering/RenderLayer.cpp b/WebCore/rendering/RenderLayer.cpp index b850ba3..559f25c 100644 --- a/WebCore/rendering/RenderLayer.cpp +++ b/WebCore/rendering/RenderLayer.cpp @@ -1159,14 +1159,6 @@ RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, int& xPos, i return; EPosition position = renderer()->style()->position(); -#if PLATFORM(ANDROID) - if (position == FixedPosition) { - if (renderer() && renderer()->isBox()) { - (toRenderBox(renderer()))->computeLogicalWidth(); - (toRenderBox(renderer()))->computeLogicalHeight(); - } - } -#endif if (position == FixedPosition && (!ancestorLayer || ancestorLayer == renderer()->view()->layer())) { // If the fixed layer's container is the root, just add in the offset of the view. We can obtain this by calling // localToAbsolute() on the RenderView. diff --git a/WebCore/rendering/RenderLayerBacking.cpp b/WebCore/rendering/RenderLayerBacking.cpp index 48aa3ec..0d39f7a 100644 --- a/WebCore/rendering/RenderLayerBacking.cpp +++ b/WebCore/rendering/RenderLayerBacking.cpp @@ -1021,14 +1021,6 @@ void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext* bool selectionOnly = paintBehavior & PaintBehaviorSelectionOnly; if (shouldPaint && (paintingPhase & GraphicsLayerPaintForeground)) { -#if ENABLE(ANDROID_OVERFLOW_SCROLL) - // Scroll to 0,0 and paint the entire contents, then scroll back the - // the original offset. - int x = m_owningLayer->scrollXOffset(); - int y = m_owningLayer->scrollYOffset(); - if (m_owningLayer->hasOverflowScroll()) - m_owningLayer->scrollToOffset(0, 0, false, false); -#endif // Set up the clip used when painting our children. setClip(context, paintDirtyRect, clipRectToApply); PaintInfo paintInfo(context, clipRectToApply, @@ -1067,10 +1059,6 @@ void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext* // Now walk the sorted list of children with positive z-indices. m_owningLayer->paintList(m_owningLayer->posZOrderList(), rootLayer, context, paintDirtyRect, paintBehavior, paintingRoot, 0, 0); -#if ENABLE(ANDROID_OVERFLOW_SCROLL) - if (m_owningLayer->hasOverflowScroll()) - m_owningLayer->scrollToOffset(x, y, false, false); -#endif } if (shouldPaint && (paintingPhase & GraphicsLayerPaintMask)) { diff --git a/WebCore/rendering/RenderLayerCompositor.cpp b/WebCore/rendering/RenderLayerCompositor.cpp index f31ab9d..a115bfe 100644 --- a/WebCore/rendering/RenderLayerCompositor.cpp +++ b/WebCore/rendering/RenderLayerCompositor.cpp @@ -1193,10 +1193,6 @@ bool RenderLayerCompositor::requiresCompositingForAndroidLayers(const RenderLaye return true; #endif #if ENABLE(COMPOSITED_FIXED_ELEMENTS) - // First, check if we are in an iframe, and if so bail out - if (m_renderView->document()->frame()->tree()->parent()) - return false; - // For the moment, we want to only enable fixed composited layers on mobile websites. // Enable composited layers (for fixed elements) // We can consider a website as being a 'mobile' site if all the @@ -1288,6 +1284,10 @@ bool RenderLayerCompositor::clippedByAncestor(RenderLayer* layer) const // into the hierarchy between this layer and its children in the z-order hierarchy. bool RenderLayerCompositor::clipsCompositingDescendants(const RenderLayer* layer) const { +#if ENABLE(ANDROID_OVERFLOW_SCROLL) + if (layer->hasOverflowScroll()) + return false; +#endif return layer->hasCompositingDescendant() && (layer->renderer()->hasOverflowClip() || layer->renderer()->hasClip()); } diff --git a/WebCore/rendering/RenderTable.cpp b/WebCore/rendering/RenderTable.cpp index 43b6b03..521dea1 100644 --- a/WebCore/rendering/RenderTable.cpp +++ b/WebCore/rendering/RenderTable.cpp @@ -167,7 +167,7 @@ void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild) if (!wrapInAnonymousSection) { // If the next renderer is actually wrapped in an anonymous table section, we need to go up and find that. - while (beforeChild && !beforeChild->isTableSection() && !beforeChild->isTableCol() && beforeChild->style()->display() != TABLE_CAPTION) + while (beforeChild && beforeChild->parent() != this) beforeChild = beforeChild->parent(); RenderBox::addChild(child, beforeChild); @@ -1172,6 +1172,8 @@ int RenderTable::firstLineBoxBaseline() const if (isWritingModeRoot()) return -1; + recalcSectionsIfNeeded(); + RenderTableSection* firstNonEmptySection = m_head ? m_head : (m_firstBody ? m_firstBody : m_foot); if (firstNonEmptySection && !firstNonEmptySection->numRows()) firstNonEmptySection = sectionBelow(firstNonEmptySection, true); diff --git a/WebCore/rendering/RenderTextControlMultiLine.cpp b/WebCore/rendering/RenderTextControlMultiLine.cpp index eaa7eca..1a7ba36 100644 --- a/WebCore/rendering/RenderTextControlMultiLine.cpp +++ b/WebCore/rendering/RenderTextControlMultiLine.cpp @@ -41,7 +41,7 @@ RenderTextControlMultiLine::RenderTextControlMultiLine(Node* node, bool placehol RenderTextControlMultiLine::~RenderTextControlMultiLine() { - if (node()) + if (node() && node()->inDocument()) static_cast<HTMLTextAreaElement*>(node())->rendererWillBeDestroyed(); } diff --git a/WebCore/rendering/RenderTheme.cpp b/WebCore/rendering/RenderTheme.cpp index 522bd4d..538b6c6 100644 --- a/WebCore/rendering/RenderTheme.cpp +++ b/WebCore/rendering/RenderTheme.cpp @@ -198,7 +198,7 @@ void RenderTheme::adjustStyle(CSSStyleSelector* selector, RenderStyle* style, El return adjustTextFieldStyle(selector, style, e); case TextAreaPart: return adjustTextAreaStyle(selector, style, e); -#ifdef ANDROID_LISTBOX_USES_MENU_LIST +#if ENABLE(NO_LISTBOX_RENDERING) case ListboxPart: return adjustListboxStyle(selector, style, e); #endif diff --git a/WebCore/rendering/RenderTheme.h b/WebCore/rendering/RenderTheme.h index aedb8eb..13c69e6 100644 --- a/WebCore/rendering/RenderTheme.h +++ b/WebCore/rendering/RenderTheme.h @@ -236,7 +236,7 @@ protected: virtual void adjustTextAreaStyle(CSSStyleSelector*, RenderStyle*, Element*) const; virtual bool paintTextArea(RenderObject*, const PaintInfo&, const IntRect&) { return true; } -#ifdef ANDROID_LISTBOX_USES_MENU_LIST +#if ENABLE(NO_LISTBOX_RENDERING) virtual void adjustListboxStyle(CSSStyleSelector*, RenderStyle*, Element*) const {} #endif virtual void adjustMenuListStyle(CSSStyleSelector*, RenderStyle*, Element*) const; diff --git a/WebCore/svg/SVGDocumentExtensions.cpp b/WebCore/svg/SVGDocumentExtensions.cpp index 3fd9761..7f7ba67 100644 --- a/WebCore/svg/SVGDocumentExtensions.cpp +++ b/WebCore/svg/SVGDocumentExtensions.cpp @@ -93,8 +93,12 @@ void SVGDocumentExtensions::startAnimations() // FIXME: Eventually every "Time Container" will need a way to latch on to some global timer // starting animations for a document will do this "latching" #if ENABLE(SVG_ANIMATION) - HashSet<SVGSVGElement*>::iterator end = m_timeContainers.end(); - for (HashSet<SVGSVGElement*>::iterator itr = m_timeContainers.begin(); itr != end; ++itr) + // FIXME: We hold a ref pointers to prevent a shadow tree from getting removed out from underneath us. + // In the future we should refactor the use-element to avoid this. See https://webkit.org/b/53704 + Vector<RefPtr<SVGSVGElement> > timeContainers; + timeContainers.appendRange(m_timeContainers.begin(), m_timeContainers.end()); + Vector<RefPtr<SVGSVGElement> >::iterator end = timeContainers.end(); + for (Vector<RefPtr<SVGSVGElement> >::iterator itr = timeContainers.begin(); itr != end; ++itr) (*itr)->timeContainer()->begin(); #endif } diff --git a/WebCore/svg/SVGFont.cpp b/WebCore/svg/SVGFont.cpp index 898c259..25dbbe3 100644 --- a/WebCore/svg/SVGFont.cpp +++ b/WebCore/svg/SVGFont.cpp @@ -241,7 +241,7 @@ struct SVGTextRunWalker { { ASSERT(0 <= from && from <= to && to - from <= run.length()); - const String text = Font::normalizeSpaces(String(run.data(from), run.length())); + const String text = Font::normalizeSpaces(String(run.data(from), to - from)); Vector<SVGGlyphIdentifier::ArabicForm> chars(charactersWithArabicForm(text, run.rtl())); SVGGlyphIdentifier identifier; diff --git a/WebCore/svg/SVGFontFaceElement.cpp b/WebCore/svg/SVGFontFaceElement.cpp index 515ce04..97f457d 100644 --- a/WebCore/svg/SVGFontFaceElement.cpp +++ b/WebCore/svg/SVGFontFaceElement.cpp @@ -262,6 +262,11 @@ String SVGFontFaceElement::fontFamily() const return m_styleDeclaration->getPropertyValue(CSSPropertyFontFamily); } +SVGFontElement* SVGFontFaceElement::associatedFontElement() const +{ + return m_fontElement.get(); +} + void SVGFontFaceElement::rebuildFontFace() { ASSERT(inDocument()); diff --git a/WebCore/svg/SVGFontFaceElement.h b/WebCore/svg/SVGFontFaceElement.h index 3ee71d8..ead2e1f 100644 --- a/WebCore/svg/SVGFontFaceElement.h +++ b/WebCore/svg/SVGFontFaceElement.h @@ -47,7 +47,7 @@ namespace WebCore { int descent() const; String fontFamily() const; - SVGFontElement* associatedFontElement() const { return m_fontElement; } + SVGFontElement* associatedFontElement() const; void rebuildFontFace(); void removeFromMappedElementSheet(); @@ -63,7 +63,7 @@ namespace WebCore { RefPtr<CSSFontFaceRule> m_fontFaceRule; RefPtr<CSSMutableStyleDeclaration> m_styleDeclaration; - SVGFontElement* m_fontElement; + RefPtr<SVGFontElement> m_fontElement; }; } // namespace WebCore diff --git a/WebCore/xml/XSLStyleSheet.h b/WebCore/xml/XSLStyleSheet.h index 4312771..b36ac1d 100644 --- a/WebCore/xml/XSLStyleSheet.h +++ b/WebCore/xml/XSLStyleSheet.h @@ -79,7 +79,8 @@ public: CachedResourceLoader* cachedResourceLoader(); - Document* ownerDocument() { return m_ownerDocument; } + Document* ownerDocument(); + XSLStyleSheet* parentStyleSheet() const { return m_parentStyleSheet; } void setParentStyleSheet(XSLStyleSheet* parent); #if USE(QXMLQUERY) diff --git a/WebCore/xml/XSLStyleSheetLibxslt.cpp b/WebCore/xml/XSLStyleSheetLibxslt.cpp index 3fb9eb5..447ba1e 100644 --- a/WebCore/xml/XSLStyleSheetLibxslt.cpp +++ b/WebCore/xml/XSLStyleSheetLibxslt.cpp @@ -57,7 +57,6 @@ namespace WebCore { XSLStyleSheet::XSLStyleSheet(XSLImportRule* parentRule, const String& originalURL, const KURL& finalURL) : StyleSheet(parentRule, originalURL, finalURL) - , m_ownerDocument(0) , m_embedded(false) , m_processed(false) // Child sheets get marked as processed when the libxslt engine has finally seen them. , m_stylesheetDoc(0) @@ -68,7 +67,6 @@ XSLStyleSheet::XSLStyleSheet(XSLImportRule* parentRule, const String& originalUR XSLStyleSheet::XSLStyleSheet(Node* parentNode, const String& originalURL, const KURL& finalURL, bool embedded) : StyleSheet(parentNode, originalURL, finalURL) - , m_ownerDocument(parentNode->document()) , m_embedded(embedded) , m_processed(true) // The root sheet starts off processed. , m_stylesheetDoc(0) @@ -130,9 +128,10 @@ void XSLStyleSheet::clearDocuments() CachedResourceLoader* XSLStyleSheet::cachedResourceLoader() { - if (!m_ownerDocument) + Document* document = ownerDocument(); + if (!document) return 0; - return m_ownerDocument->cachedResourceLoader(); + return document->cachedResourceLoader(); } bool XSLStyleSheet::parseString(const String& string, bool) @@ -258,8 +257,16 @@ xsltStylesheetPtr XSLStyleSheet::compileStyleSheet() void XSLStyleSheet::setParentStyleSheet(XSLStyleSheet* parent) { m_parentStyleSheet = parent; - if (parent) - m_ownerDocument = parent->ownerDocument(); +} + +Document* XSLStyleSheet::ownerDocument() +{ + for (XSLStyleSheet* styleSheet = this; styleSheet; styleSheet = styleSheet->parentStyleSheet()) { + Node* node = styleSheet->ownerNode(); + if (node) + return node->document(); + } + return 0; } xmlDocPtr XSLStyleSheet::locateStylesheetSubResource(xmlDocPtr parentDoc, const xmlChar* uri) diff --git a/WebCore/xml/XSLStyleSheetQt.cpp b/WebCore/xml/XSLStyleSheetQt.cpp index 0523560..0d41d1f 100644 --- a/WebCore/xml/XSLStyleSheetQt.cpp +++ b/WebCore/xml/XSLStyleSheetQt.cpp @@ -35,7 +35,6 @@ namespace WebCore { XSLStyleSheet::XSLStyleSheet(Node* parentNode, const String& originalURL, const KURL& finalURL, bool embedded) : StyleSheet(parentNode, originalURL, finalURL) - , m_ownerDocument(parentNode->document()) , m_embedded(embedded) { } @@ -63,9 +62,10 @@ void XSLStyleSheet::clearDocuments() CachedResourceLoader* XSLStyleSheet::cachedResourceLoader() { - if (!m_ownerDocument) + Document* document = ownerDocument(); + if (!document) return 0; - return m_ownerDocument->cachedResourceLoader(); + return document->cachedResourceLoader(); } bool XSLStyleSheet::parseString(const String& string, bool) @@ -88,6 +88,12 @@ void XSLStyleSheet::loadChildSheet(const String&) notImplemented(); } +Document* XSLStyleSheet::ownerDocument() +{ + Node* node = ownerNode(); + return node ? node->document() : 0; +} + void XSLStyleSheet::setParentStyleSheet(XSLStyleSheet*) { notImplemented(); diff --git a/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp b/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp index f0958d9..980c03e 100644 --- a/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp +++ b/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp @@ -87,8 +87,6 @@ void ChromeClientAndroid::attachRootGraphicsLayer(WebCore::Frame*, WebCore::Grap { // frame is not used in Android as we should only get root graphics layer for the main frame m_rootGraphicsLayer = layer; - if (!layer) - return; scheduleCompositingLayerSync(); } @@ -536,7 +534,7 @@ bool ChromeClientAndroid::selectItemWritingDirectionIsNatural() PassRefPtr<PopupMenu> ChromeClientAndroid::createPopupMenu(PopupMenuClient* client) const { - return adoptRef(new PopupMenuAndroid(client)); + return adoptRef(new PopupMenuAndroid(static_cast<ListPopupMenuClient*>(client))); } PassRefPtr<SearchPopupMenu> ChromeClientAndroid::createSearchPopupMenu(PopupMenuClient*) const diff --git a/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp b/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp index cc21dad..535c0da 100644 --- a/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp +++ b/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp @@ -577,6 +577,12 @@ void FrameLoaderClientAndroid::dispatchWillSubmitForm(FramePolicyFunction func, (m_frame->loader()->policyChecker()->*func)(PolicyUse); } +void FrameLoaderClientAndroid::dispatchWillSendSubmitEvent(HTMLFormElement* form) +{ + if (m_webFrame->shouldSaveFormData()) + m_webFrame->saveFormData(form); +} + void FrameLoaderClientAndroid::dispatchDidLoadMainResource(DocumentLoader*) { notImplemented(); } diff --git a/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h b/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h index 964ac6e..034333e 100644 --- a/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h +++ b/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h @@ -223,7 +223,7 @@ namespace android { void enableOnDemandPlugins() { m_onDemandPluginsEnabled = true; } void dispatchDidChangeIcons(); - void dispatchWillSendSubmitEvent(HTMLFormElement*) { } + void dispatchWillSendSubmitEvent(HTMLFormElement*); private: CacheBuilder m_cacheBuilder; Frame* m_frame; diff --git a/WebKit/android/WebCoreSupport/PlatformBridge.cpp b/WebKit/android/WebCoreSupport/PlatformBridge.cpp index b34ff8c..8d8d809 100644 --- a/WebKit/android/WebCoreSupport/PlatformBridge.cpp +++ b/WebKit/android/WebCoreSupport/PlatformBridge.cpp @@ -160,16 +160,16 @@ FloatRect PlatformBridge::screenRect() } // The visible size on screen in document coordinate -int PlatformBridge::visibleScreenWidth(const WebCore::FrameView* frameView) +int PlatformBridge::screenWidthInDocCoord(const WebCore::FrameView* frameView) { android::WebViewCore* webViewCore = android::WebViewCore::getWebViewCore(frameView); - return webViewCore->visibleScreenWidth(); + return webViewCore->screenWidth(); } -int PlatformBridge::visibleScreenHeight(const WebCore::FrameView* frameView) +int PlatformBridge::screenHeightInDocCoord(const WebCore::FrameView* frameView) { android::WebViewCore* webViewCore = android::WebViewCore::getWebViewCore(frameView); - return webViewCore->visibleScreenHeight(); + return webViewCore->screenHeight(); } String PlatformBridge::computeDefaultLanguage() diff --git a/WebKit/android/WebCoreSupport/ResourceLoaderAndroid.cpp b/WebKit/android/WebCoreSupport/ResourceLoaderAndroid.cpp index 3f2d9ee..7f54810 100644 --- a/WebKit/android/WebCoreSupport/ResourceLoaderAndroid.cpp +++ b/WebKit/android/WebCoreSupport/ResourceLoaderAndroid.cpp @@ -44,7 +44,8 @@ PassRefPtr<ResourceLoaderAndroid> ResourceLoaderAndroid::start( FrameLoaderClientAndroid* clientAndroid = static_cast<FrameLoaderClientAndroid*>(client); #if USE(CHROME_NETWORK_STACK) WebViewCore* webViewCore = WebViewCore::getWebViewCore(clientAndroid->getFrame()->view()); - return WebUrlLoader::start(client, handle, request, isMainResource, isSync, webViewCore->webRequestContext()); + bool isMainFrame = !(clientAndroid->getFrame()->tree() && clientAndroid->getFrame()->tree()->parent()); + return WebUrlLoader::start(client, handle, request, isMainResource, isMainFrame, isSync, webViewCore->webRequestContext()); #else return clientAndroid->webFrame()->startLoadingResource(handle, request, isMainResource, isSync); #endif diff --git a/WebKit/android/WebCoreSupport/WebCookieJar.cpp b/WebKit/android/WebCoreSupport/WebCookieJar.cpp index d290b5a..99de67e 100644 --- a/WebKit/android/WebCoreSupport/WebCookieJar.cpp +++ b/WebKit/android/WebCoreSupport/WebCookieJar.cpp @@ -31,12 +31,21 @@ #include "WebRequestContext.h" #include "WebUrlLoaderClient.h" - +#include <cutils/log.h> #include <dirent.h> +#undef ASSERT +#define ASSERT(assertion, ...) do \ + if (!(assertion)) { \ + android_printLog(ANDROID_LOG_ERROR, __FILE__, __VA_ARGS__); \ + } \ +while (0) + namespace android { static WTF::Mutex instanceMutex; +static bool isFirstInstanceCreated = false; +static bool fileSchemeCookiesEnabled = false; static const std::string& databaseDirectory() { @@ -99,6 +108,9 @@ scoped_refptr<WebCookieJar>* instance(bool isPrivateBrowsing) WebCookieJar* WebCookieJar::get(bool isPrivateBrowsing) { MutexLocker lock(instanceMutex); + if (!isFirstInstanceCreated && fileSchemeCookiesEnabled) + net::CookieMonster::EnableFileScheme(); + isFirstInstanceCreated = true; scoped_refptr<WebCookieJar>* instancePtr = instance(isPrivateBrowsing); if (!instancePtr->get()) *instancePtr = new WebCookieJar(databaseDirectory(isPrivateBrowsing)); @@ -117,9 +129,6 @@ void WebCookieJar::cleanup(bool isPrivateBrowsing) WebCookieJar::WebCookieJar(const std::string& databaseFilePath) : m_allowCookies(true) { - // This is needed for the page cycler. See http://b/2944150 - net::CookieMonster::EnableFileScheme(); - // Setup the permissions for the file const char* cDatabasePath = databaseFilePath.c_str(); mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; @@ -130,6 +139,7 @@ WebCookieJar::WebCookieJar(const std::string& databaseFilePath) if (fd >= 0) close(fd); } + FilePath cookiePath(databaseFilePath.c_str()); m_cookieDb = new SQLitePersistentCookieStore(cookiePath); m_cookieStore = new net::CookieMonster(m_cookieDb.get(), 0); @@ -190,16 +200,21 @@ public: Task* callback = NewRunnableMethod(this, &FlushSemaphore::Callback); ioThread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod( monster, &net::CookieMonster::FlushStore, callback)); + } else { + Callback(); } } // Block until the given number of callbacks has been made. void Wait(int numCallbacks) { AutoLock al(m_lock); + int lastCount = m_count; while (m_count < numCallbacks) { // TODO(husky): Maybe use TimedWait() here? But it's not obvious what // to do if the flush fails. Might be okay just to let the OS kill us. m_condition.Wait(); + ASSERT(lastCount != m_count, "Wait finished without incrementing m_count %d %d", m_count, lastCount); + lastCount = m_count; } m_count -= numCallbacks; } @@ -227,4 +242,22 @@ void WebCookieJar::flush() semaphore->Wait(2); } +bool WebCookieJar::acceptFileSchemeCookies() +{ + MutexLocker lock(instanceMutex); + return fileSchemeCookiesEnabled; +} + +void WebCookieJar::setAcceptFileSchemeCookies(bool accept) +{ + // The Chromium HTTP stack only reflects changes to this flag when creating + // a new CookieMonster instance. While we could track whether any + // CookieMonster instances currently exist, this would be complicated and is + // not required, so we only allow this flag to be changed before the first + // instance is created. + MutexLocker lock(instanceMutex); + if (!isFirstInstanceCreated) + fileSchemeCookiesEnabled = accept; +} + } diff --git a/WebKit/android/WebCoreSupport/WebCookieJar.h b/WebKit/android/WebCoreSupport/WebCookieJar.h index 2f32e1a..1f4266c 100644 --- a/WebKit/android/WebCoreSupport/WebCookieJar.h +++ b/WebKit/android/WebCoreSupport/WebCookieJar.h @@ -49,6 +49,12 @@ public: bool allowCookies(); void setAllowCookies(bool allow); + // Getter and setter for whether we accept cookies for file scheme URLS. + // Defaults to false. Note that calls to the setter are ignored once the + // first instance of this class has been created. + static bool acceptFileSchemeCookies(); + static void setAcceptFileSchemeCookies(bool); + // Instead of this it would probably be better to add the cookie methods // here so the rest of WebKit doesn't have to know about Chromium classes net::CookieStore* cookieStore() { return m_cookieStore.get(); } diff --git a/WebKit/android/WebCoreSupport/WebRequest.cpp b/WebKit/android/WebCoreSupport/WebRequest.cpp index fd6bbe2..a14036f 100644 --- a/WebKit/android/WebCoreSupport/WebRequest.cpp +++ b/WebKit/android/WebCoreSupport/WebRequest.cpp @@ -116,10 +116,28 @@ const std::string& WebRequest::getUserAgent() const return m_userAgent; } +#ifdef LOG_REQUESTS +namespace { +int remaining = 0; +} +#endif + void WebRequest::finish(bool success) { m_runnableFactory.RevokeAll(); - ASSERT(m_loadState < Finished, "called finish on an already finished WebRequest (%d)", m_loadState); + ASSERT(m_loadState < Finished, "(%p) called finish on an already finished WebRequest (%d) (%s)", this, m_loadState, m_url.c_str()); + if (m_loadState >= Finished) + return; +#ifdef LOG_REQUESTS + time_t finish; + time(&finish); + finish = finish - m_startTime; + struct tm * timeinfo; + char buffer[80]; + timeinfo = localtime(&finish); + strftime(buffer, 80, "Time: %M:%S",timeinfo); + android_printLog(ANDROID_LOG_DEBUG, "KM", "(%p) finish (%d) (%s) (%d) (%s)", this, --remaining, buffer, success, m_url.c_str()); +#endif // Make sure WebUrlLoaderClient doesn't delete us in the middle of this method. scoped_refptr<WebRequest> guard(this); @@ -183,6 +201,10 @@ void WebRequest::updateLoadFlags(int& loadFlags) void WebRequest::start() { ASSERT(m_loadState == Created, "Start called on a WebRequest not in CREATED state: (%s)", m_url.c_str()); +#ifdef LOG_REQUESTS + android_printLog(ANDROID_LOG_DEBUG, "KM", "(%p) start (%d) (%s)", this, ++remaining, m_url.c_str()); + time(&m_startTime); +#endif m_loadState = Started; diff --git a/WebKit/android/WebCoreSupport/WebRequest.h b/WebKit/android/WebCoreSupport/WebRequest.h index ae386fd..dba7559 100644 --- a/WebKit/android/WebCoreSupport/WebRequest.h +++ b/WebKit/android/WebCoreSupport/WebRequest.h @@ -113,6 +113,9 @@ private: ScopedRunnableMethodFactory<WebRequest> m_runnableFactory; bool m_wantToPause; bool m_isPaused; +#ifdef LOG_REQUESTS + time_t m_startTime; +#endif }; } // namespace android diff --git a/WebKit/android/WebCoreSupport/WebUrlLoader.cpp b/WebKit/android/WebCoreSupport/WebUrlLoader.cpp index 531619a..0c90bc5 100644 --- a/WebKit/android/WebCoreSupport/WebUrlLoader.cpp +++ b/WebKit/android/WebCoreSupport/WebUrlLoader.cpp @@ -45,7 +45,7 @@ WebUrlLoader::~WebUrlLoader() } PassRefPtr<WebUrlLoader> WebUrlLoader::start(FrameLoaderClient* client, WebCore::ResourceHandle* resourceHandle, - const WebCore::ResourceRequest& resourceRequest, bool isMainResource, bool isSync, WebRequestContext* context) + const WebCore::ResourceRequest& resourceRequest, bool isMainResource, bool isMainFrame, bool isSync, WebRequestContext* context) { FrameLoaderClientAndroid* androidClient = static_cast<FrameLoaderClientAndroid*>(client); WebFrame* webFrame = androidClient->webFrame(); @@ -58,7 +58,7 @@ PassRefPtr<WebUrlLoader> WebUrlLoader::start(FrameLoaderClient* client, WebCore: webFrame->maybeSavePassword(androidClient->getFrame(), resourceRequest); RefPtr<WebUrlLoader> loader = WebUrlLoader::create(webFrame, resourceHandle, resourceRequest); - loader->m_loaderClient->start(isMainResource, isSync, context); + loader->m_loaderClient->start(isMainResource, isMainFrame, isSync, context); return loader.release(); } diff --git a/WebKit/android/WebCoreSupport/WebUrlLoader.h b/WebKit/android/WebCoreSupport/WebUrlLoader.h index 73c022a..dd88e73 100644 --- a/WebKit/android/WebCoreSupport/WebUrlLoader.h +++ b/WebKit/android/WebCoreSupport/WebUrlLoader.h @@ -39,7 +39,7 @@ class WebRequestContext; class WebUrlLoader : public ResourceLoaderAndroid { public: virtual ~WebUrlLoader(); - static PassRefPtr<WebUrlLoader> start(FrameLoaderClient* client, WebCore::ResourceHandle*, const WebCore::ResourceRequest&, bool isMainResource, bool sync, WebRequestContext*); + static PassRefPtr<WebUrlLoader> start(FrameLoaderClient* client, WebCore::ResourceHandle*, const WebCore::ResourceRequest&, bool isMainResource, bool isMainFrame, bool sync, WebRequestContext*); virtual void cancel(); virtual void downloadFile(); diff --git a/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp b/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp index 5c54000..bf0583b 100644 --- a/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp +++ b/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp @@ -38,7 +38,6 @@ #include "WebResourceRequest.h" #include <wtf/text/CString.h> -#include <sstream> namespace android { @@ -88,6 +87,8 @@ bool WebUrlLoaderClient::isActive() const { if (m_cancelling) return false; + if (!m_resourceHandle) + return false; if (!m_resourceHandle->client()) return false; if (m_finished) @@ -100,6 +101,7 @@ WebUrlLoaderClient::WebUrlLoaderClient(WebFrame* webFrame, WebCore::ResourceHand : m_webFrame(webFrame) , m_resourceHandle(resourceHandle) , m_isMainResource(false) + , m_isMainFrame(false) , m_isCertMimeType(false) , m_cancelling(false) , m_sync(false) @@ -161,7 +163,7 @@ WebUrlLoaderClient::WebUrlLoaderClient(WebFrame* webFrame, WebCore::ResourceHand } } -bool WebUrlLoaderClient::start(bool isMainResource, bool sync, WebRequestContext* context) +bool WebUrlLoaderClient::start(bool isMainResource, bool isMainFrame, bool sync, WebRequestContext* context) { base::Thread* thread = ioThread(); if (!thread) { @@ -169,6 +171,7 @@ bool WebUrlLoaderClient::start(bool isMainResource, bool sync, WebRequestContext } m_isMainResource = isMainResource; + m_isMainFrame = isMainFrame; m_sync = sync; if (m_sync) { AutoLock autoLock(*syncLock()); @@ -344,30 +347,6 @@ void WebUrlLoaderClient::maybeCallOnMainThread(Task* task) } } -namespace { -// Convert a CertPrincipal into string readable by Java code. -// The expected format is "CN=xxx, O=xxx, OU=xxx" (see SslCertificate.DName). -// If there are multiple organization names, we print them all. -static std::string certPrincipalToString(const net::CertPrincipal& cp) -{ - std::string result; - if (!cp.common_name.empty()) { - result += "CN="; - result += cp.common_name; - } - std::vector<std::string>::const_iterator i; - for (i = cp.organization_names.begin(); i != cp.organization_names.end(); ++i) { - result += result.empty() ? "O=" : ", O="; - result += *i; - } - for (i = cp.organization_unit_names.begin(); i != cp.organization_unit_names.end(); ++i) { - result += result.empty() ? "OU=" : ", OU="; - result += *i; - } - return result; -} -} - // Response methods void WebUrlLoaderClient::didReceiveResponse(PassOwnPtr<WebResponse> webResponse) { @@ -377,15 +356,13 @@ void WebUrlLoaderClient::didReceiveResponse(PassOwnPtr<WebResponse> webResponse) m_response = webResponse; m_resourceHandle->client()->didReceiveResponse(m_resourceHandle.get(), m_response->createResourceResponse()); - if (m_isMainResource) { - // If we got an SSL certificate, tell the WebView about it. - const net::SSLInfo& ssl = m_response->getSslInfo(); - if (ssl.cert) { - m_webFrame->setCertificate( - certPrincipalToString(ssl.cert->subject()), - certPrincipalToString(ssl.cert->issuer()), - 1000L * ssl.cert->valid_start().ToDoubleT(), - 1000L * ssl.cert->valid_expiry().ToDoubleT()); + // Set the main page's certificate to WebView. + if (m_isMainResource && m_isMainFrame) { + const net::SSLInfo& ssl_info = m_response->getSslInfo(); + if (ssl_info.is_valid()) { + std::vector<std::string> chain_bytes; + ssl_info.cert->GetChainDEREncodedBytes(&chain_bytes); + m_webFrame->setCertificate(chain_bytes[0]); } } } diff --git a/WebKit/android/WebCoreSupport/WebUrlLoaderClient.h b/WebKit/android/WebCoreSupport/WebUrlLoaderClient.h index 59ec28b..dc101db 100644 --- a/WebKit/android/WebCoreSupport/WebUrlLoaderClient.h +++ b/WebKit/android/WebCoreSupport/WebUrlLoaderClient.h @@ -66,7 +66,7 @@ public: WebUrlLoaderClient(WebFrame*, WebCore::ResourceHandle*, const WebCore::ResourceRequest&); // Called from WebCore, will be forwarded to the IO thread - bool start(bool isMainResource, bool sync, WebRequestContext*); + bool start(bool isMainResource, bool isMainFrame, bool sync, WebRequestContext*); void cancel(); void downloadFile(); void pauseLoad(bool pause); @@ -104,6 +104,7 @@ private: WebFrame* m_webFrame; RefPtr<WebCore::ResourceHandle> m_resourceHandle; bool m_isMainResource; + bool m_isMainFrame; bool m_isCertMimeType; bool m_cancelling; bool m_sync; diff --git a/WebKit/android/jni/CookieManager.cpp b/WebKit/android/jni/CookieManager.cpp index 87c7fa8..a9c68fd 100644 --- a/WebKit/android/jni/CookieManager.cpp +++ b/WebKit/android/jni/CookieManager.cpp @@ -155,6 +155,25 @@ static void flushCookieStore(JNIEnv*, jobject) #endif } +static bool acceptFileSchemeCookies(JNIEnv*, jobject) +{ +#if USE(CHROME_NETWORK_STACK) + return WebCookieJar::acceptFileSchemeCookies(); +#else + // File scheme cookies are always accepted with the Android HTTP stack. + return true; +#endif +} + +static void setAcceptFileSchemeCookies(JNIEnv*, jobject, jboolean accept) +{ +#if USE(CHROME_NETWORK_STACK) + WebCookieJar::setAcceptFileSchemeCookies(accept); +#else + // File scheme cookies are always accepted with the Android HTTP stack. +#endif +} + static JNINativeMethod gCookieManagerMethods[] = { { "nativeAcceptCookie", "()Z", (void*) acceptCookie }, { "nativeGetCookie", "(Ljava/lang/String;)Ljava/lang/String;", (void*) getCookie }, @@ -165,6 +184,8 @@ static JNINativeMethod gCookieManagerMethods[] = { { "nativeSetAcceptCookie", "(Z)V", (void*) setAcceptCookie }, { "nativeSetCookie", "(Ljava/lang/String;Ljava/lang/String;)V", (void*) setCookie }, { "nativeFlushCookieStore", "()V", (void*) flushCookieStore }, + { "nativeAcceptFileSchemeCookies", "()Z", (void*) acceptFileSchemeCookies }, + { "nativeSetAcceptFileSchemeCookies", "(Z)V", (void*) setAcceptFileSchemeCookies }, }; int registerCookieManager(JNIEnv* env) diff --git a/WebKit/android/jni/WebCoreFrameBridge.cpp b/WebKit/android/jni/WebCoreFrameBridge.cpp index 9780d2d..c187d92 100644 --- a/WebKit/android/jni/WebCoreFrameBridge.cpp +++ b/WebKit/android/jni/WebCoreFrameBridge.cpp @@ -44,7 +44,6 @@ #include "Element.h" #include "FocusController.h" #include "Font.h" -#include "FormState.h" #include "Frame.h" #include "FrameLoader.h" #include "FrameLoaderClientAndroid.h" @@ -220,6 +219,8 @@ struct WebFrame::JavaBrowserFrame jmethodID mDidReceiveData; jmethodID mDidFinishLoading; jmethodID mSetCertificate; + jmethodID mShouldSaveFormData; + jmethodID mSaveFormData; AutoJObject frame(JNIEnv* env) { return getRealObject(env, mObj); } @@ -290,8 +291,9 @@ WebFrame::WebFrame(JNIEnv* env, jobject obj, jobject historyList, WebCore::Page* "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;J)V"); mJavaFrame->mDidReceiveData = env->GetMethodID(clazz, "didReceiveData", "([BI)V"); mJavaFrame->mDidFinishLoading = env->GetMethodID(clazz, "didFinishLoading", "()V"); - mJavaFrame->mSetCertificate = env->GetMethodID(clazz, "setCertificate", - "(Ljava/lang/String;Ljava/lang/String;JJ)V"); + mJavaFrame->mSetCertificate = env->GetMethodID(clazz, "setCertificate", "([B)V"); + mJavaFrame->mShouldSaveFormData = env->GetMethodID(clazz, "shouldSaveFormData", "()Z"); + mJavaFrame->mSaveFormData = env->GetMethodID(clazz, "saveFormData", "(Ljava/util/HashMap;)V"); env->DeleteLocalRef(clazz); LOG_ASSERT(mJavaFrame->mStartLoadingResource, "Could not find method startLoadingResource"); @@ -322,6 +324,8 @@ WebFrame::WebFrame(JNIEnv* env, jobject obj, jobject historyList, WebCore::Page* LOG_ASSERT(mJavaFrame->mDidReceiveData, "Could not find method didReceiveData"); LOG_ASSERT(mJavaFrame->mDidFinishLoading, "Could not find method didFinishLoading"); LOG_ASSERT(mJavaFrame->mSetCertificate, "Could not find method setCertificate"); + LOG_ASSERT(mJavaFrame->mShouldSaveFormData, "Could not find method shouldSaveFormData"); + LOG_ASSERT(mJavaFrame->mSaveFormData, "Could not find method saveFormData"); mUserAgent = WTF::String(); mUserInitiatedAction = false; @@ -782,6 +786,16 @@ WebFrame::canHandleRequest(const WebCore::ResourceRequest& request) return (ret == 0); } +bool +WebFrame::shouldSaveFormData() +{ + JNIEnv* env = getJNIEnv(); + jboolean ret = env->CallBooleanMethod(mJavaFrame->frame(env).get(), + mJavaFrame->mShouldSaveFormData); + checkException(env); + return ret; +} + WebCore::Frame* WebFrame::createWindow(bool dialog, bool userGesture) { @@ -950,20 +964,21 @@ WebFrame::didFinishLoading() { #endif #if USE(CHROME_NETWORK_STACK) -void WebFrame::setCertificate(const std::string& issuedTo, const std::string& issuedBy, long long validNotBeforeMillis, long long validNotAfterMillis) +void WebFrame::setCertificate(const std::string& cert) { #ifdef ANDROID_INSTRUMENT TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); #endif JNIEnv* env = getJNIEnv(); - jstring jIssuedTo = stdStringToJstring(env, issuedTo, true); - jstring jIssuedBy = stdStringToJstring(env, issuedBy, true); - env->CallVoidMethod(mJavaFrame->frame(env).get(), - mJavaFrame->mSetCertificate, jIssuedTo, jIssuedBy, validNotBeforeMillis, validNotAfterMillis); + int len = cert.length(); + jbyteArray jCert = env->NewByteArray(len); + jbyte* bytes = env->GetByteArrayElements(jCert, NULL); + cert.copy(reinterpret_cast<char*>(bytes), len); + + env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mSetCertificate, jCert); - env->DeleteLocalRef(jIssuedTo); - env->DeleteLocalRef(jIssuedBy); + env->DeleteLocalRef(jCert); checkException(env); } #endif @@ -1876,62 +1891,46 @@ static void SetUsernamePassword(JNIEnv *env, jobject obj, } } -static jobject GetFormTextData(JNIEnv *env, jobject obj) +void +WebFrame::saveFormData(HTMLFormElement* form) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter); -#endif - WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj); - LOG_ASSERT(pFrame, "GetFormTextData must take a valid frame pointer!"); - jobject hashMap = NULL; - - WTF::PassRefPtr<WebCore::HTMLCollection> collection = pFrame->document()->forms(); - if (collection->length() > 0) { + if (form->autoComplete()) { + JNIEnv* env = getJNIEnv(); jclass mapClass = env->FindClass("java/util/HashMap"); LOG_ASSERT(mapClass, "Could not find HashMap class!"); jmethodID init = env->GetMethodID(mapClass, "<init>", "(I)V"); LOG_ASSERT(init, "Could not find constructor for HashMap"); - hashMap = env->NewObject(mapClass, init, 1); + jobject hashMap = env->NewObject(mapClass, init, 1); LOG_ASSERT(hashMap, "Could not create a new HashMap"); jmethodID put = env->GetMethodID(mapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); LOG_ASSERT(put, "Could not find put method on HashMap"); - - WebCore::HTMLFormElement* form; - WebCore::HTMLInputElement* input; - for (WebCore::Node* node = collection->firstItem(); - node && !node->namespaceURI().isNull() && !node->namespaceURI().isEmpty(); - node = collection->nextItem()) { - form = static_cast<WebCore::HTMLFormElement*>(node); - if (form->autoComplete()) { - WTF::Vector<WebCore::HTMLFormControlElement*> elements = form->associatedElements(); - size_t size = elements.size(); - for (size_t i = 0; i < size; i++) { - WebCore::HTMLFormControlElement* e = elements[i]; - if (e->hasTagName(WebCore::HTMLNames::inputTag)) { - input = static_cast<WebCore::HTMLInputElement*>(e); - if (input->isTextField() && !input->isPasswordField() - && input->autoComplete()) { - WTF::String value = input->value(); - int len = value.length(); - if (len) { - const WTF::AtomicString& name = input->name(); - jstring key = wtfStringToJstring(env, name); - jstring val = wtfStringToJstring(env, value); - LOG_ASSERT(key && val, "name or value not set"); - env->CallObjectMethod(hashMap, put, key, val); - env->DeleteLocalRef(key); - env->DeleteLocalRef(val); - } - } + WTF::Vector<WebCore::HTMLFormControlElement*> elements = form->associatedElements(); + size_t size = elements.size(); + for (size_t i = 0; i < size; i++) { + WebCore::HTMLFormControlElement* e = elements[i]; + if (e->hasTagName(WebCore::HTMLNames::inputTag)) { + WebCore::HTMLInputElement* input = static_cast<WebCore::HTMLInputElement*>(e); + if (input->isTextField() && !input->isPasswordField() + && input->autoComplete()) { + WTF::String value = input->value(); + int len = value.length(); + if (len) { + const WTF::AtomicString& name = input->name(); + jstring key = wtfStringToJstring(env, name); + jstring val = wtfStringToJstring(env, value); + LOG_ASSERT(key && val, "name or value not set"); + env->CallObjectMethod(hashMap, put, key, val); + env->DeleteLocalRef(key); + env->DeleteLocalRef(val); } } } } + env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mSaveFormData, hashMap); + env->DeleteLocalRef(hashMap); env->DeleteLocalRef(mapClass); - } - return hashMap; } static void OrientationChanged(JNIEnv *env, jobject obj, int orientation) @@ -2048,8 +2047,6 @@ static JNINativeMethod gBrowserFrameNativeMethods[] = { (void*) GetUsernamePassword }, { "setUsernamePassword", "(Ljava/lang/String;Ljava/lang/String;)V", (void*) SetUsernamePassword }, - { "getFormTextData", "()Ljava/util/HashMap;", - (void*) GetFormTextData }, { "nativeOrientationChanged", "(I)V", (void*) OrientationChanged }, { "nativeAuthenticationProceed", "(ILjava/lang/String;Ljava/lang/String;)V", diff --git a/WebKit/android/jni/WebCoreFrameBridge.h b/WebKit/android/jni/WebCoreFrameBridge.h index ae62835..af7be60 100644 --- a/WebKit/android/jni/WebCoreFrameBridge.h +++ b/WebKit/android/jni/WebCoreFrameBridge.h @@ -37,6 +37,7 @@ #include <wtf/RefCounted.h> namespace WebCore { + class HTMLFormElement; class Frame; class HistoryItem; class Image; @@ -125,18 +126,15 @@ class WebFrame : public WebCoreRefObject { void maybeSavePassword(WebCore::Frame* frame, const WebCore::ResourceRequest& request); - void setCertificate(const std::string& issuedTo, const std::string& issuedBy, long long validNotBeforeMillis, long long validNotAfterMillis); + void setCertificate(const std::string& cert); /** - * When the user initiates an action (via trackball, key-press, or touch), - * we set mUserInitiatedAction to true. If a load happens due to this click, - * then we ask the application if it wants to override - * the load. Otherwise, we attempt to load the resource internally. + * When the user initiates a click, we set mUserInitiatedAction to true. + * If a load happens due to this click, then we ask the application if it wants + * to override the load. Otherwise, we attempt to load the resource internally. */ void setUserInitiatedAction(bool userInitiatedAction) { mUserInitiatedAction = userInitiatedAction; } - bool userInitiatedAction() { return mUserInitiatedAction; } - WebCore::Page* page() const { return mPage; } // Currently used only by the chrome net stack. A similar field is used by @@ -151,6 +149,8 @@ class WebFrame : public WebCoreRefObject { bool getUsernamePasswordFromDom(WebCore::Frame* frame, WTF::String& username, WTF::String& password); jbyteArray getPostData(const WebCore::ResourceRequest& request); + bool shouldSaveFormData(); + void saveFormData(WebCore::HTMLFormElement*); private: struct JavaBrowserFrame; JavaBrowserFrame* mJavaFrame; diff --git a/WebKit/android/jni/WebViewCore.cpp b/WebKit/android/jni/WebViewCore.cpp index b329e3b..6e6196a 100644 --- a/WebKit/android/jni/WebViewCore.cpp +++ b/WebKit/android/jni/WebViewCore.cpp @@ -35,6 +35,8 @@ #include "Chrome.h" #include "ChromeClientAndroid.h" #include "ChromiumIncludes.h" +#include "ClientRect.h" +#include "ClientRectList.h" #include "Color.h" #include "CSSPropertyNames.h" #include "CSSValueKeywords.h" @@ -250,9 +252,7 @@ struct WebViewCoreFields { struct WebViewCore::JavaGlue { jweak m_obj; - jmethodID m_spawnScrollTo; jmethodID m_scrollTo; - jmethodID m_scrollBy; jmethodID m_contentDraw; jmethodID m_layersDraw; jmethodID m_requestListBox; @@ -349,9 +349,7 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m jclass clazz = env->GetObjectClass(javaWebViewCore); m_javaGlue = new JavaGlue; m_javaGlue->m_obj = env->NewWeakGlobalRef(javaWebViewCore); - m_javaGlue->m_spawnScrollTo = GetJMethod(env, clazz, "contentSpawnScrollTo", "(II)V"); - m_javaGlue->m_scrollTo = GetJMethod(env, clazz, "contentScrollTo", "(IIZ)V"); - m_javaGlue->m_scrollBy = GetJMethod(env, clazz, "contentScrollBy", "(IIZ)V"); + m_javaGlue->m_scrollTo = GetJMethod(env, clazz, "contentScrollTo", "(IIZZ)V"); m_javaGlue->m_contentDraw = GetJMethod(env, clazz, "contentDraw", "()V"); m_javaGlue->m_layersDraw = GetJMethod(env, clazz, "layersDraw", "()V"); m_javaGlue->m_requestListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[I[I)V"); @@ -487,8 +485,6 @@ void WebViewCore::reset(bool fromConstructor) m_scrollOffsetY = 0; m_screenWidth = 0; m_screenHeight = 0; - m_visibleScreenWidth = 0; - m_visibleScreenHeight = 0; m_groupForVisitedLinks = NULL; m_currentNodeDomNavigationAxis = 0; } @@ -948,11 +944,8 @@ void WebViewCore::scrollTo(int x, int y, bool animate) // LOGD("WebViewCore::scrollTo(%d %d)\n", x, y); JNIEnv* env = JSC::Bindings::getJNIEnv(); - if (animate) - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_spawnScrollTo, x, y); - else - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_scrollTo, - x, y, m_onlyScrollIfImeIsShowing); + env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_scrollTo, + x, y, animate, m_onlyScrollIfImeIsShowing); checkException(env); } @@ -974,16 +967,6 @@ void WebViewCore::viewInvalidate(const WebCore::IntRect& rect) checkException(env); } -void WebViewCore::scrollBy(int dx, int dy, bool animate) -{ - if (!(dx | dy)) - return; - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_scrollBy, - dx, dy, animate); - checkException(env); -} - void WebViewCore::contentDraw() { JNIEnv* env = JSC::Bindings::getJNIEnv(); @@ -1154,13 +1137,14 @@ void WebViewCore::doMaxScroll(CacheBuilder::Direction dir) default: LOG_ASSERT(0, "unexpected focus selector"); } - this->scrollBy(dx, dy, true); + WebCore::FrameView* view = m_mainFrame->view(); + this->scrollTo(view->scrollX() + dx, view->scrollY() + dy, true); } -void WebViewCore::setScrollOffset(int moveGeneration, int userScrolled, int dx, int dy) +void WebViewCore::setScrollOffset(int moveGeneration, bool sendScrollEvent, int dx, int dy) { - DBG_NAV_LOGD("{%d,%d} m_scrollOffset=(%d,%d), userScrolled=%d", dx, dy, - m_scrollOffsetX, m_scrollOffsetY, userScrolled); + DBG_NAV_LOGD("{%d,%d} m_scrollOffset=(%d,%d), sendScrollEvent=%d", dx, dy, + m_scrollOffsetX, m_scrollOffsetY, sendScrollEvent); if (m_scrollOffsetX != dx || m_scrollOffsetY != dy) { m_scrollOffsetX = dx; m_scrollOffsetY = dy; @@ -1169,24 +1153,25 @@ void WebViewCore::setScrollOffset(int moveGeneration, int userScrolled, int dx, // testing work correctly. m_mainFrame->view()->platformWidget()->setLocation(m_scrollOffsetX, m_scrollOffsetY); - if (userScrolled) { + if (sendScrollEvent) { m_mainFrame->eventHandler()->sendScrollEvent(); - } - // Update history item to reflect the new scroll position. - // This also helps save the history information when the browser goes to - // background, so scroll position will be restored if browser gets - // killed while in background. - WebCore::HistoryController* history = m_mainFrame->loader()->history(); - // Because the history item saving could be heavy for large sites and - // scrolling can generate lots of small scroll offset, the following code - // reduces the saving frequency. - static const int MIN_SCROLL_DIFF = 32; - if (history->currentItem()) { - WebCore::IntPoint currentPoint = history->currentItem()->scrollPoint(); - if (std::abs(currentPoint.x() - dx) >= MIN_SCROLL_DIFF || - std::abs(currentPoint.y() - dy) >= MIN_SCROLL_DIFF) { - history->saveScrollPositionAndViewStateToItem(history->currentItem()); + // Only update history position if it's user scrolled. + // Update history item to reflect the new scroll position. + // This also helps save the history information when the browser goes to + // background, so scroll position will be restored if browser gets + // killed while in background. + WebCore::HistoryController* history = m_mainFrame->loader()->history(); + // Because the history item saving could be heavy for large sites and + // scrolling can generate lots of small scroll offset, the following code + // reduces the saving frequency. + static const int MIN_SCROLL_DIFF = 32; + if (history->currentItem()) { + WebCore::IntPoint currentPoint = history->currentItem()->scrollPoint(); + if (std::abs(currentPoint.x() - dx) >= MIN_SCROLL_DIFF || + std::abs(currentPoint.y() - dy) >= MIN_SCROLL_DIFF) { + history->saveScrollPositionAndViewStateToItem(history->currentItem()); + } } } @@ -1232,6 +1217,12 @@ void WebViewCore::setSizeScreenWidthAndScale(int width, int height, // Don't reflow if the diff is small. const bool reflow = otw && textWrapWidth && ((float) abs(otw - textWrapWidth) / textWrapWidth) >= 0.01f; + + // When the screen size change, fixed positioned element should be updated. + // This is supposed to be light weighted operation without a full layout. + if (osh != screenHeight || osw != screenWidth) + m_mainFrame->view()->updatePositionedObjects(); + if (ow != width || (!ignoreHeight && oh != height) || reflow) { WebCore::RenderObject *r = m_mainFrame->contentRenderer(); DBG_NAV_LOGD("renderer=%p view=(w=%d,h=%d)", r, @@ -2090,18 +2081,18 @@ String WebViewCore::modifySelection(const int direction, const int axis) if (selection->rangeCount() > 1) selection->removeAllRanges(); switch (axis) { - case AXIS_CHARACTER: - case AXIS_WORD: - case AXIS_SENTENCE: - return modifySelectionTextNavigationAxis(selection, direction, axis); - case AXIS_HEADING: - case AXIS_SIBLING: - case AXIS_PARENT_FIRST_CHILD: - case AXIS_DOCUMENT: - return modifySelectionDomNavigationAxis(selection, direction, axis); - default: - LOGE("Invalid navigation axis: %d", axis); - return String(); + case AXIS_CHARACTER: + case AXIS_WORD: + case AXIS_SENTENCE: + return modifySelectionTextNavigationAxis(selection, direction, axis); + case AXIS_HEADING: + case AXIS_SIBLING: + case AXIS_PARENT_FIRST_CHILD: + case AXIS_DOCUMENT: + return modifySelectionDomNavigationAxis(selection, direction, axis); + default: + LOGE("Invalid navigation axis: %d", axis); + return String(); } } @@ -2129,10 +2120,10 @@ void WebViewCore::scrollNodeIntoView(Frame* frame, Node* node) String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, int direction, int axis) { - // TODO: Add support of IFrames. - HTMLElement* body = m_mainFrame->document()->body(); + Node* body = m_mainFrame->document()->body(); ExceptionCode ec = 0; + String markup; // initialize the selection if necessary if (selection->rangeCount() == 0) { @@ -2157,14 +2148,13 @@ String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, i if (ec) return String(); selection->addRange(rangeRef.get()); - } else if (direction == DIRECTION_FORWARD) { - selection->setPosition(body->firstDescendant(), 0, ec); } else { - selection->setPosition(body->lastDescendant(), 0, ec); + selection->setPosition(body, 0, ec); } if (ec) return String(); } + // collapse the selection if (direction == DIRECTION_FORWARD) selection->collapseToEnd(ec); @@ -2173,126 +2163,52 @@ String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, i if (ec) return String(); - Node* oldAnchorNode = selection->anchorNode(); - if (!oldAnchorNode) - return String(); - // Make sure the anchor node is a text node since we are generating // the markup of the selection which includes the anchor, the focus, // and any crossed nodes. Forcing the condition that the selection // starts and ends on text nodes guarantees symmetric selection markup. + // Also this way the text content, rather its container, is highlighted. Node* anchorNode = selection->anchorNode(); if (anchorNode->isElementNode()) { - int anchorOffset = rangeCompliantChildOffset(anchorNode, - selection->anchorOffset()); - anchorNode = selection->anchorNode()->childNodes()->item(anchorOffset); - Node* nextAnchorNode = traverseVisibleNonEmptyNonWhitespaceTextNode( - anchorNode, body, direction); - if (!nextAnchorNode) + // Collapsed selection while moving forward points to the + // next unvisited node and while moving backward to the + // last visited node. + if (direction == DIRECTION_FORWARD) + advanceAnchorNode(selection, direction, markup, false, ec); + else + advanceAnchorNode(selection, direction, markup, true, ec); + if (ec) return String(); - if (direction == DIRECTION_FORWARD) { - Node* skippedControl = getFirstIntermediaryInputOrButton(anchorNode, - nextAnchorNode); - if (skippedControl) { - IntRect bounds = static_cast<Element*>( - skippedControl)->boundsInWindowSpace(); - selectAt(bounds.center().x(), bounds.center().y()); - selection->setBaseAndExtent(skippedControl, - caretMinOffset(skippedControl), skippedControl, - caretMaxOffset(skippedControl), ec); - if (ec) - return String(); - return formatMarkup(selection).stripWhiteSpace(); - } else { - selection->setPosition(nextAnchorNode, 0, ec); - if (ec) - return String(); - } - } else { - Node* skippedControl = getFirstIntermediaryInputOrButton( - nextAnchorNode, anchorNode); - if (skippedControl) { - IntRect bounds = static_cast<Element*>( - skippedControl)->boundsInWindowSpace(); - selectAt(bounds.center().x(), bounds.center().y()); - selection->setBaseAndExtent(skippedControl, - caretMaxOffset(skippedControl), skippedControl, - caretMinOffset(skippedControl), ec); - if (ec) - return String(); - return formatMarkup(selection).stripWhiteSpace(); - } else { - selection->setPosition(nextAnchorNode, - caretMaxOffset(nextAnchorNode), ec); - if (ec) - return String(); - } - } + if (!markup.isEmpty()) + return markup; } // If the selection is at the end of a non white space text move // it to the next visible text node with non white space content. // This is a workaround for the selection getting stuck. anchorNode = selection->anchorNode(); - if (!anchorNode) - return String(); if (anchorNode->isTextNode()) { if (direction == DIRECTION_FORWARD) { String suffix = anchorNode->textContent().substring( - selection->anchorOffset(), caretMaxOffset(anchorNode)); + selection->anchorOffset(), caretMaxOffset(anchorNode)); + // If at the end of non white space text we advance the + // anchor node to either an input element or non empty text. if (suffix.stripWhiteSpace().isEmpty()) { - Node* nextAnchorNode = - traverseVisibleNonEmptyNonWhitespaceTextNode(anchorNode, - body, direction); - if (!nextAnchorNode) - return String(); - Node* skippedControl = getFirstIntermediaryInputOrButton( - anchorNode, nextAnchorNode); - if (skippedControl) { - IntRect bounds = static_cast<Element*>( - skippedControl)->boundsInWindowSpace(); - selectAt(bounds.center().x(), bounds.center().y()); - selection->setBaseAndExtent(skippedControl, - caretMinOffset(skippedControl), skippedControl, - caretMaxOffset(skippedControl), ec); - if (ec) - return String(); - return formatMarkup(selection).stripWhiteSpace(); - } else { - selection->setPosition(nextAnchorNode, 0, ec); - if (ec) - return String(); - } + advanceAnchorNode(selection, direction, markup, true, ec); } } else { String prefix = anchorNode->textContent().substring(0, - selection->anchorOffset()); + selection->anchorOffset()); + // If at the end of non white space text we advance the + // anchor node to either an input element or non empty text. if (prefix.stripWhiteSpace().isEmpty()) { - Node* nextAnchorNode = - traverseVisibleNonEmptyNonWhitespaceTextNode(anchorNode, - body, direction); - if (!nextAnchorNode) - return String(); - Node* skippedControl = getFirstIntermediaryInputOrButton( - nextAnchorNode, anchorNode); - if (skippedControl) { - IntRect bounds = static_cast<Element*>( - skippedControl)->boundsInWindowSpace(); - selectAt(bounds.center().x(), bounds.center().y()); - selection->setBaseAndExtent(skippedControl, - caretMaxOffset(skippedControl), skippedControl, - caretMinOffset(skippedControl), ec); - if (ec) - return String(); - return formatMarkup(selection).stripWhiteSpace(); - } else { - selection->setPosition(nextAnchorNode, - caretMaxOffset(nextAnchorNode), ec); - if (ec) - return String(); - } + advanceAnchorNode(selection, direction, markup, true, ec); } } + if (ec) + return String(); + if (!markup.isEmpty()) + return markup; } // extend the selection @@ -2314,176 +2230,111 @@ String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, i // Make sure the focus node is a text node in order to have the // selection generate symmetric markup because the latter - // includes all nodes crossed by the selection. + // includes all nodes crossed by the selection. Also this way + // the text content, rather its container, is highlighted. Node* focusNode = selection->focusNode(); if (focusNode->isElementNode()) { - int focusOffset = rangeCompliantChildOffset(focusNode, - selection->focusOffset()); + focusNode = getImplicitBoundaryNode(selection->focusNode(), + selection->focusOffset(), direction); + if (!focusNode) + return String(); if (direction == DIRECTION_FORWARD) { - focusNode = - focusNode->childNodes()->item(focusOffset)->lastDescendant(); - if (!isVisibleNonEmptyNonWhitespaceTextNode(focusNode)) { - focusNode = traverseVisibleNonEmptyNonWhitespaceTextNode( - focusNode, body, DIRECTION_BACKWARD); - if (!focusNode) + focusNode = focusNode->traversePreviousSiblingPostOrder(body); + if (focusNode && !isContentTextNode(focusNode)) { + Node* textNode = traverseNextContentTextNode(focusNode, + anchorNode, DIRECTION_BACKWARD); + if (textNode) + anchorNode = textNode; + } + if (focusNode && isContentTextNode(focusNode)) { + selection->extend(focusNode, caretMaxOffset(focusNode), ec); + if (ec) return String(); } - selection->extend(focusNode, caretMaxOffset(focusNode), ec); - if (ec) - return String(); } else { - focusNode = - focusNode->childNodes()->item(focusOffset)->firstDescendant(); - if (!isVisibleNonEmptyNonWhitespaceTextNode(focusNode)) { - focusNode = traverseVisibleNonEmptyNonWhitespaceTextNode( - focusNode, body, DIRECTION_FORWARD); - if (!focusNode) + focusNode = focusNode->traverseNextSibling(); + if (focusNode && !isContentTextNode(focusNode)) { + Node* textNode = traverseNextContentTextNode(focusNode, + anchorNode, DIRECTION_FORWARD); + if (textNode) + anchorNode = textNode; + } + if (anchorNode && isContentTextNode(anchorNode)) { + selection->extend(focusNode, 0, ec); + if (ec) return String(); } - selection->extend(focusNode, 0, ec); - if (ec) - return String(); } } // Enforce that the selection does not cross anchor boundaries. This is // a workaround for the asymmetric behavior of WebKit while crossing // anchors. - // NOTE: The code is asymmetric since the logic is based off the common - // ancestor in both directions - backward and forward. - // TODO: Factor out common code repeated below. - anchorNode = selection->anchorNode(); - focusNode = selection->focusNode(); - if (anchorNode != focusNode - && anchorNode->isTextNode() - && focusNode->isTextNode()) { - Node* commonAncestor = Range::commonAncestorContainer(anchorNode, - focusNode); - Node* currentNode = 0; - bool selectionAdjusted = false; - if (direction == DIRECTION_FORWARD) { - // catch if the anchor is in a link but the focus is not - if (!commonAncestor->hasTagName(WebCore::HTMLNames::aTag)) { - currentNode = anchorNode; - while (currentNode != commonAncestor) { - if (isVisible(currentNode) && isInputControl(currentNode)) { - focusNode = currentNode->lastDescendant(); - if (!isVisibleNonEmptyNonWhitespaceTextNode(focusNode)) { - focusNode = - traverseVisibleNonEmptyNonWhitespaceTextNode( - focusNode, commonAncestor, - DIRECTION_BACKWARD); - if (!focusNode) - return String(); - } - selection->extend(focusNode, caretMaxOffset(focusNode), - ec); - if (ec) - return String(); - selectionAdjusted = true; - break; - } - currentNode = currentNode->parentNode(); + anchorNode = getImplicitBoundaryNode(selection->anchorNode(), + selection->anchorOffset(), direction); + focusNode = getImplicitBoundaryNode(selection->focusNode(), + selection->focusOffset(), direction); + if (anchorNode && focusNode && anchorNode != focusNode) { + Node* inputControl = getIntermediaryInputElement(anchorNode, focusNode, + direction); + if (inputControl) { + if (direction == DIRECTION_FORWARD) { + if (isDescendantOf(inputControl, anchorNode)) { + focusNode = inputControl; + } else { + focusNode = inputControl->traversePreviousSiblingPostOrder( + body); + if (!focusNode) + focusNode = inputControl; } - // catch if there is a link between the anchor and focus - if (!selectionAdjusted) { - currentNode = anchorNode; - while (currentNode != focusNode) { - if (isVisible(currentNode) - && isInputControl(currentNode)) { - focusNode = currentNode; - if (!isVisibleNonEmptyNonWhitespaceTextNode(focusNode)) { - focusNode = - traverseVisibleNonEmptyNonWhitespaceTextNode( - focusNode, commonAncestor, - DIRECTION_BACKWARD); - if (!focusNode) - return String(); - } - selection->extend(focusNode, - caretMaxOffset(focusNode), ec); - if (ec) - return String(); - break; - } - currentNode = currentNode->traverseNextNode(); - } + // We prefer a text node contained in the input element. + if (!isContentTextNode(focusNode)) { + Node* textNode = traverseNextContentTextNode(focusNode, + anchorNode, DIRECTION_BACKWARD); + if (textNode) + focusNode = textNode; } - } - } else { - // catch if the anchor is in a link but the focus is not - // NOTE: There is not such case in forward direction because - // it is implicitly covered the second case. Also the - // base position used for computing the the common - // ancestor which is asymmteric. - if (!commonAncestor->hasTagName(WebCore::HTMLNames::aTag)) { - currentNode = anchorNode; - while (currentNode != commonAncestor) { - if (isVisible(currentNode) && isInputControl(currentNode)) { - focusNode = currentNode->firstDescendant(); - if (!isVisibleNonEmptyNonWhitespaceTextNode(focusNode)) { - focusNode = - traverseVisibleNonEmptyNonWhitespaceTextNode( - focusNode, commonAncestor, - DIRECTION_FORWARD); - if (!focusNode) - return String(); - } - selection->extend(focusNode, 0, ec); - if (ec) - return String(); - selectionAdjusted = true; - break; - } - currentNode = currentNode->parentNode(); + // If we found text in the input select it. + // Otherwise, select the input element itself. + if (isContentTextNode(focusNode)) { + selection->extend(focusNode, caretMaxOffset(focusNode), ec); + } else if (anchorNode != focusNode) { + // Note that the focusNode always has parent and that + // the offset can be one more that the index of the last + // element - this is how WebKit selects such elements. + selection->extend(focusNode->parentNode(), + focusNode->nodeIndex() + 1, ec); } - // catch if there is a link between the anchor and focus - if (!selectionAdjusted) { - currentNode = anchorNode; - while (currentNode != focusNode) { - if (isVisible(currentNode) - && isInputControl(currentNode)) { - focusNode = currentNode->traverseNextSibling(); - if (!isVisibleNonEmptyNonWhitespaceTextNode(focusNode)) { - focusNode = - traverseVisibleNonEmptyNonWhitespaceTextNode( - focusNode, commonAncestor, - DIRECTION_FORWARD); - if (!focusNode) - return String(); - } - selection->extend(focusNode, 0, ec); - if (ec) - return String(); - selectionAdjusted = true; - break; - } - currentNode = currentNode->traversePreviousNode(); - } + if (ec) + return String(); + } else { + if (isDescendantOf(inputControl, anchorNode)) { + focusNode = inputControl; + } else { + focusNode = inputControl->traverseNextSibling(); + if (!focusNode) + focusNode = inputControl; } - // catch if the focus is in a link but the anchor is not - if (!selectionAdjusted) { - currentNode = focusNode; - while (currentNode != commonAncestor) { - if (isVisible(currentNode) - && isInputControl(currentNode)) { - focusNode = currentNode->traverseNextSibling(); - if (!isVisibleNonEmptyNonWhitespaceTextNode(focusNode)) { - focusNode = - traverseVisibleNonEmptyNonWhitespaceTextNode( - focusNode, commonAncestor, - DIRECTION_FORWARD); - if (!focusNode) - return String(); - } - selection->extend(focusNode, 0, ec); - if (ec) - return String(); - break; - } - currentNode = currentNode->parentNode(); - } + // We prefer a text node contained in the input element. + if (!isContentTextNode(focusNode)) { + Node* textNode = traverseNextContentTextNode(focusNode, + anchorNode, DIRECTION_FORWARD); + if (textNode) + focusNode = textNode; } + // If we found text in the input select it. + // Otherwise, select the input element itself. + if (isContentTextNode(focusNode)) { + selection->extend(focusNode, caretMinOffset(focusNode), ec); + } else if (anchorNode != focusNode) { + // Note that the focusNode always has parent and that + // the offset can be one more that the index of the last + // element - this is how WebKit selects such elements. + selection->extend(focusNode->parentNode(), + focusNode->nodeIndex() + 1, ec); + } + if (ec) + return String(); } } } @@ -2500,30 +2351,136 @@ String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, i return String(); IntRect bounds = range->boundingBox(); selectAt(bounds.center().x(), bounds.center().y()); - String markup = formatMarkup(selection).stripWhiteSpace(); + markup = formatMarkup(selection); LOGV("Selection markup: %s", markup.utf8().data()); return markup; } -bool WebViewCore::isInputControl(Node* node) +Node* WebViewCore::getImplicitBoundaryNode(Node* node, unsigned offset, int direction) { - return (node->hasTagName(WebCore::HTMLNames::aTag) - || node->hasTagName(WebCore::HTMLNames::inputTag) - || node->hasTagName(WebCore::HTMLNames::buttonTag)); + if (node->offsetInCharacters()) + return node; + if (!node->hasChildNodes()) + return node; + if (offset < node->childNodeCount()) + return node->childNode(offset); + else + if (direction == DIRECTION_FORWARD) + return node->traverseNextSibling(); + else + return node->traversePreviousNodePostOrder( + node->document()->body()); } -int WebViewCore::rangeCompliantChildOffset(Node* parent, int offset) +Node* WebViewCore::getNextAnchorNode(Node* anchorNode, bool ignoreFirstNode, int direction) { - if (offset < 0) - return 0; - int lastChildIndex = parent->childNodes()->length() - 1; - if (offset > lastChildIndex) - return lastChildIndex; - return offset; + Node* body = 0; + Node* currentNode = 0; + if (direction == DIRECTION_FORWARD) { + if (ignoreFirstNode) + currentNode = anchorNode->traverseNextNode(body); + else + currentNode = anchorNode; + } else { + body = anchorNode->document()->body(); + if (ignoreFirstNode) + currentNode = anchorNode->traversePreviousSiblingPostOrder(body); + else + currentNode = anchorNode; + } + while (currentNode) { + if (isContentTextNode(currentNode) + || isContentInputElement(currentNode)) + return currentNode; + if (direction == DIRECTION_FORWARD) + currentNode = currentNode->traverseNextNode(); + else + currentNode = currentNode->traversePreviousNodePostOrder(body); + } + return 0; } -bool WebViewCore::isVisibleNonEmptyNonWhitespaceTextNode(Node* node) +void WebViewCore::advanceAnchorNode(DOMSelection* selection, int direction, + String& markup, bool ignoreFirstNode, ExceptionCode& ec) +{ + Node* anchorNode = getImplicitBoundaryNode(selection->anchorNode(), + selection->anchorOffset(), direction); + if (!anchorNode) { + ec = NOT_FOUND_ERR; + return; + } + // If the anchor offset is invalid i.e. the anchor node has no + // child with that index getImplicitAnchorNode returns the next + // logical node in the current direction. In such a case our + // position in the DOM tree was has already been advanced, + // therefore we there is no need to do that again. + if (selection->anchorNode()->isElementNode()) { + unsigned anchorOffset = selection->anchorOffset(); + unsigned childNodeCount = selection->anchorNode()->childNodeCount(); + if (anchorOffset >= childNodeCount) + ignoreFirstNode = false; + } + // Find the next anchor node given our position in the DOM and + // whether we want the current node to be considered as well. + Node* nextAnchorNode = getNextAnchorNode(anchorNode, ignoreFirstNode, + direction); + if (!nextAnchorNode) { + ec = NOT_FOUND_ERR; + return; + } + if (nextAnchorNode->isElementNode()) { + // If this is an input element tell the WebView thread + // to set the cursor to that control. + if (isContentInputElement(nextAnchorNode)) { + IntRect bounds = nextAnchorNode->getRect(); + selectAt(bounds.center().x(), bounds.center().y()); + } + Node* textNode = 0; + // Treat the text content of links as any other text but + // for the rest input elements select the control itself. + if (nextAnchorNode->hasTagName(WebCore::HTMLNames::aTag)) + textNode = traverseNextContentTextNode(nextAnchorNode, + nextAnchorNode, direction); + // We prefer to select the text content of the link if such, + // otherwise just select the element itself. + if (textNode) { + nextAnchorNode = textNode; + } else { + if (direction == DIRECTION_FORWARD) { + selection->setBaseAndExtent(nextAnchorNode, + caretMinOffset(nextAnchorNode), nextAnchorNode, + caretMaxOffset(nextAnchorNode), ec); + } else { + selection->setBaseAndExtent(nextAnchorNode, + caretMaxOffset(nextAnchorNode), nextAnchorNode, + caretMinOffset(nextAnchorNode), ec); + } + if (!ec) + markup = formatMarkup(selection); + // make sure the selection is visible + scrollNodeIntoView(selection->frame(), nextAnchorNode); + return; + } + } + if (direction == DIRECTION_FORWARD) + selection->setPosition(nextAnchorNode, + caretMinOffset(nextAnchorNode), ec); + else + selection->setPosition(nextAnchorNode, + caretMaxOffset(nextAnchorNode), ec); +} + +bool WebViewCore::isContentInputElement(Node* node) +{ + return (isVisible(node) + && (node->hasTagName(WebCore::HTMLNames::selectTag) + || node->hasTagName(WebCore::HTMLNames::aTag) + || node->hasTagName(WebCore::HTMLNames::inputTag) + || node->hasTagName(WebCore::HTMLNames::buttonTag))); +} + +bool WebViewCore::isContentTextNode(Node* node) { if (!node || !node->isTextNode()) return false; @@ -2532,21 +2489,66 @@ bool WebViewCore::isVisibleNonEmptyNonWhitespaceTextNode(Node* node) && !textNode->containsOnlyWhitespace()); } -Text* WebViewCore::traverseVisibleNonEmptyNonWhitespaceTextNode(Node* fromNode, Node* toNode, int direction) +Text* WebViewCore::traverseNextContentTextNode(Node* fromNode, Node* toNode, int direction) { Node* currentNode = fromNode; do { if (direction == DIRECTION_FORWARD) currentNode = currentNode->traverseNextNode(toNode); else - currentNode = currentNode->traversePreviousNode(toNode); - } while (currentNode && !isVisibleNonEmptyNonWhitespaceTextNode(currentNode)); + currentNode = currentNode->traversePreviousNodePostOrder(toNode); + } while (currentNode && !isContentTextNode(currentNode)); return static_cast<Text*>(currentNode); } +Node* WebViewCore::getIntermediaryInputElement(Node* fromNode, Node* toNode, int direction) +{ + if (fromNode == toNode) + return 0; + if (direction == DIRECTION_FORWARD) { + Node* currentNode = fromNode; + while (currentNode && currentNode != toNode) { + if (isContentInputElement(currentNode)) + return currentNode; + currentNode = currentNode->traverseNextNodePostOrder(); + } + currentNode = fromNode; + while (currentNode && currentNode != toNode) { + if (isContentInputElement(currentNode)) + return currentNode; + currentNode = currentNode->traverseNextNode(); + } + } else { + Node* currentNode = fromNode->traversePreviousNode(); + while (currentNode && currentNode != toNode) { + if (isContentInputElement(currentNode)) + return currentNode; + currentNode = currentNode->traversePreviousNode(); + } + currentNode = fromNode->traversePreviousNodePostOrder(); + while (currentNode && currentNode != toNode) { + if (isContentInputElement(currentNode)) + return currentNode; + currentNode = currentNode->traversePreviousNodePostOrder(); + } + } + return 0; +} + +bool WebViewCore::isDescendantOf(Node* parent, Node* node) +{ + Node* currentNode = node; + while (currentNode) { + if (currentNode == parent) { + return true; + } + currentNode = currentNode->parentNode(); + } + return false; +} + String WebViewCore::modifySelectionDomNavigationAxis(DOMSelection* selection, int direction, int axis) { - // TODO: Add support of IFrames. HTMLElement* body = m_mainFrame->document()->body(); if (!m_currentNodeDomNavigationAxis && selection->focusNode()) { m_currentNodeDomNavigationAxis = selection->focusNode(); @@ -2639,12 +2641,27 @@ bool WebViewCore::isHeading(Node* node) bool WebViewCore::isVisible(Node* node) { - // TODO: Use DOMWindow#getComputedStyle instead. + // start off an element + Element* element = 0; + if (node->isElementNode()) + element = static_cast<Element*>(node); + else + element = node->parentElement(); + // check renderer + if (!element->renderer()) { + return false; + } + // check size + if (element->offsetHeight() == 0 || element->offsetWidth() == 0) { + return false; + } + // check style Node* body = m_mainFrame->document()->body(); - Node* currentNode = node; + Node* currentNode = element; while (currentNode && currentNode != body) { RenderStyle* style = currentNode->computedStyle(); - if (style->display() == NONE || style->visibility() == HIDDEN) { + if (style && + (style->display() == NONE || style->visibility() == HIDDEN)) { return false; } currentNode = currentNode->parentNode(); @@ -2656,52 +2673,48 @@ String WebViewCore::formatMarkup(DOMSelection* selection) { ExceptionCode ec = 0; String markup = String(); - PassRefPtr<Range> wholeRange = selection->getRangeAt(0, ec); if (ec) - return markup; - + return String(); if (!wholeRange->startContainer() || !wholeRange->startContainer()) - return markup; - + return String(); // Since formatted markup contains invisible nodes it // is created from the concatenation of the visible fragments. Node* firstNode = wholeRange->firstNode(); Node* pastLastNode = wholeRange->pastLastNode(); Node* currentNode = firstNode; PassRefPtr<Range> currentRange; + while (currentNode != pastLastNode) { Node* nextNode = currentNode->traverseNextNode(); if (!isVisible(currentNode)) { if (currentRange) { - markup = markup + stripAppleSpanFromMarkup( - currentRange->toHTML()).utf8().data(); + markup = markup + currentRange->toHTML().utf8().data(); currentRange = 0; } } else { if (!currentRange) { currentRange = selection->frame()->document()->createRange(); if (ec) - return markup; + break; if (currentNode == firstNode) { currentRange->setStart(wholeRange->startContainer(), wholeRange->startOffset(), ec); if (ec) - return markup; + break; } else { currentRange->setStart(currentNode->parentNode(), currentNode->nodeIndex(), ec); if (ec) - return markup; + break; } } if (nextNode == pastLastNode) { currentRange->setEnd(wholeRange->endContainer(), wholeRange->endOffset(), ec); if (ec) - return markup; - markup = markup + stripAppleSpanFromMarkup( - currentRange->toHTML()).utf8().data(); + break; + markup = markup + currentRange->toHTML().utf8().data(); } else { if (currentNode->offsetInCharacters()) currentRange->setEnd(currentNode, @@ -2710,24 +2723,12 @@ String WebViewCore::formatMarkup(DOMSelection* selection) currentRange->setEnd(currentNode->parentNode(), currentNode->nodeIndex() + 1, ec); if (ec) - return markup; + break; } } currentNode = nextNode; } - return markup; -} - -String WebViewCore::stripAppleSpanFromMarkup(String markup) -{ - int fromIdx = markup.find("<span class=\"Apple-style-span\""); - while (fromIdx > -1) { - int toIdx = markup.find(">"); - markup = markup.replace(fromIdx, toIdx - fromIdx + 1, ""); - markup = markup.replace("</span>", ""); - fromIdx = markup.find("<span class=\"Apple-style-span\""); - } - return markup; + return markup.stripWhiteSpace(); } void WebViewCore::selectAt(int x, int y) @@ -2738,32 +2739,6 @@ void WebViewCore::selectAt(int x, int y) checkException(env); } -Node* WebViewCore::getFirstIntermediaryInputOrButton(Node* fromNode, Node* toNode) -{ - // do bidirectional traversal to catch the case in which - // the toNode is a descendant of a control but the fromNode - // is not and the other way around - Node* currentNode = fromNode->traverseNextNode(); - while (currentNode && currentNode != toNode) { - if (isVisible(currentNode) - && (currentNode->hasTagName(WebCore::HTMLNames::inputTag) - || currentNode->hasTagName(WebCore::HTMLNames::buttonTag))) { - return currentNode; - } - currentNode = currentNode->traverseNextNode(); - } - currentNode = fromNode->traverseNextNodePostOrder(); - while (currentNode && currentNode != toNode) { - if (isVisible(currentNode) - && (currentNode->hasTagName(WebCore::HTMLNames::inputTag) - || currentNode->hasTagName(WebCore::HTMLNames::buttonTag))) { - return currentNode; - } - currentNode = currentNode->traverseNextNodePostOrder(); - } - return 0; -} - void WebViewCore::deleteSelection(int start, int end, int textGeneration) { setSelection(start, end); @@ -2888,94 +2863,6 @@ void WebViewCore::saveDocumentState(WebCore::Frame* frame) } } -// Convert a WTF::String into an array of characters where the first -// character represents the length, for easy conversion to java. -static uint16_t* stringConverter(const WTF::String& text) -{ - size_t length = text.length(); - uint16_t* itemName = new uint16_t[length+1]; - itemName[0] = (uint16_t)length; - uint16_t* firstChar = &(itemName[1]); - memcpy((void*)firstChar, text.characters(), sizeof(UChar)*length); - return itemName; -} - -// Response to dropdown created for a listbox. -class ListBoxReply : public WebCoreReply { -public: - ListBoxReply(WebCore::HTMLSelectElement* select, WebCore::Frame* frame, WebViewCore* view) - : m_select(select) - , m_frame(frame) - , m_viewImpl(view) - {} - - // Response used for a multiple selection listbox if the user did not change - // anything, in which case -2 is used. - // Also used by a listbox which has single selection but a size is set. - virtual void replyInt(int index) - { - if (-2 == index) { - // Special value for cancel. Do nothing. - return; - } - // If the select element no longer exists, due to a page change, etc, - // silently return. - if (!m_select || !CacheBuilder::validNode(m_viewImpl->m_mainFrame, - m_frame, m_select)) - return; - // Use a pointer to HTMLSelectElement's superclass, where - // listToOptionIndex is public - SelectElement* selectElement = m_select; - int optionIndex = selectElement->listToOptionIndex(index); - m_select->setSelectedIndex(optionIndex, true); - m_select->dispatchFormControlChangeEvent(); - m_viewImpl->contentInvalidate(m_select->getRect()); - } - - // Response if the listbox allows multiple selection. array stores the listIndices - // of selected positions. - virtual void replyIntArray(const int* array, int count) - { - // If the select element no longer exists, due to a page change, etc, - // silently return. - if (!m_select || !CacheBuilder::validNode(m_viewImpl->m_mainFrame, - m_frame, m_select)) - return; - - const WTF::Vector<Element*>& items = m_select->listItems(); - int totalItems = static_cast<int>(items.size()); - // Keep track of the position of the value we are comparing against. - int arrayIndex = 0; - // The value we are comparing against. - int selection = array[arrayIndex]; - WebCore::HTMLOptionElement* option; - for (int listIndex = 0; listIndex < totalItems; listIndex++) { - if (items[listIndex]->hasLocalName(WebCore::HTMLNames::optionTag)) { - option = static_cast<WebCore::HTMLOptionElement*>( - items[listIndex]); - if (listIndex == selection) { - option->setSelectedState(true); - arrayIndex++; - if (arrayIndex == count) - selection = -1; - else - selection = array[arrayIndex]; - } else - option->setSelectedState(false); - } - } - m_select->dispatchFormControlChangeEvent(); - m_viewImpl->contentInvalidate(m_select->getRect()); - } -private: - // The select element associated with this listbox. - WebCore::HTMLSelectElement* m_select; - // The frame of this select element, to verify that it is valid. - WebCore::Frame* m_frame; - // For calling invalidate and checking the select element's validity - WebViewCore* m_viewImpl; -}; - // Create an array of java Strings. static jobjectArray makeLabelArray(JNIEnv* env, const uint16_t** labels, size_t count) { @@ -3290,46 +3177,7 @@ bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* node return true; } - WebCore::RenderObject* renderer = nodePtr->renderer(); - if (renderer && renderer->isListBox()) { - WebCore::HTMLSelectElement* select = static_cast<WebCore::HTMLSelectElement*>(nodePtr); - const WTF::Vector<WebCore::Element*>& listItems = select->listItems(); - SkTDArray<const uint16_t*> names; - // Possible values for enabledArray. Keep in Sync with values in - // InvokeListBox.Container in WebView.java - enum OptionStatus { - OPTGROUP = -1, - OPTION_DISABLED = 0, - OPTION_ENABLED = 1, - }; - SkTDArray<int> enabledArray; - SkTDArray<int> selectedArray; - int size = listItems.size(); - bool multiple = select->multiple(); - for (int i = 0; i < size; i++) { - if (listItems[i]->hasTagName(WebCore::HTMLNames::optionTag)) { - WebCore::HTMLOptionElement* option = static_cast<WebCore::HTMLOptionElement*>(listItems[i]); - *names.append() = stringConverter(option->textIndentedToRespectGroupLabel()); - *enabledArray.append() = option->disabled() ? OPTION_DISABLED : OPTION_ENABLED; - if (multiple && option->selected()) - *selectedArray.append() = i; - } else if (listItems[i]->hasTagName(WebCore::HTMLNames::optgroupTag)) { - WebCore::HTMLOptGroupElement* optGroup = static_cast<WebCore::HTMLOptGroupElement*>(listItems[i]); - *names.append() = stringConverter(optGroup->groupLabelText()); - *enabledArray.append() = OPTGROUP; - } - } - WebCoreReply* reply = new ListBoxReply(select, select->document()->frame(), this); - // Use a pointer to HTMLSelectElement's superclass, where - // optionToListIndex is public. - SelectElement* selectElement = select; - listBoxRequest(reply, names.begin(), size, enabledArray.begin(), enabledArray.count(), - multiple, selectedArray.begin(), multiple ? selectedArray.count() : - selectElement->optionToListIndex(select->selectedIndex())); - DBG_NAV_LOG("list box"); - return true; - } - scrollLayer(renderer, &m_mousePos); + scrollLayer(nodePtr->renderer(), &m_mousePos); } if (!valid || !framePtr) framePtr = m_mainFrame; @@ -3795,10 +3643,12 @@ void WebViewCore::notifyWebAppCanBeInstalled() void WebViewCore::setWebTextViewAutoFillable(int queryId, const string16& previewSummary) { +#if ENABLE(WEB_AUTOFILL) JNIEnv* env = JSC::Bindings::getJNIEnv(); jstring preview = env->NewString(previewSummary.data(), previewSummary.length()); env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_setWebTextViewAutoFillable, queryId, preview); env->DeleteLocalRef(preview); +#endif } bool WebViewCore::drawIsPaused() const @@ -3881,7 +3731,7 @@ static void SetSize(JNIEnv *env, jobject obj, jint width, jint height, screenWidth, screenHeight, anchorX, anchorY, ignoreHeight); } -static void SetScrollOffset(JNIEnv *env, jobject obj, jint gen, jint userScrolled, jint x, jint y) +static void SetScrollOffset(JNIEnv *env, jobject obj, jint gen, jboolean sendScrollEvent, jint x, jint y) { #ifdef ANDROID_INSTRUMENT TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); @@ -3889,7 +3739,7 @@ static void SetScrollOffset(JNIEnv *env, jobject obj, jint gen, jint userScrolle WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); LOG_ASSERT(viewImpl, "need viewImpl"); - viewImpl->setScrollOffset(gen, userScrolled, x, y); + viewImpl->setScrollOffset(gen, sendScrollEvent, x, y); } static void SetGlobalBounds(JNIEnv *env, jobject obj, jint x, jint y, jint h, @@ -4541,7 +4391,7 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = { (void*) SendListBoxChoice }, { "nativeSetSize", "(IIIFIIIIZ)V", (void*) SetSize }, - { "nativeSetScrollOffset", "(IIII)V", + { "nativeSetScrollOffset", "(IZII)V", (void*) SetScrollOffset }, { "nativeSetGlobalBounds", "(IIII)V", (void*) SetGlobalBounds }, diff --git a/WebKit/android/jni/WebViewCore.h b/WebKit/android/jni/WebViewCore.h index 5820dc5..411be1c 100644 --- a/WebKit/android/jni/WebViewCore.h +++ b/WebKit/android/jni/WebViewCore.h @@ -149,14 +149,6 @@ namespace android { void scrollTo(int x, int y, bool animate = false); /** - * Scroll to the point x,y relative to the current position. - * @param x The relative x position. - * @param y The relative y position. - * @param animate If it is true, animate to the new scroll position - */ - void scrollBy(int x, int y, bool animate); - - /** * Record the invalid rectangle */ void contentInvalidate(const WebCore::IntRect &rect); @@ -311,7 +303,7 @@ namespace android { WebCore::Frame* frame, int x, int y); // set the scroll amount that webview.java is currently showing - void setScrollOffset(int moveGeneration, int userScrolled, int dx, int dy); + void setScrollOffset(int moveGeneration, bool sendScrollEvent, int dx, int dy); void setGlobalBounds(int x, int y, int h, int v); @@ -579,10 +571,9 @@ namespace android { bool isPaused() const { return m_isPaused; } void setIsPaused(bool isPaused) { m_isPaused = isPaused; } bool drawIsPaused() const; - int visibleScreenWidth() const { return m_visibleScreenWidth; } - int visibleScreenHeight() const { return m_visibleScreenHeight; } - void setVisibleScreenWidth(int w) { m_visibleScreenWidth = w; } - void setVisibleScreenHeight(int h) { m_visibleScreenHeight = h; } + // The actual content (without title bar) size in doc coordinate + int screenWidth() const { return m_screenWidth; } + int screenHeight() const { return m_screenHeight; } #if USE(CHROME_NETWORK_STACK) void setWebRequestContextUserAgent(); void setWebRequestContextCacheMode(int mode); @@ -638,11 +629,6 @@ namespace android { CachedHistory m_history; int m_screenWidth; // width of the visible rect in document coordinates int m_screenHeight;// height of the visible rect in document coordinates - // The m_screenHeight is not equal to the visibleRect from WebView, - // using m_visibleScreenHeight to store that info. - // After we can fix the m_screenHeight in java side, we can merge them. - int m_visibleScreenWidth; - int m_visibleScreenHeight; int m_textWrapWidth; float m_scale; unsigned m_domtree_version; @@ -677,18 +663,20 @@ namespace android { // below are members responsible for accessibility support String modifySelectionTextNavigationAxis(DOMSelection* selection, int direction, int granularity); String modifySelectionDomNavigationAxis(DOMSelection* selection, int direction, int granularity); - Text* traverseVisibleNonEmptyNonWhitespaceTextNode(Node* fromNode, Node* toNode ,int direction); + Text* traverseNextContentTextNode(Node* fromNode, Node* toNode ,int direction); bool isVisible(Node* node); bool isHeading(Node* node); String formatMarkup(DOMSelection* selection); void selectAt(int x, int y); Node* m_currentNodeDomNavigationAxis; void scrollNodeIntoView(Frame* frame, Node* node); - bool isVisibleNonEmptyNonWhitespaceTextNode(Node* node); - String stripAppleSpanFromMarkup(String markup); - int rangeCompliantChildOffset(Node* parent, int offset); - Node* getFirstIntermediaryInputOrButton(Node* fromNode, Node* toNode); - bool isInputControl(Node* node); + bool isContentTextNode(Node* node); + Node* getIntermediaryInputElement(Node* fromNode, Node* toNode, int direction); + bool isContentInputElement(Node* node); + bool isDescendantOf(Node* parent, Node* node); + void advanceAnchorNode(DOMSelection* selection, int direction, String& markup, bool ignoreFirstNode, ExceptionCode& ec); + Node* getNextAnchorNode(Node* anchorNode, bool skipFirstHack, int direction); + Node* getImplicitBoundaryNode(Node* node, unsigned offset, int direction); #if ENABLE(TOUCH_EVENTS) bool m_forwardingTouchEvents; diff --git a/WebKit/android/nav/CacheBuilder.cpp b/WebKit/android/nav/CacheBuilder.cpp index 56bce1e..d2ae0a4 100644 --- a/WebKit/android/nav/CacheBuilder.cpp +++ b/WebKit/android/nav/CacheBuilder.cpp @@ -547,6 +547,7 @@ void CacheBuilder::Debug::groups() { IntRect clipBounds = IntRect(0, 0, INT_MAX, INT_MAX); IntRect focusBounds = IntRect(0, 0, INT_MAX, INT_MAX); IntRect* rectPtr = &focusBounds; + int imageCount = 0; if (node->isTextNode()) { Text* textNode = (Text*) node; if (CacheBuilder::ConstructTextRects(textNode, 0, textNode, @@ -556,7 +557,7 @@ void CacheBuilder::Debug::groups() { } else { IntRect nodeBounds = node->getRect(); if (CacheBuilder::ConstructPartRects(node, nodeBounds, rectPtr, - globalOffsetX, globalOffsetY, &rects) == false) + globalOffsetX, globalOffsetY, &rects, &imageCount) == false) continue; } unsigned arraySize = rects.size(); @@ -592,8 +593,8 @@ void CacheBuilder::Debug::groups() { mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, ", %d, %d, %d, %d", textBox->x(), textBox->y(), textBox->logicalWidth(), textBox->logicalHeight()); int baseline = textBox->renderer()->style(textBox->isFirstLineStyle())->font().ascent(); - mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, ", %d }, // %d ", - baseline, ++rectIndex); + mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, ", %d, %d }, // %d ", + baseline, imageCount, ++rectIndex); wideString(node->textContent().characters() + textBox->start(), textBox->len(), true); DUMP_NAV_LOGD("%.*s\n", mIndex, mBuffer); textBox = textBox->nextTextBox(); @@ -1129,6 +1130,7 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, bool isFocus = node == focused; bool takesFocus = false; int columnGap = 0; + int imageCount = 0; TextDirection direction = LTR; String exported; CachedNodeType type = NORMAL_CACHEDNODETYPE; @@ -1328,7 +1330,8 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, cachedNode.setBounds(bounds); cachedNode.mCursorRing.append(bounds); } else if (ConstructPartRects(node, bounds, &cachedNode.mBounds, - globalOffsetX, globalOffsetY, &cachedNode.mCursorRing) == false) + globalOffsetX, globalOffsetY, &cachedNode.mCursorRing, + &imageCount) == false) continue; keepTextNode: if (nodeRenderer) { // area tags' node->renderer() == 0 @@ -1412,6 +1415,7 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, cachedNode.setOriginalAbsoluteBounds(originalAbsBounds); cachedNode.setParentIndex(last->mCachedNodeIndex); cachedNode.setParentGroup(ParentWithChildren(node)); + cachedNode.setSingleImage(imageCount == 1); cachedNode.setTabIndex(tabIndex); cachedNode.setType(type); if (type == TEXT_INPUT_CACHEDNODETYPE) { @@ -3024,7 +3028,8 @@ bool CacheBuilder::AddPartRect(IntRect& bounds, int x, int y, } bool CacheBuilder::ConstructPartRects(Node* node, const IntRect& bounds, - IntRect* focusBounds, int x, int y, WTF::Vector<IntRect>* result) + IntRect* focusBounds, int x, int y, WTF::Vector<IntRect>* result, + int* imageCountPtr) { WTF::Vector<ClipColumnTracker> clipTracker(1); ClipColumnTracker* baseTracker = clipTracker.data(); // sentinel @@ -3075,6 +3080,7 @@ bool CacheBuilder::ConstructPartRects(Node* node, const IntRect& bounds, bounds.intersect(clipBounds); if (AddPartRect(bounds, x, y, result, focusBounds) == false) return false; + *imageCountPtr += 1; continue; } if (hasClip == false) { diff --git a/WebKit/android/nav/CacheBuilder.h b/WebKit/android/nav/CacheBuilder.h index d229df0..d48a045 100644 --- a/WebKit/android/nav/CacheBuilder.h +++ b/WebKit/android/nav/CacheBuilder.h @@ -83,7 +83,8 @@ public: void allowAllTextDetection() { mAllowableTypes = ALL_CACHEDNODE_BITS; } void buildCache(CachedRoot* root); static bool ConstructPartRects(Node* node, const IntRect& bounds, - IntRect* focusBounds, int x, int y, WTF::Vector<IntRect>* result); + IntRect* focusBounds, int x, int y, WTF::Vector<IntRect>* result, + int* imageCountPtr); Node* currentFocus() const; void disallowAddressDetection() { mAllowableTypes = (CachedNodeBits) ( mAllowableTypes & ~ADDRESS_CACHEDNODE_BIT); } diff --git a/WebKit/android/nav/CachedFrame.cpp b/WebKit/android/nav/CachedFrame.cpp index b25ad7d..419be14 100644 --- a/WebKit/android/nav/CachedFrame.cpp +++ b/WebKit/android/nav/CachedFrame.cpp @@ -153,11 +153,9 @@ bool CachedFrame::checkBetween(BestData* best, Direction direction) } bool CachedFrame::checkRings(const CachedNode* node, - const WTF::Vector<WebCore::IntRect>& rings, - const WebCore::IntRect& nodeBounds, const WebCore::IntRect& testBounds) const { - return mRoot->checkRings(picture(node), rings, nodeBounds, testBounds); + return mRoot->checkRings(picture(node), node, testBounds); } bool CachedFrame::checkVisited(const CachedNode* node, Direction direction) const diff --git a/WebKit/android/nav/CachedFrame.h b/WebKit/android/nav/CachedFrame.h index 8ca73cf..470f522 100644 --- a/WebKit/android/nav/CachedFrame.h +++ b/WebKit/android/nav/CachedFrame.h @@ -83,8 +83,6 @@ public: WebCore::IntRect unadjustBounds(const CachedNode*, const WebCore::IntRect& ) const; bool checkRings(const CachedNode* node, - const WTF::Vector<WebCore::IntRect>& rings, - const WebCore::IntRect& nodeBounds, const WebCore::IntRect& testBounds) const; bool checkVisited(const CachedNode* , CachedFrame::Direction ) const; size_t childCount() { return mCachedFrames.size(); } diff --git a/WebKit/android/nav/CachedLayer.cpp b/WebKit/android/nav/CachedLayer.cpp index c8220b3..3321797 100644 --- a/WebKit/android/nav/CachedLayer.cpp +++ b/WebKit/android/nav/CachedLayer.cpp @@ -55,9 +55,36 @@ IntRect CachedLayer::adjustBounds(const LayerAndroid* root, temp.move(position.x(), position.y()); // Add in any layer translation. + // FIXME: Should use bounds() and apply the entire transformation matrix. const FloatPoint& translation = aLayer->translation(); temp.move(translation.x(), translation.y()); + SkRect clip; + aLayer->bounds(&clip); + + // Do not try to traverse the parent chain if this is the root as the parent + // will not be a LayerAndroid. + if (aLayer != root) { + LayerAndroid* parent = static_cast<LayerAndroid*>(aLayer->getParent()); + while (parent) { + SkRect pClip; + parent->bounds(&pClip); + + // Move our position into our parent's coordinate space. + clip.offset(pClip.fLeft, pClip.fTop); + // Clip our visible rectangle to the parent. + clip.intersect(pClip); + + // Stop at the root. + if (parent == root) + break; + parent = static_cast<LayerAndroid*>(parent->getParent()); + } + } + + // Intersect the result with the visible clip. + temp.intersect(clip); + IntRect result = enclosingIntRect(temp); DBG_NAV_LOGV("root=%p aLayer=%p [%d]" @@ -177,7 +204,6 @@ void CachedLayer::Debug::print() const { CachedLayer* b = base(); DUMP_NAV_LOGD(" // int mCachedNodeIndex=%d;\n", b->mCachedNodeIndex); - DUMP_NAV_LOGD(" // LayerAndroid* mLayer=%p;\n", b->mLayer); DUMP_NAV_LOGD(" // int mOffset=(%d, %d);\n", b->mOffset.x(), b->mOffset.y()); DUMP_NAV_LOGD(" // int mUniqueId=%p;\n", b->mUniqueId); diff --git a/WebKit/android/nav/CachedNode.cpp b/WebKit/android/nav/CachedNode.cpp index 4ba7b48..e3ba34d 100644 --- a/WebKit/android/nav/CachedNode.cpp +++ b/WebKit/android/nav/CachedNode.cpp @@ -110,7 +110,7 @@ void CachedNode::fixUpCursorRects(const CachedFrame* frame) mFixedUpCursorRects = true; // if the hit-test rect doesn't intersect any other rect, use it if (mHitBounds != mBounds && mHitBounds.contains(mBounds) && - frame->checkRings(this, mCursorRing, mBounds, mHitBounds)) { + frame->checkRings(this, mHitBounds)) { DBG_NAV_LOGD("use mHitBounds (%d,%d,%d,%d)", mHitBounds.x(), mHitBounds.y(), mHitBounds.width(), mHitBounds.height()); mUseHitBounds = true; @@ -122,7 +122,7 @@ void CachedNode::fixUpCursorRects(const CachedFrame* frame) // any other cursor ring bounds, use it IntRect sloppyBounds = mBounds; sloppyBounds.inflate(2); // give it a couple of extra pixels - if (frame->checkRings(this, mCursorRing, mBounds, sloppyBounds)) { + if (frame->checkRings(this, sloppyBounds)) { DBG_NAV_LOGD("use mBounds (%d,%d,%d,%d)", mBounds.x(), mBounds.y(), mBounds.width(), mBounds.height()); mUseBounds = true; @@ -424,6 +424,7 @@ void CachedNode::Debug::print() const DEBUG_PRINT_BOOL(mLast); DEBUG_PRINT_BOOL(mUseBounds); DEBUG_PRINT_BOOL(mUseHitBounds); + DEBUG_PRINT_BOOL(mSingleImage); } #endif diff --git a/WebKit/android/nav/CachedNode.h b/WebKit/android/nav/CachedNode.h index 961018b..f9bcbed 100644 --- a/WebKit/android/nav/CachedNode.h +++ b/WebKit/android/nav/CachedNode.h @@ -145,8 +145,10 @@ public: void* parentGroup() const { return mParentGroup; } int parentIndex() const { return mParentIndex; } bool partRectsContains(const CachedNode* other) const; + const WebCore::IntRect& rawBounds() const { return mBounds; } void reset(); WebCore::IntRect ring(const CachedFrame* , size_t part) const; + const WTF::Vector<WebCore::IntRect>& rings() const { return mCursorRing; } void setBounds(const WebCore::IntRect& bounds) { mBounds = bounds; } void setClippedOut(bool clipped) { mClippedOut = clipped; } void setColorIndex(int index) { mColorIndex = index; } @@ -170,9 +172,11 @@ public: void setNavableRects() { mNavableRects = mCursorRing.size(); } void setParentGroup(void* group) { mParentGroup = group; } void setParentIndex(int parent) { mParentIndex = parent; } + void setSingleImage(bool single) { mSingleImage = single; } void setTabIndex(int index) { mTabIndex = index; } void setType(CachedNodeType type) { mType = type; } void show() { mIsHidden = false; } + bool singleImage() const { return mSingleImage; } int tabIndex() const { return mTabIndex; } int textInputIndex() const { return isTextInput() ? mDataIndex : -1; } const CachedNode* traverseNextNode() const { return mLast ? NULL : &this[1]; } @@ -210,6 +214,7 @@ private: bool mIsTransparent : 1; bool mIsUnclipped : 1; bool mLast : 1; // true if this is the last node in a group + bool mSingleImage : 1; bool mUseBounds : 1; bool mUseHitBounds : 1; #ifdef BROWSER_DEBUG diff --git a/WebKit/android/nav/CachedRoot.cpp b/WebKit/android/nav/CachedRoot.cpp index 2f0e74d..2662071 100644 --- a/WebKit/android/nav/CachedRoot.cpp +++ b/WebKit/android/nav/CachedRoot.cpp @@ -131,104 +131,6 @@ public: #define kMargin 16 #define kSlop 2 -class BoundsCheck : public CommonCheck { -public: - BoundsCheck() { - mAllDrawnIn.setEmpty(); - mLastAll.setEmpty(); - mLastOver.setEmpty(); - } - - static int Area(SkIRect test) { - return test.width() * test.height(); - } - - void checkLast() { - if (mAllDrawnIn.isEmpty()) - return; - if (mLastAll.isEmpty() || Area(mLastAll) < Area(mAllDrawnIn)) { - mLastAll = mAllDrawnIn; - mDrawnOver.setEmpty(); - } - mAllDrawnIn.setEmpty(); - } - - bool hidden() { - return (mLastAll.isEmpty() && mLastOver.isEmpty()) || - mDrawnOver.contains(mBounds); - } - - virtual bool onIRect(const SkIRect& rect) { - if (joinGlyphs(rect)) - return false; - bool interestingType = mType == kDrawBitmap_Type - || mType == kDrawSprite_Type - || mType == kDrawRect_Type || isTextType(mType); - if (SkIRect::Intersects(mBounds, rect) == false) { - DBG_NAV_LOGD("BoundsCheck (no intersect) rect={%d,%d,%d,%d}" - " mType=%s", rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, - TypeNames[mType]); - if (interestingType) - checkLast(); - return false; - } - if (interestingType == false) - return false; - if (!mDrawnOver.contains(rect) && (mBoundsSlop.contains(rect) || - (mBounds.fLeft == rect.fLeft && mBounds.fRight == rect.fRight && - mBounds.fTop >= rect.fTop && mBounds.fBottom <= rect.fBottom) || - (mBounds.fTop == rect.fTop && mBounds.fBottom == rect.fBottom && - mBounds.fLeft >= rect.fLeft && mBounds.fRight <= rect.fRight))) { - mDrawnOver.setEmpty(); - mAllDrawnIn.join(rect); - DBG_NAV_LOGD("BoundsCheck (contains) rect={%d,%d,%d,%d}" - " mAllDrawnIn={%d,%d,%d,%d} mType=%s", - rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, - mAllDrawnIn.fLeft, mAllDrawnIn.fTop, mAllDrawnIn.fRight, - mAllDrawnIn.fBottom, TypeNames[mType]); - } else { - checkLast(); - if (!isTextType(mType)) { - if ( -#if 0 -// should the opaqueness of the bitmap disallow its ability to draw over? -// not sure that this test is needed - (mType != kDrawBitmap_Type || - (mIsOpaque && mAllOpaque)) && -#endif - mLastAll.isEmpty() == false) - mDrawnOver.op(rect, SkRegion::kUnion_Op); - } else { -// FIXME -// sometimes the text is not drawn entirely inside the cursor area, even though -// it is the correct text. Until I figure out why, I allow text drawn at the -// end that is not covered up by something else to represent the link -// example that triggers this that should be figured out: -// http://cdn.labpixies.com/campaigns/blackjack/blackjack.html?lang=en&country=US&libs=assets/feature/core -// ( http://tinyurl.com/ywsyzb ) - mLastOver = rect; - } -#if DEBUG_NAV_UI - const SkIRect& drawnOver = mDrawnOver.getBounds(); - DBG_NAV_LOGD("(overlaps) rect={%d,%d,%d,%d}" - " mDrawnOver={%d,%d,%d,%d} mType=%s mIsOpaque=%s mAllOpaque=%s", - rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, - drawnOver.fLeft, drawnOver.fTop, drawnOver.fRight, drawnOver.fBottom, - TypeNames[mType], mIsOpaque ? "true" : "false", - mAllOpaque ? "true" : "false"); -#endif - } - return false; - } - - SkIRect mBounds; - SkIRect mBoundsSlop; - SkRegion mDrawnOver; - SkIRect mLastOver; - SkIRect mAllDrawnIn; - SkIRect mLastAll; -}; - class BoundsCanvas : public ParseCanvas { public: @@ -675,10 +577,12 @@ public: class RingCheck : public CommonCheck { public: RingCheck(const WTF::Vector<WebCore::IntRect>& rings, - const WebCore::IntRect& bitBounds, const WebCore::IntRect& testBounds) + const WebCore::IntRect& bitBounds, const WebCore::IntRect& testBounds, + bool singleImage) : mTestBounds(testBounds) , mBitBounds(bitBounds) , mPushPop(false) + , mSingleImage(singleImage) { const WebCore::IntRect* r; for (r = rings.begin(); r != rings.end(); r++) { @@ -910,7 +814,7 @@ protected: && mType != kDrawSprite_Type && mType != kDrawBitmap_Type) return false; if (mLayerTypes.isEmpty() || mLayerTypes.last() != mType - || !mAppendLikeTypes || mPushPop + || !mAppendLikeTypes || mPushPop || mSingleImage // if the last and current were not glyphs, // and the two bounds have a gap between, don't join them -- push // an empty between them @@ -1054,6 +958,7 @@ private: char mCh; bool mAppendLikeTypes; bool mPushPop; + bool mSingleImage; }; class RingCanvas : public BoundsCanvas { @@ -1205,16 +1110,16 @@ void CachedRoot::checkForJiggle(int* xDeltaPtr) const *xDeltaPtr = jiggleCheck.jiggle(); } -bool CachedRoot::checkRings(SkPicture* picture, - const WTF::Vector<WebCore::IntRect>& rings, - const WebCore::IntRect& nodeBounds, +bool CachedRoot::checkRings(SkPicture* picture, const CachedNode* node, const WebCore::IntRect& testBounds) const { if (!picture) return false; + const WTF::Vector<WebCore::IntRect>& rings = node->rings(); + const WebCore::IntRect& nodeBounds = node->rawBounds(); IntRect bitBounds; calcBitBounds(nodeBounds, &bitBounds); - RingCheck ringCheck(rings, bitBounds, testBounds); + RingCheck ringCheck(rings, bitBounds, testBounds, node->singleImage()); RingCanvas checker(&ringCheck); SkBitmap bitmap; bitmap.setConfig(SkBitmap::kARGB_8888_Config, bitBounds.width(), @@ -1576,7 +1481,7 @@ bool CachedRoot::maskIfHidden(BestData* best) const const WebCore::IntRect& bounds = bestNode->bounds(frame); IntRect bitBounds; calcBitBounds(bounds, &bitBounds); - RingCheck ringCheck(rings, bitBounds, bounds); + RingCheck ringCheck(rings, bitBounds, bounds, bestNode->singleImage()); RingCanvas checker(&ringCheck); SkBitmap bitmap; bitmap.setConfig(SkBitmap::kARGB_8888_Config, bitBounds.width(), diff --git a/WebKit/android/nav/CachedRoot.h b/WebKit/android/nav/CachedRoot.h index a09e4fb..1f8b851 100644 --- a/WebKit/android/nav/CachedRoot.h +++ b/WebKit/android/nav/CachedRoot.h @@ -52,8 +52,7 @@ public: void calcBitBounds(const IntRect& , IntRect* ) const; int checkForCenter(int x, int y) const; void checkForJiggle(int* ) const; - bool checkRings(SkPicture* , const WTF::Vector<WebCore::IntRect>& rings, - const WebCore::IntRect& nodeBounds, + bool checkRings(SkPicture* , const CachedNode* , const WebCore::IntRect& testBounds) const; WebCore::IntPoint cursorLocation() const; int documentHeight() { return mContents.height(); } diff --git a/WebKit/android/nav/SelectText.cpp b/WebKit/android/nav/SelectText.cpp index a07fa8c..87d1791 100644 --- a/WebKit/android/nav/SelectText.cpp +++ b/WebKit/android/nav/SelectText.cpp @@ -141,40 +141,6 @@ void ReverseBidi(UChar* chars, int len) { namespace android { -/* SpaceBounds and SpaceCanvas are used to measure the left and right side - * bearings of two consecutive glyphs to help determine if the glyphs were - * originally laid out with a space character between the glyphs. - */ -class SpaceBounds : public SkBounder { -public: - virtual bool onIRectGlyph(const SkIRect& , const SkBounder::GlyphRec& rec) - { - mFirstGlyph = mLastGlyph; - mLastGlyph = rec; - return false; - } - - SkBounder::GlyphRec mFirstGlyph; - SkBounder::GlyphRec mLastGlyph; -}; - -class SpaceCanvas : public ParseCanvas { -public: - SpaceCanvas() - { - setBounder(&mBounder); - SkBitmap bitmap; - // Configure a very large bitmap so the pair of glyphs can be anywhere - // on the page. Skia constrains the bitmap to be 2^31-1 bytes. The - // bitmap is never allocated, but this constraint avoids triggering - // a failure when the configuration is checked. - bitmap.setConfig(SkBitmap::kA1_Config, 16383, 1048576); - setBitmapDevice(bitmap); - } - - SpaceBounds mBounder; -}; - #define HYPHEN_MINUS 0x2D // ASCII hyphen #define SOLIDUS 0x2F // ASCII slash #define REVERSE_SOLIDUS 0x5C // ASCII backslash @@ -266,8 +232,7 @@ public: if (mLastGlyph.fGlyphID == static_cast<uint16_t>(-1)) return true; DBG_NAV_LOGD("mLastGlyph=((%g, %g),(%g, %g), %d)" - " rec=((%g, %g),(%g, %g), %d)" - " mMinSpaceWidth=%g mLastUni=0x%04x '%c'", + " rec=((%g, %g),(%g, %g), %d) mLastUni=0x%04x '%c'", SkFixedToScalar(mLastGlyph.fLSB.fX), SkFixedToScalar(mLastGlyph.fLSB.fY), SkFixedToScalar(mLastGlyph.fRSB.fX), @@ -275,7 +240,6 @@ public: SkFixedToScalar(rec.fLSB.fX), SkFixedToScalar(rec.fLSB.fY), SkFixedToScalar(rec.fRSB.fX), SkFixedToScalar(rec.fRSB.fY), rec.fGlyphID, - SkFixedToScalar(mMinSpaceWidth), mLastUni, mLastUni && mLastUni < 0x7f ? mLastUni : '?'); bool newBaseLine = mLastGlyph.fLSB.fY != rec.fLSB.fY; if (newBaseLine) @@ -284,35 +248,24 @@ public: SkFixed gapTwo = rec.fLSB.fX - mLastGlyph.fRSB.fX; if (gapOne < 0 && gapTwo < 0) return false; // overlaps - uint16_t test[2]; - test[0] = mLastGlyph.fGlyphID; - test[1] = rec.fGlyphID; - SpaceCanvas spaceChecker; - spaceChecker.drawText(test, sizeof(test), - SkFixedToScalar(mLastGlyph.fLSB.fX), - SkFixedToScalar(mLastGlyph.fLSB.fY), mPaint); - const SkBounder::GlyphRec& g1 = spaceChecker.mBounder.mFirstGlyph; - const SkBounder::GlyphRec& g2 = spaceChecker.mBounder.mLastGlyph; - DBG_NAV_LOGD("g1=(%g, %g, %g, %g) g2=(%g, %g, %g, %g)", - SkFixedToScalar(g1.fLSB.fX), SkFixedToScalar(g1.fLSB.fY), - SkFixedToScalar(g1.fRSB.fX), SkFixedToScalar(g1.fRSB.fY), - SkFixedToScalar(g2.fLSB.fX), SkFixedToScalar(g2.fLSB.fY), - SkFixedToScalar(g2.fRSB.fX), SkFixedToScalar(g2.fRSB.fY)); - gapOne = SkFixedAbs(gapOne); - gapTwo = SkFixedAbs(gapTwo); - SkFixed gap = gapOne < gapTwo ? gapOne : gapTwo; - SkFixed overlap = g2.fLSB.fX - g1.fRSB.fX; - if (overlap < 0) - gap -= overlap; - DBG_NAV_LOGD("gap=%g overlap=%g gapOne=%g gapTwo=%g minSpaceWidth()=%g", - SkFixedToScalar(gap), SkFixedToScalar(overlap), - SkFixedToScalar(gapOne), SkFixedToScalar(gapTwo), - SkFixedToScalar(minSpaceWidth())); - // FIXME: the -1/8 below takes care of slop beween the computed gap - // and the actual space width -- it's a rounding error from - // moving from fixed to float and back and could be much smaller. - spaceChecker.setBounder(0); - return gap >= minSpaceWidth() - SK_Fixed1 / 8; + const SkBounder::GlyphRec& first = mLastGlyph.fLSB.fX < rec.fLSB.fX + ? mLastGlyph : rec; + const SkBounder::GlyphRec& second = mLastGlyph.fLSB.fX < rec.fLSB.fX + ? rec : mLastGlyph; + uint16_t firstGlyph = first.fGlyphID; + SkScalar firstWidth = mPaint.measureText(&firstGlyph, sizeof(firstGlyph)); + SkFixed ceilWidth = SkIntToFixed(SkScalarCeil(firstWidth)); + SkFixed posNoSpace = first.fLSB.fX + ceilWidth; + SkFixed ceilSpace = SkIntToFixed(SkFixedCeil(minSpaceWidth())); + SkFixed posWithSpace = posNoSpace + ceilSpace; + SkFixed diffNoSpace = SkFixedAbs(second.fLSB.fX - posNoSpace); + SkFixed diffWithSpace = SkFixedAbs(second.fLSB.fX - posWithSpace); + DBG_NAV_LOGD("second=%g width=%g (%g) noSpace=%g (%g) withSpace=%g (%g)", + SkFixedToScalar(second.fLSB.fX), + firstWidth, SkFixedToScalar(ceilWidth), + SkFixedToScalar(posNoSpace), SkFixedToScalar(diffNoSpace), + SkFixedToScalar(posWithSpace), SkFixedToScalar(diffWithSpace)); + return diffWithSpace < diffNoSpace; } SkFixed minSpaceWidth() diff --git a/WebKit/android/nav/WebView.cpp b/WebKit/android/nav/WebView.cpp index 38d0ccb..edd362c 100644 --- a/WebKit/android/nav/WebView.cpp +++ b/WebKit/android/nav/WebView.cpp @@ -303,10 +303,8 @@ void nativeRecordButtons(bool hasFocus, bool pressed, bool invalidate) if (hasFocus) { if (pressed || m_ring.m_isPressed) state = RenderSkinAndroid::kPressed; - else if (SkTime::GetMSecs() < m_ringAnimationEnd - && m_ringAnimationEnd != UINT_MAX) { + else if (SkTime::GetMSecs() < m_ringAnimationEnd) state = RenderSkinAndroid::kFocused; - } } } ptr->updateFocusState(state); @@ -390,6 +388,7 @@ bool drawCursorPreamble(CachedRoot* root) resetCursorRing(); return false; } + m_ring.setIsButton(node); if (node->isHidden()) { DBG_NAV_LOG("node->isHidden()"); m_viewImpl->m_hasCursorBounds = false; @@ -439,7 +438,7 @@ bool drawGL(WebCore::IntRect& viewRect, float scale, int extras) m_glWebViewState = new GLWebViewState(&m_viewImpl->gButtonMutex); if (m_baseLayer->content()) { IntRect rect(0, 0, m_baseLayer->content()->width(), m_baseLayer->content()->height()); - m_glWebViewState->setBaseLayer(m_baseLayer, rect); + m_glWebViewState->setBaseLayer(m_baseLayer, rect, false); } } @@ -473,6 +472,7 @@ bool drawGL(WebCore::IntRect& viewRect, float scale, int extras) SkPicture picture; IntRect rect(0, 0, 0, 0); + bool allowSame = false; if (extra) { LayerAndroid mainPicture(m_navPictureUI); PictureSet* content = m_baseLayer->content(); @@ -480,8 +480,15 @@ bool drawGL(WebCore::IntRect& viewRect, float scale, int extras) content->height()); extra->draw(canvas, &mainPicture, &rect); picture.endRecording(); + } else if (extras == DrawExtrasCursorRing && m_ring.m_isButton) { + const CachedFrame* cachedFrame; + const CachedNode* cachedCursor = root->currentCursor(&cachedFrame); + if (cachedCursor) { + rect = cachedCursor->bounds(cachedFrame); + allowSame = true; + } } - m_glWebViewState->setExtra(m_baseLayer, picture, rect); + m_glWebViewState->setExtra(m_baseLayer, picture, rect, allowSame); LayerAndroid* compositeLayer = compositeRoot(); if (compositeLayer) @@ -489,12 +496,7 @@ bool drawGL(WebCore::IntRect& viewRect, float scale, int extras) SkRect visibleRect; calcOurContentVisibleRect(&visibleRect); - - m_viewImpl->setVisibleScreenWidth(visibleRect.width()); - m_viewImpl->setVisibleScreenHeight(visibleRect.height()); - bool ret = m_glWebViewState->drawGL(viewRect, visibleRect, scale); - if (ret || m_glWebViewState->currentPictureCounter() != pic) return true; #endif @@ -556,8 +558,6 @@ PictureSet* draw(SkCanvas* canvas, SkColor bgColor, int extras, bool split) compositeLayer->setExtra(extra); SkRect visible; calcOurContentVisibleRect(&visible); - m_viewImpl->setVisibleScreenWidth(visible.width()); - m_viewImpl->setVisibleScreenHeight(visible.height()); // call this to be sure we've adjusted for any scrolling or animations // before we actually draw compositeLayer->updateFixedLayersPositions(visible); @@ -1383,11 +1383,11 @@ static void copyScrollPositionRecursive(const LayerAndroid* from, } #endif -void setBaseLayer(BaseLayerAndroid* layer, WebCore::IntRect& rect) +void setBaseLayer(BaseLayerAndroid* layer, WebCore::IntRect& rect, bool showVisualIndicator) { #if USE(ACCELERATED_COMPOSITING) if (m_glWebViewState) - m_glWebViewState->setBaseLayer(layer, rect); + m_glWebViewState->setBaseLayer(layer, rect, showVisualIndicator); #endif #if ENABLE(ANDROID_OVERFLOW_SCROLL) @@ -1770,11 +1770,12 @@ static bool nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj) return false; } -static void nativeSetBaseLayer(JNIEnv *env, jobject obj, jint layer, jobject jrect) +static void nativeSetBaseLayer(JNIEnv *env, jobject obj, jint layer, jobject jrect, + jboolean showVisualIndicator) { BaseLayerAndroid* layerImpl = reinterpret_cast<BaseLayerAndroid*>(layer); WebCore::IntRect rect = jrect_to_webrect(env, jrect); - GET_NATIVE_VIEW(env, obj)->setBaseLayer(layerImpl, rect); + GET_NATIVE_VIEW(env, obj)->setBaseLayer(layerImpl, rect, showVisualIndicator); } static void nativeReplaceBaseContent(JNIEnv *env, jobject obj, jint content) @@ -2566,7 +2567,7 @@ static JNINativeMethod gJavaWebViewMethods[] = { (void*) nativeSetFindIsUp }, { "nativeSetHeightCanMeasure", "(Z)V", (void*) nativeSetHeightCanMeasure }, - { "nativeSetBaseLayer", "(ILandroid/graphics/Rect;)V", + { "nativeSetBaseLayer", "(ILandroid/graphics/Rect;Z)V", (void*) nativeSetBaseLayer }, { "nativeReplaceBaseContent", "(I)V", (void*) nativeReplaceBaseContent }, diff --git a/WebKit/android/plugins/PluginWidgetAndroid.cpp b/WebKit/android/plugins/PluginWidgetAndroid.cpp index 7f6948c..be89a68 100644 --- a/WebKit/android/plugins/PluginWidgetAndroid.cpp +++ b/WebKit/android/plugins/PluginWidgetAndroid.cpp @@ -589,7 +589,7 @@ void PluginWidgetAndroid::scrollToVisiblePluginRect() { #if DEBUG_VISIBLE_RECTS PLUGIN_LOG("%s call scrollBy (%d,%d)", __FUNCTION__, deltaX, deltaY); #endif - core->scrollBy(deltaX, deltaY, true); + core->scrollTo(rectCenterX, rectCenterY, true); } void PluginWidgetAndroid::requestFullScreen() { |