diff options
143 files changed, 2283 insertions, 1830 deletions
diff --git a/ThirdPartyProject.prop b/ThirdPartyProject.prop index 4efb8e4..3637d75 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.107/DEPS diff --git a/WebCore/Android.mk b/WebCore/Android.mk index 749c9ba..27baa6d 100644 --- a/WebCore/Android.mk +++ b/WebCore/Android.mk @@ -626,7 +626,6 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ platform/graphics/android/SharedBufferStream.cpp \ platform/graphics/android/ShaderProgram.cpp \ platform/graphics/android/SharedTexture.cpp \ - platform/graphics/android/TextureOwner.cpp \ platform/graphics/android/TexturesGenerator.cpp \ platform/graphics/android/TilesManager.cpp \ platform/graphics/android/TiledPage.cpp \ diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog index ae5f73f..6ad75bd 100644 --- a/WebCore/ChangeLog +++ b/WebCore/ChangeLog @@ -1,3 +1,275 @@ +2011-02-16 Abhishek Arya <inferno@chromium.org> + + Reviewed by James Robinson. + + Remove the early bail added in r75823 since we can run into anonymous + blocks when traversing the parents chain for clearing floats. + https://bugs.webkit.org/show_bug.cgi?id=54601 + + removeFloatingOrPositionedChildFromBlockLists tries to find the topmost + parent containing "this" block and then tries to remove it from its floats + list and mark all descendants blocks for layout. I added a bailout condition + in r75823 because we thought that if one of the parent render block does not + contain "this" float, then it is safe to assume that none of the grand parents + will have it. This is a wrong assumption since anonymous blocks do not have + float objects and we need to go higher in the chain to find the top most parent + containing this float. Instead of breaking out of the loop, it is ok to keep + traversing the chain till we find that parent. Otherwise, we will leave deleted + floats in the grand parents floats list. + + Test: fast/block/float/floats-not-cleared-from-grand-parents.html + + * rendering/RenderBox.cpp: + (WebCore::RenderBox::removeFloatingOrPositionedChildFromBlockLists): + +2011-02-04 Hironori Bono <hbono@chromium.org> + + Reviewed by Adam Barth. + + [chromium] JPEG corruption + https://bugs.webkit.org/show_bug.cgi?id=53250 + + Same as gray-scale JPEGs, we convert the colors of CMYK JPEGs with color + profiles from CMYK to RGB twice and it causes color corruption. This + change suppresses the color profiles for CMYK JPEGs same as gray-scale + ones. + + Test: fast/images/cmyk-jpeg-with-color-profile.html + + * platform/image-decoders/jpeg/JPEGImageDecoder.cpp: + (WebCore::JPEGImageReader::decode): + +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..a74acd6 100644 --- a/WebCore/config.h +++ b/WebCore/config.h @@ -157,10 +157,13 @@ // thread #define ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS +// Allow us to turn off the blinking caret as desired. +#define ANDROID_ALLOW_TURNING_OFF_CARET + #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/SelectionController.cpp b/WebCore/editing/SelectionController.cpp index bc6ef24..42802ca 100644 --- a/WebCore/editing/SelectionController.cpp +++ b/WebCore/editing/SelectionController.cpp @@ -58,6 +58,9 @@ #include "TypingCommand.h" #include "htmlediting.h" #include "visible_units.h" +#ifdef ANDROID_ALLOW_TURNING_OFF_CARET +#include "WebViewCore.h" +#endif #include <stdio.h> #include <wtf/text/CString.h> @@ -1079,6 +1082,10 @@ void SelectionController::invalidateCaretRect() void SelectionController::paintCaret(GraphicsContext* context, int tx, int ty, const IntRect& clipRect) { +#ifdef ANDROID_ALLOW_TURNING_OFF_CARET + if (m_frame && !android::WebViewCore::getWebViewCore(m_frame->view())->shouldPaintCaret()) + return; +#endif #if ENABLE(TEXT_CARET) if (!m_caretVisible) return; 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/inspector/front-end/ScriptsPanel.js b/WebCore/inspector/front-end/ScriptsPanel.js index 2a216cc..30bd513 100644 --- a/WebCore/inspector/front-end/ScriptsPanel.js +++ b/WebCore/inspector/front-end/ScriptsPanel.js @@ -245,9 +245,6 @@ WebInspector.ScriptsPanel.prototype = { // Resource is finished, bind the script right away. resource.addScript(script); this._sourceIDMap[sourceID] = resource; - var view = WebInspector.ResourceManager.existingResourceViewForResource(resource); - if (view && view.sourceFrame) - view.sourceFrame.addScript(script); } else { // Resource is not finished, bind the script later. if (!resource._scriptsPendingResourceLoad) { @@ -315,7 +312,7 @@ WebInspector.ScriptsPanel.prototype = { return; // Need to clear breakpoints and re-create them later when editing source. - var breakpoints = WebInspector.breakpointManager.breakpointsForSourceID(sourceID); + var breakpoints = WebInspector.breakpointManager.breakpointsForSourceID(editData.sourceID); for (var i = 0; i < breakpoints.length; ++i) breakpoints[i].remove(); diff --git a/WebCore/inspector/front-end/SourceFrame.js b/WebCore/inspector/front-end/SourceFrame.js index 6cf226b..8e077cd 100644 --- a/WebCore/inspector/front-end/SourceFrame.js +++ b/WebCore/inspector/front-end/SourceFrame.js @@ -132,11 +132,6 @@ WebInspector.SourceFrame.prototype = { this._addMessageToSource(msg); }, - addScript: function(script) - { - this._scripts[script.sourceID] = script; - }, - clearMessages: function() { for (var line in this._messageBubbles) { 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..422343d 100644 --- a/WebCore/page/FrameView.cpp +++ b/WebCore/page/FrameView.cpp @@ -515,11 +515,9 @@ void FrameView::calculateScrollbarModesForLayout(ScrollbarMode& hMode, Scrollbar Node* body = document->body(); if (body && body->renderer()) { if (body->hasTagName(framesetTag) && m_frame->settings() && !m_frame->settings()->frameFlatteningEnabled()) { -#if !defined(ANDROID_FLATTEN_IFRAME) && !defined(ANDROID_FLATTEN_FRAMESET) body->renderer()->setChildNeedsLayout(true); vMode = ScrollbarAlwaysOff; hMode = ScrollbarAlwaysOff; -#endif } else if (body->hasTagName(bodyTag)) { // It's sufficient to just check the X overflow, // since it's illegal to have visible in only one direction. @@ -928,7 +926,7 @@ void FrameView::layout(bool allowSubtree) InspectorInstrumentation::didLayout(cookie); m_nestedLayoutCount--; -#if ENABLE(ANDROID_OVERFLOW_SCROLL) && !defined(ANDROID_FLATTEN_IFRAME) +#if ENABLE(ANDROID_OVERFLOW_SCROLL) // Reset to false each time we layout in case the overflow status changed. bool hasOverflowScroll = false; RenderObject* ownerRenderer = m_frame->ownerRenderer(); @@ -952,6 +950,15 @@ void FrameView::layout(bool allowSubtree) } m_hasOverflowScroll = hasOverflowScroll; #endif +#ifdef ANDROID_FLATTEN_FRAMESET + // Request a layout to use the content dimensions. + if (m_frame->ownerRenderer() && m_frame->ownerElement()->hasTagName(frameTag)) { + if (canHaveScrollbars() && layoutWidth() > 1 && layoutHeight() > 1) { + if (layoutWidth() < contentsWidth() || layoutHeight() < contentsHeight()) + m_frame->ownerRenderer()->setNeedsLayout(true, true); + } + } +#endif } void FrameView::addWidgetToUpdate(RenderEmbeddedObject* object) @@ -1067,6 +1074,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; @@ -1533,13 +1563,6 @@ void FrameView::scheduleRelayout() if (!m_frame->document()->shouldScheduleLayout()) return; -#if defined(ANDROID_FLATTEN_IFRAME) || defined(ANDROID_FLATTEN_FRAMESET) - // This is the Android frame flattening code. The common code below is not - // used as frameSetFlatteningEnabled() is false on Android. - if (m_frame->ownerRenderer()) - m_frame->ownerRenderer()->setNeedsLayoutAndPrefWidthsRecalc(); -#endif - // When frame flattening is enabled, the contents of the frame affects layout of the parent frames. // Also invalidate parent frame starting from the owner element of this frame. if (m_frame->settings() && m_frame->settings()->frameFlatteningEnabled() && m_frame->ownerRenderer()) { 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/BackedDoubleBufferedTexture.cpp b/WebCore/platform/graphics/android/BackedDoubleBufferedTexture.cpp index d16b53e..7cfa480 100644 --- a/WebCore/platform/graphics/android/BackedDoubleBufferedTexture.cpp +++ b/WebCore/platform/graphics/android/BackedDoubleBufferedTexture.cpp @@ -133,10 +133,9 @@ void BackedDoubleBufferedTexture::setNotBusy() android::Mutex::Autolock lock(m_busyLock); m_busy = false; if (m_delayedRelease) { - if (m_owner == m_delayedReleaseOwner) { - m_owner->removeOwned(this); + if (m_owner == m_delayedReleaseOwner) m_owner = 0; - } + m_delayedRelease = false; m_delayedReleaseOwner = 0; } @@ -207,7 +206,6 @@ bool BackedDoubleBufferedTexture::setOwner(TextureOwner* owner) if (proceed) { m_owner = owner; - owner->addOwned(this); return true; } } @@ -219,7 +217,6 @@ bool BackedDoubleBufferedTexture::release(TextureOwner* owner) android::Mutex::Autolock lock(m_busyLock); if (m_owner == owner) { if (!m_busy) { - m_owner->removeOwned(this); m_owner = 0; return true; } else { 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..9499870 100644 --- a/WebCore/platform/graphics/android/BaseTile.cpp +++ b/WebCore/platform/graphics/android/BaseTile.cpp @@ -254,7 +254,27 @@ void BaseTile::paintBitmap() float w = tileWidth * invScale; float h = tileHeight * invScale; - SkCanvas* canvas = texture->canvas(); + SkCanvas* canvas; + +#ifdef USE_SKIA_GPU + GLuint fboId; + glGenFramebuffersEXT(1, &fboId); + glBindFramebuffer(GL_FRAMEBUFFER, fboId); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureInfo->m_textureId, 0); + glCheckFramebufferStatus(GL_FRAMEBUFFER)); // should return GL_FRAMEBUFFER_COMPLETE + + //Do I need to assign a width/height/format? + + GrContext* context = gr_get_global_ctx(); + context->resetContext(); + GrRenderTarget* target = context->createPlatformRenderTarget(fboId, tileWidth, tileHeight); + SkCanvas tmpCanvas; + SkDevice* device = new SkGpuDevice(context, bm, target); + tmpCanvas.setDevice(device)->unref(); + canvas = &tmpCanvas; +#else + canvas = texture->canvas(); +#endif canvas->save(); canvas->drawColor(tiledPage->glWebViewState()->getBackgroundColor()); @@ -265,21 +285,32 @@ 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); + +#ifdef USE_SKIA_GPU + // set the texture info w/h/format + textureInfo->m_width = tileWidth; + textureInfo->m_height = tileHeight; + texture->producerReleaseAndSwap(); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); // rebind the standard FBO + glDeleteFramebuffers(1, &fboId); +#else texture->producerUpdate(textureInfo); +#endif m_atomicSync.lock(); m_lastPaintedPicture = pictureCount; diff --git a/WebCore/platform/graphics/android/FontCustomPlatformData.cpp b/WebCore/platform/graphics/android/FontCustomPlatformData.cpp index e17e532..4795d9e 100644 --- a/WebCore/platform/graphics/android/FontCustomPlatformData.cpp +++ b/WebCore/platform/graphics/android/FontCustomPlatformData.cpp @@ -35,13 +35,13 @@ namespace WebCore { FontCustomPlatformData::FontCustomPlatformData(SkTypeface* face) { - face->safeRef(); + SkSafeRef(face); m_typeface = face; } FontCustomPlatformData::~FontCustomPlatformData() { - m_typeface->safeUnref(); + SkSafeUnref(m_typeface); // the unref is enough to release the font data... } diff --git a/WebCore/platform/graphics/android/FontDataAndroid.cpp b/WebCore/platform/graphics/android/FontDataAndroid.cpp index 36fb2e0..13e9500 100644 --- a/WebCore/platform/graphics/android/FontDataAndroid.cpp +++ b/WebCore/platform/graphics/android/FontDataAndroid.cpp @@ -91,7 +91,7 @@ bool SimpleFontData::containsCharacters(const UChar* characters, int length) con void SimpleFontData::determinePitch() { - m_treatAsFixedPitch = false; + m_treatAsFixedPitch = m_platformData.isFixedPitch(); } FloatRect SimpleFontData::platformBoundsForGlyph(Glyph) const diff --git a/WebCore/platform/graphics/android/FontPlatformData.h b/WebCore/platform/graphics/android/FontPlatformData.h index ce2f62a..ba30efe 100644 --- a/WebCore/platform/graphics/android/FontPlatformData.h +++ b/WebCore/platform/graphics/android/FontPlatformData.h @@ -79,6 +79,7 @@ public: float size() const { return mTextSize; } unsigned hash() const; + bool isFixedPitch() const; #ifndef NDEBUG String description() const { return ""; } diff --git a/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp b/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp index 974b828..352516b 100644 --- a/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp +++ b/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp @@ -83,7 +83,7 @@ FontPlatformData::FontPlatformData() FontPlatformData::FontPlatformData(const FontPlatformData& src) { if (hashTableDeletedFontValue() != src.mTypeface) { - src.mTypeface->safeRef(); + SkSafeRef(src.mTypeface); } mTypeface = src.mTypeface; @@ -101,7 +101,7 @@ FontPlatformData::FontPlatformData(SkTypeface* tf, float textSize, bool fakeBold : mTypeface(tf), mTextSize(textSize), mFakeBold(fakeBold), mFakeItalic(fakeItalic) { if (hashTableDeletedFontValue() != mTypeface) { - mTypeface->safeRef(); + SkSafeRef(mTypeface); } inc_count(); @@ -113,7 +113,7 @@ FontPlatformData::FontPlatformData(const FontPlatformData& src, float textSize) m_harfbuzzFace(src.m_harfbuzzFace) { if (hashTableDeletedFontValue() != mTypeface) { - mTypeface->safeRef(); + SkSafeRef(mTypeface); } inc_count(); @@ -135,17 +135,17 @@ FontPlatformData::~FontPlatformData() #endif if (hashTableDeletedFontValue() != mTypeface) { - mTypeface->safeUnref(); + SkSafeUnref(mTypeface); } } FontPlatformData& FontPlatformData::operator=(const FontPlatformData& src) { if (hashTableDeletedFontValue() != src.mTypeface) { - src.mTypeface->safeRef(); + SkSafeRef(src.mTypeface); } if (hashTableDeletedFontValue() != mTypeface) { - mTypeface->safeUnref(); + SkSafeUnref(mTypeface); } mTypeface = src.mTypeface; @@ -205,6 +205,11 @@ unsigned FontPlatformData::hash() const return h; } +bool FontPlatformData::isFixedPitch() const +{ + return mTypeface ? mTypeface->isFixedWidth() : false; +} + HB_FaceRec_* FontPlatformData::harfbuzzFace() const { #ifdef SUPPORT_COMPLEX_SCRIPTS diff --git a/WebCore/platform/graphics/android/GLUtils.cpp b/WebCore/platform/graphics/android/GLUtils.cpp index b62072b..de794cb 100644 --- a/WebCore/platform/graphics/android/GLUtils.cpp +++ b/WebCore/platform/graphics/android/GLUtils.cpp @@ -99,13 +99,23 @@ void GLUtils::setOrthographicMatrix(TransformationMatrix& ortho, float left, flo // GL & EGL error checks ///////////////////////////////////////////////////////////////////////////////////////// +static void crashIfOOM(GLint errorCode) { + const GLint OOM_ERROR_CODE = 0x505; + if (errorCode == OOM_ERROR_CODE) { + XLOG("Fatal OOM detected."); + CRASH(); + } +} + void GLUtils::checkEglError(const char* op, EGLBoolean returnVal) { if (returnVal != EGL_TRUE) XLOG("EGL ERROR - %s() returned %d\n", op, returnVal); - for (EGLint error = eglGetError(); error != EGL_SUCCESS; error = eglGetError()) + for (EGLint error = eglGetError(); error != EGL_SUCCESS; error = eglGetError()) { XLOG("after %s() eglError (0x%x)\n", op, error); + crashIfOOM(error); + } } bool GLUtils::checkGlError(const char* op) @@ -113,6 +123,7 @@ bool GLUtils::checkGlError(const char* op) bool ret = false; for (GLint error = glGetError(); error; error = glGetError()) { XLOG("GL ERROR - after %s() glError (0x%x)\n", op, error); + crashIfOOM(error); ret = true; } return ret; @@ -123,6 +134,7 @@ bool GLUtils::checkGlErrorOn(void* p, const char* op) bool ret = false; for (GLint error = glGetError(); error; error = glGetError()) { XLOG("GL ERROR on %x - after %s() glError (0x%x)\n", p, op, error); + crashIfOOM(error); ret = true; } return ret; diff --git a/WebCore/platform/graphics/android/GLWebViewState.cpp b/WebCore/platform/graphics/android/GLWebViewState.cpp index 0e7f559..5e1285f 100644 --- a/WebCore/platform/graphics/android/GLWebViewState.cpp +++ b/WebCore/platform/graphics/android/GLWebViewState.cpp @@ -34,11 +34,14 @@ #include "TilesManager.h" #include <wtf/CurrentTime.h> -#ifdef DEBUG - #include <cutils/log.h> #include <wtf/text/CString.h> +#undef XLOGC +#define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "GLWebViewState", __VA_ARGS__) + +#ifdef DEBUG + #undef XLOG #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "GLWebViewState", __VA_ARGS__) @@ -84,19 +87,31 @@ GLWebViewState::GLWebViewState(android::Mutex* buttonMutex) #ifdef DEBUG_COUNT ClassTracker::instance()->increment("GLWebViewState"); #endif +#ifdef MEASURES_PERF + m_timeCounter = 0; + m_totalTimeCounter = 0; + m_measurePerfs = false; +#endif } GLWebViewState::~GLWebViewState() { - m_currentBaseLayer->safeUnref(); + // We have to destroy the two tiled pages first as their destructor + // may depend on the existence of this GLWebViewState and some of its + // instance variables in order to complete. + // Explicitely, currently we need to have the m_currentBaseLayer around + // in order to complete any pending paint operations (the tiled pages + // will remove any pending operations, and wait if one is underway). delete m_tiledPageA; delete m_tiledPageB; + SkSafeUnref(m_currentBaseLayer); #ifdef DEBUG_COUNT ClassTracker::instance()->decrement("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) { @@ -112,18 +127,26 @@ void GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, const IntRect& rect) // We only update the layers if we are not currently // waiting for a tiledPage to be painted if (m_baseLayerUpdate) { - layer->safeRef(); - m_currentBaseLayer->safeUnref(); + SkSafeRef(layer); + SkSafeUnref(m_currentBaseLayer); m_currentBaseLayer = layer; } inval(rect); + +#ifdef MEASURES_PERF + if (m_measurePerfs && !showVisualIndicator) + dumpMeasures(); + m_measurePerfs = showVisualIndicator; +#endif + + TilesManager::instance()->setShowVisualIndicator(showVisualIndicator); } void GLWebViewState::unlockBaseLayerUpdate() { m_baseLayerUpdate = true; android::Mutex::Autolock lock(m_baseLayerLock); - m_baseLayer->safeRef(); - m_currentBaseLayer->safeUnref(); + SkSafeRef(m_baseLayer); + SkSafeUnref(m_currentBaseLayer); m_currentBaseLayer = m_baseLayer; inval(m_invalidateRect); IntRect empty; @@ -131,7 +154,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) @@ -139,7 +162,7 @@ void GLWebViewState::setExtra(BaseLayerAndroid* layer, SkPicture& picture, layer->setExtra(picture); - if (m_lastInval == rect) + if (!allowSame && m_lastInval == rect) return; if (!rect.isEmpty()) @@ -299,6 +322,19 @@ void GLWebViewState::setViewport(SkRect& viewport, float scale) m_tiledPageB->updateBaseTileSize(); } +#ifdef MEASURES_PERF +void GLWebViewState::dumpMeasures() +{ + for (int i = 0; i < m_timeCounter; i++) { + XLOGC("%d delay: %d ms", m_totalTimeCounter + i, + static_cast<int>(m_delayTimes[i]*1000)); + m_delayTimes[i] = 0; + } + m_totalTimeCounter += m_timeCounter; + m_timeCounter = 0; +} +#endif // MEASURES_PERF + bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, float scale, SkColor color) { glFinish(); @@ -313,12 +349,22 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, float scale, SkColo m_baseLayerLock.lock(); BaseLayerAndroid* baseLayer = m_currentBaseLayer; - baseLayer->safeRef(); + SkSafeRef(baseLayer); m_baseLayerLock.unlock(); if (!baseLayer) return false; + bool ret = baseLayer->drawGL(rect, viewport, scale, color); - baseLayer->safeUnref(); + +#ifdef MEASURES_PERF + if (m_measurePerfs) { + m_delayTimes[m_timeCounter++] = delta; + if (m_timeCounter >= MAX_MEASURES_PERF) + dumpMeasures(); + } +#endif + + SkSafeUnref(baseLayer); return ret; } diff --git a/WebCore/platform/graphics/android/GLWebViewState.h b/WebCore/platform/graphics/android/GLWebViewState.h index 9940631..b8194f4 100644 --- a/WebCore/platform/graphics/android/GLWebViewState.h +++ b/WebCore/platform/graphics/android/GLWebViewState.h @@ -35,6 +35,12 @@ #include "TiledPage.h" #include <utils/threads.h> +// Performance measurements probe +// To use it, enable the visual indicators in debug mode. +// turning off the visual indicators will flush the measures. +// #define MEASURES_PERF +#define MAX_MEASURES_PERF 2000 + namespace WebCore { class BaseLayerAndroid; @@ -168,8 +174,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,11 +211,15 @@ public: return false; } + bool drawGL(IntRect& rect, SkRect& viewport, + float scale, SkColor color = SK_ColorWHITE); + void setBackgroundColor(SkColor color) { m_backgroundColor = color; } SkColor getBackgroundColor() { return m_backgroundColor; } - bool drawGL(IntRect& rect, SkRect& viewport, - float scale, SkColor color = SK_ColorWHITE); +#ifdef MEASURES_PERF + void dumpMeasures(); +#endif private: void inval(const IntRect& rect); // caller must hold m_baseLayerLock @@ -253,6 +263,13 @@ private: SkColor m_backgroundColor; double m_prevDrawTime; + +#ifdef MEASURES_PERF + unsigned int m_totalTimeCounter; + int m_timeCounter; + double m_delayTimes[MAX_MEASURES_PERF]; + bool m_measurePerfs; +#endif }; } // namespace WebCore diff --git a/WebCore/platform/graphics/android/GradientAndroid.cpp b/WebCore/platform/graphics/android/GradientAndroid.cpp index 72ae336..b8dc9dd 100644 --- a/WebCore/platform/graphics/android/GradientAndroid.cpp +++ b/WebCore/platform/graphics/android/GradientAndroid.cpp @@ -38,7 +38,7 @@ class PlatformGradientRec { public: PlatformGradientRec() : m_shader(NULL) {} - ~PlatformGradientRec() { m_shader->safeUnref(); } + ~PlatformGradientRec() { SkSafeUnref(m_shader); } SkShader* m_shader; SkShader::TileMode m_tileMode; @@ -102,7 +102,7 @@ SkShader* Gradient::getShader(SkShader::TileMode mode) s = new SkColorShader(0); // zap our previous shader, if present - m_gradient->m_shader->safeUnref(); + SkSafeUnref(m_gradient->m_shader); m_gradient->m_shader = s; m_gradient->m_tileMode = mode; SkMatrix matrix = m_gradientSpaceTransformation; diff --git a/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp b/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp index 06a53b1..dce7b27 100644 --- a/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp +++ b/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp @@ -128,13 +128,13 @@ public: , useAA(other.useAA) { path = deepCopyPtr<SkPath>(other.path); - pathEffect->safeRef(); + SkSafeRef(pathEffect); } ~State() { delete path; - pathEffect->safeUnref(); + SkSafeUnref(pathEffect); } void setShadow(int radius, int dx, int dy, SkColor c) @@ -1043,7 +1043,7 @@ void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset) for (unsigned int i = 0; i < count; i++) intervals[i] = SkFloatToScalar(dashes[i % dashLength]); SkPathEffect **effectPtr = &m_data->getState()->pathEffect; - (*effectPtr)->safeUnref(); + SkSafeUnref(*effectPtr); *effectPtr = new SkDashPathEffect(intervals, count, SkFloatToScalar(dashOffset)); delete[] intervals; diff --git a/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp b/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp index e887964..7963ae0 100644 --- a/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp +++ b/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp @@ -25,6 +25,7 @@ #include "GraphicsContext.h" #include "Image.h" #include "Length.h" +#include "MediaLayer.h" #include "PlatformBridge.h" #include "PlatformGraphicsContext.h" #include "RenderLayerBacking.h" @@ -122,8 +123,8 @@ GraphicsLayerAndroid::GraphicsLayerAndroid(GraphicsLayerClient* client) : m_foregroundLayer(0), m_foregroundClipLayer(0) { - m_contentLayer = new LayerAndroid(true); RenderLayer* renderLayer = renderLayerFromClient(m_client); + m_contentLayer = new LayerAndroid(renderLayer, true); if (renderLayer) { m_contentLayer->setIsRootLayer(renderLayer->isRootLayer() && !(renderLayer->renderer()->frame()->ownerElement())); @@ -227,6 +228,9 @@ void GraphicsLayerAndroid::updateFixedPosition() RenderLayer* renderLayer = renderLayerFromClient(m_client); RenderView* view = static_cast<RenderView*>(renderLayer->renderer()); + // We will need the Iframe flag in the LayerAndroid tree for fixed position + if (view && view->isRenderIFrame()) + m_contentLayer->setIsIframe(true); // If we are a fixed position layer, just set it if (view->isPositioned() && view->style()->position() == FixedPosition) { // We need to get the passed CSS properties for the element @@ -271,15 +275,24 @@ 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)", this, point.x(), point.y(), m_position.x(), m_position.y(), 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(); } @@ -309,8 +322,20 @@ void GraphicsLayerAndroid::setSize(const FloatSize& size) return; MLOG("(%x) setSize (%.2f,%.2f)", this, size.width(), size.height()); GraphicsLayer::setSize(size); + + // If it is a media layer the size may have changed as a result of the media + // element (e.g. plugin) gaining focus. Therefore, we must sync the size of + // the focus' outline so that our UI thread can draw accordingly. + if (m_contentLayer->isMedia() && m_client) { + RenderLayer* layer = renderLayerFromClient(m_client); + RenderBox* box = layer->renderBox(); + int outline = box->view()->maximalOutlineSize(); + static_cast<MediaLayer*>(m_contentLayer)->setOutlineSize(outline); + LOG("Media Outline: %d %p %p %p", outline, m_client, layer, box); + LOG("Media Size: %g,%g", size.width(), size.height()); + } + m_contentLayer->setSize(size.width(), size.height()); - updateFixedPosition(); askForSync(); } @@ -368,31 +393,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 +478,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(layer); + m_foregroundClipLayer = new LayerAndroid(layer, 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 +577,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 +906,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 +939,8 @@ void GraphicsLayerAndroid::syncCompositingState() for (unsigned int i = 0; i < m_children.size(); i++) m_children[i]->syncCompositingState(); + updateScrollingLayers(); + updateFixedPosition(); 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..3706d20 100644 --- a/WebCore/platform/graphics/android/LayerAndroid.cpp +++ b/WebCore/platform/graphics/android/LayerAndroid.cpp @@ -61,10 +61,11 @@ class OpacityDrawFilter : public SkDrawFilter { /////////////////////////////////////////////////////////////////////////////// -LayerAndroid::LayerAndroid(bool isRootLayer) : SkLayer(), +LayerAndroid::LayerAndroid(RenderLayer* owner, bool isRootLayer) : SkLayer(), m_isRootLayer(isRootLayer), m_haveClip(false), m_isFixed(false), + m_isIframe(false), m_preserves3D(false), m_anchorPointZ(0), m_recordingPicture(0), @@ -75,13 +76,15 @@ LayerAndroid::LayerAndroid(bool isRootLayer) : SkLayer(), m_reservedTexture(0), m_pictureUsed(0), m_requestSent(false), - m_scale(1) + m_scale(1), + m_lastComputeTextureSize(0), + m_owningLayer(owner) { m_backgroundColor = 0; m_preserves3D = false; m_dirty = false; - + m_iframeOffset.set(0,0); #ifdef DEBUG_COUNT ClassTracker::instance()->increment("LayerAndroid"); #endif @@ -90,15 +93,17 @@ LayerAndroid::LayerAndroid(bool isRootLayer) : SkLayer(), LayerAndroid::LayerAndroid(const LayerAndroid& layer) : SkLayer(layer), m_isRootLayer(layer.m_isRootLayer), m_haveClip(layer.m_haveClip), + m_isIframe(layer.m_isIframe), m_extra(0), // deliberately not copied m_uniqueId(layer.m_uniqueId), m_drawingTexture(0), m_reservedTexture(0), - m_requestSent(false) + m_requestSent(false), + m_owningLayer(layer.m_owningLayer) { m_isFixed = layer.m_isFixed; m_contentsImage = layer.m_contentsImage; - m_contentsImage->safeRef(); + SkSafeRef(m_contentsImage); m_renderLayerPos = layer.m_renderLayerPos; m_transform = layer.m_transform; m_backgroundColor = layer.m_backgroundColor; @@ -112,7 +117,7 @@ LayerAndroid::LayerAndroid(const LayerAndroid& layer) : SkLayer(layer), m_fixedMarginRight = layer.m_fixedMarginRight; m_fixedMarginBottom = layer.m_fixedMarginBottom; m_fixedRect = layer.m_fixedRect; - + m_iframeOffset = layer.m_iframeOffset; m_recordingPicture = layer.m_recordingPicture; SkSafeRef(m_recordingPicture); @@ -123,6 +128,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(); @@ -140,6 +146,7 @@ LayerAndroid::LayerAndroid(SkPicture* picture) : SkLayer(), m_isRootLayer(true), m_haveClip(false), m_isFixed(false), + m_isIframe(false), m_recordingPicture(picture), m_contentsImage(0), m_extra(0), @@ -147,11 +154,14 @@ LayerAndroid::LayerAndroid(SkPicture* picture) : SkLayer(), m_drawingTexture(0), m_reservedTexture(0), m_requestSent(false), - m_scale(1) + m_scale(1), + m_lastComputeTextureSize(0), + m_owningLayer(0) { m_backgroundColor = 0; m_dirty = false; SkSafeRef(m_recordingPicture); + m_iframeOffset.set(0,0); #ifdef DEBUG_COUNT ClassTracker::instance()->increment("LayerAndroid"); #endif @@ -189,8 +199,8 @@ LayerAndroid::~LayerAndroid() removeTexture(0); removeChildren(); delete m_extra; - m_contentsImage->safeUnref(); - m_recordingPicture->safeUnref(); + SkSafeUnref(m_contentsImage); + SkSafeUnref(m_recordingPicture); m_animations.clear(); #ifdef DEBUG_COUNT ClassTracker::instance()->decrement("LayerAndroid"); @@ -460,9 +470,31 @@ const LayerAndroid* LayerAndroid::find(int* xPtr, int* yPtr, SkPicture* root) co /////////////////////////////////////////////////////////////////////////////// -void LayerAndroid::updateFixedLayersPositions(const SkRect& viewport) +void LayerAndroid::updateFixedLayersPositions(SkRect viewport, LayerAndroid* parentIframeLayer) { + // If this is an iframe, accumulate the offset from the parent with + // current position, and change the parent pointer. + if (m_isIframe) { + // If this is the top level, take the current position + SkPoint parentOffset; + parentOffset.set(0,0); + if (parentIframeLayer) + parentOffset = parentIframeLayer->getPosition(); + + m_iframeOffset = parentOffset + getPosition(); + + parentIframeLayer = this; + } + if (m_isFixed) { + // So if this is a fixed layer inside a iframe, use the iframe offset + // and the iframe's size as the viewport and pass to the children + if (parentIframeLayer) { + viewport = SkRect::MakeXYWH(parentIframeLayer->m_iframeOffset.fX, + parentIframeLayer->m_iframeOffset.fY, + parentIframeLayer->getSize().width(), + parentIframeLayer->getSize().height()); + } float w = viewport.width(); float h = viewport.height(); float dx = viewport.fLeft; @@ -494,7 +526,7 @@ void LayerAndroid::updateFixedLayersPositions(const SkRect& viewport) int count = this->countChildren(); for (int i = 0; i < count; i++) - this->getChild(i)->updateFixedLayersPositions(viewport); + this->getChild(i)->updateFixedLayersPositions(viewport, parentIframeLayer); } void LayerAndroid::updatePositions() @@ -651,8 +683,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 +1021,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) @@ -1045,11 +1081,11 @@ bool LayerAndroid::prepareContext(bool force) || (m_recordingPicture && ((m_recordingPicture->width() != (int) getSize().width()) || (m_recordingPicture->height() != (int) getSize().height())))) { - m_recordingPicture->safeUnref(); + SkSafeUnref(m_recordingPicture); m_recordingPicture = new SkPicture(); } } else if (m_recordingPicture) { - m_recordingPicture->safeUnref(); + SkSafeUnref(m_recordingPicture); m_recordingPicture = 0; } @@ -1197,6 +1233,8 @@ void LayerAndroid::dumpLayers(FILE* file, int indentLevel) const writeIntVal(file, indentLevel + 1, "haveClip", m_haveClip); writeIntVal(file, indentLevel + 1, "isRootLayer", m_isRootLayer); writeIntVal(file, indentLevel + 1, "isFixed", m_isFixed); + writeIntVal(file, indentLevel + 1, "m_isIframe", m_isIframe); + writePoint(file, indentLevel + 1, "m_iframeOffset", m_iframeOffset); writeFloatVal(file, indentLevel + 1, "opacity", getOpacity()); writeSize(file, indentLevel + 1, "size", getSize()); diff --git a/WebCore/platform/graphics/android/LayerAndroid.h b/WebCore/platform/graphics/android/LayerAndroid.h index 2cb56c1..c315488 100644 --- a/WebCore/platform/graphics/android/LayerAndroid.h +++ b/WebCore/platform/graphics/android/LayerAndroid.h @@ -83,12 +83,13 @@ namespace WebCore { class AndroidAnimation; class BackedDoubleBufferedTexture; class LayerAndroidFindState; +class RenderLayer; class TiledPage; class LayerAndroid : public SkLayer, public TextureOwner { public: - LayerAndroid(bool isRootLayer); + LayerAndroid(RenderLayer* owner, bool isRootLayer); LayerAndroid(const LayerAndroid& layer); LayerAndroid(SkPicture*); virtual ~LayerAndroid(); @@ -111,7 +112,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; @@ -201,7 +202,7 @@ public: This call is recursive, so it should be called on the root of the hierarchy. */ - void updateFixedLayersPositions(const SkRect& viewPort); + void updateFixedLayersPositions(SkRect viewPort, LayerAndroid* parentIframeLayer = 0); /** Call this to update the position attribute, so that later calls like bounds() will report the corrected position. @@ -245,6 +246,10 @@ public: virtual bool isMedia() const { return false; } + RenderLayer* owningLayer() const { return m_owningLayer; } + + void setIsIframe(bool isIframe) { m_isIframe = isIframe; } + protected: virtual void onDraw(SkCanvas*, SkScalar opacity); @@ -263,6 +268,7 @@ private: bool m_haveClip; bool m_isFixed; bool m_backgroundColorSet; + bool m_isIframe; SkLength m_fixedLeft; SkLength m_fixedTop; @@ -274,6 +280,7 @@ private: SkLength m_fixedMarginBottom; SkRect m_fixedRect; + SkPoint m_iframeOffset; // When fixed element is undefined or auto, the render layer's position // is needed for offset computation IntPoint m_renderLayerPos; @@ -325,11 +332,17 @@ 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. android::Mutex m_atomicSync; + RenderLayer* m_owningLayer; + typedef SkLayer INHERITED; }; diff --git a/WebCore/platform/graphics/android/MediaLayer.cpp b/WebCore/platform/graphics/android/MediaLayer.cpp index 46f0dfc..3d95211 100644 --- a/WebCore/platform/graphics/android/MediaLayer.cpp +++ b/WebCore/platform/graphics/android/MediaLayer.cpp @@ -49,6 +49,7 @@ MediaLayer::MediaLayer(jobject weakWebViewRef) : LayerAndroid(false) m_currentTextureInfo = 0; m_isContentInverted = false; + m_outlineSize = 0; XLOG("Creating Media Layer %p", this); } @@ -61,6 +62,7 @@ MediaLayer::MediaLayer(const MediaLayer& layer) : LayerAndroid(layer) m_currentTextureInfo = 0; m_isContentInverted = layer.m_isContentInverted; + m_outlineSize = layer.m_outlineSize; XLOG("Creating Media Layer Copy %p -> %p", &layer, this); } @@ -73,7 +75,13 @@ MediaLayer::~MediaLayer() bool MediaLayer::drawGL(SkMatrix& matrix) { - TilesManager::instance()->shader()->clip(drawClip()); + // when the plugin gains focus webkit applies an outline to the widget, + // which causes the layer to expand to accommodate the outline. Therefore, + // we shrink the clip by the outline's dimensions to ensure the plugin does + // not draw outside of its bounds. + FloatRect clip = drawClip(); + clip.inflate(-m_outlineSize); + TilesManager::instance()->shader()->clip(clip); // check to see if we need to create a video texture m_videoTexture->initNativeWindowIfNeeded(); diff --git a/WebCore/platform/graphics/android/MediaLayer.h b/WebCore/platform/graphics/android/MediaLayer.h index 15bd6d8..203ef93 100644 --- a/WebCore/platform/graphics/android/MediaLayer.h +++ b/WebCore/platform/graphics/android/MediaLayer.h @@ -49,6 +49,7 @@ public: TextureInfo* getCurrentTextureInfo() const { return m_currentTextureInfo; } void invertContents(bool invertContent) { m_isContentInverted = invertContent; } + void setOutlineSize(int size) { m_outlineSize = size; } // functions to manipulate secondary layers for video playback ANativeWindow* acquireNativeWindowForVideo(); @@ -62,6 +63,7 @@ private: TextureInfo* m_currentTextureInfo; bool m_isContentInverted; + int m_outlineSize; // Video texture variables VideoTexture* m_videoTexture; diff --git a/WebCore/platform/graphics/android/MediaTexture.cpp b/WebCore/platform/graphics/android/MediaTexture.cpp index a92b570..4ec50d8 100644 --- a/WebCore/platform/graphics/android/MediaTexture.cpp +++ b/WebCore/platform/graphics/android/MediaTexture.cpp @@ -17,6 +17,7 @@ #include "MediaTexture.h" #include "TilesManager.h" #include "GLUtils.h" +#include "VideoListener.h" #if USE(ACCELERATED_COMPOSITING) @@ -47,43 +48,6 @@ namespace WebCore { -class VideoListener : public android::SurfaceTexture::FrameAvailableListener { - -public: - VideoListener(jobject weakWebViewRef) - : m_weakWebViewRef(weakWebViewRef) - , m_postInvalMethod(0) - { - if (!m_weakWebViewRef) - return; - - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jobject localWebViewRef = env->NewLocalRef(m_weakWebViewRef); - if (localWebViewRef) { - jclass wvClass = env->GetObjectClass(localWebViewRef); - m_postInvalMethod = env->GetMethodID(wvClass, "postInvalidate", "()V"); - env->DeleteLocalRef(wvClass); - env->DeleteLocalRef(localWebViewRef); - } - checkException(env); - } - - virtual void onFrameAvailable() - { - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jobject localWebViewRef = env->NewLocalRef(m_weakWebViewRef); - if (localWebViewRef) { - env->CallVoidMethod(localWebViewRef, m_postInvalMethod); - env->DeleteLocalRef(localWebViewRef); - } - checkException(env); - } - -private: - jobject m_weakWebViewRef; - jmethodID m_postInvalMethod; -}; - VideoTexture::VideoTexture(jobject weakWebViewRef) : android::LightRefBase<VideoTexture>() { m_weakWebViewRef = weakWebViewRef; @@ -91,6 +55,7 @@ VideoTexture::VideoTexture(jobject weakWebViewRef) : android::LightRefBase<Video m_dimensions.setEmpty(); m_newWindowRequest = false; m_newWindowReady = false; + m_videoListener = new VideoListener(m_weakWebViewRef); } VideoTexture::~VideoTexture() @@ -106,24 +71,26 @@ VideoTexture::~VideoTexture() void VideoTexture::initNativeWindowIfNeeded() { - android::Mutex::Autolock lock(m_videoLock); + { + android::Mutex::Autolock lock(m_videoLock); - if(!m_newWindowRequest) - return; + if(!m_newWindowRequest) + return; - // reuse an existing texture if possible - if (!m_textureId) - glGenTextures(1, &m_textureId); + // reuse an existing texture if possible + if (!m_textureId) + glGenTextures(1, &m_textureId); - m_surfaceTexture = new android::SurfaceTexture(m_textureId); - m_surfaceTextureClient = new android::SurfaceTextureClient(m_surfaceTexture); + m_surfaceTexture = new android::SurfaceTexture(m_textureId); + m_surfaceTextureClient = new android::SurfaceTextureClient(m_surfaceTexture); - //setup callback - sp<VideoListener> listener = new VideoListener(m_weakWebViewRef); - m_surfaceTexture->setFrameAvailableListener(listener); + //setup callback + m_videoListener->resetFrameAvailable(); + m_surfaceTexture->setFrameAvailableListener(m_videoListener); - m_newWindowRequest = false; - m_newWindowReady = true; + m_newWindowRequest = false; + m_newWindowReady = true; + } m_newVideoRequestCond.signal(); } @@ -131,7 +98,8 @@ void VideoTexture::drawVideo(const TransformationMatrix& matrix) { android::Mutex::Autolock lock(m_videoLock); - if(!m_surfaceTexture.get() || m_dimensions.isEmpty()) + if(!m_surfaceTexture.get() || m_dimensions.isEmpty() + || !m_videoListener->isFrameAvailable()) return; m_surfaceTexture->updateTexImage(); @@ -174,7 +142,11 @@ ANativeWindow* VideoTexture::requestNewWindow() } //block until the request can be fulfilled or we time out - m_newVideoRequestCond.waitRelative(m_videoLock, 500000000); // .5 sec + bool timedOut = false; + while (m_newWindowRequest && !timedOut) { + int ret = m_newVideoRequestCond.waitRelative(m_videoLock, 500000000); // .5 sec + timedOut = ret == TIMED_OUT; + } if (m_surfaceTextureClient.get()) m_newWindowReady = false; diff --git a/WebCore/platform/graphics/android/MediaTexture.h b/WebCore/platform/graphics/android/MediaTexture.h index 189905c..b3e1d07 100644 --- a/WebCore/platform/graphics/android/MediaTexture.h +++ b/WebCore/platform/graphics/android/MediaTexture.h @@ -31,6 +31,8 @@ namespace android { namespace WebCore { +class VideoListener; + class MediaTexture : public DoubleBufferedTexture, public android::LightRefBase<MediaTexture> { @@ -57,6 +59,7 @@ private: GLuint m_textureId; sp<android::SurfaceTexture> m_surfaceTexture; sp<ANativeWindow> m_surfaceTextureClient; + sp<VideoListener> m_videoListener; SkRect m_dimensions; bool m_newWindowRequest; bool m_newWindowReady; diff --git a/WebCore/platform/graphics/android/PatternAndroid.cpp b/WebCore/platform/graphics/android/PatternAndroid.cpp index 5a3fd8f..568036c 100644 --- a/WebCore/platform/graphics/android/PatternAndroid.cpp +++ b/WebCore/platform/graphics/android/PatternAndroid.cpp @@ -42,7 +42,7 @@ static SkShader::TileMode toTileMode(bool doRepeat) { void Pattern::platformDestroy() { - m_pattern->safeUnref(); + SkSafeUnref(m_pattern); m_pattern = 0; } diff --git a/WebCore/platform/graphics/android/ScrollableLayerAndroid.h b/WebCore/platform/graphics/android/ScrollableLayerAndroid.h index 697fe74..68fba77 100644 --- a/WebCore/platform/graphics/android/ScrollableLayerAndroid.h +++ b/WebCore/platform/graphics/android/ScrollableLayerAndroid.h @@ -26,8 +26,8 @@ namespace WebCore { class ScrollableLayerAndroid : public LayerAndroid { public: - ScrollableLayerAndroid() - : LayerAndroid(false) {} + ScrollableLayerAndroid(RenderLayer* owner) + : LayerAndroid(owner, false) {} ScrollableLayerAndroid(const ScrollableLayerAndroid& layer) : LayerAndroid(layer) , m_scrollLimits(layer.m_scrollLimits) {} diff --git a/WebCore/platform/graphics/android/TextureOwner.cpp b/WebCore/platform/graphics/android/TextureOwner.cpp deleted file mode 100644 index c4446d7..0000000 --- a/WebCore/platform/graphics/android/TextureOwner.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2011, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "TextureOwner.h" - -#include "BackedDoubleBufferedTexture.h" - -namespace WebCore { - -TextureOwner::~TextureOwner() -{ - if (m_ownedTextures.size()) { - // This TextureOwner owns textures still! - HashSet<BackedDoubleBufferedTexture*> textures; - // Swap to a local copy because release will modify the iterator. - textures.swap(m_ownedTextures); - HashSet<BackedDoubleBufferedTexture*>::const_iterator it = textures.begin(); - for (; it != textures.end(); ++it) - (*it)->release(this); - } -} - -void TextureOwner::addOwned(BackedDoubleBufferedTexture* t) -{ - // This TextureOwner now owns texture t - m_ownedTextures.add(t); -} - -void TextureOwner::removeOwned(BackedDoubleBufferedTexture* t) -{ - // This textureowner no longer owns texture t. - m_ownedTextures.remove(t); -} -} diff --git a/WebCore/platform/graphics/android/TextureOwner.h b/WebCore/platform/graphics/android/TextureOwner.h index 684efac..aebbf90 100644 --- a/WebCore/platform/graphics/android/TextureOwner.h +++ b/WebCore/platform/graphics/android/TextureOwner.h @@ -26,8 +26,6 @@ #ifndef TextureOwner_h #define TextureOwner_h -#include <wtf/HashSet.h> - namespace WebCore { class TiledPage; @@ -35,15 +33,9 @@ class BackedDoubleBufferedTexture; class TextureOwner { public: - virtual ~TextureOwner(); + virtual ~TextureOwner() { } virtual bool removeTexture(BackedDoubleBufferedTexture* texture) = 0; virtual TiledPage* page() = 0; - - void addOwned(BackedDoubleBufferedTexture*); - void removeOwned(BackedDoubleBufferedTexture*); - -private: - WTF::HashSet<BackedDoubleBufferedTexture*> m_ownedTextures; }; } diff --git a/WebCore/platform/graphics/android/TexturesGenerator.cpp b/WebCore/platform/graphics/android/TexturesGenerator.cpp index 5b9c809..fae7ece 100644 --- a/WebCore/platform/graphics/android/TexturesGenerator.cpp +++ b/WebCore/platform/graphics/android/TexturesGenerator.cpp @@ -53,24 +53,24 @@ namespace WebCore { void TexturesGenerator::scheduleOperation(QueuedOperation* operation) { - android::Mutex::Autolock lock(mRequestedOperationsLock); - for (unsigned int i = 0; i < mRequestedOperations.size(); i++) { - QueuedOperation** s = &mRequestedOperations[i]; - // A similar operation is already in the queue. The newer operation may - // have additional dirty tiles so delete the existing operation and - // replace it with the new one. - if (*s && *s == operation) { - QueuedOperation* oldOperation = *s; - *s = operation; - delete oldOperation; - return; + { + android::Mutex::Autolock lock(mRequestedOperationsLock); + for (unsigned int i = 0; i < mRequestedOperations.size(); i++) { + QueuedOperation** s = &mRequestedOperations[i]; + // A similar operation is already in the queue. The newer operation may + // have additional dirty tiles so delete the existing operation and + // replace it with the new one. + if (*s && *s == operation) { + QueuedOperation* oldOperation = *s; + *s = operation; + delete oldOperation; + return; + } } - } - mRequestedOperations.append(operation); - m_newRequestLock.lock(); - m_newRequestCond.signal(); - m_newRequestLock.unlock(); + mRequestedOperations.append(operation); + } + mRequestedOperationsCond.signal(); } void TexturesGenerator::removeOperationsForPage(TiledPage* page) @@ -90,7 +90,7 @@ void TexturesGenerator::removeOperationsForTexture(LayerTexture* texture) void TexturesGenerator::removeOperationsForFilter(OperationFilter* filter) { - mRequestedOperationsLock.lock(); + android::Mutex::Autolock lock(mRequestedOperationsLock); for (unsigned int i = 0; i < mRequestedOperations.size();) { QueuedOperation* operation = mRequestedOperations[i]; if (filter->check(operation)) { @@ -105,23 +105,14 @@ void TexturesGenerator::removeOperationsForFilter(OperationFilter* filter) if (operation && filter->check(operation)) m_waitForCompletion = true; - mRequestedOperationsLock.unlock(); - delete filter; - mRequestedOperationsLock.lock(); - if (!m_waitForCompletion) { - mRequestedOperationsLock.unlock(); - return; // operation treated - } - // At this point, it means that we are currently executing an operation that // we want to be removed -- we should wait until it is done, so that // when we return our caller can be sure that there is no more operations // in the queue matching the given filter. - mRequestedOperationsCond.wait(mRequestedOperationsLock); - m_waitForCompletion = false; - mRequestedOperationsLock.unlock(); + while (m_waitForCompletion) + mRequestedOperationsCond.wait(mRequestedOperationsLock); } status_t TexturesGenerator::readyToRun() @@ -133,19 +124,13 @@ status_t TexturesGenerator::readyToRun() bool TexturesGenerator::threadLoop() { + // Check if we have any pending operations. mRequestedOperationsLock.lock(); + while (!mRequestedOperations.size()) + mRequestedOperationsCond.wait(mRequestedOperationsLock); - if (!mRequestedOperations.size()) { - XLOG("threadLoop, waiting for signal"); - m_newRequestLock.lock(); - mRequestedOperationsLock.unlock(); - m_newRequestCond.wait(m_newRequestLock); - m_newRequestLock.unlock(); - XLOG("threadLoop, got signal"); - } else { - XLOG("threadLoop going as we already have something in the queue"); - mRequestedOperationsLock.unlock(); - } + XLOG("threadLoop, got signal"); + mRequestedOperationsLock.unlock(); m_currentOperation = 0; bool stop = false; @@ -170,15 +155,15 @@ bool TexturesGenerator::threadLoop() if (m_currentOperation) { delete m_currentOperation; m_currentOperation = 0; - mRequestedOperationsCond.signal(); } if (!mRequestedOperations.size()) stop = true; if (m_waitForCompletion) { - mRequestedOperationsCond.signal(); m_waitForCompletion = false; + mRequestedOperationsCond.signal(); } mRequestedOperationsLock.unlock(); + } return true; diff --git a/WebCore/platform/graphics/android/TexturesGenerator.h b/WebCore/platform/graphics/android/TexturesGenerator.h index d98eb5b..e36d85e 100644 --- a/WebCore/platform/graphics/android/TexturesGenerator.h +++ b/WebCore/platform/graphics/android/TexturesGenerator.h @@ -61,8 +61,6 @@ private: Vector<QueuedOperation*> mRequestedOperations; android::Mutex mRequestedOperationsLock; android::Condition mRequestedOperationsCond; - android::Mutex m_newRequestLock; - android::Condition m_newRequestCond; bool m_waitForCompletion; QueuedOperation* m_currentOperation; }; 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..8c44bea 100644 --- a/WebCore/platform/graphics/android/TilesManager.h +++ b/WebCore/platform/graphics/android/TilesManager.h @@ -84,9 +84,11 @@ public: void markGeneratorAsReady() { - android::Mutex::Autolock lock(m_generatorLock); + { + android::Mutex::Autolock lock(m_generatorLock); + m_generatorReady = true; + } m_generatorReadyCond.signal(); - m_generatorReady = true; } void printTextures(); @@ -108,6 +110,14 @@ public: m_expandedTileBounds = enabled; } + bool getShowVisualIndicator() { + return m_showVisualIndicator; + } + + void setShowVisualIndicator(bool showVisualIndicator) { + m_showVisualIndicator = showVisualIndicator; + } + private: TilesManager(); @@ -115,7 +125,7 @@ private: void waitForGenerator() { android::Mutex::Autolock lock(m_generatorLock); - if (!m_generatorReady) + while (!m_generatorReady) m_generatorReadyCond.wait(m_generatorLock); } @@ -129,6 +139,8 @@ private: bool m_generatorReady; + bool m_showVisualIndicator; + sp<TexturesGenerator> m_pixmapsGenerationThread; android::Mutex m_texturesLock; diff --git a/WebCore/platform/graphics/android/VideoListener.h b/WebCore/platform/graphics/android/VideoListener.h new file mode 100644 index 0000000..7cac6d6 --- /dev/null +++ b/WebCore/platform/graphics/android/VideoListener.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef VideoListener_h +#define VideoListener_h + +#if USE(ACCELERATED_COMPOSITING) + +#include <gui/SurfaceTexture.h> +#include <jni.h> +#include <JNIUtility.h> +#include "WebCoreJni.h" + +#ifdef DEBUG + +#include <cutils/log.h> +#include <wtf/text/CString.h> + +#undef XLOG +#define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "VideoListener", __VA_ARGS__) + +#else + +#undef XLOG +#define XLOG(...) + +#endif // DEBUG + +namespace WebCore { + +class VideoListener : public android::SurfaceTexture::FrameAvailableListener { + +public: + VideoListener(jobject weakWebViewRef) + : m_weakWebViewRef(weakWebViewRef) + , m_postInvalMethod(0) + , m_frameAvailable(false) + { + if (!m_weakWebViewRef) + return; + + JNIEnv* env = JSC::Bindings::getJNIEnv(); + jobject localWebViewRef = env->NewLocalRef(m_weakWebViewRef); + if (localWebViewRef) { + jclass wvClass = env->GetObjectClass(localWebViewRef); + m_postInvalMethod = env->GetMethodID(wvClass, "postInvalidate", "()V"); + env->DeleteLocalRef(wvClass); + env->DeleteLocalRef(localWebViewRef); + } + checkException(env); + } + + virtual void onFrameAvailable() + { + JNIEnv* env = JSC::Bindings::getJNIEnv(); + jobject localWebViewRef = env->NewLocalRef(m_weakWebViewRef); + if (localWebViewRef) { + env->CallVoidMethod(localWebViewRef, m_postInvalMethod); + env->DeleteLocalRef(localWebViewRef); + } + checkException(env); + if (!m_frameAvailable) { + m_frameAvailable = true; + } + } + + void resetFrameAvailable() { m_frameAvailable = false; } + bool isFrameAvailable() { return m_frameAvailable; } + +private: + jobject m_weakWebViewRef; + jmethodID m_postInvalMethod; + bool m_frameAvailable; +}; + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) +#endif // VideoListener_h 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/platform/image-decoders/jpeg/JPEGImageDecoder.cpp b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp index a2b9f8e..855ba24 100644 --- a/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp +++ b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp @@ -222,6 +222,12 @@ public: // jpeglib cannot convert these to rgb, but it can convert ycck // to cmyk. m_info.out_color_space = JCS_CMYK; + + // Same as with grayscale images, we convert CMYK images to RGBA + // ones. When we keep the color profiles of these CMYK images, + // CoreGraphics will convert their colors again. So, we discard + // their color profiles to prevent color corruption. + m_decoder->setIgnoreGammaAndColorProfile(true); break; default: return m_decoder->setFailed(); diff --git a/WebCore/platform/text/android/HyphenationAndroid.cpp b/WebCore/platform/text/android/HyphenationAndroid.cpp index cff0a66..d1bd839 100644 --- a/WebCore/platform/text/android/HyphenationAndroid.cpp +++ b/WebCore/platform/text/android/HyphenationAndroid.cpp @@ -75,7 +75,7 @@ size_t lastHyphenLocation(const UChar* characters, size_t length, size_t beforeI return 0; char word[maxWordLen]; - int wordLength = 0; + size_t wordLength = 0; for (size_t i = 0; i < length; ++i) { const UChar ch = characters[i]; // Only English for now. diff --git a/WebCore/plugins/android/PluginViewAndroid.cpp b/WebCore/plugins/android/PluginViewAndroid.cpp index b9d7a4f..6c712d0 100644 --- a/WebCore/plugins/android/PluginViewAndroid.cpp +++ b/WebCore/plugins/android/PluginViewAndroid.cpp @@ -108,6 +108,7 @@ extern void ANPWindowInterfaceV0_Init(ANPInterface* value); extern void ANPWindowInterfaceV1_Init(ANPInterface* value); extern void ANPSystemInterfaceV0_Init(ANPInterface* value); extern void ANPSystemInterfaceV1_Init(ANPInterface* value); +extern void ANPSystemInterfaceV2_Init(ANPInterface* value); extern void ANPOpenGLInterfaceV0_Init(ANPInterface* value); extern void ANPVideoInterfaceV0_Init(ANPInterface* value); @@ -136,6 +137,7 @@ static const VarProcPair gVarProcs[] = { { VARPROCLINE(WindowInterfaceV1) }, { VARPROCLINE(SystemInterfaceV0) }, { VARPROCLINE(SystemInterfaceV1) }, + { VARPROCLINE(SystemInterfaceV2) }, { VARPROCLINE(OpenGLInterfaceV0) }, { VARPROCLINE(VideoInterfaceV0) }, }; 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/RenderBlockLineLayout.cpp b/WebCore/rendering/RenderBlockLineLayout.cpp index 6b9fc68..c722136 100644 --- a/WebCore/rendering/RenderBlockLineLayout.cpp +++ b/WebCore/rendering/RenderBlockLineLayout.cpp @@ -609,23 +609,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica else if (fullLayout || o->needsLayout()) { // Replaced elements toRenderBox(o)->dirtyLineBoxes(fullLayout); -#if defined(ANDROID_FLATTEN_IFRAME) || defined(ANDROID_FLATTEN_FRAMESET) - // Android frame flattening during layout() may cause the - // renderer to be destroyed, if for example a frames onresize handler - // deletes the frame - see http://trac.webkit.org/changeset/61070 for example. - // We may be able to remove this protector when we switch to the upstream - // frame flattening code. In the case of an anonymous render object like RenderListMarker - // the document is the DOM node associated with this RenderObject. - RefPtr<Node> protector(o->isAnonymous() ? o->document() : o->node()); -#endif o->layoutIfNeeded(); -#if defined(ANDROID_FLATTEN_IFRAME) || defined(ANDROID_FLATTEN_FRAMESET) - // Ensure that the renderer still exists. If it's gone away we will crash pretty - // fast by continuing to use the now invalid o pointer. If the renderer has gone, - // then there's no point in continuing to try to layout it's children so we break. - if (!protector->renderer()) - break; -#endif } } #else diff --git a/WebCore/rendering/RenderBox.cpp b/WebCore/rendering/RenderBox.cpp index fe78fd5..0944c37 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,28 @@ 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; + } } - 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 +2082,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 +2119,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/RenderFrame.cpp b/WebCore/rendering/RenderFrame.cpp index c3283f8..bc40976 100644 --- a/WebCore/rendering/RenderFrame.cpp +++ b/WebCore/rendering/RenderFrame.cpp @@ -28,12 +28,6 @@ #include "HTMLFrameElement.h" #include "RenderView.h" -#ifdef ANDROID_FLATTEN_FRAMESET -#include "Frame.h" -#include "Document.h" -#include "RenderView.h" -#endif - namespace WebCore { RenderFrame::RenderFrame(HTMLFrameElement* frame) @@ -68,29 +62,29 @@ void RenderFrame::viewCleared() #ifdef ANDROID_FLATTEN_FRAMESET void RenderFrame::layout() { - if (widget() && widget()->isFrameView()) { - FrameView* view = static_cast<FrameView*>(widget()); - RenderView* root = NULL; - if (view->frame() && view->frame()->document() && - view->frame()->document()->renderer() && - view->frame()->document()->renderer()->isRenderView()) - root = static_cast<RenderView*>(view->frame()->document()->renderer()); - if (root) { - // Resize the widget so that the RenderView will layout according to those dimensions. - view->resize(width(), height()); - view->layout(); - // We can only grow in width and height because if positionFrames gives us a width and we become smaller, - // then the fixup process of forcing the frame to fill extra space will fail. - const int docLeft = root->docLeft(); - if (width() > root->docWidth(docLeft)) { - view->resize(root->docWidth(docLeft), 0); - view->layout(); - } - // Honor the height set by RenderFrameSet::positionFrames unless our document height is larger. - setHeight(max(root->docHeight(), height())); - setWidth(max(root->docWidth(docLeft), width())); - } + FrameView* view = static_cast<FrameView*>(widget()); + RenderView* root = view ? view->frame()->contentRenderer() : 0; + if (!width() || !height() || !root) { + setNeedsLayout(false); + return; } + + HTMLFrameElementBase* element = static_cast<HTMLFrameElementBase*>(node()); + if (element->scrollingMode() == ScrollbarAlwaysOff && !root->isFrameSet()) { + setNeedsLayout(false); + return; + } + + int layoutWidth = width(); + + setWidth(max(view->contentsWidth() + borderAndPaddingWidth(), width())); + setHeight(max(view->contentsHeight() + borderAndPaddingHeight(), height())); + + // This should trigger a layout of the FrameView which will schedule a + // relayout of this RenderFrame. + if (layoutWidth < width()) + setHeight(0); + setNeedsLayout(false); } #endif diff --git a/WebCore/rendering/RenderIFrame.cpp b/WebCore/rendering/RenderIFrame.cpp index 36d2449..19bca49 100644 --- a/WebCore/rendering/RenderIFrame.cpp +++ b/WebCore/rendering/RenderIFrame.cpp @@ -44,30 +44,6 @@ RenderIFrame::RenderIFrame(Element* element) void RenderIFrame::computeLogicalHeight() { RenderPart::computeLogicalHeight(); -#ifdef ANDROID_FLATTEN_IFRAME - if (!node()->hasTagName(iframeTag) || !widget() || !widget()->isFrameView()) - return; - FrameView* view = static_cast<FrameView*>(widget()); - RenderView* root = static_cast<RenderView*>(view->frame()->contentRenderer()); - if (!root) - return; - // Do not expand if the scrollbars are suppressed and the height is fixed. - bool scrolling = static_cast<HTMLIFrameElement*>(node())->scrollingMode() != ScrollbarAlwaysOff; - if (!scrolling && style()->height().isFixed()) - return; - // Update the widget - updateWidgetPosition(); - - // Layout to get the content height - view->layout(); - - int extraHeight = paddingTop() + paddingBottom() + borderTop() + borderBottom(); - setHeight(max(width(), view->contentsHeight() + extraHeight)); - - // Update one last time to ensure the dimensions. - updateWidgetPosition(); - return; -#endif if (!flattenFrame()) return; @@ -86,38 +62,6 @@ void RenderIFrame::computeLogicalHeight() void RenderIFrame::computeLogicalWidth() { RenderPart::computeLogicalWidth(); -#ifdef ANDROID_FLATTEN_IFRAME - if (!node()->hasTagName(iframeTag) || !widget() || !widget()->isFrameView()) - return; - FrameView* view = static_cast<FrameView*>(widget()); - RenderView* root = static_cast<RenderView*>(view->frame()->contentRenderer()); - if (!root) - return; - // Do not expand if the scrollbars are suppressed and the width is fixed. - bool scrolling = static_cast<HTMLIFrameElement*>(node())->scrollingMode() != ScrollbarAlwaysOff; - if (!scrolling && style()->width().isFixed()) - return; - // Update the dimensions to get the correct minimum preferred - // width - updateWidgetPosition(); - - int extraWidth = paddingLeft() + paddingRight() + borderLeft() + borderRight(); - // Set the width - setWidth(max(width(), root->minPreferredLogicalWidth()) + extraWidth); - - // Update based on the new width - updateWidgetPosition(); - - // Layout to get the content width - view->layout(); - - setWidth(max(width(), view->contentsWidth() + extraWidth)); - - // Update one last time to ensure the dimensions. - updateWidgetPosition(); - return; -#endif - if (!flattenFrame()) return; @@ -166,79 +110,6 @@ void RenderIFrame::layout() RenderPart::computeLogicalWidth(); RenderPart::computeLogicalHeight(); -#ifdef ANDROID_FLATTEN_IFRAME - // Calculate the styled dimensions by subtracting the border and padding. - int extraWidth = paddingLeft() + paddingRight() + borderLeft() + borderRight(); - int extraHeight = paddingTop() + paddingBottom() + borderTop() + borderBottom(); - int styleWidth = width() - extraWidth; - int styleHeight = height() - extraHeight; - // Some IFrames have a width and/or height of 1 when they are meant to be - // hidden. If that is the case, do not try to expand. - if (node()->hasTagName(iframeTag) && widget() && widget()->isFrameView() && - styleWidth > 1 && styleHeight > 1) { - HTMLIFrameElement* element = static_cast<HTMLIFrameElement*>(node()); - bool scrolling = element->scrollingMode() != ScrollbarAlwaysOff; - bool widthIsFixed = style()->width().isFixed(); - bool heightIsFixed = style()->height().isFixed(); - // If an iframe has a fixed dimension and suppresses scrollbars, it - // will disrupt layout if we force it to expand. Plus on a desktop, - // the extra content is not accessible. - if (scrolling || !widthIsFixed || !heightIsFixed) { - FrameView* view = static_cast<FrameView*>(widget()); - RenderView* root = view ? view->frame()->contentRenderer() : NULL; - if (root && style()->visibility() != HIDDEN) { - // Update the dimensions to get the correct minimum preferred - // width - updateWidgetPosition(); - - // Use the preferred width if it is larger and only if - // scrollbars are visible or the width style is not fixed. - if (scrolling || !widthIsFixed) - setWidth(max(width(), root->minPreferredLogicalWidth()) + extraWidth); - - // Resize the view to recalc the height. - int h = height() - extraHeight; - int w = width() - extraWidth; - if (w > view->width()) - h = 0; - if (w != view->width() || h != view->height()) { - view->resize(w, h); - } - - // Layout the view. - view->layout(); - - int contentHeight = view->contentsHeight(); - int contentWidth = view->contentsWidth(); - // Only change the width or height if scrollbars are visible or - // if the style is not a fixed value. Use the maximum value so - // that iframes never shrink. - if (scrolling || !heightIsFixed) - setHeight(max(height(), contentHeight + extraHeight)); - if (scrolling || !widthIsFixed) - setWidth(max(width(), contentWidth + extraWidth)); - - // Update one last time - updateWidgetPosition(); - - // Layout one more time to ensure all objects have the correct - // height. - view->layout(); - -#if !ASSERT_DISABLED - ASSERT(!view->layoutPending()); - ASSERT(!root->needsLayout()); - // Sanity check when assertions are enabled. - RenderObject* c = root->nextInPreOrder(); - while (c) { - ASSERT(!c->needsLayout()); - c = c->nextInPreOrder(); - } -#endif - } - } - } -#endif if (flattenFrame()) { layoutWithFlattening(style()->width().isFixed(), style()->height().isFixed()); return; diff --git a/WebCore/rendering/RenderLayer.cpp b/WebCore/rendering/RenderLayer.cpp index b850ba3..f055e34 100644 --- a/WebCore/rendering/RenderLayer.cpp +++ b/WebCore/rendering/RenderLayer.cpp @@ -62,6 +62,9 @@ #include "GraphicsContext.h" #include "HTMLFrameOwnerElement.h" #include "HTMLNames.h" +#if ENABLE(ANDROID_OVERFLOW_SCROLL) +#include "HTMLTextAreaElement.h" +#endif #include "HitTestRequest.h" #include "HitTestResult.h" #include "OverflowEvent.h" @@ -1159,14 +1162,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. @@ -2183,7 +2178,9 @@ RenderLayer::updateScrollInfoAfterLayout() #if ENABLE(ANDROID_OVERFLOW_SCROLL) bool hasOverflowScroll = ((horizontalOverflow && m_hBar) || (verticalOverflow && m_vBar)) - && !renderer()->isTextArea(); + // Disable UI side scrolling for textareas, unless they are readonly. + && (!renderer()->isTextArea() || (renderer()->node() + && static_cast<HTMLTextAreaElement*>(renderer()->node())->readOnly())); if (hasOverflowScroll != m_hasOverflowScroll) { m_hasOverflowScroll = hasOverflowScroll; dirtyZOrderLists(); 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..6578d1d 100644 --- a/WebCore/rendering/RenderLayerCompositor.cpp +++ b/WebCore/rendering/RenderLayerCompositor.cpp @@ -1193,27 +1193,10 @@ 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 - // following checks are true: - // 1) - the viewport width is either undefined (-1) or equal to device-width (0), and - // 2) - no scaling is allowed - if (!layer->isFixed()) - return false; - - Settings* settings = m_renderView->document()->settings(); - if (!settings) - return false; - - if ((settings->viewportWidth() == -1 || settings->viewportWidth() == 0) && - !settings->viewportUserScalable()) + if (layer->isFixed()) return true; - #endif return false; } @@ -1288,6 +1271,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/rendering/RenderView.h b/WebCore/rendering/RenderView.h index 66b1d74..8436762 100644 --- a/WebCore/rendering/RenderView.h +++ b/WebCore/rendering/RenderView.h @@ -176,9 +176,6 @@ protected: private: bool shouldRepaint(const IntRect& r) const; -#ifdef ANDROID_FLATTEN_FRAMESET -public: // used by layout function -#endif int docHeight() const; int docLeft() const; int docWidth(int leftOverflow) const; diff --git a/WebCore/rendering/RenderWidget.cpp b/WebCore/rendering/RenderWidget.cpp index e5ccd05..6ea620f 100644 --- a/WebCore/rendering/RenderWidget.cpp +++ b/WebCore/rendering/RenderWidget.cpp @@ -345,7 +345,6 @@ void RenderWidget::updateWidgetPosition() bool boundsChanged = setWidgetGeometry(IntRect(absPos.x(), absPos.y(), w, h)); -#ifndef ANDROID_FLATTEN_IFRAME // if the frame bounds got changed, or if view needs layout (possibly indicating // content size is wrong) we have to do a layout to set the right widget size if (m_widget && m_widget->isFrameView()) { @@ -354,7 +353,6 @@ void RenderWidget::updateWidgetPosition() if ((boundsChanged || frameView->needsLayout()) && frameView->frame()->page()) frameView->layout(); } -#endif } void RenderWidget::widgetPositionsUpdated() 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/RenderSkinRadio.cpp b/WebKit/android/RenderSkinRadio.cpp index ef26f01..5dfee4a 100644 --- a/WebKit/android/RenderSkinRadio.cpp +++ b/WebKit/android/RenderSkinRadio.cpp @@ -38,10 +38,10 @@ #include "SkRect.h" #include <wtf/text/CString.h> -static const char* checks[] = { "btn_check_off.png", - "btn_check_on.png", - "btn_radio_off.png", - "btn_radio_on.png"}; +static const char* checks[] = { "btn_check_off_holo.png", + "btn_check_on_holo.png", + "btn_radio_off_holo.png", + "btn_radio_on_holo.png"}; // Matches the width of the bitmap static SkScalar SIZE; diff --git a/WebKit/android/WebCoreSupport/CacheResult.cpp b/WebKit/android/WebCoreSupport/CacheResult.cpp index 91c0ede..5309c66 100644 --- a/WebKit/android/WebCoreSupport/CacheResult.cpp +++ b/WebKit/android/WebCoreSupport/CacheResult.cpp @@ -89,7 +89,7 @@ String CacheResult::mimeType() const if (responseHeaders()) responseHeaders()->GetMimeType(&mimeType); if (!mimeType.length() && m_url.length()) - mimeType = WebResponse::resolveMimeType(std::string(m_url.utf8().data(), m_url.length())); + mimeType = WebResponse::resolveMimeType(std::string(m_url.utf8().data(), m_url.length()), ""); return String(mimeType.c_str()); } 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/WebRequestContext.cpp b/WebKit/android/WebCoreSupport/WebRequestContext.cpp index 341a23c..78c3501 100644 --- a/WebKit/android/WebCoreSupport/WebRequestContext.cpp +++ b/WebKit/android/WebCoreSupport/WebRequestContext.cpp @@ -39,6 +39,8 @@ static WTF::Mutex acceptLanguageMutex; static int numPrivateBrowsingInstances; +extern void ANPSystemInterface_CleanupIncognito(); + using namespace WTF; namespace android { @@ -79,6 +81,7 @@ WebRequestContext::~WebRequestContext() if (!numPrivateBrowsingInstances) { WebCookieJar::cleanup(true); WebCache::cleanup(true); + ANPSystemInterface_CleanupIncognito(); } } } diff --git a/WebKit/android/WebCoreSupport/WebResponse.cpp b/WebKit/android/WebCoreSupport/WebResponse.cpp index f4e64bb..4d297d7 100644 --- a/WebKit/android/WebCoreSupport/WebResponse.cpp +++ b/WebKit/android/WebCoreSupport/WebResponse.cpp @@ -120,16 +120,16 @@ const string& WebResponse::getMimeType() return m_mime; if (!m_mime.length() || !m_mime.compare("text/plain") || !m_mime.compare("application/octet-stream")) - m_mime = resolveMimeType(m_url); + m_mime = resolveMimeType(m_url, m_mime); return m_mime; } -const string WebResponse::resolveMimeType(string url) +const string WebResponse::resolveMimeType(const string& url, const string& old_mime) { // Use "text/html" as a default (matching the behaviour of the Apache // HTTP stack -- see guessMimeType() in LoadListener.java). - string mimeType = "text/html"; + string mimeType = old_mime.length() ? old_mime : "text/html"; // Try to guess a better MIME type from the URL. We call // getMIMETypeForExtension rather than getMIMETypeForPath because the // latter defaults to "application/octet-stream" on failure. diff --git a/WebKit/android/WebCoreSupport/WebResponse.h b/WebKit/android/WebCoreSupport/WebResponse.h index baae9a0..88c8917 100644 --- a/WebKit/android/WebCoreSupport/WebResponse.h +++ b/WebKit/android/WebCoreSupport/WebResponse.h @@ -61,7 +61,7 @@ public: WebCore::ResourceResponse createResourceResponse(); WebCore::ResourceError createResourceError(); - static const std::string resolveMimeType(std::string url); + static const std::string resolveMimeType(const std::string& url, const std::string& old_mime); private: net::Error m_error; 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..96dd04c 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()); @@ -221,7 +224,7 @@ void WebUrlLoaderClient::downloadFile() if (m_response) { std::string contentDisposition; m_response->getHeader("content-disposition", &contentDisposition); - m_webFrame->downloadStart(m_request->getUrl(), m_request->getUserAgent(), contentDisposition, m_response->getMimeType(), m_response->getExpectedSize()); + m_webFrame->downloadStart(m_response->getUrl(), m_request->getUserAgent(), contentDisposition, m_response->getMimeType(), m_response->getExpectedSize()); m_isCertMimeType = isMimeTypeForCert(m_response->getMimeType()); // Currently, only certificate mime type needs to receive the data. @@ -287,26 +290,18 @@ void WebUrlLoaderClient::cancelAuth() void WebUrlLoaderClient::proceedSslCertError() { - if (!isActive()) - return; - base::Thread* thread = ioThread(); - if (!thread) { - return; - } - thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::proceedSslCertError)); + if (isActive() && thread) + thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::proceedSslCertError)); + this->Release(); } void WebUrlLoaderClient::cancelSslCertError(int cert_error) { - if (!isActive()) - return; - base::Thread* thread = ioThread(); - if (!thread) { - return; - } - thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::cancelSslCertError, cert_error)); + if (isActive() && thread) + thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::cancelSslCertError, cert_error)); + this->Release(); } @@ -344,30 +339,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 +348,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]); } } } @@ -485,6 +454,7 @@ void WebUrlLoaderClient::reportSslCertError(int cert_error, net::X509Certificate std::vector<std::string> chain_bytes; cert->GetChainDEREncodedBytes(&chain_bytes); + this->AddRef(); m_webFrame->reportSslCertError(this, cert_error, 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..0bdf303 100644 --- a/WebKit/android/jni/CookieManager.cpp +++ b/WebKit/android/jni/CookieManager.cpp @@ -54,13 +54,13 @@ static bool acceptCookie(JNIEnv*, jobject) #endif } -static jstring getCookie(JNIEnv* env, jobject, jstring url) +static jstring getCookie(JNIEnv* env, jobject, jstring url, jboolean privateBrowsing) { #if USE(CHROME_NETWORK_STACK) GURL gurl(jstringToStdString(env, url)); CookieOptions options; options.set_include_httponly(); - std::string cookies = WebCookieJar::get(false)->cookieStore()->GetCookieMonster()->GetCookiesWithOptions(gurl, options); + std::string cookies = WebCookieJar::get(privateBrowsing)->cookieStore()->GetCookieMonster()->GetCookiesWithOptions(gurl, options); return stdStringToJstring(env, cookies); #else // The Android HTTP stack is implemented Java-side. @@ -69,10 +69,10 @@ static jstring getCookie(JNIEnv* env, jobject, jstring url) #endif } -static bool hasCookies(JNIEnv*, jobject) +static bool hasCookies(JNIEnv*, jobject, jboolean privateBrowsing) { #if USE(CHROME_NETWORK_STACK) - return WebCookieJar::get(false)->getNumCookiesInDatabase() > 0; + return WebCookieJar::get(privateBrowsing)->getNumCookiesInDatabase() > 0; #else // The Android HTTP stack is implemented Java-side. ASSERT_NOT_REACHED(); @@ -137,14 +137,14 @@ static void setAcceptCookie(JNIEnv*, jobject, jboolean accept) #endif } -static void setCookie(JNIEnv* env, jobject, jstring url, jstring value) +static void setCookie(JNIEnv* env, jobject, jstring url, jstring value, jboolean privateBrowsing) { #if USE(CHROME_NETWORK_STACK) GURL gurl(jstringToStdString(env, url)); std::string line(jstringToStdString(env, value)); CookieOptions options; options.set_include_httponly(); - WebCookieJar::get(false)->cookieStore()->GetCookieMonster()->SetCookieWithOptions(gurl, line, options); + WebCookieJar::get(privateBrowsing)->cookieStore()->GetCookieMonster()->SetCookieWithOptions(gurl, line, options); #endif } @@ -155,16 +155,37 @@ 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 }, - { "nativeHasCookies", "()Z", (void*) hasCookies }, + { "nativeGetCookie", "(Ljava/lang/String;Z)Ljava/lang/String;", (void*) getCookie }, + { "nativeHasCookies", "(Z)Z", (void*) hasCookies }, { "nativeRemoveAllCookie", "()V", (void*) removeAllCookie }, { "nativeRemoveExpiredCookie", "()V", (void*) removeExpiredCookie }, { "nativeRemoveSessionCookie", "()V", (void*) removeSessionCookie }, { "nativeSetAcceptCookie", "(Z)V", (void*) setAcceptCookie }, - { "nativeSetCookie", "(Ljava/lang/String;Ljava/lang/String;)V", (void*) setCookie }, + { "nativeSetCookie", "(Ljava/lang/String;Ljava/lang/String;Z)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/PictureSet.cpp b/WebKit/android/jni/PictureSet.cpp index 98cda23..6dafd26 100644 --- a/WebKit/android/jni/PictureSet.cpp +++ b/WebKit/android/jni/PictureSet.cpp @@ -68,7 +68,7 @@ PictureSet::~PictureSet() void PictureSet::add(const Pictures* temp) { Pictures pictureAndBounds = *temp; - pictureAndBounds.mPicture->safeRef(); + SkSafeRef(pictureAndBounds.mPicture); pictureAndBounds.mWroteElapsed = false; mPictures.append(pictureAndBounds); } @@ -80,7 +80,7 @@ void PictureSet::add(const SkRegion& area, SkPicture* picture, area.getBounds().fLeft, area.getBounds().fTop, area.getBounds().fRight, area.getBounds().fBottom, picture, elapsed, split); - picture->safeRef(); + SkSafeRef(picture); /* if nothing is drawn beneath part of the new picture, mark it as a base */ SkRegion diff = SkRegion(area); Pictures* last = mPictures.end(); @@ -150,7 +150,7 @@ bool PictureSet::build() } } if (tossPicture) { - working->mPicture->safeUnref(); + SkSafeUnref(working->mPicture); working->mPicture = NULL; // mark to redraw } if (working->mPicture == NULL) // may have been set to null elsewhere @@ -211,7 +211,7 @@ void PictureSet::clear() Pictures* last = mPictures.end(); for (Pictures* working = mPictures.begin(); working != last; working++) { working->mArea.setEmpty(); - working->mPicture->safeUnref(); + SkSafeUnref(working->mPicture); } mPictures.clear(); mWidth = mHeight = 0; @@ -362,7 +362,7 @@ public: return true; } - virtual void commonDrawBitmap(const SkBitmap& bitmap, + virtual void commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* rect, const SkMatrix& , const SkPaint& ) { if (bitmap.width() <= 1 || bitmap.height() <= 1) return; @@ -476,7 +476,7 @@ bool PictureSet::reuseSubdivided(const SkRegion& inval) if ((working->mSplit == false || invalBounds != working->mUnsplit) && inval.contains(working->mArea) == false) continue; - working->mPicture->safeUnref(); + SkSafeUnref(working->mPicture); working->mPicture = NULL; } return true; @@ -526,7 +526,7 @@ void PictureSet::setDrawTimes(const PictureSet& src) void PictureSet::setPicture(size_t i, SkPicture* p) { - mPictures[i].mPicture->safeUnref(); + SkSafeUnref(mPictures[i].mPicture); mPictures[i].mPicture = p; mPictures[i].mEmpty = emptyPicture(p); } diff --git a/WebKit/android/jni/WebCoreFrameBridge.cpp b/WebKit/android/jni/WebCoreFrameBridge.cpp index 9780d2d..f800e2d 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 @@ -1402,6 +1417,9 @@ static jstring SaveWebArchive(JNIEnv *env, jobject obj, jstring basename, jboole #if ENABLE(ARCHIVE) WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj); LOG_ASSERT(pFrame, "nativeSaveWebArchive must take a valid frame pointer!"); + String mimeType = pFrame->loader()->documentLoader()->mainResource()->mimeType(); + if ((mimeType != "text/html") && (mimeType != "application/xhtml+xml")) + return NULL; const char* basenameNative = getCharactersFromJStringInEnv(env, basename); String basenameString = String::fromUTF8(basenameNative); @@ -1876,62 +1894,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 +2050,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/WebCoreJni.h b/WebKit/android/jni/WebCoreJni.h index 6e6a486..ec25c8f 100644 --- a/WebKit/android/jni/WebCoreJni.h +++ b/WebKit/android/jni/WebCoreJni.h @@ -36,6 +36,9 @@ namespace android { // returned from getRealObject. class AutoJObject { public: + AutoJObject(const AutoJObject& other) + : m_env(other.m_env) + , m_obj(other.m_obj ? other.m_env->NewLocalRef(other.m_obj) : NULL) {} ~AutoJObject() { if (m_obj) m_env->DeleteLocalRef(m_obj); @@ -54,6 +57,7 @@ public: return m_env; } private: + AutoJObject(); // Not permitted. AutoJObject(JNIEnv* env, jobject obj) : m_env(env) , m_obj(obj) {} diff --git a/WebKit/android/jni/WebViewCore.cpp b/WebKit/android/jni/WebViewCore.cpp index b329e3b..5744609 100644 --- a/WebKit/android/jni/WebViewCore.cpp +++ b/WebKit/android/jni/WebViewCore.cpp @@ -29,12 +29,15 @@ #include "WebViewCore.h" #include "AccessibilityObject.h" +#include "Attribute.h" #include "BaseLayerAndroid.h" #include "CachedNode.h" #include "CachedRoot.h" #include "Chrome.h" #include "ChromeClientAndroid.h" #include "ChromiumIncludes.h" +#include "ClientRect.h" +#include "ClientRectList.h" #include "Color.h" #include "CSSPropertyNames.h" #include "CSSValueKeywords.h" @@ -76,6 +79,7 @@ #include "HitTestResult.h" #include "InlineTextBox.h" #include "MemoryUsage.h" +#include "NamedNodeMap.h" #include "Navigator.h" #include "Node.h" #include "NodeList.h" @@ -250,9 +254,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; @@ -343,15 +345,14 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m m_isPaused = false; m_screenOnCounter = 0; m_onlyScrollIfImeIsShowing = false; + m_shouldPaintCaret = true; LOG_ASSERT(m_mainFrame, "Uh oh, somehow a frameview was made without an initial frame!"); 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 +488,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; } @@ -674,7 +673,7 @@ void WebViewCore::recordPictureSet(PictureSet* content) DBG_SET_LOGD("{%d,%d,w=%d,h=%d}", inval.fLeft, inval.fTop, inval.width(), inval.height()); content->add(m_addInval, picture, 0, false); - picture->safeUnref(); + SkSafeUnref(picture); } // Remove any pictures already in the set that are obscured by the new one, // and check to see if any already split pieces need to be redrawn. @@ -948,11 +947,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 +970,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 +1140,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 +1156,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 +1220,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, @@ -1489,7 +1483,7 @@ void WebViewCore::revealSelection() WebCore::Frame* focusedFrame = focus->document()->frame(); if (!focusedFrame->page()->focusController()->isActive()) return; - focusedFrame->selection()->revealSelection(); + focusedFrame->selection()->revealSelection(ScrollAlignment::alignToEdgeIfNeeded); } void WebViewCore::updateCacheOnNodeChange() @@ -2081,7 +2075,7 @@ void WebViewCore::setSelection(int start, int end) // For password fields, this is done in the UI side via // bringPointIntoView, since the UI does the drawing. if (renderer->isTextArea() || !isPasswordField) - focusedFrame->selection()->revealSelection(); + revealSelection(); } String WebViewCore::modifySelection(const int direction, const int axis) @@ -2090,18 +2084,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 +2123,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 +2151,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 +2166,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 +2233,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 +2354,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; +} + +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::isVisibleNonEmptyNonWhitespaceTextNode(Node* node) +bool WebViewCore::isContentTextNode(Node* node) { if (!node || !node->isTextNode()) return false; @@ -2532,21 +2492,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 +2644,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 +2676,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 +2726,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 +2742,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); @@ -2783,6 +2761,7 @@ void WebViewCore::deleteSelection(int start, int end, int textGeneration) key(up); client->setUiGeneratedSelectionChange(false); m_textGeneration = textGeneration; + m_shouldPaintCaret = true; } void WebViewCore::replaceTextfieldText(int oldStart, @@ -2804,6 +2783,7 @@ void WebViewCore::replaceTextfieldText(int oldStart, // setSelection calls revealSelection, so there is no need to do it here. setSelection(start, end); m_textGeneration = textGeneration; + m_shouldPaintCaret = true; } void WebViewCore::passToJs(int generation, const WTF::String& current, @@ -2843,6 +2823,7 @@ void WebViewCore::passToJs(int generation, const WTF::String& current, } // Now that the selection has settled down, send it. updateTextSelection(); + m_shouldPaintCaret = true; } void WebViewCore::scrollFocusedTextInput(float xPercent, int y) @@ -2888,94 +2869,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) { @@ -3226,49 +3119,20 @@ void WebViewCore::touchUp(int touchGeneration, handleMouseClick(frame, node, false); } -// Return the RenderLayer for the given RenderObject only if the layer is -// composited and it contains a scrollable content layer. -static WebCore::RenderLayer* getScrollingLayerFromRenderer( - WebCore::RenderObject* renderer) -{ -#if ENABLE(ANDROID_OVERFLOW_SCROLL) - if (!renderer) - return 0; - WebCore::RenderLayer* layer = renderer->enclosingSelfPaintingLayer(); - if (!layer) - return 0; - // Find the layer that actually has overflow scroll in case this renderer is - // inside a child layer. - while (layer && !layer->hasOverflowScroll()) - layer = layer->parent(); - return layer; -#endif - return 0; -} - -// Scroll the RenderLayer associated with a scrollable div element. This is -// done so that the node is visible when it is clicked. -static void scrollLayer(WebCore::RenderObject* renderer, WebCore::IntPoint* pos) -{ - WebCore::RenderLayer* layer = getScrollingLayerFromRenderer(renderer); - if (!layer) - return; - // The cache uses absolute coordinates when clicking on nodes and it assumes - // the layer is not scrolled. - layer->scrollToOffset(0, 0, true, false); - - WebCore::IntRect absBounds = renderer->absoluteBoundingBoxRect(); - // Do not include the outline when moving the node's bounds. - WebCore::IntRect layerBounds = layer->renderer()->absoluteBoundingBoxRect(); - - // Move the node's bounds into the layer's coordinates. - absBounds.move(-layerBounds.x(), -layerBounds.y()); - - // Scroll the layer to the node's position. - layer->scrollToOffset(absBounds.x(), absBounds.y(), true, true); - - // Update the mouse position to the layer offset. - pos->move(-layer->scrollXOffset(), -layer->scrollYOffset()); +// Check for the "x-webkit-soft-keyboard" attribute. If it is there and +// set to hidden, do not show the soft keyboard. Node passed as a parameter +// must not be null. +static bool shouldSuppressKeyboard(const WebCore::Node* node) { + LOG_ASSERT(node, "node passed to shouldSuppressKeyboard cannot be null"); + const NamedNodeMap* attributes = node->attributes(); + if (!attributes) return false; + size_t length = attributes->length(); + for (size_t i = 0; i < length; i++) { + const Attribute* a = attributes->attributeItem(i); + if (a->localName() == "x-webkit-soft-keyboard" && a->value() == "hidden") + return true; + } + return false; } // Common code for both clicking with the trackball and touchUp @@ -3289,47 +3153,6 @@ bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* node DBG_NAV_LOG("area"); 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); } if (!valid || !framePtr) framePtr = m_mainFrame; @@ -3353,8 +3176,8 @@ bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* node if (focusNode) { WebCore::RenderObject* renderer = focusNode->renderer(); if (renderer && (renderer->isTextField() || renderer->isTextArea())) { - bool ime = !(static_cast<WebCore::HTMLInputElement*>(focusNode)) - ->readOnly(); + bool ime = !shouldSuppressKeyboard(focusNode) + && !(static_cast<WebCore::HTMLInputElement*>(focusNode))->readOnly(); if (ime) { #if ENABLE(WEB_AUTOFILL) if (renderer->isTextField()) { @@ -3418,15 +3241,15 @@ void WebViewCore::formDidBlur(const WebCore::Node* node) void WebViewCore::focusNodeChanged(const WebCore::Node* newFocus) { - if (!m_blurringNodePointer) - return; - if (!isTextInput(newFocus)) { + if (isTextInput(newFocus)) + m_shouldPaintCaret = true; + else if (m_blurringNodePointer) { JNIEnv* env = JSC::Bindings::getJNIEnv(); env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_formDidBlur, m_blurringNodePointer); checkException(env); + m_blurringNodePointer = 0; } - m_blurringNodePointer = 0; } void WebViewCore::addMessageToConsole(const WTF::String& message, unsigned int lineNumber, const WTF::String& sourceID, int msgLevel) { @@ -3537,13 +3360,13 @@ bool WebViewCore::jsConfirm(const WTF::String& url, const WTF::String& text) bool WebViewCore::jsPrompt(const WTF::String& url, const WTF::String& text, const WTF::String& defaultValue, WTF::String& result) { JNIEnv* env = JSC::Bindings::getJNIEnv(); + jstring jUrlStr = wtfStringToJstring(env, url); jstring jInputStr = wtfStringToJstring(env, text); jstring jDefaultStr = wtfStringToJstring(env, defaultValue); - jstring jUrlStr = wtfStringToJstring(env, url); jstring returnVal = static_cast<jstring>(env->CallObjectMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsPrompt, jUrlStr, jInputStr, jDefaultStr)); + env->DeleteLocalRef(jUrlStr); env->DeleteLocalRef(jInputStr); env->DeleteLocalRef(jDefaultStr); - env->DeleteLocalRef(jUrlStr); checkException(env); // If returnVal is null, it means that the user cancelled the dialog. @@ -3551,6 +3374,7 @@ bool WebViewCore::jsPrompt(const WTF::String& url, const WTF::String& text, cons return false; result = jstringToWtfString(env, returnVal); + env->DeleteLocalRef(returnVal); return true; } @@ -3795,10 +3619,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 @@ -3838,6 +3664,30 @@ WebRequestContext* WebViewCore::webRequestContext() } #endif +void WebViewCore::scrollRenderLayer(int layer, const SkRect& rect) +{ +#if USE(ACCELERATED_COMPOSITING) + GraphicsLayerAndroid* root = graphicsRootLayer(); + if (!root) + return; + + LayerAndroid* layerAndroid = root->platformLayer(); + if (!layerAndroid) + return; + + LayerAndroid* target = layerAndroid->findById(layer); + if (!target) + return; + + RenderLayer* owner = target->owningLayer(); + if (!owner) + return; + + if (owner->stackingContext()) + owner->scrollToOffset(rect.fLeft, rect.fTop, true, false); +#endif +} + //---------------------------------------------------------------------- // Native JNI methods //---------------------------------------------------------------------- @@ -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, @@ -4192,6 +4042,11 @@ static jstring RetrieveImageSource(JNIEnv *env, jobject obj, jint x, jint y) return !result.isEmpty() ? wtfStringToJstring(env, result) : 0; } +static void StopPaintingCaret(JNIEnv *env, jobject obj) +{ + GET_NATIVE_VIEW(env, obj)->setShouldPaintCaret(false); +} + static void MoveFocus(JNIEnv *env, jobject obj, jint framePtr, jint nodePtr) { #ifdef ANDROID_INSTRUMENT @@ -4519,6 +4374,13 @@ static void AutoFillForm(JNIEnv* env, jobject obj, jint queryId) #endif } +static void ScrollRenderLayer(JNIEnv* env, jobject obj, jint layer, jobject jRect) +{ + SkRect rect; + GraphicsJNI::jrect_to_rect(env, jRect, &rect); + GET_NATIVE_VIEW(env, obj)->scrollRenderLayer(layer, rect); +} + // ---------------------------------------------------------------------------- /* @@ -4541,7 +4403,7 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = { (void*) SendListBoxChoice }, { "nativeSetSize", "(IIIFIIIIZ)V", (void*) SetSize }, - { "nativeSetScrollOffset", "(IIII)V", + { "nativeSetScrollOffset", "(IZII)V", (void*) SetScrollOffset }, { "nativeSetGlobalBounds", "(IIII)V", (void*) SetGlobalBounds }, @@ -4579,6 +4441,8 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = { (void*) RetrieveAnchorText }, { "nativeRetrieveImageSource", "(II)Ljava/lang/String;", (void*) RetrieveImageSource }, + { "nativeStopPaintingCaret", "()V", + (void*) StopPaintingCaret }, { "nativeUpdateFrameCache", "()V", (void*) UpdateFrameCache }, { "nativeGetContentMinPrefWidth", "()I", @@ -4626,6 +4490,8 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = { (void*) GetTouchHighlightRects }, { "nativeAutoFillForm", "(I)V", (void*) AutoFillForm }, + { "nativeScrollLayer", "(ILandroid/graphics/Rect;)V", + (void*) ScrollRenderLayer }, }; int registerWebViewCore(JNIEnv* env) diff --git a/WebKit/android/jni/WebViewCore.h b/WebKit/android/jni/WebViewCore.h index 5820dc5..be8de94 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); @@ -554,6 +546,8 @@ namespace android { void listBoxRequest(WebCoreReply* reply, const uint16_t** labels, size_t count, const int enabled[], size_t enabledCount, bool multiple, const int selected[], size_t selectedCountOrSelection); + bool shouldPaintCaret() { return m_shouldPaintCaret; } + void setShouldPaintCaret(bool should) { m_shouldPaintCaret = should; } // these members are shared with webview.cpp static Mutex gFrameCacheMutex; @@ -579,15 +573,19 @@ 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); WebRequestContext* webRequestContext(); #endif + + // Attempts to scroll the layer to the x,y coordinates of rect. The + // layer is the id of the LayerAndroid. + void scrollRenderLayer(int layer, const SkRect& rect); + // end of shared members // internal functions @@ -638,11 +636,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; @@ -650,6 +643,7 @@ namespace android { PageGroup* m_groupForVisitedLinks; bool m_isPaused; int m_cacheMode; + bool m_shouldPaintCaret; SkTDArray<PluginWidgetAndroid*> m_plugins; WebCore::Timer<WebViewCore> m_pluginInvalTimer; @@ -677,18 +671,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..f45572a 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; @@ -1239,6 +1241,8 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, if (node->hasTagName(WebCore::HTMLNames::inputTag)) { HTMLInputElement* input = static_cast<HTMLInputElement*>(node); if (input->isTextField()) { + if (input->readOnly()) + continue; type = TEXT_INPUT_CACHEDNODETYPE; cachedInput.init(); cachedInput.setAutoComplete(input->autoComplete()); @@ -1257,9 +1261,11 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, else if (input->isRadioButton() || input->isCheckbox()) isTransparent = false; } else if (node->hasTagName(HTMLNames::textareaTag)) { + HTMLTextAreaElement* area = static_cast<HTMLTextAreaElement*>(node); + if (area->readOnly()) + continue; cachedInput.init(); type = TEXT_INPUT_CACHEDNODETYPE; - HTMLTextAreaElement* area = static_cast<HTMLTextAreaElement*>(node); cachedInput.setFormPointer(area->form()); cachedInput.setIsTextArea(true); exported = area->value().threadsafeCopy(); @@ -1328,7 +1334,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 +1419,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 +3032,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 +3084,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..b26e24b 100644 --- a/WebKit/android/nav/CachedFrame.cpp +++ b/WebKit/android/nav/CachedFrame.cpp @@ -65,24 +65,6 @@ WebCore::IntRect CachedFrame::adjustBounds(const CachedNode* node, return rect; } -// This is for nodes inside a layer. It takes an IntRect that has been -// adjusted by the layer's position and removes the adjustment made by the -// layer. -WebCore::IntRect CachedFrame::unadjustBounds(const CachedNode* node, - const WebCore::IntRect& rect) const -{ -#if USE(ACCELERATED_COMPOSITING) - if (node->isInLayer()) { - const CachedLayer* cachedLayer = layer(node); - const WebCore::LayerAndroid* rootLayer = mRoot->rootLayer(); - const LayerAndroid* aLayer = cachedLayer->layer(rootLayer); - if (aLayer) - return cachedLayer->unadjustBounds(rootLayer, rect); - } -#endif - return rect; -} - bool CachedFrame::CheckBetween(Direction direction, const WebCore::IntRect& bestRect, const WebCore::IntRect& prior, WebCore::IntRect* result) { @@ -153,11 +135,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 @@ -437,7 +417,6 @@ const CachedNode* CachedFrame::findBestAt(const WebCore::IntRect& rect, *directHit = test; *directHitFramePtr = this; IntRect r(center, IntSize(0, 0)); - r = unadjustBounds(test, r); *x = r.x(); *y = r.y(); } else { @@ -482,7 +461,6 @@ const CachedNode* CachedFrame::findBestAt(const WebCore::IntRect& rect, *inside = testInside; result = test; *framePtr = this; - both = unadjustBounds(test, both); *x = both.x() + (both.width() >> 1); *y = both.y() + (both.height() >> 1); } @@ -554,7 +532,6 @@ const CachedNode* CachedFrame::findBestHitAt(const WebCore::IntRect& rect, if (cursorRect.intersects(rect)) { WebCore::IntRect intersection(cursorRect); intersection.intersect(rect); - intersection = unadjustBounds(test, intersection); *x = intersection.x() + (intersection.width() >> 1); *y = intersection.y() + (intersection.height() >> 1); *framePtr = this; diff --git a/WebKit/android/nav/CachedFrame.h b/WebKit/android/nav/CachedFrame.h index 8ca73cf..039a0ee 100644 --- a/WebKit/android/nav/CachedFrame.h +++ b/WebKit/android/nav/CachedFrame.h @@ -80,11 +80,7 @@ public: void addFrame(CachedFrame& child) { mCachedFrames.append(child); } WebCore::IntRect adjustBounds(const CachedNode* , const WebCore::IntRect& ) const; - 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..299f2d1 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]" @@ -72,38 +99,6 @@ IntRect CachedLayer::adjustBounds(const LayerAndroid* root, return result; } -IntRect CachedLayer::unadjustBounds(const LayerAndroid* root, - const IntRect& bounds) const -{ - const LayerAndroid* aLayer = layer(root); - if (!aLayer) - return bounds; - - IntRect temp = bounds; - // Remove the new position (i.e. fixed position elements). - FloatPoint position = getGlobalPosition(aLayer); - - temp.move(-position.x(), -position.y()); - - // Remove any layer translation. - const FloatPoint& translation = aLayer->translation(); - temp.move(-translation.x(), -translation.y()); - - // Move it back to the original offset. - temp.move(mOffset.x(), mOffset.y()); - - DBG_NAV_LOGD("root=%p aLayer=%p [%d]" - " bounds=(%d,%d,w=%d,h=%d) trans=(%g,%g) pos=(%f,%f)" - " offset=(%d,%d)" - " result=(%d,%d,w=%d,h=%d)", - root, aLayer, aLayer->uniqueId(), - bounds.x(), bounds.y(), bounds.width(), bounds.height(), - translation.x(), translation.y(), position.x(), position.y(), - mOffset.x(), mOffset.y(), - temp.x(), temp.y(), temp.width(), temp.height()); - return temp; -} - FloatPoint CachedLayer::getGlobalPosition(const LayerAndroid* aLayer) const { SkPoint result = aLayer->getPosition(); @@ -177,7 +172,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/CachedLayer.h b/WebKit/android/nav/CachedLayer.h index 0a382fd..3d963e0 100644 --- a/WebKit/android/nav/CachedLayer.h +++ b/WebKit/android/nav/CachedLayer.h @@ -48,10 +48,6 @@ public: } // FIXME: adjustBounds should be renamed globalBounds or toGlobal IntRect adjustBounds(const LayerAndroid* root, const IntRect& bounds) const; - // Moves the bounds by the layer's position. Assumes the incoming - // bounds have been adjusted by adjustBounds. - IntRect unadjustBounds(const LayerAndroid* root, - const IntRect& bounds) const; int cachedNodeIndex() const { return mCachedNodeIndex; } FloatPoint getGlobalPosition(const LayerAndroid* ) const; const LayerAndroid* layer(const LayerAndroid* root) const; 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..f5f8a71 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: @@ -258,11 +160,11 @@ public: INHERITED::drawPath(path, paint); } - virtual void commonDrawBitmap(const SkBitmap& bitmap, + virtual void commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* rect, const SkMatrix& matrix, const SkPaint& paint) { mBounder.setType(CommonCheck::kDrawBitmap_Type); mBounder.setIsOpaque(bitmap.isOpaque()); - INHERITED::commonDrawBitmap(bitmap, matrix, paint); + INHERITED::commonDrawBitmap(bitmap, rect, matrix, paint); } virtual void drawSprite(const SkBitmap& bitmap, int left, int top, @@ -606,7 +508,7 @@ protected: // Currently webkit's bitmap draws always seem to be cull'd before this entry // point is called, so we assume that any bitmap that gets here is inside our // tiny clip (may not be true in the future) - virtual void commonDrawBitmap(const SkBitmap& bitmap, + virtual void commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* rect, const SkMatrix& , const SkPaint& ) { SkPixelRef* pixelRef = bitmap.pixelRef(); if (pixelRef != NULL) { @@ -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(), @@ -1474,9 +1379,7 @@ void CachedRoot::innerMove(const CachedNode* node, BestData* bestData, if (bestData->mNode != NULL) { mHistory->addToVisited(bestData->mNode, direction); mHistory->mNavBounds = bestData->bounds(); - mHistory->mMouseBounds = - bestData->mFrame->unadjustBounds(bestData->mNode, - bestData->mouseBounds()); + mHistory->mMouseBounds = bestData->mouseBounds(); } else if (scroll->x() != 0 || scroll->y() != 0) { WebCore::IntRect newBounds = mHistory->mNavBounds; int offsetX = scroll->x(); @@ -1576,7 +1479,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(), @@ -1604,7 +1507,11 @@ bool CachedRoot::maskIfHidden(BestData* best) const clipRgn.getBounds().fLeft, clipRgn.getBounds().fTop, clipRgn.getBounds().fRight, clipRgn.getBounds().fBottom); best->setMouseBounds(clipRgn.getBounds()); - node->clip(best->mouseBounds()); + if (!node->clip(best->mouseBounds())) { + node->setDisabled(true); + node->setClippedOut(true); + return true; + } } else node->fixUpCursorRects(frame); return false; 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/FindCanvas.cpp b/WebKit/android/nav/FindCanvas.cpp index e1bfd82..2d310b3 100644 --- a/WebKit/android/nav/FindCanvas.cpp +++ b/WebKit/android/nav/FindCanvas.cpp @@ -49,18 +49,18 @@ MatchInfo::MatchInfo() { } MatchInfo::~MatchInfo() { - m_picture->safeUnref(); + SkSafeUnref(m_picture); } MatchInfo::MatchInfo(const MatchInfo& src) { m_layerId = src.m_layerId; m_location = src.m_location; m_picture = src.m_picture; - m_picture->safeRef(); + SkSafeRef(m_picture); } void MatchInfo::set(const SkRegion& region, SkPicture* pic, int layerId) { - m_picture->safeUnref(); + SkSafeUnref(m_picture); m_layerId = layerId; m_location = region; m_picture = pic; @@ -161,7 +161,7 @@ FindCanvas::~FindCanvas() { setBounder(NULL); /* Just in case getAndClear was not called. */ delete mMatches; - mWorkingPicture->safeUnref(); + SkSafeUnref(mWorkingPicture); } // Each version of addMatch returns a rectangle for a match. diff --git a/WebKit/android/nav/SelectText.cpp b/WebKit/android/nav/SelectText.cpp index a07fa8c..1524058 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 @@ -194,6 +160,7 @@ public: reset(); } + /* called only while the picture is parsed */ int base() { if (mBase == INT_MAX) { SkPoint result; @@ -202,7 +169,8 @@ public: } return mBase; } - + + /* called only while the picture is parsed */ int bottom() { if (mBottom == INT_MAX) { SkPoint result; @@ -245,12 +213,14 @@ public: { mLastGlyph = mLastCandidate; mLastUni = mLastUniCandidate; + mLastPaint = mLastPaintCandidate; } const SkIRect& getArea() const { return mArea; } + /* called only while the picture is parsed */ SkUnichar getUniChar(const SkBounder::GlyphRec& rec) { SkUnichar unichar; @@ -266,8 +236,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 +244,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,45 +252,36 @@ 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; - } - - SkFixed minSpaceWidth() + 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 = mLastPaint.measureText(&firstGlyph, sizeof(firstGlyph)); + SkFixed ceilWidth = SkIntToFixed(SkScalarCeil(firstWidth)); + SkFixed posNoSpace = first.fLSB.fX + ceilWidth; + SkFixed ceilSpace = SkIntToFixed(SkFixedCeil(minSpaceWidth(mLastPaint))); + 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)" + " fontSize=%g", + SkFixedToScalar(second.fLSB.fX), + firstWidth, SkFixedToScalar(ceilWidth), + SkFixedToScalar(posNoSpace), SkFixedToScalar(diffNoSpace), + SkFixedToScalar(posWithSpace), SkFixedToScalar(diffWithSpace), + mLastPaint.getTextSize()); + return diffWithSpace <= diffNoSpace; + } + + SkFixed minSpaceWidth(SkPaint& paint) { if (mMinSpaceWidth == SK_FixedMax) { - SkPaint::TextEncoding save = mPaint.getTextEncoding(); - mPaint.setTextEncoding(SkPaint::kUTF8_TextEncoding); - SkScalar width = mPaint.measureText(" ", 1); + SkPaint::TextEncoding save = paint.getTextEncoding(); + paint.setTextEncoding(SkPaint::kUTF8_TextEncoding); + SkScalar width = paint.measureText(" ", 1); mMinSpaceWidth = SkScalarToFixed(width * mMatrix.getScaleX()); - mPaint.setTextEncoding(save); + paint.setTextEncoding(save); DBG_NAV_LOGV("width=%g matrix sx/sy=(%g, %g) tx/ty=(%g, %g)" " mMinSpaceWidth=%g", width, mMatrix.getScaleX(), mMatrix.getScaleY(), @@ -336,6 +295,7 @@ public: { mLastCandidate = rec; mLastUniCandidate = getUniChar(rec); + mLastPaintCandidate = mPaint; } void reset() @@ -349,7 +309,7 @@ public: mLastGlyph = check.mLastGlyph; mLastUni = check.mLastUni; mMatrix = check.mMatrix; - mPaint = check.mPaint; + mLastPaint = check.mLastPaint; reset(); } @@ -357,6 +317,7 @@ public: { mLastGlyph = check.mLastGlyph; mLastUni = check.mLastUni; + mLastPaint = check.mLastPaint; } void setUp(const SkPaint& paint, const SkMatrix& matrix, SkScalar y, @@ -369,6 +330,7 @@ public: reset(); } + /* called only while the picture is parsed */ int top() { if (mTop == INT_MAX) { SkPoint result; @@ -392,10 +354,12 @@ protected: SkIRect mArea; SkBounder::GlyphRec mLastCandidate; SkBounder::GlyphRec mLastGlyph; + SkPaint mLastPaint; // available after picture has been parsed + SkPaint mLastPaintCandidate; // associated with candidate glyph SkUnichar mLastUni; SkUnichar mLastUniCandidate; SkMatrix mMatrix; - SkPaint mPaint; + SkPaint mPaint; // only set up while the picture is parsed const uint16_t* mText; SkScalar mY; private: @@ -493,7 +457,7 @@ public: // assume that characters must be consecutive to describe spaces // (i.e., don't join rects drawn at different times) if (bounds.fTop != mLast.fTop || bounds.fBottom != mLast.fBottom - || bounds.fLeft > mLast.fRight + minSpaceWidth() + || bounds.fLeft > mLast.fRight + minSpaceWidth(mPaint) || bounds.fLeft < mLast.fLeft) { processLine(); mLast = bounds; @@ -524,7 +488,6 @@ protected: SkIRect mLast; SkTDArray<SkIRect> mParagraphs; SkTDArray<SkIRect> mSelected; - SkTDArray<SkIRect> mInColumn; bool mInBetween; private: typedef CommonCheck INHERITED; @@ -698,7 +661,7 @@ public: , mLast(area) , mLeft(left) { - mLast.set(last); + mLast.set(last); // CommonCheck::set() setGlyph(last); } @@ -753,7 +716,7 @@ public: mFocusX, mLeft ? "true" : "false", bounds.fLeft, bounds.fRight); reset(); mFocusX = mLeft ? bounds.fLeft : bounds.fRight; - mLast.set(*this); + mLast.set(*this); // CommonCheck::set() } protected: @@ -891,7 +854,7 @@ protected: mEndExtra.join(full); return mLastIntersects; } - int spaceGap = SkFixedRound(minSpaceWidth() * 3); + int spaceGap = SkFixedRound(minSpaceWidth(mPaint) * 3); // should text to the left of the start be added to the selection bounds? if (!mStartExtra.isEmpty()) { if (VERBOSE_LOGGING) DBG_NAV_LOGD("mSelectRect=(%d,%d,r=%d,b=%d)" @@ -1255,7 +1218,7 @@ public: virtual void drawPath(const SkPath& path, const SkPaint& paint) { } - virtual void commonDrawBitmap(const SkBitmap& bitmap, + virtual void commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* rect, const SkMatrix& matrix, const SkPaint& paint) { } @@ -1433,13 +1396,13 @@ SelectText::SelectText() paint.setShader(dropGradient); canvas->drawRect(endDropRect, paint); m_endControl.endRecording(); - fillGradient->safeUnref(); - dropGradient->safeUnref(); + SkSafeUnref(fillGradient); + SkSafeUnref(dropGradient); } SelectText::~SelectText() { - m_picture->safeUnref(); + SkSafeUnref(m_picture); } void SelectText::draw(SkCanvas* canvas, LayerAndroid* layer, IntRect* inval) @@ -1447,9 +1410,9 @@ void SelectText::draw(SkCanvas* canvas, LayerAndroid* layer, IntRect* inval) if (m_layerId != layer->uniqueId()) return; // reset m_picture to match m_layerId - m_picture->safeUnref(); + SkSafeUnref(m_picture); m_picture = layer->picture(); - m_picture->safeRef(); + SkSafeRef(m_picture); DBG_NAV_LOGD("m_extendSelection=%d m_drawPointer=%d layer [%d]", m_extendSelection, m_drawPointer, layer->uniqueId()); if (m_extendSelection) @@ -1846,7 +1809,7 @@ void SelectText::reset() m_lastEnd.setEmpty(); m_extendSelection = false; m_startSelection = false; - m_picture->safeUnref(); + SkSafeUnref(m_picture); m_picture = 0; m_layerId = 0; } @@ -1905,7 +1868,7 @@ bool SelectText::startSelection(const CachedRoot* root, const IntRect& vis, m_wordSelection = false; m_startOffset.set(x, y); DBG_NAV_LOGD("x/y=(%d,%d)", x, y); - m_picture->safeUnref(); + SkSafeUnref(m_picture); m_picture = root->pictureAt(&x, &y, &m_layerId); DBG_NAV_LOGD("m_picture=%p m_layerId=%d x/y=(%d,%d)", m_picture, m_layerId, x, y); diff --git a/WebKit/android/nav/WebView.cpp b/WebKit/android/nav/WebView.cpp index 38d0ccb..4031439 100644 --- a/WebKit/android/nav/WebView.cpp +++ b/WebKit/android/nav/WebView.cpp @@ -148,7 +148,7 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl) : m_javaGlue.m_overrideLoading = GetJMethod(env, clazz, "overrideLoading", "(Ljava/lang/String;)V"); m_javaGlue.m_sendMoveFocus = GetJMethod(env, clazz, "sendMoveFocus", "(II)V"); m_javaGlue.m_sendMoveMouse = GetJMethod(env, clazz, "sendMoveMouse", "(IIII)V"); - m_javaGlue.m_sendMoveMouseIfLatest = GetJMethod(env, clazz, "sendMoveMouseIfLatest", "(Z)V"); + m_javaGlue.m_sendMoveMouseIfLatest = GetJMethod(env, clazz, "sendMoveMouseIfLatest", "(ZZ)V"); m_javaGlue.m_sendMotionUp = GetJMethod(env, clazz, "sendMotionUp", "(IIIII)V"); m_javaGlue.m_domChangedFocus = GetJMethod(env, clazz, "domChangedFocus", "()V"); m_javaGlue.m_getScaledMaxXScroll = GetJMethod(env, clazz, "getScaledMaxXScroll", "()I"); @@ -210,7 +210,7 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl) : #endif delete m_frameCacheUI; delete m_navPictureUI; - m_baseLayer->safeUnref(); + SkSafeUnref(m_baseLayer); delete m_glDrawFunctor; } @@ -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); @@ -686,7 +686,7 @@ CachedRoot* getFrameCache(FrameCachePermission allowNewer) } m_viewImpl->gFrameCacheMutex.lock(); delete m_frameCacheUI; - m_navPictureUI->safeUnref(); + SkSafeUnref(m_navPictureUI); m_viewImpl->m_updatedFrameCache = false; m_frameCacheUI = m_viewImpl->m_frameCacheKit; m_navPictureUI = m_viewImpl->m_navPictureKit; @@ -866,7 +866,9 @@ bool moveCursor(int keyCode, int count, bool ignoreScroll) const CachedNode* focus = root->currentFocus(); bool clearTextEntry = cachedNode != focus && focus && cachedNode->nodePointer() != focus->nodePointer() && focus->isTextInput(); - sendMoveMouseIfLatest(clearTextEntry); + // Stop painting the caret if the old focus was a text input and so is the new cursor. + bool stopPaintingCaret = clearTextEntry && cachedNode->wantsKeyEvents(); + sendMoveMouseIfLatest(clearTextEntry, stopPaintingCaret); } else { int docHeight = root->documentHeight(); int docWidth = root->documentWidth(); @@ -936,13 +938,13 @@ void selectBestAt(const WebCore::IntRect& rect) } else { DBG_NAV_LOGD("CachedNode:%p (%d)", node, node->index()); WebCore::IntRect bounds = node->bounds(frame); - root->rootHistory()->setMouseBounds(frame->unadjustBounds(node, bounds)); + root->rootHistory()->setMouseBounds(bounds); m_viewImpl->updateCursorBounds(root, frame, node); showCursorTimed(); root->setCursor(const_cast<CachedFrame*>(frame), const_cast<CachedNode*>(node)); } - sendMoveMouseIfLatest(false); + sendMoveMouseIfLatest(false, false); if (!node) return; } @@ -988,8 +990,6 @@ bool motionUp(int x, int y, int slop) } DBG_NAV_LOGD("CachedNode:%p (%d) x=%d y=%d rx=%d ry=%d", result, result->index(), x, y, rx, ry); - // No need to call unadjustBounds below. rx and ry are already adjusted to - // the absolute position of the node. WebCore::IntRect navBounds = WebCore::IntRect(rx, ry, 1, 1); history->setNavBounds(navBounds); history->setMouseBounds(navBounds); @@ -1210,12 +1210,12 @@ void sendMoveMouse(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int checkException(env); } -void sendMoveMouseIfLatest(bool clearTextEntry) +void sendMoveMouseIfLatest(bool clearTextEntry, bool stopPaintingCaret) { LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); env->CallVoidMethod(m_javaGlue.object(env).get(), - m_javaGlue.m_sendMoveMouseIfLatest, clearTextEntry); + m_javaGlue.m_sendMoveMouseIfLatest, clearTextEntry, stopPaintingCaret); checkException(env); } @@ -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) @@ -1396,7 +1396,7 @@ void setBaseLayer(BaseLayerAndroid* layer, WebCore::IntRect& rect) copyScrollPositionRecursive(compositeRoot(), newCompositeRoot); } #endif - m_baseLayer->safeUnref(); + SkSafeUnref(m_baseLayer); m_baseLayer = layer; CachedRoot* root = getFrameCache(DontAllowNewer); if (!root) @@ -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) @@ -2239,7 +2240,7 @@ static bool nativeMoveCursorToNextTextInput(JNIEnv *env, jobject obj) if (!next) return false; const WebCore::IntRect& bounds = next->bounds(frame); - root->rootHistory()->setMouseBounds(frame->unadjustBounds(next, bounds)); + root->rootHistory()->setMouseBounds(bounds); view->getWebViewCore()->updateCursorBounds(root, frame, next); view->showCursorUntimed(); root->setCursor(const_cast<CachedFrame*>(frame), @@ -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/ANPSystemInterface.cpp b/WebKit/android/plugins/ANPSystemInterface.cpp index 8510c2e..7199635 100644 --- a/WebKit/android/plugins/ANPSystemInterface.cpp +++ b/WebKit/android/plugins/ANPSystemInterface.cpp @@ -27,19 +27,33 @@ #include "config.h" #include "ANPSystem_npapi.h" +#include "Frame.h" #include "JavaSharedClient.h" #include "PluginClient.h" #include "PluginPackage.h" #include "PluginView.h" #include "PluginWidgetAndroid.h" +#include "Settings.h" #include "SkString.h" #include "WebViewCore.h" #include <wtf/text/CString.h> +#include <dirent.h> + +//#define PLUGIN_DEBUG_LOCAL // controls the printing of log messages +#include "PluginDebugAndroid.h" + static const char* gApplicationDataDir = NULL; +static const char* gApplicationDataDirIncognito = NULL; using namespace android; +static WebCore::PluginView* pluginViewForInstance(NPP instance) { + if (instance && instance->ndata) + return static_cast<WebCore::PluginView*>(instance->ndata); + return WebCore::PluginView::currentPluginView(); +} + static const char* anp_getApplicationDataDirectory() { if (NULL == gApplicationDataDir) { PluginClient* client = JavaSharedClient::GetPluginClient(); @@ -58,18 +72,49 @@ static const char* anp_getApplicationDataDirectory() { memcpy(storage, path.utf8().data(), length); storage[length] = '\0'; + static const char incognitoPath[] = "/incognito_plugins"; + char* incognitoStorage = (char*) malloc(length + strlen(incognitoPath) + 1); + + strcpy(incognitoStorage, storage); + strcat(incognitoStorage, incognitoPath); + // save this assignment for last, so that if multiple threads call us // (which should never happen), we never return an incomplete global. // At worst, we would allocate storage for the path twice. gApplicationDataDir = storage; + gApplicationDataDirIncognito = incognitoStorage; } + return gApplicationDataDir; } -static WebCore::PluginView* pluginViewForInstance(NPP instance) { - if (instance && instance->ndata) - return static_cast<WebCore::PluginView*>(instance->ndata); - return PluginView::currentPluginView(); +static const char* anp_getApplicationDataDirectoryV2(NPP instance) { + WebCore::PluginView* pluginView = pluginViewForInstance(instance); + PluginWidgetAndroid* pluginWidget = pluginView->platformPluginWidget(); + + if (NULL == gApplicationDataDir) { + anp_getApplicationDataDirectory(); + } + + WebCore::Settings* settings = pluginWidget->webViewCore()->mainFrame()->settings(); + if (settings && settings->privateBrowsingEnabled()) { + // if this is an incognito view then check the path to see if it exists + // and if it is a directory, otherwise if it does not exist create it. + struct stat st; + if (stat(gApplicationDataDirIncognito, &st) == 0) { + if (!S_ISDIR(st.st_mode)) { + return NULL; + } + } else { + if (mkdir(gApplicationDataDirIncognito, S_IRWXU) != 0) { + return NULL; + } + } + + return gApplicationDataDirIncognito; + } + + return gApplicationDataDir; } static jclass anp_loadJavaClass(NPP instance, const char* className) { @@ -107,3 +152,71 @@ void ANPSystemInterfaceV1_Init(ANPInterface* v) { ANPSystemInterfaceV1* i = reinterpret_cast<ANPSystemInterfaceV1*>(v); ASSIGN(i, setPowerState); } + +void ANPSystemInterfaceV2_Init(ANPInterface* v) { + // initialize the functions from the previous interface + ANPSystemInterfaceV1_Init(v); + // add any new functions or override existing functions + ANPSystemInterfaceV2* i = reinterpret_cast<ANPSystemInterfaceV2*>(v); + i->getApplicationDataDirectory = anp_getApplicationDataDirectoryV2; +} + +/////////////////////////////////////////////////////////////////////////////// + +static bool isDirectory(const char* path) { + struct stat st; + return stat(path, &st) == 0 && S_ISDIR(st.st_mode); +} + +static void removeDirectory(const char* path) { + // create a pointer to a directory + DIR *dir = NULL; + dir = opendir(path); + if (!dir) + return; + + struct dirent* entry = 0; + while ((entry = readdir(dir))) { // while there is still something in the directory to list + if (!entry) + return; + + if (!strcmp(".", entry->d_name) || !strcmp("..", entry->d_name)) { + PLUGIN_LOG(". file: %s", entry->d_name); + continue; + } + + // concatenate the strings to get the complete path + static const char separator[] = "/"; + char* file = (char*) malloc(strlen(path) + strlen(separator) + strlen(entry->d_name) + 1); + strcpy(file, path); + strcat(file, separator); + strcat(file, entry->d_name); + + if (isDirectory(file) == true) { + PLUGIN_LOG("remove dir: %s", file); + removeDirectory(file); + } else { // it's a file, we can use remove + PLUGIN_LOG("remove file: %s", file); + remove(file); + } + + free(file); + } + + // clean up + closedir (dir); // close the directory + rmdir(path); // delete the directory +} + +void ANPSystemInterface_CleanupIncognito() { + PLUGIN_LOG("cleanup incognito plugin directory"); + + if (gApplicationDataDirIncognito == NULL) + anp_getApplicationDataDirectory(); + if (gApplicationDataDirIncognito == NULL) + return; + + // check to see if the directory exists and if so delete it + if (isDirectory(gApplicationDataDirIncognito)) + removeDirectory(gApplicationDataDirIncognito); +} diff --git a/WebKit/android/plugins/ANPSystem_npapi.h b/WebKit/android/plugins/ANPSystem_npapi.h index 5d91cfb..835bc7c 100644 --- a/WebKit/android/plugins/ANPSystem_npapi.h +++ b/WebKit/android/plugins/ANPSystem_npapi.h @@ -57,4 +57,16 @@ struct ANPSystemInterfaceV1 : ANPSystemInterfaceV0 { void (*setPowerState)(NPP instance, ANPPowerState powerState); }; +struct ANPSystemInterfaceV2 : ANPInterface { + /** Return the path name for the current Application's plugin data directory, + or NULL if not supported. This directory will change depending on whether + or not the plugin is found within an incognito tab. + */ + const char* (*getApplicationDataDirectory)(NPP instance); + + // redeclaration of existing features + jclass (*loadJavaClass)(NPP instance, const char* className); + void (*setPowerState)(NPP instance, ANPPowerState powerState); +}; + #endif //ANPSystem_npapi_H diff --git a/WebKit/android/plugins/ANPTypefaceInterface.cpp b/WebKit/android/plugins/ANPTypefaceInterface.cpp index 4b2dda2..99734a7 100644 --- a/WebKit/android/plugins/ANPTypefaceInterface.cpp +++ b/WebKit/android/plugins/ANPTypefaceInterface.cpp @@ -46,11 +46,11 @@ static int32_t anp_getRefCount(const ANPTypeface* tf) { } static void anp_ref(ANPTypeface* tf) { - tf->safeRef(); + SkSafeRef(tf); } static void anp_unref(ANPTypeface* tf) { - tf->safeUnref(); + SkSafeUnref(tf); } static ANPTypefaceStyle anp_getStyle(const ANPTypeface* tf) { diff --git a/WebKit/android/plugins/PluginWidgetAndroid.cpp b/WebKit/android/plugins/PluginWidgetAndroid.cpp index 7f6948c..b8a10cc 100644 --- a/WebKit/android/plugins/PluginWidgetAndroid.cpp +++ b/WebKit/android/plugins/PluginWidgetAndroid.cpp @@ -95,7 +95,7 @@ PluginWidgetAndroid::~PluginWidgetAndroid() { env->DeleteGlobalRef(m_embeddedView); } - m_flipPixelRef->safeUnref(); + SkSafeUnref(m_flipPixelRef); if (m_layer) m_layer->unref(); @@ -148,7 +148,7 @@ void PluginWidgetAndroid::setWindow(NPWindow* window, bool isTransparent) { layoutSurface(boundsChanged); if (m_drawingModel != kSurface_ANPDrawingModel) { - m_flipPixelRef->safeUnref(); + SkSafeUnref(m_flipPixelRef); m_flipPixelRef = new SkFlipPixelRef(computeConfig(isTransparent), window->width, window->height); } @@ -390,7 +390,7 @@ void PluginWidgetAndroid::sendSizeAndVisibilityEvents(const bool updateDimension const float zoomLevel = m_core->scale(); // notify the plugin of the new size - if (m_drawingModel == kOpenGL_ANPDrawingModel && updateDimensions) { + if (m_drawingModel == kOpenGL_ANPDrawingModel && updateDimensions && m_pluginWindow) { PLUGIN_LOG("%s (%d,%d)[%f]", __FUNCTION__, m_pluginWindow->width, m_pluginWindow->height, zoomLevel); ANPEvent event; @@ -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() { diff --git a/WebKit/android/plugins/android_npapi.h b/WebKit/android/plugins/android_npapi.h index fb13b43..b0c3765 100644 --- a/WebKit/android/plugins/android_npapi.h +++ b/WebKit/android/plugins/android_npapi.h @@ -126,6 +126,8 @@ typedef uint32_t ANPMatrixFlag; #define kVideoInterfaceV0_ANPGetValue ((NPNVariable)1015) #define kSystemInterfaceV1_ANPGetValue ((NPNVariable)1016) +#define kSystemInterfaceV2_ANPGetValue ((NPNVariable)1017) + /** queries for the drawing models supported on this device. NPN_GetValue(inst, kSupportedDrawingModel_ANPGetValue, uint32_t* bits) |