# Currently we track the Chromium 9.0.597 release branch:
# http://trac.webkit.org/browser/branches/chromium/597
# which is WebKit r72805 + stability cherry picks.
-webkit.chromiumRelease=http\://src.chromium.org/svn/releases/9.0.597.83/DEPS
+webkit.chromiumRelease=http\://src.chromium.org/svn/releases/9.0.597.106/DEPS
+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.
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);
// 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
#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 {
}
#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());
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
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
};
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;
}
m_lstCSSRules->deleteRule(index);
- // stylesheet() can only return 0 for computed style declarations.
- stylesheet()->styleSheetChanged();
+ if (stylesheet())
+ stylesheet()->styleSheetChanged();
}
String CSSMediaRule::cssText() const
#include "config.h"
#include "CSSRuleList.h"
+#include "CSSMutableStyleDeclaration.h"
#include "CSSRule.h"
#include "StyleList.h"
+#include "WebKitCSSKeyframeRule.h"
namespace WebCore {
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);
}
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())
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)
, m_hasSyntacticallyValidCSSHeader(true)
{
CSSStyleSheet* parentSheet = ownerRule ? ownerRule->parentStyleSheet() : 0;
- m_document = parentSheet ? parentSheet->document() : 0;
m_isUserStyleSheet = parentSheet ? parentSheet->isUserStyleSheet() : false;
}
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;
virtual void checkLoaded();
- Document* document() { return m_document; }
+ Document* document();
const String& charset() const { return m_charset; }
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;
*/
#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 {
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
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)
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);
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;
};
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)
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);
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;
};
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
#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>
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;
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();
}
, m_visitCount(0)
, m_itemSequenceNumber(generateSequenceNumber())
, m_documentSequenceNumber(generateSequenceNumber())
+ , m_next(0)
+ , m_prev(0)
{
}
, m_visitCount(0)
, m_itemSequenceNumber(generateSequenceNumber())
, m_documentSequenceNumber(generateSequenceNumber())
+ , m_next(0)
+ , m_prev(0)
{
iconDatabase()->retainIconForPageURL(m_urlString);
}
, m_visitCount(0)
, m_itemSequenceNumber(generateSequenceNumber())
, m_documentSequenceNumber(generateSequenceNumber())
+ , m_next(0)
+ , m_prev(0)
{
iconDatabase()->retainIconForPageURL(m_urlString);
}
, m_visitCount(0)
, m_itemSequenceNumber(generateSequenceNumber())
, m_documentSequenceNumber(generateSequenceNumber())
+ , m_next(0)
+ , m_prev(0)
{
iconDatabase()->retainIconForPageURL(m_urlString);
}
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;
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;
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&);
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;
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)
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)) {
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);
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;
#include "HTMLFormControlElement.h"
#include "OptionElement.h"
-#if PLATFORM(ANDROID)
-namespace android {
-class WebViewCore;
-class ListBoxReply;
-};
-#endif
-
namespace WebCore {
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*);
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;
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
// 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()
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.
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) {
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) {
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;
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.
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;
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());
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)
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;
page->chrome()->unfocus();
}
-void DOMWindow::close()
+void DOMWindow::close(ScriptExecutionContext* context)
{
if (!m_frame)
return;
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();
void focus();
void blur();
- void close();
+ void close(ScriptExecutionContext* = 0);
void print();
void stop();
[DoNotCheckDomainSecurity] void focus();
[DoNotCheckDomainSecurity] void blur();
- [DoNotCheckDomainSecurity] void close();
+ [DoNotCheckDomainSecurity, CallWith=ScriptExecutionContext] void close();
void print();
void stop();
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;
bool needsFullRepaint() const { return m_doFullRepaint; }
+#if PLATFORM(ANDROID)
+ void updatePositionedObjects();
+#endif
+
#if USE(ACCELERATED_COMPOSITING)
void updateCompositingLayers();
#include "History.h"
#include "BackForwardController.h"
+#include "Document.h"
#include "ExceptionCode.h"
#include "Frame.h"
#include "FrameLoader.h"
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);
}
namespace WebCore {
class Frame;
+class ScriptExecutionContext;
class SerializedScriptValue;
typedef int ExceptionCode;
void forward();
void go(int distance);
+ void back(ScriptExecutionContext*);
+ void forward(ScriptExecutionContext*);
+ void go(ScriptExecutionContext*, int distance);
+
enum StateObjectType {
StateObjectPush,
StateObjectReplace
] 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);
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)
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*);
};
}
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)
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()
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)
{
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)
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)) {
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;
};
// 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)
{
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
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));
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);
}
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;
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)
}
#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;
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));
scale = m_glWebViewState->futureScale();
}
compositedRoot->setScale(scale);
- compositedRoot->computeTextureSize();
+ compositedRoot->computeTextureSize(currentTime);
compositedRoot->reserveGLTextures();
#ifdef DEBUG
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();
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;
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());
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;
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...
}
FontPlatformData::FontPlatformData(const FontPlatformData& src)
{
if (hashTableDeletedFontValue() != src.mTypeface) {
- src.mTypeface->safeRef();
+ SkSafeRef(src.mTypeface);
}
mTypeface = src.mTypeface;
: mTypeface(tf), mTextSize(textSize), mFakeBold(fakeBold), mFakeItalic(fakeItalic)
{
if (hashTableDeletedFontValue() != mTypeface) {
- mTypeface->safeRef();
+ SkSafeRef(mTypeface);
}
inc_count();
m_harfbuzzFace(src.m_harfbuzzFace)
{
if (hashTableDeletedFontValue() != mTypeface) {
- mTypeface->safeRef();
+ SkSafeRef(mTypeface);
}
inc_count();
#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;
GLWebViewState::~GLWebViewState()
{
- m_currentBaseLayer->safeUnref();
+ SkSafeUnref(m_currentBaseLayer);
delete m_tiledPageA;
delete m_tiledPageB;
#ifdef DEBUG_COUNT
#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) {
// 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);
+
+ 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;
}
void GLWebViewState::setExtra(BaseLayerAndroid* layer, SkPicture& picture,
- const IntRect& rect)
+ const IntRect& rect, bool allowSame)
{
android::Mutex::Autolock lock(m_baseLayerLock);
if (!m_baseLayerUpdate)
layer->setExtra(picture);
- if (m_lastInval == rect)
+ if (!allowSame && m_lastInval == rect)
return;
if (!rect.isEmpty())
{
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();
+ SkSafeUnref(baseLayer);
return ret;
}
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);
return false;
}
- void setBackgroundColor(SkColor color) { m_backgroundColor = color; }
- SkColor getBackgroundColor() { return m_backgroundColor; }
-
bool drawGL(IntRect& rect, SkRect& viewport,
float scale, SkColor color = SK_ColorWHITE);
+ void setBackgroundColor(SkColor color) { m_backgroundColor = color; }
+ SkColor getBackgroundColor() { return m_backgroundColor; }
+
private:
void inval(const IntRect& rect); // caller must hold m_baseLayerLock
class PlatformGradientRec {
public:
PlatformGradientRec() : m_shader(NULL) {}
- ~PlatformGradientRec() { m_shader->safeUnref(); }
+ ~PlatformGradientRec() { SkSafeUnref(m_shader); }
SkShader* m_shader;
SkShader::TileMode m_tileMode;
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;
, 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)
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;
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()));
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
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();
}
MLOG("(%x) setSize (%.2f,%.2f)", this, size.width(), size.height());
GraphicsLayer::setSize(size);
m_contentLayer->setSize(size.width(), size.height());
- updateFixedPosition();
askForSync();
}
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();
}
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) ",
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();
{
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;
}
}
for (unsigned int i = 0; i < m_children.size(); i++)
m_children[i]->syncCompositingState();
+ updateScrollingLayers();
+ updateFixedPosition();
syncChildren();
syncMask();
void syncMask();
void updateFixedPosition();
+ void updateScrollingLayers();
// with SkPicture, we always repaint the entire layer's content.
bool repaint();
///////////////////////////////////////////////////////////////////////////////
-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),
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
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;
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);
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();
m_isRootLayer(true),
m_haveClip(false),
m_isFixed(false),
+ m_isIframe(false),
m_recordingPicture(picture),
m_contentsImage(0),
m_extra(0),
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
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");
///////////////////////////////////////////////////////////////////////////////
-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;
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()
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;
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)
|| (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;
}
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());
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();
void showLayers(int indent = 0);
// Texture size functions
- void computeTextureSize();
+ void computeTextureSize(double time);
void collect(Vector<LayerAndroid*>& layers,
int& size);
int clippedTextureSize() const;
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.
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);
bool m_haveClip;
bool m_isFixed;
bool m_backgroundColorSet;
+ bool m_isIframe;
SkLength m_fixedLeft;
SkLength m_fixedTop;
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;
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;
};
#include "MediaTexture.h"
#include "TilesManager.h"
#include "GLUtils.h"
+#include "VideoListener.h"
#if USE(ACCELERATED_COMPOSITING)
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;
m_dimensions.setEmpty();
m_newWindowRequest = false;
m_newWindowReady = false;
+ m_videoListener = new VideoListener(m_weakWebViewRef);
}
VideoTexture::~VideoTexture()
m_surfaceTextureClient = new android::SurfaceTextureClient(m_surfaceTexture);
//setup callback
- sp<VideoListener> listener = new VideoListener(m_weakWebViewRef);
- m_surfaceTexture->setFrameAvailableListener(listener);
+ m_videoListener->resetFrameAvailable();
+ m_surfaceTexture->setFrameAvailableListener(m_videoListener);
m_newWindowRequest = false;
m_newWindowReady = true;
{
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();
namespace WebCore {
+class VideoListener;
+
class MediaTexture : public DoubleBufferedTexture,
public android::LightRefBase<MediaTexture> {
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;
void Pattern::platformDestroy()
{
- m_pattern->safeUnref();
+ SkSafeUnref(m_pattern);
m_pattern = 0;
}
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) {}
, m_maxTextureCount(0)
, m_expandedTileBounds(false)
, m_generatorReady(false)
+ , m_showVisualIndicator(false)
{
XLOG("TilesManager ctor");
m_textures.reserveCapacity(MAX_TEXTURE_ALLOCATION);
m_expandedTileBounds = enabled;
}
+ bool getShowVisualIndicator() {
+ return m_showVisualIndicator;
+ }
+
+ void setShowVisualIndicator(bool showVisualIndicator) {
+ m_showVisualIndicator = showVisualIndicator;
+ }
+
private:
TilesManager();
bool m_generatorReady;
+ bool m_showVisualIndicator;
+
sp<TexturesGenerator> m_pixmapsGenerationThread;
android::Mutex m_texturesLock;
--- /dev/null
+/*
+ * 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
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
// 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)) {
}
}
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);
CursorRing(WebViewCore* core) : m_viewImpl(core) {}
virtual ~CursorRing() {}
virtual void draw(SkCanvas* , LayerAndroid* , IntRect* );
+ void setIsButton(const CachedNode* );
bool setup();
private:
friend class WebView;
, m_continuation(0)
, m_rareData(0)
, m_lineHeight(-1)
+ , m_beingDestroyed(false)
{
setChildrenInline(true);
}
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();
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.
nextBlock->deleteLineBoxTree();
nextBlock->destroy();
next = 0;
-
- // FIXME: Revert the continuation change done above.
- if (oldChildBlock)
- oldChildBlock->setContinuation(0);
}
}
// 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());
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();
}
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;
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).
#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"
return;
if (isFloating()) {
- RenderBlock* outermostBlock = containingBlock();
- for (RenderBlock* p = outermostBlock; p && !p->isRenderView(); p = p->containingBlock()) {
- if (p->containsFloat(this))
- outermostBlock = p;
+ RenderBlock* parentBlock = 0;
+ for (RenderObject* curr = parent(); curr && !curr->isRenderView(); curr = curr->parent()) {
+ if (curr->isRenderBlock()) {
+ RenderBlock* currBlock = toRenderBlock(curr);
+ if (currBlock->containsFloat(this))
+ parentBlock = currBlock;
+ else
+ break;
+ }
}
- if (outermostBlock) {
- RenderObject* parent = outermostBlock->parent();
+ if (parentBlock) {
+ RenderObject* parent = parentBlock->parent();
if (parent && parent->isFlexibleBox())
- outermostBlock = toRenderBlock(parent);
+ parentBlock = toRenderBlock(parent);
- outermostBlock->markAllDescendantsWithFloatsForLayout(this, false);
+ parentBlock->markAllDescendantsWithFloatsForLayout(this, false);
}
}
if (isPositioned()) {
- RenderObject* p;
- for (p = parent(); p; p = p->parent()) {
- if (p->isRenderBlock())
- toRenderBlock(p)->removePositionedObject(this);
+ for (RenderObject* curr = parent(); curr; curr = curr->parent()) {
+ if (curr->isRenderBlock())
+ toRenderBlock(curr)->removePositionedObject(this);
}
}
}
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();
}
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();
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.
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,
// 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)) {
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;
}
// 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());
}
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);
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);
RenderTextControlMultiLine::~RenderTextControlMultiLine()
{
- if (node())
+ if (node() && node()->inDocument())
static_cast<HTMLTextAreaElement*>(node())->rendererWillBeDestroyed();
}
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
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;
// 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
}
{
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;
return m_styleDeclaration->getPropertyValue(CSSPropertyFontFamily);
}
+SVGFontElement* SVGFontFaceElement::associatedFontElement() const
+{
+ return m_fontElement.get();
+}
+
void SVGFontFaceElement::rebuildFontFace()
{
ASSERT(inDocument());
int descent() const;
String fontFamily() const;
- SVGFontElement* associatedFontElement() const { return m_fontElement; }
+ SVGFontElement* associatedFontElement() const;
void rebuildFontFace();
void removeFromMappedElementSheet();
RefPtr<CSSFontFaceRule> m_fontFaceRule;
RefPtr<CSSMutableStyleDeclaration> m_styleDeclaration;
- SVGFontElement* m_fontElement;
+ RefPtr<SVGFontElement> m_fontElement;
};
} // namespace WebCore
CachedResourceLoader* cachedResourceLoader();
- Document* ownerDocument() { return m_ownerDocument; }
+ Document* ownerDocument();
+ XSLStyleSheet* parentStyleSheet() const { return m_parentStyleSheet; }
void setParentStyleSheet(XSLStyleSheet* parent);
#if USE(QXMLQUERY)
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)
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)
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)
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)
XSLStyleSheet::XSLStyleSheet(Node* parentNode, const String& originalURL, const KURL& finalURL, bool embedded)
: StyleSheet(parentNode, originalURL, finalURL)
- , m_ownerDocument(parentNode->document())
, m_embedded(embedded)
{
}
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)
notImplemented();
}
+Document* XSLStyleSheet::ownerDocument()
+{
+ Node* node = ownerNode();
+ return node ? node->document() : 0;
+}
+
void XSLStyleSheet::setParentStyleSheet(XSLStyleSheet*)
{
notImplemented();
{
// 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();
}
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
(m_frame->loader()->policyChecker()->*func)(PolicyUse);
}
+void FrameLoaderClientAndroid::dispatchWillSendSubmitEvent(HTMLFormElement* form)
+{
+ if (m_webFrame->shouldSaveFormData())
+ m_webFrame->saveFormData(form);
+}
+
void FrameLoaderClientAndroid::dispatchDidLoadMainResource(DocumentLoader*) {
notImplemented();
}
void enableOnDemandPlugins() { m_onDemandPluginsEnabled = true; }
void dispatchDidChangeIcons();
- void dispatchWillSendSubmitEvent(HTMLFormElement*) { }
+ void dispatchWillSendSubmitEvent(HTMLFormElement*);
private:
CacheBuilder m_cacheBuilder;
Frame* m_frame;
}
// 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()
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
#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()
{
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));
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;
if (fd >= 0)
close(fd);
}
+
FilePath cookiePath(databaseFilePath.c_str());
m_cookieDb = new SQLitePersistentCookieStore(cookiePath);
m_cookieStore = new net::CookieMonster(m_cookieDb.get(), 0);
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;
}
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;
+}
+
}
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(); }
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);
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;
ScopedRunnableMethodFactory<WebRequest> m_runnableFactory;
bool m_wantToPause;
bool m_isPaused;
+#ifdef LOG_REQUESTS
+ time_t m_startTime;
+#endif
};
} // namespace android
}
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();
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();
}
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();
#include "WebResourceRequest.h"
#include <wtf/text/CString.h>
-#include <sstream>
namespace android {
{
if (m_cancelling)
return false;
+ if (!m_resourceHandle)
+ return false;
if (!m_resourceHandle->client())
return false;
if (m_finished)
: m_webFrame(webFrame)
, m_resourceHandle(resourceHandle)
, m_isMainResource(false)
+ , m_isMainFrame(false)
, m_isCertMimeType(false)
, m_cancelling(false)
, m_sync(false)
}
}
-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) {
}
m_isMainResource = isMainResource;
+ m_isMainFrame = isMainFrame;
m_sync = sync;
if (m_sync) {
AutoLock autoLock(*syncLock());
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.
}
}
-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)
{
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]);
}
}
}
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);
WebFrame* m_webFrame;
RefPtr<WebCore::ResourceHandle> m_resourceHandle;
bool m_isMainResource;
+ bool m_isMainFrame;
bool m_isCertMimeType;
bool m_cancelling;
bool m_sync;
#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 },
{ "nativeSetAcceptCookie", "(Z)V", (void*) setAcceptCookie },
{ "nativeSetCookie", "(Ljava/lang/String;Ljava/lang/String;)V", (void*) setCookie },
{ "nativeFlushCookieStore", "()V", (void*) flushCookieStore },
+ { "nativeAcceptFileSchemeCookies", "()Z", (void*) acceptFileSchemeCookies },
+ { "nativeSetAcceptFileSchemeCookies", "(Z)V", (void*) setAcceptFileSchemeCookies },
};
int registerCookieManager(JNIEnv* env)
void PictureSet::add(const Pictures* temp)
{
Pictures pictureAndBounds = *temp;
- pictureAndBounds.mPicture->safeRef();
+ SkSafeRef(pictureAndBounds.mPicture);
pictureAndBounds.mWroteElapsed = false;
mPictures.append(pictureAndBounds);
}
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();
}
}
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
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;
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;
if ((working->mSplit == false || invalBounds != working->mUnsplit) &&
inval.contains(working->mArea) == false)
continue;
- working->mPicture->safeUnref();
+ SkSafeUnref(working->mPicture);
working->mPicture = NULL;
}
return true;
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);
}
#include "Element.h"
#include "FocusController.h"
#include "Font.h"
-#include "FormState.h"
#include "Frame.h"
#include "FrameLoader.h"
#include "FrameLoaderClientAndroid.h"
jmethodID mDidReceiveData;
jmethodID mDidFinishLoading;
jmethodID mSetCertificate;
+ jmethodID mShouldSaveFormData;
+ jmethodID mSaveFormData;
AutoJObject frame(JNIEnv* env) {
return getRealObject(env, mObj);
}
"(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");
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;
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)
{
#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
}
}
-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)
(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",
#include <wtf/RefCounted.h>
namespace WebCore {
+ class HTMLFormElement;
class Frame;
class HistoryItem;
class Image;
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
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;
// 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);
return m_env;
}
private:
+ AutoJObject(); // Not permitted.
AutoJObject(JNIEnv* env, jobject obj)
: m_env(env)
, m_obj(obj) {}
#include "Chrome.h"
#include "ChromeClientAndroid.h"
#include "ChromiumIncludes.h"
+#include "ClientRect.h"
+#include "ClientRectList.h"
#include "Color.h"
#include "CSSPropertyNames.h"
#include "CSSValueKeywords.h"
struct WebViewCore::JavaGlue {
jweak m_obj;
- jmethodID m_spawnScrollTo;
jmethodID m_scrollTo;
- jmethodID m_scrollBy;
jmethodID m_contentDraw;
jmethodID m_layersDraw;
jmethodID m_requestListBox;
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");
m_scrollOffsetY = 0;
m_screenWidth = 0;
m_screenHeight = 0;
- m_visibleScreenWidth = 0;
- m_visibleScreenHeight = 0;
m_groupForVisitedLinks = NULL;
m_currentNodeDomNavigationAxis = 0;
}
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.
// 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);
}
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();
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;
// 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());
+ }
}
}
// 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,
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();
}
}
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) {
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);
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
// 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();
}
}
}
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)
+{
+ 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());
+}
+
+Node* WebViewCore::getNextAnchorNode(Node* anchorNode, bool ignoreFirstNode, int direction)
{
- return (node->hasTagName(WebCore::HTMLNames::aTag)
- || node->hasTagName(WebCore::HTMLNames::inputTag)
- || node->hasTagName(WebCore::HTMLNames::buttonTag));
+ 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;
}
-int WebViewCore::rangeCompliantChildOffset(Node* parent, int offset)
+void WebViewCore::advanceAnchorNode(DOMSelection* selection, int direction,
+ String& markup, bool ignoreFirstNode, ExceptionCode& ec)
{
- if (offset < 0)
- return 0;
- int lastChildIndex = parent->childNodes()->length() - 1;
- if (offset > lastChildIndex)
- return lastChildIndex;
- return offset;
+ 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::isVisibleNonEmptyNonWhitespaceTextNode(Node* node)
+bool WebViewCore::isContentInputElement(Node* node)
+{
+ return (isVisible(node)
+ && (node->hasTagName(WebCore::HTMLNames::selectTag)
+ || node->hasTagName(WebCore::HTMLNames::aTag)
+ || node->hasTagName(WebCore::HTMLNames::inputTag)
+ || node->hasTagName(WebCore::HTMLNames::buttonTag)));
+}
+
+bool WebViewCore::isContentTextNode(Node* node)
{
if (!node || !node->isTextNode())
return false;
&& !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();
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();
{
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,
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)
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);
key(up);
client->setUiGeneratedSelectionChange(false);
m_textGeneration = textGeneration;
+ m_shouldPaintCaret = true;
}
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,
}
// Now that the selection has settled down, send it.
updateTextSelection();
+ m_shouldPaintCaret = true;
}
void WebViewCore::scrollFocusedTextInput(float xPercent, int y)
}
}
-// 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)
{
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());
-}
-
// Common code for both clicking with the trackball and touchUp
// Also used when typing into a non-focused textfield to give the textfield focus,
// in which case, 'fake' is set to true
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;
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) {
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.
return false;
result = jstringToWtfString(env, returnVal);
+ env->DeleteLocalRef(returnVal);
return true;
}
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
}
#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)
+ owner->scrollToOffset(rect.fLeft, rect.fTop, true, false);
+#endif
+}
+
//----------------------------------------------------------------------
// Native JNI methods
//----------------------------------------------------------------------
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);
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,
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
#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);
+}
+
// ----------------------------------------------------------------------------
/*
(void*) SendListBoxChoice },
{ "nativeSetSize", "(IIIFIIIIZ)V",
(void*) SetSize },
- { "nativeSetScrollOffset", "(IIII)V",
+ { "nativeSetScrollOffset", "(IZII)V",
(void*) SetScrollOffset },
{ "nativeSetGlobalBounds", "(IIII)V",
(void*) SetGlobalBounds },
(void*) RetrieveAnchorText },
{ "nativeRetrieveImageSource", "(II)Ljava/lang/String;",
(void*) RetrieveImageSource },
+ { "nativeStopPaintingCaret", "()V",
+ (void*) StopPaintingCaret },
{ "nativeUpdateFrameCache", "()V",
(void*) UpdateFrameCache },
{ "nativeGetContentMinPrefWidth", "()I",
(void*) GetTouchHighlightRects },
{ "nativeAutoFillForm", "(I)V",
(void*) AutoFillForm },
+ { "nativeScrollLayer", "(ILandroid/graphics/Rect;)V",
+ (void*) ScrollRenderLayer },
};
int registerWebViewCore(JNIEnv* env)
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);
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);
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;
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
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;
PageGroup* m_groupForVisitedLinks;
bool m_isPaused;
int m_cacheMode;
+ bool m_shouldPaintCaret;
SkTDArray<PluginWidgetAndroid*> m_plugins;
WebCore::Timer<WebViewCore> m_pluginInvalTimer;
// 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;
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,
} 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();
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();
bool isFocus = node == focused;
bool takesFocus = false;
int columnGap = 0;
+ int imageCount = 0;
TextDirection direction = LTR;
String exported;
CachedNodeType type = NORMAL_CACHEDNODETYPE;
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
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) {
}
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
bounds.intersect(clipBounds);
if (AddPartRect(bounds, x, y, result, focusBounds) == false)
return false;
+ *imageCountPtr += 1;
continue;
}
if (hasClip == false) {
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); }
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)
{
}
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
*directHit = test;
*directHitFramePtr = this;
IntRect r(center, IntSize(0, 0));
- r = unadjustBounds(test, r);
*x = r.x();
*y = r.y();
} else {
*inside = testInside;
result = test;
*framePtr = this;
- both = unadjustBounds(test, both);
*x = both.x() + (both.width() >> 1);
*y = both.y() + (both.height() >> 1);
}
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;
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(); }
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]"
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();
{
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);
}
// 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;
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;
// 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;
DEBUG_PRINT_BOOL(mLast);
DEBUG_PRINT_BOOL(mUseBounds);
DEBUG_PRINT_BOOL(mUseHitBounds);
+ DEBUG_PRINT_BOOL(mSingleImage);
}
#endif
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; }
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]; }
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
#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:
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,
// 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) {
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++) {
&& 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
char mCh;
bool mAppendLikeTypes;
bool mPushPop;
+ bool mSingleImage;
};
class RingCanvas : public BoundsCanvas {
*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(),
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();
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(),
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(); }
}
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;
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.
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
reset();
}
+ /* called only while the picture is parsed */
int base() {
if (mBase == INT_MAX) {
SkPoint result;
}
return mBase;
}
-
+
+ /* called only while the picture is parsed */
int bottom() {
if (mBottom == INT_MAX) {
SkPoint result;
{
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;
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),
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)
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(),
{
mLastCandidate = rec;
mLastUniCandidate = getUniChar(rec);
+ mLastPaintCandidate = mPaint;
}
void reset()
mLastGlyph = check.mLastGlyph;
mLastUni = check.mLastUni;
mMatrix = check.mMatrix;
- mPaint = check.mPaint;
+ mLastPaint = check.mLastPaint;
reset();
}
{
mLastGlyph = check.mLastGlyph;
mLastUni = check.mLastUni;
+ mLastPaint = check.mLastPaint;
}
void setUp(const SkPaint& paint, const SkMatrix& matrix, SkScalar y,
reset();
}
+ /* called only while the picture is parsed */
int top() {
if (mTop == INT_MAX) {
SkPoint result;
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:
// 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;
SkIRect mLast;
SkTDArray<SkIRect> mParagraphs;
SkTDArray<SkIRect> mSelected;
- SkTDArray<SkIRect> mInColumn;
bool mInBetween;
private:
typedef CommonCheck INHERITED;
, mLast(area)
, mLeft(left)
{
- mLast.set(last);
+ mLast.set(last); // CommonCheck::set()
setGlyph(last);
}
mFocusX, mLeft ? "true" : "false", bounds.fLeft, bounds.fRight);
reset();
mFocusX = mLeft ? bounds.fLeft : bounds.fRight;
- mLast.set(*this);
+ mLast.set(*this); // CommonCheck::set()
}
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)"
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) {
}
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)
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)
m_lastEnd.setEmpty();
m_extendSelection = false;
m_startSelection = false;
- m_picture->safeUnref();
+ SkSafeUnref(m_picture);
m_picture = 0;
m_layerId = 0;
}
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);
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");
#endif
delete m_frameCacheUI;
delete m_navPictureUI;
- m_baseLayer->safeUnref();
+ SkSafeUnref(m_baseLayer);
delete m_glDrawFunctor;
}
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);
resetCursorRing();
return false;
}
+ m_ring.setIsButton(node);
if (node->isHidden()) {
DBG_NAV_LOG("node->isHidden()");
m_viewImpl->m_hasCursorBounds = false;
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);
}
}
SkPicture picture;
IntRect rect(0, 0, 0, 0);
+ bool allowSame = false;
if (extra) {
LayerAndroid mainPicture(m_navPictureUI);
PictureSet* content = m_baseLayer->content();
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)
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
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);
}
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;
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();
} 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;
}
}
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);
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);
}
}
#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)
copyScrollPositionRecursive(compositeRoot(), newCompositeRoot);
}
#endif
- m_baseLayer->safeUnref();
+ SkSafeUnref(m_baseLayer);
m_baseLayer = layer;
CachedRoot* root = getFrameCache(DontAllowNewer);
if (!root)
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)
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),
(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 },
}
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) {
env->DeleteGlobalRef(m_embeddedView);
}
- m_flipPixelRef->safeUnref();
+ SkSafeUnref(m_flipPixelRef);
if (m_layer)
m_layer->unref();
layoutSurface(boundsChanged);
if (m_drawingModel != kSurface_ANPDrawingModel) {
- m_flipPixelRef->safeUnref();
+ SkSafeUnref(m_flipPixelRef);
m_flipPixelRef = new SkFlipPixelRef(computeConfig(isTransparent),
window->width, window->height);
}
#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() {