diff options
Diffstat (limited to 'WebKit/android')
62 files changed, 4393 insertions, 3751 deletions
diff --git a/WebKit/android/RenderSkinButton.cpp b/WebKit/android/RenderSkinButton.cpp index c878cb9..0f792a7 100644 --- a/WebKit/android/RenderSkinButton.cpp +++ b/WebKit/android/RenderSkinButton.cpp @@ -90,8 +90,7 @@ void RenderSkinButton::Draw(SkCanvas* canvas, const IntRect& r, RenderSkinAndroi static_cast<unsigned>(RenderSkinAndroid::kNumStates)); // Set up the ninepatch information for drawing. - SkRect bounds; - android_setrect(&bounds, r); + SkRect bounds(r); const PatchData& pd = gFiles[newState]; int marginValue = pd.margin + pd.outset; diff --git a/WebKit/android/RenderSkinCombo.cpp b/WebKit/android/RenderSkinCombo.cpp index 902f2c0..870c13e 100644 --- a/WebKit/android/RenderSkinCombo.cpp +++ b/WebKit/android/RenderSkinCombo.cpp @@ -27,6 +27,7 @@ #include "RenderSkinCombo.h" #include "Document.h" +#include "Element.h" #include "Node.h" #include "SkCanvas.h" #include "SkNinePatch.h" @@ -58,7 +59,8 @@ bool RenderSkinCombo::Draw(SkCanvas* canvas, Node* element, int x, int y, int wi { if (!s_decoded) return true; - State state = element && element->isEnabled() ? kNormal : kDisabled; + + State state = (element->isElementNode() && static_cast<Element*>(element)->isEnabledFormControl()) ? kNormal : kDisabled; if (height < (s_margin<<1) + 1) { height = (s_margin<<1) + 1; } diff --git a/WebKit/android/RenderSkinRadio.cpp b/WebKit/android/RenderSkinRadio.cpp index 2fca175..ff5e908 100644 --- a/WebKit/android/RenderSkinRadio.cpp +++ b/WebKit/android/RenderSkinRadio.cpp @@ -28,6 +28,8 @@ #include "android_graphics.h" #include "Document.h" +#include "Element.h" +#include "InputElement.h" #include "IntRect.h" #include "Node.h" #include "RenderSkinAndroid.h" @@ -60,11 +62,12 @@ void RenderSkinRadio::Draw(SkCanvas* canvas, Node* element, const IntRect& ir, if (!s_decoded || !element) { return; } - SkRect r; - android_setrect(&r, ir); + SkRect r(ir); int saveLayerCount = 0; int saveScaleCount = 0; - if (!element->isEnabled()) { + + if (!element->isElementNode() || + !static_cast<Element*>(element)->isEnabledFormControl()) { saveLayerCount = canvas->saveLayerAlpha(&r, 0x80); } SkScalar width = r.width(); @@ -72,7 +75,12 @@ void RenderSkinRadio::Draw(SkCanvas* canvas, Node* element, const IntRect& ir, SkScalar scale = SkScalarDiv(width, SIZE); saveScaleCount = canvas->scale(scale, scale); } - canvas->drawBitmap(s_bitmap[element->isChecked() + 2*(!isCheckBox)], + bool checked = false; + if (InputElement* inputElement = toInputElement(static_cast<Element*>(element))) { + checked = inputElement->isChecked(); + } + + canvas->drawBitmap(s_bitmap[checked + 2*(!isCheckBox)], r.fLeft, r.fTop, NULL); if (saveLayerCount != 0) { canvas->restoreToCount(saveLayerCount); diff --git a/WebKit/android/TimeCounter.cpp b/WebKit/android/TimeCounter.cpp index b423441..5f69cf6 100644 --- a/WebKit/android/TimeCounter.cpp +++ b/WebKit/android/TimeCounter.cpp @@ -31,19 +31,21 @@ #include "CString.h" #include "Cache.h" #include "KURL.h" -#include "GCController.h" -#include "JSDOMWindow.h" #include "Node.h" -#include "Nodes.h" #include "SystemTime.h" #include "StyleBase.h" + +#if USE(JSC) +#include "JSDOMWindow.h" #include <runtime/JSGlobalObject.h> #include <runtime/JSLock.h> +#endif + #include <utils/Log.h> -using namespace JSC; using namespace WebCore; using namespace WTF; +using namespace JSC; namespace android { @@ -66,7 +68,9 @@ uint32_t TimeCounter::sStartTime[TimeCounter::TotalTimeCounterCount]; static const char* timeCounterNames[] = { "css parsing", "javascript", + "javascript init", "javascript parsing", + "javascript execution", "calculate style", "Java callback (frame bridge)", "parsing (may include calcStyle or Java callback)", @@ -113,11 +117,12 @@ void TimeCounter::report(const KURL& url, int live, int dead, size_t arenaSize) } LOGD("Current cache has %d bytes live and %d bytes dead", live, dead); LOGD("Current render arena takes %d bytes", arenaSize); +#if USE(JSC) JSLock lock(false); Heap::Statistics jsHeapStatistics = JSDOMWindow::commonJSGlobalData()->heap.statistics(); LOGD("Current JavaScript heap size is %d and has %d bytes free", jsHeapStatistics.size, jsHeapStatistics.free); - LOGD("Current JavaScript nodes use %d bytes", JSC::Node::reportJavaScriptNodesSize()); +#endif LOGD("Current CSS styles use %d bytes", StyleBase::reportStyleSize()); LOGD("Current DOM nodes use %d bytes", WebCore::Node::reportDOMNodesSize()); } diff --git a/WebKit/android/TimeCounter.h b/WebKit/android/TimeCounter.h index 054141b..c78d10f 100644 --- a/WebKit/android/TimeCounter.h +++ b/WebKit/android/TimeCounter.h @@ -44,7 +44,9 @@ public: // function base counters CSSParseTimeCounter, JavaScriptTimeCounter, + JavaScriptInitTimeCounter, JavaScriptParseTimeCounter, + JavaScriptExecuteTimeCounter, CalculateStyleTimeCounter, JavaCallbackTimeCounter, ParsingTimeCounter, diff --git a/WebKit/android/TimerClient.h b/WebKit/android/TimerClient.h index 09f9fc0..f8cbb9d 100644 --- a/WebKit/android/TimerClient.h +++ b/WebKit/android/TimerClient.h @@ -35,6 +35,7 @@ namespace android { virtual void setSharedTimerCallback(void(*f)()) = 0; virtual void setSharedTimer(long long timemillis) = 0; virtual void stopSharedTimer() = 0; + virtual void signalServiceFuncPtrQueue() = 0; }; } diff --git a/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp b/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp index 7b09975..71d9f59 100644 --- a/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp +++ b/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp @@ -29,6 +29,7 @@ #include "ChromeClientAndroid.h" #include "CString.h" +#include "DatabaseTracker.h" #include "Document.h" #include "PlatformString.h" #include "FloatRect.h" @@ -142,10 +143,10 @@ bool ChromeClientAndroid::menubarVisible() { notImplemented(); return false; } void ChromeClientAndroid::setResizable(bool) { notImplemented(); } // This function is called by the JavaScript bindings to print usually an error to -// a message console. -void ChromeClientAndroid::addMessageToConsole(const String& message, unsigned int lineNumber, const String& sourceID) { - notImplemented(); - LOGD("Console: %s line: %d source: %s\n", message.latin1().data(), lineNumber, sourceID.latin1().data()); +// a message console. Pass the message to the java side so that the client can +// handle it as it sees fit. +void ChromeClientAndroid::addMessageToConsole(MessageSource, MessageLevel, const String& message, unsigned int lineNumber, const String& sourceID) { + android::WebViewCore::getWebViewCore(m_webFrame->page()->mainFrame()->view())->addMessageToConsole(message, lineNumber, sourceID); } bool ChromeClientAndroid::canRunBeforeUnloadConfirmPanel() { return true; } @@ -167,7 +168,7 @@ void ChromeClientAndroid::closeWindowSoon() mainFrame->loader()->stopAllLoaders(); // Remove all event listeners so that no javascript can execute as a result // of mouse/keyboard events. - mainFrame->document()->removeAllEventListenersFromAllNodes(); + mainFrame->document()->removeAllEventListeners(); // Close the window. m_webFrame->closeWindow(android::WebViewCore::getWebViewCore(mainFrame->view())); } @@ -248,13 +249,16 @@ PlatformWidget ChromeClientAndroid::platformWindow() const { return viewBridge; } -// new to webkit4 (Feb 27, 2009) void ChromeClientAndroid::contentsSizeChanged(Frame*, const IntSize&) const { notImplemented(); } -// new to webkit4 (Feb 27, 2009) +void ChromeClientAndroid::scrollRectIntoView(const IntRect&, const ScrollView*) const +{ + notImplemented(); +} + void ChromeClientAndroid::formStateDidChange(const Node*) { notImplemented(); @@ -264,9 +268,69 @@ void ChromeClientAndroid::mouseDidMoveOverElement(const HitTestResult&, unsigned void ChromeClientAndroid::setToolTip(const String&) {} void ChromeClientAndroid::print(Frame*) {} -void ChromeClientAndroid::exceededDatabaseQuota(Frame*, const String&) {} +/* + * This function is called on the main (webcore) thread by SQLTransaction::deliverQuotaIncreaseCallback. + * The way that the callback mechanism is designed inside SQLTransaction means that there must be a new quota + * (which may be equal to the old quota if the user did not allow more quota) when this function returns. As + * we call into the browser thread to ask what to do with the quota, we block here and get woken up when the + * browser calls the native WebViewCore::SetDatabaseQuota method with the new quota value. + */ +#if ENABLE(DATABASE) +void ChromeClientAndroid::exceededDatabaseQuota(Frame* frame, const String& name) +{ + SecurityOrigin* origin = frame->document()->securityOrigin(); + + // TODO: This default quota value should be pulled from the web browser + // settings. For now, settle for 5 meg. + const unsigned long long defaultQuota = 1024 * 1024 * 5; + + + if (WebCore::DatabaseTracker::tracker().hasEntryForOrigin(origin)) { + // We want to wait on a new quota from the UI thread. Reset the m_newQuota variable to represent we haven't received a new quota. + m_newQuota = -1; + + // This origin is being tracked and has exceeded it's quota. Call into + // the Java side of things to inform the user. + const unsigned long long currentQuota = WebCore::DatabaseTracker::tracker().quotaForOrigin(origin); + android::WebViewCore::getWebViewCore(frame->view())->exceededDatabaseQuota(frame->document()->documentURI(), name, currentQuota); + + // We've sent notification to the browser so now wait for it to come back. + m_quotaThreadLock.lock(); + while (m_newQuota == -1) { + m_quotaThreadCondition.wait(m_quotaThreadLock); + } + m_quotaThreadLock.unlock(); + + // Update the DatabaseTracker with the new quota value (if the user declined + // new quota, this may equal the old quota) + DatabaseTracker::tracker().setQuota(origin, m_newQuota); + } else { + // This origin is not being tracked, so set it's entry in the Origins table + // to the default quota, casusing it to be tracked from now on. + DatabaseTracker::tracker().setQuota(origin, defaultQuota); + } +} +#endif +#if ENABLE(OFFLINE_WEB_APPLICATIONS) +void ChromeClientAndroid::reachedMaxAppCacheSize(int64_t spaceNeeded) +{ + // FIXME: Free some space. + notImplemented(); +} +#endif -// new to change 38068 (Nov 6, 2008) +void ChromeClientAndroid::requestGeolocationPermissionForFrame(Frame*, Geolocation*) { notImplemented(); } void ChromeClientAndroid::runOpenPanel(Frame*, PassRefPtr<FileChooser>) { notImplemented(); } +bool ChromeClientAndroid::setCursor(PlatformCursorHandle) +{ + notImplemented(); + return false; +} + +void ChromeClientAndroid::wakeUpMainThreadWithNewQuota(long newQuota) { + MutexLocker locker(m_quotaThreadLock); + m_newQuota = newQuota; + m_quotaThreadCondition.signal(); +} } diff --git a/WebKit/android/WebCoreSupport/ChromeClientAndroid.h b/WebKit/android/WebCoreSupport/ChromeClientAndroid.h index 7343c88..93426b8 100644 --- a/WebKit/android/WebCoreSupport/ChromeClientAndroid.h +++ b/WebKit/android/WebCoreSupport/ChromeClientAndroid.h @@ -28,6 +28,8 @@ #include "ChromeClient.h" +#include "Threading.h" + using namespace WebCore; namespace android { @@ -75,7 +77,7 @@ namespace android { virtual void setResizable(bool); - virtual void addMessageToConsole(const String& message, unsigned int lineNumber, const String& sourceID); + virtual void addMessageToConsole(MessageSource, MessageLevel, const String& message, unsigned int lineNumber, const String& sourceID); virtual bool canRunBeforeUnloadConfirmPanel(); virtual bool runBeforeUnloadConfirmPanel(const String& message, Frame* frame); @@ -98,6 +100,7 @@ namespace android { virtual IntRect windowToScreen(const IntRect&) const; virtual PlatformWidget platformWindow() const; virtual void contentsSizeChanged(Frame*, const IntSize&) const; + virtual void scrollRectIntoView(const IntRect&, const ScrollView*) const; // End methods used by HostWindow. virtual void mouseDidMoveOverElement(const HitTestResult&, unsigned int); @@ -105,19 +108,30 @@ namespace android { virtual void setToolTip(const String&); virtual void print(Frame*); - +#if ENABLE(DATABASE) virtual void exceededDatabaseQuota(Frame*, const String&); - +#endif +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + virtual void reachedMaxAppCacheSize(int64_t spaceNeeded); +#endif + virtual void requestGeolocationPermissionForFrame(Frame*, Geolocation*); virtual void runOpenPanel(Frame*, PassRefPtr<FileChooser>); + virtual bool setCursor(PlatformCursorHandle); // Notification that the given form element has changed. This function // will be called frequently, so handling should be very fast. virtual void formStateDidChange(const Node*); - // Android-specific + virtual PassOwnPtr<HTMLParserQuirks> createHTMLParserQuirks() { return 0; } + + // Android-specific void setWebFrame(android::WebFrame* webframe); + void wakeUpMainThreadWithNewQuota(long newQuota); private: android::WebFrame* m_webFrame; + WTF::ThreadCondition m_quotaThreadCondition; + WTF::Mutex m_quotaThreadLock; + long m_newQuota; }; } diff --git a/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp b/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp index 780ea53..4918ee9 100644 --- a/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp +++ b/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp @@ -215,10 +215,11 @@ void EditorClientAndroid::redo() {} // functions new to Jun-07 tip of tree merge: void EditorClientAndroid::showSpellingUI(bool) {} -void EditorClientAndroid::getGuessesForWord(String const&, Vector<String>&) {} +void EditorClientAndroid::getGuessesForWord(String const&, WTF::Vector<String>&) {} bool EditorClientAndroid::spellingUIIsShowing() { return false; } -void EditorClientAndroid::checkGrammarOfString(unsigned short const*, int, Vector<GrammarDetail>&, int*, int*) {} +void EditorClientAndroid::checkGrammarOfString(unsigned short const*, int, WTF::Vector<GrammarDetail>&, int*, int*) {} void EditorClientAndroid::checkSpellingOfString(unsigned short const*, int, int*, int*) {} +String EditorClientAndroid::getAutoCorrectSuggestionForMisspelledWord(const String&) { return String(); } void EditorClientAndroid::textFieldDidEndEditing(Element*) {} void EditorClientAndroid::textDidChangeInTextArea(Element*) {} void EditorClientAndroid::textDidChangeInTextField(Element*) {} diff --git a/WebKit/android/WebCoreSupport/EditorClientAndroid.h b/WebKit/android/WebCoreSupport/EditorClientAndroid.h index 42e9c43..9697d66 100644 --- a/WebKit/android/WebCoreSupport/EditorClientAndroid.h +++ b/WebKit/android/WebCoreSupport/EditorClientAndroid.h @@ -94,12 +94,13 @@ public: virtual void ignoreWordInSpellDocument(const String&); virtual void learnWord(const String&); virtual void checkSpellingOfString(const UChar*, int length, int* misspellingLocation, int* misspellingLength); - virtual void checkGrammarOfString(const UChar*, int length, Vector<GrammarDetail>&, int* badGrammarLocation, int* badGrammarLength); + virtual String getAutoCorrectSuggestionForMisspelledWord(const String& misspelledWorld); + virtual void checkGrammarOfString(const UChar*, int length, WTF::Vector<GrammarDetail>&, int* badGrammarLocation, int* badGrammarLength); virtual void updateSpellingUIWithGrammarString(const String&, const GrammarDetail& detail); virtual void updateSpellingUIWithMisspelledWord(const String&); virtual void showSpellingUI(bool show); virtual bool spellingUIIsShowing(); - virtual void getGuessesForWord(const String&, Vector<String>& guesses); + virtual void getGuessesForWord(const String&, WTF::Vector<String>& guesses); virtual void setInputMethodState(bool); // Android specific: diff --git a/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp b/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp index 5a07278..b81e5f3 100644 --- a/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp +++ b/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp @@ -29,14 +29,14 @@ #include "android_graphics.h" #include "CString.h" #include "DocumentLoader.h" +#include "DOMImplementation.h" #include "Frame.h" #include "FrameLoader.h" #include "FrameLoaderClientAndroid.h" #include "FrameTree.h" #include "GraphicsContext.h" -// HTMLFormElement needed for a bad include -#include "HTMLFormElement.h" #include "HTMLFrameOwnerElement.h" +#include "HTMLPlugInElement.h" #include "IconDatabase.h" #include "MIMETypeRegistry.h" #include "NotImplemented.h" @@ -45,11 +45,6 @@ #include "PlatformString.h" #include "PluginDatabase.h" #include "PluginView.h" -#ifdef ANDROID_PLUGINS -// Removed. -#else -#include "PluginViewBridgeAndroid.h" -#endif #include "ProgressTracker.h" #include "RenderPart.h" #include "ResourceError.h" @@ -110,7 +105,7 @@ void FrameLoaderClientAndroid::makeRepresentation(DocumentLoader*) { void FrameLoaderClientAndroid::forceLayout() { ASSERT(m_frame); - m_frame->forceLayout(); + m_frame->view()->forceLayout(); // FIXME, should we adjust view size here? m_frame->view()->adjustViewSize(); } @@ -190,6 +185,10 @@ bool FrameLoaderClientAndroid::dispatchDidLoadResourceFromMemoryCache(DocumentLo return false; } +void FrameLoaderClientAndroid::dispatchDidLoadResourceByXMLHttpRequest(unsigned long identifier, const ScriptString&) { + return; +} + void FrameLoaderClientAndroid::dispatchDidHandleOnloadEvents() { } @@ -225,10 +224,12 @@ void FrameLoaderClientAndroid::dispatchDidReceiveIcon() { WebCore::Image* icon = WebCore::iconDatabase()->iconForPageURL( url, WebCore::IntSize(16, 16)); // If the request fails, try the original request url. - if (!icon) + if (!icon) { + DocumentLoader* docLoader = m_frame->loader()->activeDocumentLoader(); + KURL originalURL = docLoader->originalRequest().url(); icon = WebCore::iconDatabase()->iconForPageURL( - m_frame->loader()->originalRequestURL().string(), - WebCore::IntSize(16, 16)); + originalURL, WebCore::IntSize(16, 16)); + } // There is a bug in webkit where cancelling an icon load is treated as a // failure. When this is fixed, we can ASSERT again that we have an icon. if (icon) { @@ -256,8 +257,7 @@ void FrameLoaderClientAndroid::dispatchDidReceiveTitle(const String& title) { } void FrameLoaderClientAndroid::dispatchDidCommitLoad() { - ASSERT(m_frame); - WebViewCore::getWebViewCore(m_frame->view())->updateFrameGeneration(m_frame); + verifiedOk(); } static void loadDataIntoFrame(Frame* frame, KURL baseUrl, const String& url, @@ -568,17 +568,21 @@ void FrameLoaderClientAndroid::finishedLoading(DocumentLoader* docLoader) { void FrameLoaderClientAndroid::updateGlobalHistory() { ASSERT(m_frame); - ASSERT(m_frame->loader()->documentLoader()); - KURL url; - DocumentLoader* loader = m_frame->loader()->documentLoader(); - if (loader->urlForHistoryReflectsServerRedirect()) - url = loader->url(); - else - url = loader->urlForHistory(); - m_webFrame->updateVisitedHistory(url, false); + + DocumentLoader* docLoader = m_frame->loader()->documentLoader(); + ASSERT(docLoader); + + // Code copied from FrameLoader.cpp:createHistoryItem + // Only add this URL to the database if it is a valid page + if (docLoader->unreachableURL().isEmpty() + && docLoader->response().httpStatusCode() < 400) { + m_webFrame->updateVisitedHistory(docLoader->urlForHistory(), false); + if (!docLoader->serverRedirectSourceForHistory().isNull()) + m_webFrame->updateVisitedHistory(KURL(docLoader->serverRedirectDestinationForHistory()), false); + } } -void FrameLoaderClientAndroid::updateGlobalHistoryForRedirectWithoutHistoryItem() { +void FrameLoaderClientAndroid::updateGlobalHistoryRedirectLinks() { // Note, do we need to do anything where there is no HistoryItem? If we call // updateGlobalHistory(), we will add bunch of "data:xxx" urls for gmail.com // which is not what we want. Opt to do nothing now. @@ -653,7 +657,9 @@ bool FrameLoaderClientAndroid::canShowMIMEType(const String& mimeType) const { if (MIMETypeRegistry::isSupportedImageResourceMIMEType(mimeType) || MIMETypeRegistry::isSupportedNonImageMIMEType(mimeType) || MIMETypeRegistry::isSupportedJavaScriptMIMEType(mimeType) || - PluginDatabase::installedPlugins()->isMIMETypeRegistered(mimeType)) + PluginDatabase::installedPlugins()->isMIMETypeRegistered(mimeType) || + DOMImplementation::isTextMIMEType(mimeType) || + DOMImplementation::isXMLMIMEType(mimeType)) return true; return false; } @@ -674,7 +680,6 @@ String FrameLoaderClientAndroid::generatedMIMETypeForURLScheme(const String& URL void FrameLoaderClientAndroid::frameLoadCompleted() { // copied from Apple port, without this back with sub-frame will trigger ASSERT ASSERT(m_frame); - m_frame->loader()->setPreviousHistoryItem(0); } void FrameLoaderClientAndroid::saveViewStateToItem(HistoryItem* item) { @@ -687,7 +692,8 @@ void FrameLoaderClientAndroid::saveViewStateToItem(HistoryItem* item) { ASSERT(bridge); // store the current scale (only) for the top frame if (!m_frame->tree()->parent()) { - bridge->setScale(WebViewCore::getWebViewCore(m_frame->view())->scale()); + float scale = WebViewCore::getWebViewCore(m_frame->view())->scale(); + bridge->setScale((int)(scale * 100)); } WebCore::notifyHistoryItemChanged(item); @@ -735,8 +741,7 @@ void FrameLoaderClientAndroid::didFinishLoad() { } void FrameLoaderClientAndroid::prepareForDataSourceReplacement() { - ASSERT(m_frame); - m_frame->loader()->detachChildren(); + verifiedOk(); } PassRefPtr<DocumentLoader> FrameLoaderClientAndroid::createDocumentLoader( @@ -786,19 +791,16 @@ void FrameLoaderClientAndroid::transitionToCommittedForNewPage() { m_frame->setView(NULL); // Create a new FrameView and associate it with the saved webFrameView - FrameView* view = new FrameView(m_frame); - webFrameView->setView(view); + RefPtr<FrameView> view = FrameView::create(m_frame); + webFrameView->setView(view.get()); Release(webFrameView); // Give the new FrameView to the Frame m_frame->setView(view); - // Deref since FrameViews are created with a ref of 1 - view->deref(); - if (m_frame->ownerRenderer()) - m_frame->ownerRenderer()->setWidget(view); + m_frame->ownerRenderer()->setWidget(view.get()); m_frame->view()->initScrollbars(); @@ -830,15 +832,13 @@ WTF::PassRefPtr<WebCore::Frame> FrameLoaderClientAndroid::createFrame(const KURL parent->tree()->appendChild(newFrame); newFrame->tree()->setName(name); // Create a new FrameView and WebFrameView for the child frame to draw into. - FrameView* frameView = new WebCore::FrameView(newFrame); - WebFrameView* webFrameView = new WebFrameView(frameView, + RefPtr<FrameView> frameView = FrameView::create(newFrame); + WebFrameView* webFrameView = new WebFrameView(frameView.get(), WebViewCore::getWebViewCore(parent->view())); // frameView Retains webFrameView, so call Release for webFrameView Release(webFrameView); // Attach the frameView to the newFrame. newFrame->setView(frameView); - // setView() refs the frameView so call deref on the frameView - frameView->deref(); newFrame->init(); newFrame->selection()->setFocused(true); LOGV("::WebCore:: createSubFrame returning %p", newFrame); @@ -894,7 +894,7 @@ static bool isYouTubeUrl(const KURL& url, const String& mimeType) Widget* FrameLoaderClientAndroid::createPlugin( const IntSize& size, - Element* element, + HTMLPlugInElement* element, const KURL& url, const WTF::Vector<String, 0u>& names, const WTF::Vector<String, 0u>& values, @@ -902,8 +902,7 @@ Widget* FrameLoaderClientAndroid::createPlugin( bool loadManually) { // Create an iframe for youtube urls. if (isYouTubeUrl(url, mimeType)) { - RefPtr<Frame> frame = createFrame(blankURL(), String(), - static_cast<HTMLFrameOwnerElement*>(element), + RefPtr<Frame> frame = createFrame(blankURL(), String(), element, String(), false, 0, 0); if (frame) { // grab everything after /v/ @@ -949,7 +948,7 @@ void FrameLoaderClientAndroid::redirectDataToPlugin(Widget* pluginWidget) { notImplemented(); } -Widget* FrameLoaderClientAndroid::createJavaAppletWidget(const IntSize&, Element*, +Widget* FrameLoaderClientAndroid::createJavaAppletWidget(const IntSize&, HTMLAppletElement*, const KURL& baseURL, const WTF::Vector<String>& paramNames, const WTF::Vector<String>& paramValues) { // don't support widget yet @@ -979,17 +978,17 @@ ObjectContentType FrameLoaderClientAndroid::objectContentType(const KURL& url, } return ObjectContentFrame; } - if (equalIgnoringCase(mimeType, "text/html") || - equalIgnoringCase(mimeType, "text/xml") || - equalIgnoringCase(mimeType, "text/") || - equalIgnoringCase(mimeType, "application/xml") || - equalIgnoringCase(mimeType, "application/xhtml+xml") || - equalIgnoringCase(mimeType, "application/x-javascript")) - return ObjectContentFrame; + if (Image::supportsType(mimeType)) return ObjectContentImage; - // Use OtherPlugin so embed and object tags draw the null plugin view - return ObjectContentOtherPlugin; + + if (PluginDatabase::installedPlugins()->isMIMETypeRegistered(mimeType)) + return ObjectContentOtherPlugin; + + if (MIMETypeRegistry::isSupportedNonImageMIMEType(mimeType)) + return ObjectContentFrame; + + return ObjectContentNone; } // This function allows the application to set the correct CSS media @@ -1009,6 +1008,9 @@ void FrameLoaderClientAndroid::windowObjectCleared() { m_webFrame->windowObjectCleared(m_frame); } +void FrameLoaderClientAndroid::documentElementAvailable() { +} + // functions new to Jun-07 tip of tree merge: ResourceError FrameLoaderClientAndroid::blockedError(ResourceRequest const& request) { return ResourceError(String(), InternalErrorFileDoesNotExist, String(), String()); diff --git a/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h b/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h index 9d71c9d..d491750 100644 --- a/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h +++ b/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h @@ -71,6 +71,7 @@ namespace android { virtual void dispatchDidFinishLoading(DocumentLoader*, unsigned long identifier); virtual void dispatchDidFailLoading(DocumentLoader*, unsigned long identifier, const ResourceError&); virtual bool dispatchDidLoadResourceFromMemoryCache(DocumentLoader*, const ResourceRequest&, const ResourceResponse&, int length); + virtual void dispatchDidLoadResourceByXMLHttpRequest(unsigned long identifier, const ScriptString&); virtual void dispatchDidHandleOnloadEvents(); virtual void dispatchDidReceiveServerRedirectForProvisionalLoad(); @@ -122,7 +123,7 @@ namespace android { virtual void finishedLoading(DocumentLoader*); virtual void updateGlobalHistory(); - virtual void updateGlobalHistoryForRedirectWithoutHistoryItem(); + virtual void updateGlobalHistoryRedirectLinks(); virtual bool shouldGoToHistoryItem(HistoryItem*) const; #ifdef ANDROID_HISTORY_CLIENT @@ -168,17 +169,18 @@ namespace android { virtual WTF::PassRefPtr<Frame> createFrame(const KURL& url, const String& name, HTMLFrameOwnerElement* ownerElement, const String& referrer, bool allowsScrolling, int marginWidth, int marginHeight); - virtual Widget* createPlugin(const IntSize&, Element*, const KURL&, + virtual Widget* createPlugin(const IntSize&, HTMLPlugInElement*, const KURL&, const WTF::Vector<WebCore::String, 0u>&, const WTF::Vector<String, 0u>&, const String&, bool); virtual void redirectDataToPlugin(Widget* pluginWidget); - virtual Widget* createJavaAppletWidget(const IntSize&, Element*, const KURL& baseURL, const Vector<String>& paramNames, const Vector<String>& paramValues); + virtual Widget* createJavaAppletWidget(const IntSize&, HTMLAppletElement*, const KURL& baseURL, const WTF::Vector<String>& paramNames, const WTF::Vector<String>& paramValues); virtual ObjectContentType objectContentType(const KURL& url, const String& mimeType); virtual String overrideMediaType() const; virtual void windowObjectCleared(); + virtual void documentElementAvailable(); virtual void didPerformFirstNavigation() const; virtual void registerForIconNotification(bool listen = true); diff --git a/WebKit/android/WebCoreSupport/InspectorClientAndroid.h b/WebKit/android/WebCoreSupport/InspectorClientAndroid.h index 9eb85e5..2fb3d2a 100644 --- a/WebKit/android/WebCoreSupport/InspectorClientAndroid.h +++ b/WebKit/android/WebCoreSupport/InspectorClientAndroid.h @@ -57,6 +57,7 @@ public: virtual void populateSetting(const String&, InspectorController::Setting&) {} virtual void storeSetting(const String&, const InspectorController::Setting&) {} virtual void removeSetting(const String&) {} + virtual String hiddenPanels() { return String(); } }; } diff --git a/WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp b/WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp new file mode 100644 index 0000000..2465e29 --- /dev/null +++ b/WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp @@ -0,0 +1,285 @@ +/* + * Copyright 2009, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(VIDEO) + +#include "MediaPlayerPrivateAndroid.h" +#include "WebCoreJni.h" +#include "WebViewCore.h" +#include "jni_utility.h" + +#include <JNIHelp.h> +using namespace android; + +namespace WebCore { + +static const char* g_ProxyJavaClass = "android/webkit/HTML5VideoViewProxy"; + +struct MediaPlayerPrivate::JavaGlue +{ + jobject m_javaProxy; + jmethodID m_getInstance; + jmethodID m_play; + jmethodID m_createView; + jmethodID m_attachView; + jmethodID m_removeView; +}; + +MediaPlayerPrivate::~MediaPlayerPrivate() +{ + if (m_glue->m_javaProxy) { + JNIEnv* env = JSC::Bindings::getJNIEnv(); + if (env) { + env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_removeView); + env->DeleteGlobalRef(m_glue->m_javaProxy); + } + } + + delete m_glue; +} + +void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar) +{ + registrar(create, getSupportedTypes, supportsType); +} + +void MediaPlayerPrivate::load(const String& url) +{ + // To be able to create our java player, we need a Context object. To get + // the Context object, we need a WebViewCore java object. To get a java + // WebViewCore object, we need a WebCore::FrameView pointer. To get + // the FrameView pointer, the MediaPlayer::setFrameView() must have been + // called. However, that method is called only after the MediaPlayerClient + // is called back and informed that enough data has been loaded. + // We therefore need to fake a readyStateChanged callback before creating + // the java player. + m_player->readyStateChanged(); + // We now have a RenderVideo created and the MediaPlayer must have + // been updated with a FrameView. Create our JavaPlayer. + createJavaPlayerIfNeeded(); + // Save the URl. + m_url = url; +} + +void MediaPlayerPrivate::cancelLoad() +{ +} + +void MediaPlayerPrivate::play() +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + if (!env || !m_glue->m_javaProxy || !m_url.length()) + return; + + FrameView* frameView = m_player->frameView(); + if (!frameView) + return; + + WebViewCore* webViewCore = WebViewCore::getWebViewCore(frameView); + ASSERT(webViewCore); + jstring jUrl = env->NewString((unsigned short *)m_url.characters(), m_url.length()); + env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_play, jUrl); + env->DeleteLocalRef(jUrl); + checkException(env); +} + +void MediaPlayerPrivate::pause() +{ +} + +IntSize MediaPlayerPrivate::naturalSize() const +{ + return IntSize(300, 150); +} + +bool MediaPlayerPrivate::hasVideo() const +{ + return false; +} + +void MediaPlayerPrivate::setVisible(bool) +{ +} + +float MediaPlayerPrivate::duration() const +{ + return 100; +} + +float MediaPlayerPrivate::currentTime() const +{ + return 0; +} + +void MediaPlayerPrivate::seek(float time) +{ +} + +bool MediaPlayerPrivate::seeking() const +{ + return false; +} + +void MediaPlayerPrivate::setEndTime(float time) +{ +} + +void MediaPlayerPrivate::setRate(float) +{ +} + +bool MediaPlayerPrivate::paused() const +{ + return true; +} + +void MediaPlayerPrivate::setVolume(float) +{ +} + +MediaPlayer::NetworkState MediaPlayerPrivate::networkState() const +{ + return MediaPlayer::Loaded; +} + +MediaPlayer::ReadyState MediaPlayerPrivate::readyState() const +{ + return MediaPlayer::HaveEnoughData; +} + +float MediaPlayerPrivate::maxTimeSeekable() const +{ + return 0; +} + +float MediaPlayerPrivate::maxTimeBuffered() const +{ + return 0; +} + +int MediaPlayerPrivate::dataRate() const +{ + return 0; +} + +unsigned MediaPlayerPrivate::totalBytes() const +{ + return 0; +} + +unsigned MediaPlayerPrivate::bytesLoaded() const +{ + return 0; +} + +void MediaPlayerPrivate::setSize(const IntSize&) +{ +} + +void MediaPlayerPrivate::paint(GraphicsContext*, const IntRect& r) +{ + createJavaPlayerIfNeeded(); + JNIEnv* env = JSC::Bindings::getJNIEnv(); + if (!env) + return; + + IntSize size = m_player->size(); + env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_attachView, + r.x(), r.y(), size.width(), size.height()); +} + +MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player) +{ + return new MediaPlayerPrivate(player); +} + +void MediaPlayerPrivate::getSupportedTypes(HashSet<String>&) +{ +} + +MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, const String& codecs) +{ + return MediaPlayer::IsNotSupported; +} + +MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) : m_player(player), m_glue(NULL) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + if (!env) + return; + + jclass clazz = env->FindClass(g_ProxyJavaClass); + if (!clazz) + return; + + m_glue = new JavaGlue; + m_glue->m_getInstance = env->GetStaticMethodID(clazz, "getInstance", "(Landroid/webkit/WebViewCore;)Landroid/webkit/HTML5VideoViewProxy;"); + m_glue->m_play = env->GetMethodID(clazz, "play", "(Ljava/lang/String;)V"); + m_glue->m_createView = env->GetMethodID(clazz, "createView", "()V"); + m_glue->m_attachView = env->GetMethodID(clazz, "attachView", "(IIII)V"); + m_glue->m_removeView = env->GetMethodID(clazz, "removeView", "()V"); + m_glue->m_javaProxy = NULL; + env->DeleteLocalRef(clazz); + // An exception is raised if any of the above fails. + checkException(env); +} + +void MediaPlayerPrivate::createJavaPlayerIfNeeded() +{ + // Check if we have been already created. + if (m_glue->m_javaProxy) + return; + + FrameView* frameView = m_player->frameView(); + if (!frameView) + return; + + JNIEnv* env = JSC::Bindings::getJNIEnv(); + if (!env) + return; + + jclass clazz = env->FindClass(g_ProxyJavaClass); + if (!clazz) + return; + + WebViewCore* webViewCore = WebViewCore::getWebViewCore(frameView); + ASSERT(webViewCore); + + // Get the HTML5VideoViewProxy instance + jobject obj = env->CallStaticObjectMethod(clazz, m_glue->m_getInstance, webViewCore->getJavaObject().get()); + m_glue->m_javaProxy = env->NewGlobalRef(obj); + // Create our VideoView object. + env->CallVoidMethod(obj, m_glue->m_createView); + // Clean up. + env->DeleteLocalRef(obj); + env->DeleteLocalRef(clazz); + checkException(env); +} + +} + +#endif // VIDEO diff --git a/WebKit/android/jni/JavaBridge.cpp b/WebKit/android/jni/JavaBridge.cpp index d0f7f0e..7c4636f 100644 --- a/WebKit/android/jni/JavaBridge.cpp +++ b/WebKit/android/jni/JavaBridge.cpp @@ -34,6 +34,9 @@ #include "KeyGeneratorClient.h" #include "KURL.h" #include "NetworkStateNotifier.h" +#include "Page.h" +#include "PluginClient.h" +#include "PluginDatabase.h" #include "Timer.h" #include "TimerClient.h" #include "jni_utility.h" @@ -56,7 +59,7 @@ static jfieldID gJavaBridge_ObjectID; // ---------------------------------------------------------------------------- -class JavaBridge : public TimerClient, public CookieClient, public KeyGeneratorClient +class JavaBridge : public TimerClient, public CookieClient, public PluginClient, public KeyGeneratorClient { public: JavaBridge(JNIEnv* env, jobject obj); @@ -68,10 +71,12 @@ public: virtual void setSharedTimer(long long timemillis); virtual void stopSharedTimer(); - virtual void setCookies(WebCore::KURL const& url, WebCore::KURL const& docURL, WebCore::String const& value); + virtual void setCookies(WebCore::KURL const& url, WebCore::String const& value); virtual WebCore::String cookies(WebCore::KURL const& url); virtual bool cookiesEnabled(); + virtual WTF::Vector<WebCore::String> getPluginDirectories(); + virtual WTF::Vector<String> getSupportedKeyStrengthList(); virtual WebCore::String getSignedPublicKeyAndChallengeString(unsigned index, const WebCore::String& challenge, const WebCore::KURL& url); @@ -82,7 +87,7 @@ public: //////////////////////////////////////////// - void signalServiceFuncPtrQueue(); + virtual void signalServiceFuncPtrQueue(); // jni functions static void Constructor(JNIEnv* env, jobject obj); @@ -92,6 +97,7 @@ public: static void SetNetworkOnLine(JNIEnv* env, jobject obj, jboolean online); static void SetDeferringTimers(JNIEnv* env, jobject obj, jboolean defer); static void ServiceFuncPtrQueue(JNIEnv*); + static void UpdatePluginDirectories(JNIEnv* env, jobject obj, jobjectArray array, jboolean reload); private: jobject mJavaObject; @@ -100,13 +106,13 @@ private: jmethodID mSetCookies; jmethodID mCookies; jmethodID mCookiesEnabled; + jmethodID mGetPluginDirectories; jmethodID mSignalFuncPtrQueue; jmethodID mGetKeyStrengthList; jmethodID mGetSignedPublicKey; }; static void (*sSharedTimerFiredCallback)(); -static JavaBridge* gJavaBridge; JavaBridge::JavaBridge(JNIEnv* env, jobject obj) { @@ -115,9 +121,10 @@ JavaBridge::JavaBridge(JNIEnv* env, jobject obj) mSetSharedTimer = env->GetMethodID(clazz, "setSharedTimer", "(J)V"); mStopSharedTimer = env->GetMethodID(clazz, "stopSharedTimer", "()V"); - mSetCookies = env->GetMethodID(clazz, "setCookies", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + mSetCookies = env->GetMethodID(clazz, "setCookies", "(Ljava/lang/String;Ljava/lang/String;)V"); mCookies = env->GetMethodID(clazz, "cookies", "(Ljava/lang/String;)Ljava/lang/String;"); mCookiesEnabled = env->GetMethodID(clazz, "cookiesEnabled", "()Z"); + mGetPluginDirectories = env->GetMethodID(clazz, "getPluginDirectories", "()[Ljava/lang/String;"); mSignalFuncPtrQueue = env->GetMethodID(clazz, "signalServiceFuncPtrQueue", "()V"); mGetKeyStrengthList = env->GetMethodID(clazz, "getKeyStrengthList", "()[Ljava/lang/String;"); mGetSignedPublicKey = env->GetMethodID(clazz, "getSignedPublicKey", "(ILjava/lang/String;Ljava/lang/String;)Ljava/lang/String;"); @@ -132,10 +139,10 @@ JavaBridge::JavaBridge(JNIEnv* env, jobject obj) JavaSharedClient::SetTimerClient(this); JavaSharedClient::SetCookieClient(this); + JavaSharedClient::SetPluginClient(this); JavaSharedClient::SetKeyGeneratorClient(this); - gJavaBridge = this; -} - +} + JavaBridge::~JavaBridge() { if (mJavaObject) { @@ -146,6 +153,7 @@ JavaBridge::~JavaBridge() JavaSharedClient::SetTimerClient(NULL); JavaSharedClient::SetCookieClient(NULL); + JavaSharedClient::SetPluginClient(NULL); JavaSharedClient::SetKeyGeneratorClient(NULL); } @@ -166,19 +174,16 @@ JavaBridge::stopSharedTimer() } void -JavaBridge::setCookies(WebCore::KURL const& url, WebCore::KURL const& docUrl, WebCore::String const& value) +JavaBridge::setCookies(WebCore::KURL const& url, WebCore::String const& value) { JNIEnv* env = JSC::Bindings::getJNIEnv(); const WebCore::String& urlStr = url.string(); jstring jUrlStr = env->NewString(urlStr.characters(), urlStr.length()); - const WebCore::String& docUrlStr = docUrl.string(); - jstring jDocUrlStr = env->NewString(docUrlStr.characters(), docUrlStr.length()); jstring jValueStr = env->NewString(value.characters(), value.length()); AutoJObject obj = getRealObject(env, mJavaObject); - env->CallVoidMethod(obj.get(), mSetCookies, jUrlStr, jDocUrlStr, jValueStr); + env->CallVoidMethod(obj.get(), mSetCookies, jUrlStr, jValueStr); env->DeleteLocalRef(jUrlStr); - env->DeleteLocalRef(jDocUrlStr); env->DeleteLocalRef(jValueStr); } @@ -207,6 +212,25 @@ JavaBridge::cookiesEnabled() return (ret != 0); } +WTF::Vector<WebCore::String> +JavaBridge::getPluginDirectories() +{ + WTF::Vector<WebCore::String> directories; + JNIEnv* env = JSC::Bindings::getJNIEnv(); + AutoJObject obj = getRealObject(env, mJavaObject); + jobjectArray array = (jobjectArray) + env->CallObjectMethod(obj.get(), mGetPluginDirectories); + int count = env->GetArrayLength(array); + for (int i = 0; i < count; i++) { + jstring dir = (jstring) env->GetObjectArrayElement(array, i); + directories.append(to_string(env, dir)); + env->DeleteLocalRef(dir); + } + env->DeleteLocalRef(array); + checkException(env); + return directories; +} + void JavaBridge::setSharedTimerCallback(void (*f)()) { @@ -262,14 +286,6 @@ WebCore::String JavaBridge::getSignedPublicKeyAndChallengeString(unsigned index, // ---------------------------------------------------------------------------- -// visible to Shared -void AndroidSignalServiceFuncPtrQueue() -{ - gJavaBridge->signalServiceFuncPtrQueue(); -} - -// ---------------------------------------------------------------------------- - void JavaBridge::Constructor(JNIEnv* env, jobject obj) { JavaBridge* javaBridge = new JavaBridge(env, obj); @@ -312,16 +328,28 @@ void JavaBridge::SetNetworkOnLine(JNIEnv* env, jobject obj, jboolean online) WebCore::networkStateNotifier().networkStateChange(online); } -void JavaBridge::SetDeferringTimers(JNIEnv* env, jobject obj, jboolean defer) -{ - WebCore::setDeferringTimers(defer); -} - void JavaBridge::ServiceFuncPtrQueue(JNIEnv*) { JavaSharedClient::ServiceFunctionPtrQueue(); } +void JavaBridge::UpdatePluginDirectories(JNIEnv* env, jobject obj, + jobjectArray array, jboolean reload) { + WTF::Vector<WebCore::String> directories; + int count = env->GetArrayLength(array); + for (int i = 0; i < count; i++) { + jstring dir = (jstring) env->GetObjectArrayElement(array, i); + directories.append(to_string(env, dir)); + env->DeleteLocalRef(dir); + } + checkException(env); + WebCore::PluginDatabase *pluginDatabase = + WebCore::PluginDatabase::installedPlugins(); + pluginDatabase->setPluginDirectories(directories); + // refreshPlugins() should refresh both PluginDatabase and Page's PluginData + WebCore::Page::refreshPlugins(reload); +} + // ---------------------------------------------------------------------------- /* @@ -339,10 +367,10 @@ static JNINativeMethod gWebCoreJavaBridgeMethods[] = { (void*) JavaBridge::SetCacheSize }, { "setNetworkOnLine", "(Z)V", (void*) JavaBridge::SetNetworkOnLine }, - { "setDeferringTimers", "(Z)V", - (void*) JavaBridge::SetDeferringTimers }, { "nativeServiceFuncPtrQueue", "()V", (void*) JavaBridge::ServiceFuncPtrQueue }, + { "nativeUpdatePluginDirectories", "([Ljava/lang/String;Z)V", + (void*) JavaBridge::UpdatePluginDirectories } }; int register_javabridge(JNIEnv* env) diff --git a/WebKit/android/jni/JavaSharedClient.cpp b/WebKit/android/jni/JavaSharedClient.cpp index bf52ecd..2eec7b9 100644 --- a/WebKit/android/jni/JavaSharedClient.cpp +++ b/WebKit/android/jni/JavaSharedClient.cpp @@ -25,52 +25,54 @@ #include "config.h" #include "JavaSharedClient.h" -#define LOG_TAG "JavaSharedClient" -#include "utils/Log.h" +#include "TimerClient.h" #include "SkDeque.h" #include "SkThread.h" namespace android { - void AndroidSignalServiceFuncPtrQueue(); - TimerClient* JavaSharedClient::GetTimerClient() { - //LOG_ASSERT(gTimerClient != NULL, "gTimerClient not initialized!!!"); return gTimerClient; } CookieClient* JavaSharedClient::GetCookieClient() { - //LOG_ASSERT(gCookieClient != NULL, "gCookieClient not initialized!!!"); return gCookieClient; } + PluginClient* JavaSharedClient::GetPluginClient() + { + return gPluginClient; + } + KeyGeneratorClient* JavaSharedClient::GetKeyGeneratorClient() { - //LOG_ASSERT(gKeyGeneratorClient != NULL, "gKeyGeneratorClient not initialized!!!"); return gKeyGeneratorClient; } void JavaSharedClient::SetTimerClient(TimerClient* client) { - //LOG_ASSERT(gTimerClient == NULL || client == NULL, "gTimerClient already set, aborting..."); gTimerClient = client; } void JavaSharedClient::SetCookieClient(CookieClient* client) { - //LOG_ASSERT(gCookieClient == NULL || client == NULL, "gCookieClient already set, aborting..."); gCookieClient = client; } + void JavaSharedClient::SetPluginClient(PluginClient* client) + { + gPluginClient = client; + } + void JavaSharedClient::SetKeyGeneratorClient(KeyGeneratorClient* client) { - //LOG_ASSERT(gKeyGeneratorClient == NULL || client == NULL, "gKeyGeneratorClient already set, aborting..."); gKeyGeneratorClient = client; } TimerClient* JavaSharedClient::gTimerClient = NULL; CookieClient* JavaSharedClient::gCookieClient = NULL; + PluginClient* JavaSharedClient::gPluginClient = NULL; KeyGeneratorClient* JavaSharedClient::gKeyGeneratorClient = NULL; /////////////////////////////////////////////////////////////////////////// @@ -94,7 +96,7 @@ namespace android { gFuncPtrQMutex.release(); - android::AndroidSignalServiceFuncPtrQueue(); + gTimerClient->signalServiceFuncPtrQueue(); } void JavaSharedClient::ServiceFunctionPtrQueue() diff --git a/WebKit/android/jni/JavaSharedClient.h b/WebKit/android/jni/JavaSharedClient.h index 862b508..bf59969 100644 --- a/WebKit/android/jni/JavaSharedClient.h +++ b/WebKit/android/jni/JavaSharedClient.h @@ -30,6 +30,7 @@ namespace android { class TimerClient; class CookieClient; + class PluginClient; class KeyGeneratorClient; class JavaSharedClient @@ -37,20 +38,23 @@ namespace android { public: static TimerClient* GetTimerClient(); static CookieClient* GetCookieClient(); + static PluginClient* GetPluginClient(); static KeyGeneratorClient* GetKeyGeneratorClient(); static void SetTimerClient(TimerClient* client); static void SetCookieClient(CookieClient* client); + static void SetPluginClient(PluginClient* client); static void SetKeyGeneratorClient(KeyGeneratorClient* client); // can be called from any thread, to be executed in webkit thread static void EnqueueFunctionPtr(void (*proc)(void*), void* payload); // only call this from webkit thread static void ServiceFunctionPtrQueue(); - + private: static TimerClient* gTimerClient; static CookieClient* gCookieClient; + static PluginClient* gPluginClient; static KeyGeneratorClient* gKeyGeneratorClient; }; } diff --git a/WebKit/android/jni/PictureSet.cpp b/WebKit/android/jni/PictureSet.cpp index ac3f38a..e8fcba5 100644 --- a/WebKit/android/jni/PictureSet.cpp +++ b/WebKit/android/jni/PictureSet.cpp @@ -263,7 +263,7 @@ bool PictureSet::draw(SkCanvas* canvas) SkPath pathClip; area.getBoundaryPath(&pathClip); canvas->clipPath(pathClip); - pathClip.computeBounds(&pathBounds, SkPath::kFast_BoundsType); + pathBounds = pathClip.getBounds(); } else { pathBounds.set(area.getBounds()); canvas->clipRect(pathBounds); diff --git a/WebKit/android/jni/WebCoreFrameBridge.cpp b/WebKit/android/jni/WebCoreFrameBridge.cpp index e2299c8..46e1fdc 100644 --- a/WebKit/android/jni/WebCoreFrameBridge.cpp +++ b/WebKit/android/jni/WebCoreFrameBridge.cpp @@ -41,14 +41,16 @@ #include "EditorClientAndroid.h" #include "Element.h" #include "Font.h" +#include "FormState.h" #include "Frame.h" #include "FrameLoader.h" #include "FrameLoaderClientAndroid.h" +#include "FrameLoadRequest.h" #include "FrameTree.h" #include "FrameView.h" -#include "GCController.h" #include "GraphicsContext.h" #include "HistoryItem.h" +#include "HTMLCollection.h" #include "HTMLElement.h" #include "HTMLFormElement.h" #include "HTMLInputElement.h" @@ -56,9 +58,18 @@ #include "IconDatabase.h" #include "Image.h" #include "InspectorClientAndroid.h" + +#if USE(JSC) +#include "GCController.h" #include "JSDOMWindow.h" #include <runtime/InitializeThreading.h> #include <runtime/JSLock.h> +#elif USE(V8) +#include "V8InitializeThreading.h" +#include "jni_npobject.h" +#include "jni_instance.h" +#endif // USE(JSC) + #include "KURL.h" #include "Page.h" #include "PageCache.h" @@ -82,11 +93,17 @@ #include "WebViewCore.h" #include "wds/DebugServer.h" +#if USE(JSC) #include <runtime_root.h> #include <runtime_object.h> +#endif // USE(JSC) + #include <jni_utility.h> #include "jni.h" + +#if USE(JSC) #include "jni_instance.h" +#endif // USE(JSC) #include <JNIHelp.h> #include <SkGraphics.h> @@ -96,12 +113,8 @@ #ifdef ANDROID_INSTRUMENT #include "TimeCounter.h" -#include <runtime/JSLock.h> #endif -using namespace JSC; -using namespace JSC::Bindings; - namespace android { // ---------------------------------------------------------------------------- @@ -152,7 +165,7 @@ WebFrame::WebFrame(JNIEnv* env, jobject obj, jobject historyList, WebCore::Page* mJavaFrame->mObj = adoptGlobalRef(env, obj); mJavaFrame->mHistoryList = adoptGlobalRef(env, historyList); mJavaFrame->mStartLoadingResource = env->GetMethodID(clazz, "startLoadingResource", - "(ILjava/lang/String;Ljava/lang/String;Ljava/util/HashMap;[BIZZ)Landroid/webkit/LoadListener;"); + "(ILjava/lang/String;Ljava/lang/String;Ljava/util/HashMap;[BIZ)Landroid/webkit/LoadListener;"); mJavaFrame->mLoadStarted = env->GetMethodID(clazz, "loadStarted", "(Ljava/lang/String;Landroid/graphics/Bitmap;IZ)V"); mJavaFrame->mTransitionToCommitted = env->GetMethodID(clazz, "transitionToCommitted", @@ -247,6 +260,7 @@ static jobject createJavaMapFromHTTPHeaders(JNIEnv* env, const WebCore::HTTPHead env->DeleteLocalRef(val); } } + env->DeleteLocalRef(mapClass); return hashMap; @@ -255,7 +269,7 @@ static jobject createJavaMapFromHTTPHeaders(JNIEnv* env, const WebCore::HTTPHead WebCoreResourceLoader* WebFrame::startLoadingResource(WebCore::ResourceHandle* loader, const WebCore::ResourceRequest& request, - bool isHighPriority, bool synchronous) + bool synchronous) { #ifdef ANDROID_INSTRUMENT TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); @@ -340,7 +354,7 @@ WebFrame::startLoadingResource(WebCore::ResourceHandle* loader, jobject jLoadListener = env->CallObjectMethod(mJavaFrame->frame(env).get(), mJavaFrame->mStartLoadingResource, (int)loader, jUrlStr, jMethodStr, jHeaderMap, - jPostDataStr, cacheMode, isHighPriority, synchronous); + jPostDataStr, cacheMode, synchronous); env->DeleteLocalRef(jUrlStr); env->DeleteLocalRef(jMethodStr); @@ -570,17 +584,11 @@ WebFrame::canHandleRequest(const WebCore::ResourceRequest& request) #ifdef ANDROID_INSTRUMENT TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); #endif - // Internal loads are ok but any request that is due to a user hitting a key - // should be checked. - bool userGesture = false; -#ifdef ANDROID_USER_GESTURE - userGesture = request.userGesture(); -#endif // always handle "POST" in place if (equalIgnoringCase(request.httpMethod(), "POST")) return true; WebCore::KURL requestUrl = request.url(); - if (!mUserInitiatedClick && !userGesture && + if (!mUserInitiatedClick && (requestUrl.protocolIs("http") || requestUrl.protocolIs("https") || requestUrl.protocolIs("file") || requestUrl.protocolIs("about") || requestUrl.protocolIs("javascript"))) @@ -680,7 +688,12 @@ static void CallPolicyFunction(JNIEnv* env, jobject obj, jint func, jint decisio static void CreateFrame(JNIEnv* env, jobject obj, jobject javaview, jobject jAssetManager, jobject historyList) { +#if USE(JSC) JSC::initializeThreading(); +#elif USE(V8) + V8::initializeThreading(); +#endif + #ifdef ANDROID_INSTRUMENT TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter); #endif @@ -723,17 +736,15 @@ static void CreateFrame(JNIEnv* env, jobject obj, jobject javaview, jobject jAss WebViewCore* webViewCore = new WebViewCore(env, javaview, frame); // Create a FrameView - WebCore::FrameView* frameView = new WebCore::FrameView(frame); + RefPtr<WebCore::FrameView> frameView = WebCore::FrameView::create(frame); // Create a WebFrameView - WebFrameView* webFrameView = new WebFrameView(frameView, webViewCore); + WebFrameView* webFrameView = new WebFrameView(frameView.get(), webViewCore); // As webFrameView Retains webViewCore, release our ownership Release(webViewCore); // As frameView Retains webFrameView, release our ownership Release(webFrameView); // Attach the frameView to the frame and release our ownership frame->setView(frameView); - frameView->deref(); - // Set the frame to active to turn on keyboard focus. frame->init(); frame->selection()->setFocused(true); @@ -805,6 +816,7 @@ static void PostUrl(JNIEnv *env, jobject obj, jstring url, jbyteArray postData) WebCore::KURL kurl(WebCore::KURL(), to_string(env, url)); WebCore::ResourceRequest request(kurl); + request.setHTTPMethod("POST"); request.setHTTPContentType("application/x-www-form-urlencoded"); if (postData) { @@ -815,8 +827,8 @@ static void PostUrl(JNIEnv *env, jobject obj, jstring url, jbyteArray postData) } LOGV("PostUrl %s", kurl.string().latin1().data()); - pFrame->loader()->loadPostRequest(request, String(), String(), false, - WebCore::FrameLoadTypeStandard, 0, 0, true); + WebCore::FrameLoadRequest frameRequest(request); + pFrame->loader()->loadFrameRequest(frameRequest, false, false, 0, 0); } static void LoadData(JNIEnv *env, jobject obj, jstring baseUrl, jstring data, @@ -950,21 +962,22 @@ static jobject StringByEvaluatingJavaScriptFromString(JNIEnv *env, jobject obj, return env->NewString((unsigned short*)result.characters(), len); } +#if USE(JSC) // Wrap the JavaInstance used when binding custom javascript interfaces. Use a // weak reference so that the gc can collect the WebView. Override virtualBegin // and virtualEnd and swap the weak reference for the real object. -class WeakJavaInstance : public JavaInstance { +class WeakJavaInstance : public JSC::Bindings::JavaInstance { public: static PassRefPtr<WeakJavaInstance> create(jobject obj, - PassRefPtr<RootObject> root) { + PassRefPtr<JSC::Bindings::RootObject> root) { return adoptRef(new WeakJavaInstance(obj, root)); } protected: - WeakJavaInstance(jobject instance, PassRefPtr<RootObject> rootObject) - : JavaInstance(instance, rootObject) + WeakJavaInstance(jobject instance, PassRefPtr<JSC::Bindings::RootObject> rootObject) + : JSC::Bindings::JavaInstance(instance, rootObject) { - JNIEnv* env = getJNIEnv(); + JNIEnv* env = JSC::Bindings::getJNIEnv(); // JavaInstance creates a global ref to instance in its constructor. env->DeleteGlobalRef(_instance->_instance); // Set the object to our WeakReference wrapper. @@ -973,7 +986,7 @@ protected: virtual void virtualBegin() { _weakRef = _instance->_instance; - JNIEnv* env = getJNIEnv(); + JNIEnv* env = JSC::Bindings::getJNIEnv(); // This is odd. getRealObject returns an AutoJObject which is used to // cleanly create and delete a local reference. But, here we need to // maintain the local reference across calls to virtualBegin() and @@ -990,16 +1003,17 @@ protected: // Call the base class method first to pop the local frame. INHERITED::virtualEnd(); // Get rid of the local reference to the real object. - getJNIEnv()->DeleteLocalRef(_realObject); + JSC::Bindings::getJNIEnv()->DeleteLocalRef(_realObject); // Point back to the WeakReference. _instance->_instance = _weakRef; } private: - typedef JavaInstance INHERITED; + typedef JSC::Bindings::JavaInstance INHERITED; jobject _realObject; jobject _weakRef; }; +#endif // USE(JSC) static void AddJavascriptInterface(JNIEnv *env, jobject obj, jint nativeFramePointer, jobject javascriptObj, jstring interfaceName) @@ -1014,6 +1028,7 @@ static void AddJavascriptInterface(JNIEnv *env, jobject obj, jint nativeFramePoi env->GetJavaVM(&vm); LOGV("::WebCore:: addJSInterface: %p", pFrame); +#if USE(JSC) // Copied from qwebframe.cpp JSC::JSLock lock(false); WebCore::JSDOMWindow *window = WebCore::toJSDOMWindow(pFrame); @@ -1034,6 +1049,24 @@ static void AddJavascriptInterface(JNIEnv *env, jobject obj, jint nativeFramePoi checkException(env); } } +#endif // USE(JSC) + +#if USE(V8) + if (pFrame) { + const char* name = JSC::Bindings::getCharactersFromJStringInEnv(env, interfaceName); + NPObject* obj = JSC::Bindings::JavaInstanceToNPObject(new JSC::Bindings::JavaInstance(javascriptObj)); + pFrame->script()->bindToWindowObject(pFrame, name, obj); + // JavaInstanceToNPObject calls NPN_RetainObject on the + // returned one (see CreateV8ObjectForNPObject in V8NPObject.cpp). + // BindToWindowObject also increases obj's ref count and decrease + // the ref count when the object is not reachable from JavaScript + // side. Code here must release the reference count increased by + // JavaInstanceToNPObject. + NPN_ReleaseObject(obj); + JSC::Bindings::releaseCharactersForJString(interfaceName, name); + } +#endif + } static void SetCacheDisabled(JNIEnv *env, jobject obj, jboolean disabled) @@ -1056,22 +1089,25 @@ static void ClearCache(JNIEnv *env, jobject obj) { #ifdef ANDROID_INSTRUMENT TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter); - +#if USE(JSC) JSC::JSLock lock(false); JSC::Heap::Statistics jsHeapStatistics = WebCore::JSDOMWindow::commonJSGlobalData()->heap.statistics(); LOGD("About to gc and JavaScript heap size is %d and has %d bytes free", jsHeapStatistics.size, jsHeapStatistics.free); +#endif // USE(JSC) LOGD("About to clear cache and current cache has %d bytes live and %d bytes dead", cache()->getLiveSize(), cache()->getDeadSize()); -#endif +#endif // ANDROID_INSTRUMENT if (!WebCore::cache()->disabled()) { // Disabling the cache will remove all resources from the cache. They may // still live on if they are referenced by some Web page though. WebCore::cache()->setDisabled(true); WebCore::cache()->setDisabled(false); } +#if USE(JSC) // force JavaScript to GC when clear cache WebCore::gcController().garbageCollectSoon(); +#endif // USE(JSC) } static jboolean DocumentHasImages(JNIEnv *env, jobject obj) diff --git a/WebKit/android/jni/WebCoreFrameBridge.h b/WebKit/android/jni/WebCoreFrameBridge.h index f554117..5bfd1fb 100644 --- a/WebKit/android/jni/WebCoreFrameBridge.h +++ b/WebKit/android/jni/WebCoreFrameBridge.h @@ -63,7 +63,6 @@ class WebFrame : public WebCoreRefObject { virtual WebCoreResourceLoader* startLoadingResource(WebCore::ResourceHandle*, const WebCore::ResourceRequest& request, - bool isHighPriority, bool synchronous); void reportError(int errorCode, const WebCore::String& description, diff --git a/WebKit/android/jni/WebCoreJni.cpp b/WebKit/android/jni/WebCoreJni.cpp index f9d9cc9..b757e3a 100644 --- a/WebKit/android/jni/WebCoreJni.cpp +++ b/WebKit/android/jni/WebCoreJni.cpp @@ -33,15 +33,6 @@ namespace android { -extern int register_webframe(JNIEnv*); -extern int register_javabridge(JNIEnv*); -extern int register_resource_loader(JNIEnv*); -extern int register_webviewcore(JNIEnv*); -extern int register_webhistory(JNIEnv*); -extern int register_webicondatabase(JNIEnv*); -extern int register_websettings(JNIEnv*); -extern int register_webview(JNIEnv*); - // Class, constructor, and get method on WeakReference jclass gWeakRefClass; jmethodID gWeakRefInit; @@ -93,41 +84,11 @@ WebCore::String to_string(JNIEnv* env, jstring str) return ret; } -} - -struct RegistrationMethod { - const char* name; - int (*func)(JNIEnv*); -}; - -static RegistrationMethod gWebCoreRegMethods[] = { - { "JavaBridge", android::register_javabridge }, - { "WebFrame", android::register_webframe }, - { "WebCoreResourceLoader", android::register_resource_loader }, - { "WebViewCore", android::register_webviewcore }, - { "WebHistory", android::register_webhistory }, - { "WebIconDatabase", android::register_webicondatabase }, - { "WebSettings", android::register_websettings }, - { "WebView", android::register_webview } -}; - -EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) -{ - // Save the JavaVM pointer for use globally. - JSC::Bindings::setJavaVM(vm); - - JNIEnv* env = NULL; - jint result = -1; - - if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { - LOGE("GetEnv failed!"); - return result; - } - LOG_ASSERT(env, "Could not retrieve the env!"); - +int register_webcorejni(JNIEnv* env) { // Instantiate the WeakReference fields. - android::gWeakRefClass = env->FindClass("java/lang/ref/WeakReference"); - LOG_ASSERT(android::gWeakRefClass, "Could not find WeakReference"); + jclass weakRef = env->FindClass("java/lang/ref/WeakReference"); + LOG_ASSERT(weakRef, "Could not find WeakReference"); + android::gWeakRefClass = (jclass)env->NewGlobalRef(weakRef); android::gWeakRefInit = env->GetMethodID(android::gWeakRefClass, "<init>", "(Ljava/lang/Object;)V"); LOG_ASSERT(android::gWeakRefInit, @@ -136,20 +97,7 @@ EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) "()Ljava/lang/Object;"); LOG_ASSERT(android::gWeakRefInit, "Could not find get method for WeakReference"); + return JNI_OK; +} - const RegistrationMethod* method = gWebCoreRegMethods; - const RegistrationMethod* end = method + sizeof(gWebCoreRegMethods)/sizeof(RegistrationMethod); - while (method != end) { - if (method->func(env) < 0) { - LOGE("%s registration failed!", method->name); - return result; - } - method++; - } - - // Initialize rand() function. The rand() function is used in - // FileSystemAndroid to create a random temporary filename. - srand(time(NULL)); - - return JNI_VERSION_1_4; } diff --git a/WebKit/android/jni/WebCoreJniOnLoad.cpp b/WebKit/android/jni/WebCoreJniOnLoad.cpp new file mode 100644 index 0000000..c6b0022 --- /dev/null +++ b/WebKit/android/jni/WebCoreJniOnLoad.cpp @@ -0,0 +1,100 @@ +/* + * Copyright 2009, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#define LOG_TAG "webcoreglue" + +#include "config.h" + +#include "jni_utility.h" +#include <jni.h> +#include <utils/Log.h> + +namespace android { + +extern int register_webframe(JNIEnv*); +extern int register_javabridge(JNIEnv*); +extern int register_resource_loader(JNIEnv*); +extern int register_webviewcore(JNIEnv*); +extern int register_webhistory(JNIEnv*); +extern int register_webicondatabase(JNIEnv*); +extern int register_websettings(JNIEnv*); +extern int register_webview(JNIEnv*); +extern int register_webcorejni(JNIEnv*); + +#if ENABLE(DATABASE) +extern int register_webstorage(JNIEnv*); +#endif + +} + +struct RegistrationMethod { + const char* name; + int (*func)(JNIEnv*); +}; + +static RegistrationMethod gWebCoreRegMethods[] = { + { "JavaBridge", android::register_javabridge }, + { "WebFrame", android::register_webframe }, + { "WebCoreResourceLoader", android::register_resource_loader }, + { "WebCoreJni", android::register_webcorejni }, + { "WebViewCore", android::register_webviewcore }, + { "WebHistory", android::register_webhistory }, + { "WebIconDatabase", android::register_webicondatabase }, + { "WebSettings", android::register_websettings }, +#if ENABLE(DATABASE) + { "WebStorage", android::register_webstorage }, +#endif + { "WebView", android::register_webview } +}; + +EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) +{ + // Save the JavaVM pointer for use globally. + JSC::Bindings::setJavaVM(vm); + + JNIEnv* env = NULL; + jint result = -1; + + if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { + LOGE("GetEnv failed!"); + return result; + } + LOG_ASSERT(env, "Could not retrieve the env!"); + + const RegistrationMethod* method = gWebCoreRegMethods; + const RegistrationMethod* end = method + sizeof(gWebCoreRegMethods)/sizeof(RegistrationMethod); + while (method != end) { + if (method->func(env) < 0) { + LOGE("%s registration failed!", method->name); + return result; + } + method++; + } + + // Initialize rand() function. The rand() function is used in + // FileSystemAndroid to create a random temporary filename. + srand(time(NULL)); + + return JNI_VERSION_1_4; +} diff --git a/WebKit/android/jni/WebCoreResourceLoader.cpp b/WebKit/android/jni/WebCoreResourceLoader.cpp index d4eda81..5ccd09c 100644 --- a/WebKit/android/jni/WebCoreResourceLoader.cpp +++ b/WebKit/android/jni/WebCoreResourceLoader.cpp @@ -134,7 +134,7 @@ void WebCoreResourceLoader::SetResponseHeader(JNIEnv* env, jobject obj, jint nat jint WebCoreResourceLoader::CreateResponse(JNIEnv* env, jobject obj, jstring url, jint statusCode, jstring statusText, jstring mimeType, jlong expectedLength, - jstring encoding, jlong expireTime) + jstring encoding) { #ifdef ANDROID_INSTRUMENT TimeCounterAuto counter(TimeCounter::ResourceTimeCounter); @@ -160,10 +160,6 @@ jint WebCoreResourceLoader::CreateResponse(JNIEnv* env, jobject obj, jstring url response->setHTTPStatusText(status); LOGV("Response setStatusText: %s", status.latin1().data()); } - // FIXME: This assumes that time_t is a long and that long is the same size as int. - if ((unsigned long)expireTime > INT_MAX) - expireTime = INT_MAX; - response->setExpirationDate((time_t)expireTime); return (int)response; } @@ -286,7 +282,7 @@ static JNINativeMethod gResourceloaderMethods[] = { /* name, signature, funcPtr */ { "nativeSetResponseHeader", "(ILjava/lang/String;Ljava/lang/String;)V", (void*) WebCoreResourceLoader::SetResponseHeader }, - { "nativeCreateResponse", "(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;JLjava/lang/String;J)I", + { "nativeCreateResponse", "(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;JLjava/lang/String;)I", (void*) WebCoreResourceLoader::CreateResponse }, { "nativeReceivedResponse", "(I)V", (void*) WebCoreResourceLoader::ReceivedResponse }, diff --git a/WebKit/android/jni/WebCoreResourceLoader.h b/WebKit/android/jni/WebCoreResourceLoader.h index 5dd5abe..60c0d0e 100644 --- a/WebKit/android/jni/WebCoreResourceLoader.h +++ b/WebKit/android/jni/WebCoreResourceLoader.h @@ -58,7 +58,7 @@ public: // Native jni functions static void SetResponseHeader(JNIEnv*, jobject, jint, jstring, jstring); static jint CreateResponse(JNIEnv*, jobject, jstring, jint, jstring, - jstring, jlong, jstring, jlong); + jstring, jlong, jstring); static void ReceivedResponse(JNIEnv*, jobject, jint); static void AddData(JNIEnv*, jobject, jbyteArray, jint); static void Finished(JNIEnv*, jobject); diff --git a/WebKit/android/jni/WebFrameView.cpp b/WebKit/android/jni/WebFrameView.cpp index f9a9a5b..0ab7410 100644 --- a/WebKit/android/jni/WebFrameView.cpp +++ b/WebKit/android/jni/WebFrameView.cpp @@ -84,12 +84,9 @@ void WebFrameView::draw(WebCore::GraphicsContext* ctx, const WebCore::IntRect& r transRect.move(-bounds.x(), -bounds.y()); // Translate the canvas, add a clip. - SkRect r; - android_setrect(&r, transRect); - canvas->save(); canvas->translate(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y())); - canvas->clipRect(r); + canvas->clipRect(transRect); } mFrameView->paintContents(ctx, transRect); if (canvas) diff --git a/WebKit/android/jni/WebHistory.cpp b/WebKit/android/jni/WebHistory.cpp index cd6e0f1..aa80bf0 100644 --- a/WebKit/android/jni/WebHistory.cpp +++ b/WebKit/android/jni/WebHistory.cpp @@ -120,7 +120,7 @@ static void WebHistoryClose(JNIEnv* env, jobject obj, jint frame) while (child) { // Use the old history item since the current one may have a // deleted parent. - WebCore::HistoryItem* item = parent->childItemWithName(child->tree()->name()); + WebCore::HistoryItem* item = parent->childItemWithTarget(child->tree()->name()); child->loader()->setCurrentHistoryItem(item); // Append the first child to the queue if it exists. if (WebCore::Frame* f = child->tree()->firstChild()) @@ -153,7 +153,6 @@ static void WebHistoryRestoreIndex(JNIEnv* env, jobject obj, jint frame, jint in // Update the current and previous history item. WebCore::FrameLoader* loader = pFrame->loader(); loader->setCurrentHistoryItem(currentItem); - loader->setPreviousHistoryItem(list->backItem()); // load the current page with FrameLoadTypeIndexedBackForward so that it // will use cache when it is possible diff --git a/WebKit/android/jni/WebSettings.cpp b/WebKit/android/jni/WebSettings.cpp index 407544a..7d2b12d 100644 --- a/WebKit/android/jni/WebSettings.cpp +++ b/WebKit/android/jni/WebSettings.cpp @@ -28,17 +28,15 @@ #include <config.h> #include <wtf/Platform.h> +#include "ApplicationCacheStorage.h" +#include "DatabaseTracker.h" +#include "DocLoader.h" #include "Document.h" #include "Frame.h" #include "FrameLoader.h" #include "FrameView.h" -#include "DocLoader.h" #include "Page.h" #include "RenderTable.h" -#ifdef ANDROID_PLUGINS -#include "PlatformString.h" -#include "PluginDatabase.h" -#endif #include "Settings.h" #include "WebCoreFrameBridge.h" #include "WebCoreJni.h" @@ -46,11 +44,6 @@ #include <JNIHelp.h> #include <utils/misc.h> -namespace WebCore { -// Defined in FileSystemAndroid.cpp -extern String sPluginPath; -} - namespace android { struct FieldIds { @@ -85,8 +78,20 @@ struct FieldIds { #endif mJavaScriptEnabled = env->GetFieldID(clazz, "mJavaScriptEnabled", "Z"); mPluginsEnabled = env->GetFieldID(clazz, "mPluginsEnabled", "Z"); -#ifdef ANDROID_PLUGINS - mPluginsPath = env->GetFieldID(clazz, "mPluginsPath", "Ljava/lang/String;"); +#if ENABLE(DATABASE) + mDatabaseEnabled = env->GetFieldID(clazz, "mDatabaseEnabled", "Z"); +#endif +#if ENABLE(DOM_STORAGE) + mDomStorageEnabled = env->GetFieldID(clazz, "mDomStorageEnabled", "Z"); +#endif +#if ENABLE(DATABASE) || ENABLE(DOM_STORAGE) + // The databases saved to disk for both the SQL and DOM Storage APIs are stored + // in the same base directory. + mDatabasePath = env->GetFieldID(clazz, "mDatabasePath", "Ljava/lang/String;"); +#endif +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + mAppCacheEnabled = env->GetFieldID(clazz, "mAppCacheEnabled", "Z"); + mAppCachePath = env->GetFieldID(clazz, "mAppCachePath", "Ljava/lang/String;"); #endif mJavaScriptCanOpenWindowsAutomatically = env->GetFieldID(clazz, "mJavaScriptCanOpenWindowsAutomatically", "Z"); @@ -112,11 +117,12 @@ struct FieldIds { LOG_ASSERT(mLoadsImagesAutomatically, "Could not find field mLoadsImagesAutomatically"); #ifdef ANDROID_BLOCK_NETWORK_IMAGE LOG_ASSERT(mBlockNetworkImage, "Could not find field mBlockNetworkImage"); -#endif +#endif LOG_ASSERT(mJavaScriptEnabled, "Could not find field mJavaScriptEnabled"); LOG_ASSERT(mPluginsEnabled, "Could not find field mPluginsEnabled"); -#ifdef ANDROID_PLUGINS - LOG_ASSERT(mPluginsPath, "Could not find field mPluginsPath"); +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + LOG_ASSERT(mAppCacheEnabled, "Could not find field mAppCacheEnabled"); + LOG_ASSERT(mAppCachePath, "Could not find field mAppCachePath"); #endif LOG_ASSERT(mJavaScriptCanOpenWindowsAutomatically, "Could not find field mJavaScriptCanOpenWindowsAutomatically"); @@ -155,18 +161,28 @@ struct FieldIds { #endif jfieldID mJavaScriptEnabled; jfieldID mPluginsEnabled; -#ifdef ANDROID_PLUGINS - jfieldID mPluginsPath; +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + jfieldID mAppCacheEnabled; + jfieldID mAppCachePath; #endif jfieldID mJavaScriptCanOpenWindowsAutomatically; jfieldID mUseWideViewport; jfieldID mSupportMultipleWindows; jfieldID mShrinksStandaloneImagesToFit; jfieldID mUseDoubleTree; - // Ordinal() method and value field for enums jmethodID mOrdinal; jfieldID mTextSizeValue; + +#if ENABLE(DATABASE) + jfieldID mDatabaseEnabled; +#endif +#if ENABLE(DOM_STORAGE) + jfieldID mDomStorageEnabled; +#endif +#if ENABLE(DATABASE) || ENABLE(DOM_STORAGE) + jfieldID mDatabasePath; +#endif }; static struct FieldIds* gFieldIds; @@ -273,47 +289,17 @@ public: flag = env->GetBooleanField(obj, gFieldIds->mPluginsEnabled); s->setPluginsEnabled(flag); -#ifdef ANDROID_PLUGINS - ::WebCore::PluginDatabase *pluginDatabase = - ::WebCore::PluginDatabase::installedPlugins(); - str = (jstring)env->GetObjectField(obj, gFieldIds->mPluginsPath); +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + flag = env->GetBooleanField(obj, gFieldIds->mAppCacheEnabled); + s->setOfflineWebApplicationCacheEnabled(flag); + str = (jstring)env->GetObjectField(obj, gFieldIds->mAppCachePath); if (str) { - WebCore::String pluginsPath = to_string(env, str); - // When a new browser Tab is created, the corresponding - // Java WebViewCore object will sync (with the native - // side) its associated WebSettings at initialization - // time. However, at that point, the WebSettings object's - // mPluginsPaths member is set to the empty string. The - // real plugin path will be set later by the tab and the - // WebSettings will be synced again. - // - // There is no point in instructing WebCore's - // PluginDatabase instance to set the plugin path to the - // empty string. Furthermore, if the PluginDatabase - // instance is already initialized, setting the path to - // the empty string will cause the PluginDatabase to - // forget about the plugin files it has already - // inspected. When the path is subsequently set to the - // correct value, the PluginDatabase will attempt to load - // and initialize plugins that are already loaded and - // initialized. - if (pluginsPath.length()) { - s->setPluginsPath(pluginsPath); - // Set the plugin directories to this single entry. - Vector< ::WebCore::String > paths(1); - paths[0] = pluginsPath; - pluginDatabase->setPluginDirectories(paths); - // Set the home directory for plugin temporary files - WebCore::sPluginPath = paths[0]; - // Reload plugins. We call Page::refreshPlugins() instead - // of pluginDatabase->refresh(), as we need to ensure that - // the list of mimetypes exposed by the browser are also - // updated. - WebCore::Page::refreshPlugins(false); + WebCore::String path = to_string(env, str); + if (path.length()) { + WebCore::cacheStorage().setCacheDirectory(path); } } #endif - flag = env->GetBooleanField(obj, gFieldIds->mJavaScriptCanOpenWindowsAutomatically); s->setJavaScriptCanOpenWindowsAutomatically(flag); @@ -328,9 +314,22 @@ public: #endif flag = env->GetBooleanField(obj, gFieldIds->mShrinksStandaloneImagesToFit); s->setShrinksStandaloneImagesToFit(flag); -#if USE(LOW_BANDWIDTH_DISPLAY) - flag = env->GetBooleanField(obj, gFieldIds->mUseDoubleTree); - pFrame->loader()->setUseLowBandwidthDisplay(flag); +#if ENABLE(DATABASE) + flag = env->GetBooleanField(obj, gFieldIds->mDatabaseEnabled); + s->setDatabasesEnabled(flag); + str = (jstring)env->GetObjectField(obj, gFieldIds->mDatabasePath); + WebCore::DatabaseTracker::tracker().setDatabaseDirectoryPath(to_string(env, str)); +#endif +#if ENABLE(DOM_STORAGE) + flag = env->GetBooleanField(obj, gFieldIds->mDomStorageEnabled); + s->setLocalStorageEnabled(flag); + str = (jstring)env->GetObjectField(obj, gFieldIds->mDatabasePath); + if (str) { + WebCore::String localStorageDatabasePath = to_string(env,str); + if (localStorageDatabasePath.length()) { + s->setLocalStorageDatabasePath(localStorageDatabasePath); + } + } #endif } }; diff --git a/WebKit/android/jni/WebStorage.cpp b/WebKit/android/jni/WebStorage.cpp new file mode 100644 index 0000000..aa83892 --- /dev/null +++ b/WebKit/android/jni/WebStorage.cpp @@ -0,0 +1,166 @@ +/* + * Copyright 2009, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(DATABASE) + +#include <JNIHelp.h> + +#include <WebCore/loader/appcache/ApplicationCacheStorage.h> +#include <WebCore/page/SecurityOrigin.h> +#include <WebCore/storage/DatabaseTracker.h> + +#include "JavaSharedClient.h" +#include "jni_utility.h" +#include "KURL.h" +#include "WebCoreJni.h" + +namespace android { + +static jobject GetOrigins(JNIEnv* env, jobject obj) +{ + Vector<RefPtr<WebCore::SecurityOrigin> > coreOrigins; + WebCore::DatabaseTracker::tracker().origins(coreOrigins); + Vector<WebCore::KURL> manifestUrls; + if (WebCore::cacheStorage().manifestURLs(&manifestUrls)) { + int size = manifestUrls.size(); + for (int i = 0; i < size; ++i) { + RefPtr<WebCore::SecurityOrigin> manifestOrigin = WebCore::SecurityOrigin::create(manifestUrls[i]); + if (manifestOrigin.get() == 0) + continue; + coreOrigins.append(manifestOrigin); + } + } + + jclass setClass = env->FindClass("java/util/HashSet"); + jmethodID cid = env->GetMethodID(setClass, "<init>", "()V"); + jmethodID mid = env->GetMethodID(setClass, "add", "(Ljava/lang/Object;)Z"); + jobject set = env->NewObject(setClass, cid); + + for (unsigned i = 0; i < coreOrigins.size(); ++i) { + WebCore::SecurityOrigin* origin = coreOrigins[i].get(); + WebCore::String url = origin->toString(); + jstring jUrl = env->NewString(url.characters(), url.length()); + env->CallBooleanMethod(set, mid, jUrl); + env->DeleteLocalRef(jUrl); + } + + return set; +} + +static unsigned long long GetQuotaForOrigin(JNIEnv* env, jobject obj, jstring origin) +{ + WebCore::String originStr = to_string(env, origin); + RefPtr<WebCore::SecurityOrigin> securityOrigin = WebCore::SecurityOrigin::createFromString(originStr); + unsigned long long quota = WebCore::DatabaseTracker::tracker().quotaForOrigin(securityOrigin.get()); + return quota; +} + +static unsigned long long GetUsageForOrigin(JNIEnv* env, jobject obj, jstring origin) +{ + WebCore::String originStr = to_string(env, origin); + RefPtr<WebCore::SecurityOrigin> securityOrigin = WebCore::SecurityOrigin::createFromString(originStr); + unsigned long long usage = WebCore::DatabaseTracker::tracker().usageForOrigin(securityOrigin.get()); + Vector<WebCore::KURL> manifestUrls; + if (!WebCore::cacheStorage().manifestURLs(&manifestUrls)) + return usage; + int size = manifestUrls.size(); + for (int i = 0; i < size; ++i) { + RefPtr<WebCore::SecurityOrigin> manifestOrigin = WebCore::SecurityOrigin::create(manifestUrls[i]); + if (manifestOrigin.get() == 0) + continue; + if (manifestOrigin->isSameSchemeHostPort(securityOrigin.get())) { + int64_t size = 0; + WebCore::cacheStorage().cacheGroupSize(manifestUrls[i].string(), &size); + usage += size; + } + } + return usage; +} + +static void SetQuotaForOrigin(JNIEnv* env, jobject obj, jstring origin, unsigned long long quota) +{ + WebCore::String originStr = to_string(env, origin); + RefPtr<WebCore::SecurityOrigin> securityOrigin = WebCore::SecurityOrigin::createFromString(originStr); + WebCore::DatabaseTracker::tracker().setQuota(securityOrigin.get(), quota); +} + +static void DeleteOrigin(JNIEnv* env, jobject obj, jstring origin) +{ + WebCore::String originStr = to_string(env, origin); + RefPtr<WebCore::SecurityOrigin> securityOrigin = WebCore::SecurityOrigin::createFromString(originStr); + WebCore::DatabaseTracker::tracker().deleteOrigin(securityOrigin.get()); + + Vector<WebCore::KURL> manifestUrls; + if (!WebCore::cacheStorage().manifestURLs(&manifestUrls)) + return; + int size = manifestUrls.size(); + for (int i = 0; i < size; ++i) { + RefPtr<WebCore::SecurityOrigin> manifestOrigin = WebCore::SecurityOrigin::create(manifestUrls[i]); + if (manifestOrigin.get() == 0) + continue; + if (manifestOrigin->isSameSchemeHostPort(securityOrigin.get())) + WebCore::cacheStorage().deleteCacheGroup(manifestUrls[i]); + } +} + +static void DeleteAllData(JNIEnv* env, jobject obj) +{ + WebCore::DatabaseTracker::tracker().deleteAllDatabases(); + WebCore::cacheStorage().empty(); +} + +/* + * JNI registration + */ +static JNINativeMethod gWebStorageMethods[] = { + { "nativeGetOrigins", "()Ljava/util/Set;", + (void*) GetOrigins }, + { "nativeGetUsageForOrigin", "(Ljava/lang/String;)J", + (void*) GetUsageForOrigin }, + { "nativeGetQuotaForOrigin", "(Ljava/lang/String;)J", + (void*) GetQuotaForOrigin }, + { "nativeSetQuotaForOrigin", "(Ljava/lang/String;J)V", + (void*) SetQuotaForOrigin }, + { "nativeDeleteOrigin", "(Ljava/lang/String;)V", + (void*) DeleteOrigin }, + { "nativeDeleteAllData", "()V", + (void*) DeleteAllData } +}; + +int register_webstorage(JNIEnv* env) +{ + jclass webStorage = env->FindClass("android/webkit/WebStorage"); + LOG_ASSERT(webStorage, "Unable to find class android.webkit.WebStorage"); + + return jniRegisterNativeMethods(env, "android/webkit/WebStorage", + gWebStorageMethods, NELEM(gWebStorageMethods)); +} + +} + +#endif //ENABLE(DATABASE) + diff --git a/WebKit/android/jni/WebViewCore.cpp b/WebKit/android/jni/WebViewCore.cpp index f1cb3fa..9f457f4 100644 --- a/WebKit/android/jni/WebViewCore.cpp +++ b/WebKit/android/jni/WebViewCore.cpp @@ -31,14 +31,18 @@ #include "AtomicString.h" #include "CachedNode.h" #include "CachedRoot.h" +#include "ChromeClientAndroid.h" #include "Color.h" +#include "DatabaseTracker.h" #include "Document.h" #include "Element.h" #include "Editor.h" #include "EditorClientAndroid.h" #include "EventHandler.h" #include "EventNames.h" +#include "FocusController.h" #include "Font.h" +#include "Frame.h" #include "FrameLoader.h" #include "FrameLoaderClientAndroid.h" #include "FrameTree.h" @@ -64,11 +68,13 @@ #include "Page.h" #include "PlatformKeyboardEvent.h" #include "PlatformString.h" -#include "PluginInfoStore.h" #include "PluginWidgetAndroid.h" +#include "PluginView.h" #include "Position.h" #include "ProgressTracker.h" +#include "RenderBox.h" #include "RenderLayer.h" +#include "RenderPart.h" #include "RenderText.h" #include "RenderTextControl.h" #include "RenderThemeAndroid.h" @@ -76,11 +82,13 @@ #include "ResourceRequest.h" #include "SelectionController.h" #include "Settings.h" +#include "SkANP.h" #include "SkTemplates.h" #include "SkTypes.h" #include "SkCanvas.h" #include "SkPicture.h" #include "SkUtils.h" +#include "SurfaceCallback.h" #include "StringImpl.h" #include "Text.h" #include "TypingCommand.h" @@ -92,6 +100,11 @@ #include "jni_utility.h" #include <wtf/CurrentTime.h> +#if USE(V8) +#include "CString.h" +#include "ScriptController.h" +#endif + #if DEBUG_NAV_UI #include "SkTime.h" #endif @@ -155,14 +168,18 @@ struct WebViewCore::JavaGlue { jmethodID m_jsUnload; jmethodID m_jsInterrupt; jmethodID m_didFirstLayout; - jmethodID m_sendMarkNodeInvalid; - jmethodID m_sendNotifyFocusSet; jmethodID m_sendNotifyProgressFinished; - jmethodID m_sendRecomputeFocus; jmethodID m_sendViewInvalidate; jmethodID m_updateTextfield; + jmethodID m_clearTextEntry; jmethodID m_restoreScale; jmethodID m_needTouchEvents; + jmethodID m_requestKeyboard; + jmethodID m_exceededDatabaseQuota; + jmethodID m_addMessageToConsole; + jmethodID m_createSurface; + jmethodID m_destroySurface; + jmethodID m_attachSurface; AutoJObject object(JNIEnv* env) { return getRealObject(env, m_obj); } @@ -180,9 +197,8 @@ static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const } Mutex WebViewCore::gFrameCacheMutex; -Mutex WebViewCore::gFrameGenerationMutex; -Mutex WebViewCore::gRecomputeFocusMutex; Mutex WebViewCore::gButtonMutex; +Mutex WebViewCore::gCursorBoundsMutex; Mutex WebViewCore::m_contentMutex; WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* mainframe) @@ -191,7 +207,6 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m m_mainFrame = mainframe; m_popupReply = 0; - m_buildGeneration = 0; m_moveGeneration = 0; m_generation = 0; m_lastGeneration = 0; @@ -202,7 +217,7 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m m_maxYScroll = 240/4; m_textGeneration = 0; m_screenWidth = 320; - m_scale = 100; + m_scale = 1; LOG_ASSERT(m_mainFrame, "Uh oh, somehow a frameview was made without an initial frame!"); @@ -220,15 +235,19 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m m_javaGlue->m_jsPrompt = GetJMethod(env, clazz, "jsPrompt", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"); m_javaGlue->m_jsUnload = GetJMethod(env, clazz, "jsUnload", "(Ljava/lang/String;Ljava/lang/String;)Z"); m_javaGlue->m_jsInterrupt = GetJMethod(env, clazz, "jsInterrupt", "()Z"); - m_javaGlue->m_didFirstLayout = GetJMethod(env, clazz, "didFirstLayout", "()V"); - m_javaGlue->m_sendMarkNodeInvalid = GetJMethod(env, clazz, "sendMarkNodeInvalid", "(I)V"); - m_javaGlue->m_sendNotifyFocusSet = GetJMethod(env, clazz, "sendNotifyFocusSet", "()V"); + m_javaGlue->m_didFirstLayout = GetJMethod(env, clazz, "didFirstLayout", "(Z)V"); m_javaGlue->m_sendNotifyProgressFinished = GetJMethod(env, clazz, "sendNotifyProgressFinished", "()V"); - m_javaGlue->m_sendRecomputeFocus = GetJMethod(env, clazz, "sendRecomputeFocus", "()V"); m_javaGlue->m_sendViewInvalidate = GetJMethod(env, clazz, "sendViewInvalidate", "(IIII)V"); m_javaGlue->m_updateTextfield = GetJMethod(env, clazz, "updateTextfield", "(IZLjava/lang/String;I)V"); + m_javaGlue->m_clearTextEntry = GetJMethod(env, clazz, "clearTextEntry", "()V"); m_javaGlue->m_restoreScale = GetJMethod(env, clazz, "restoreScale", "(I)V"); m_javaGlue->m_needTouchEvents = GetJMethod(env, clazz, "needTouchEvents", "(Z)V"); + m_javaGlue->m_requestKeyboard = GetJMethod(env, clazz, "requestKeyboard", "(Z)V"); + m_javaGlue->m_exceededDatabaseQuota = GetJMethod(env, clazz, "exceededDatabaseQuota", "(Ljava/lang/String;Ljava/lang/String;J)V"); + m_javaGlue->m_addMessageToConsole = GetJMethod(env, clazz, "addMessageToConsole", "(Ljava/lang/String;ILjava/lang/String;)V"); + m_javaGlue->m_createSurface = GetJMethod(env, clazz, "createSurface", "(I)Landroid/view/SurfaceView;"); + m_javaGlue->m_destroySurface = GetJMethod(env, clazz, "destroySurface", "(Landroid/view/SurfaceView;)V"); + m_javaGlue->m_attachSurface = GetJMethod(env, clazz, "attachSurface", "(Landroid/view/SurfaceView;IIII)V"); env->SetIntField(javaWebViewCore, gWebViewCoreFields.m_nativeClass, (jint)this); @@ -260,6 +279,8 @@ WebViewCore* WebViewCore::getWebViewCore(const WebCore::FrameView* view) WebViewCore* WebViewCore::getWebViewCore(const WebCore::ScrollView* view) { WebFrameView* webFrameView = static_cast<WebFrameView*>(view->platformWidget()); + if (!webFrameView) + return 0; return webFrameView->webViewCore(); } @@ -280,16 +301,22 @@ void WebViewCore::reset(bool fromConstructor) m_lastFocused = 0; m_lastFocusedBounds = WebCore::IntRect(0,0,0,0); + m_lastMoveGeneration = 0; clearContent(); m_updatedFrameCache = true; m_frameCacheOutOfDate = true; - m_blockFocusChange = false; m_snapAnchorNode = 0; - m_useReplay = false; m_skipContentDraw = false; m_findIsUp = false; m_domtree_version = 0; m_check_domtree_version = true; + m_progressDone = false; + m_hasCursorBounds = false; + + m_scrollOffsetX = 0; + m_scrollOffsetY = 0; + m_screenWidth = 0; + m_screenHeight = 0; } static bool layoutIfNeededRecursive(WebCore::Frame* f) @@ -303,7 +330,7 @@ static bool layoutIfNeededRecursive(WebCore::Frame* f) if (v->needsLayout()) v->layout(f->tree()->parent()); - + WebCore::Frame* child = f->tree()->firstChild(); bool success = true; while (child) { @@ -314,6 +341,16 @@ static bool layoutIfNeededRecursive(WebCore::Frame* f) return success && !v->needsLayout(); } +CacheBuilder& WebViewCore::cacheBuilder() +{ + return FrameLoaderClientAndroid::get(m_mainFrame)->getCacheBuilder(); +} + +WebCore::Node* WebViewCore::currentFocus() +{ + return cacheBuilder().currentFocus(); +} + void WebViewCore::recordPicture(SkPicture* picture) { // if there is no document yet, just return @@ -374,6 +411,71 @@ void WebViewCore::recordPictureSet(PictureSet* content) WebCore::FrameView* view = m_mainFrame->view(); int width = view->contentsWidth(); int height = view->contentsHeight(); + + // Use the contents width and height as a starting point. + SkIRect contentRect; + contentRect.set(0, 0, width, height); + SkIRect total(contentRect); + + // Traverse all the frames and add their sizes if they are in the visible + // rectangle. + for (WebCore::Frame* frame = m_mainFrame->tree()->traverseNext(); frame; + frame = frame->tree()->traverseNext()) { + // If the frame doesn't have an owner then it is the top frame and the + // view size is the frame size. + WebCore::RenderPart* owner = frame->ownerRenderer(); + if (owner) { + int x = owner->x(); + int y = owner->y(); + + // Traverse the tree up to the parent to find the absolute position + // of this frame. + WebCore::Frame* parent = frame->tree()->parent(); + while (parent) { + WebCore::RenderPart* parentOwner = parent->ownerRenderer(); + if (parentOwner) { + x += parentOwner->x(); + y += parentOwner->y(); + } + parent = parent->tree()->parent(); + } + // Use the owner dimensions so that padding and border are + // included. + int right = x + owner->width(); + int bottom = y + owner->height(); + SkIRect frameRect = {x, y, right, bottom}; + // Ignore a width or height that is smaller than 1. Some iframes + // have small dimensions in order to be hidden. The iframe + // expansion code does not expand in that case so we should ignore + // them here. + if (frameRect.width() > 1 && frameRect.height() > 1 + && SkIRect::Intersects(total, frameRect)) + total.join(x, y, right, bottom); + } + } + + // If the new total is larger than the content, resize the view to include + // all the content. + if (!contentRect.contains(total)) { + // Resize the view to change the overflow clip. + view->resize(total.fRight, total.fBottom); + + // We have to force a layout in order for the clip to change. + m_mainFrame->contentRenderer()->setNeedsLayoutAndPrefWidthsRecalc(); + view->forceLayout(); + + // Relayout similar to above + m_skipContentDraw = true; + bool success = layoutIfNeededRecursive(m_mainFrame); + m_skipContentDraw = false; + if (!success) + return; + + // Set the computed content width + width = view->contentsWidth(); + height = view->contentsHeight(); + } + content->checkDimensions(width, height, &m_addInval); // The inval region may replace existing pictures. The existing pictures @@ -395,33 +497,38 @@ void WebViewCore::recordPictureSet(PictureSet* content) if (content->build()) rebuildPictureSet(content); } // WebViewCoreRecordTimeCounter - CacheBuilder& builder = FrameLoaderClientAndroid::get(m_mainFrame)->getCacheBuilder(); - WebCore::Node* oldFocusNode = builder.currentFocus(); + WebCore::Node* oldFocusNode = currentFocus(); m_frameCacheOutOfDate = true; WebCore::IntRect oldBounds = oldFocusNode ? oldFocusNode->getRect() : WebCore::IntRect(0,0,0,0); - DBG_NAV_LOGD("m_lastFocused=%p oldFocusNode=%p" - " m_lastFocusedBounds={%d,%d,%d,%d} oldBounds={%d,%d,%d,%d}", - m_lastFocused, oldFocusNode, - m_lastFocusedBounds.x(), m_lastFocusedBounds.y(), m_lastFocusedBounds.width(), m_lastFocusedBounds.height(), - oldBounds.x(), oldBounds.y(), oldBounds.width(), oldBounds.height()); unsigned latestVersion = 0; if (m_check_domtree_version) { - // as domTreeVersion only increment, we can just check the sum to see + // as domTreeVersion only increment, we can just check the sum to see // whether we need to update the frame cache for (Frame* frame = m_mainFrame; frame; frame = frame->tree()->traverseNext()) { latestVersion += frame->document()->domTreeVersion(); } } - if (m_lastFocused != oldFocusNode || m_lastFocusedBounds != oldBounds || m_findIsUp - || (m_check_domtree_version && latestVersion != m_domtree_version)) { - m_lastFocused = oldFocusNode; - m_lastFocusedBounds = oldBounds; - DBG_NAV_LOGD("call updateFrameCache m_domtree_version=%d latest=%d", - m_domtree_version, latestVersion); - m_domtree_version = latestVersion; - updateFrameCache(); + DBG_NAV_LOGD("m_lastFocused=%p oldFocusNode=%p" + " m_lastFocusedBounds={%d,%d,%d,%d} oldBounds={%d,%d,%d,%d}" + " m_check_domtree_version=%s latestVersion=%d m_domtree_version=%d", + m_lastFocused, oldFocusNode, + m_lastFocusedBounds.x(), m_lastFocusedBounds.y(), + m_lastFocusedBounds.width(), m_lastFocusedBounds.height(), + oldBounds.x(), oldBounds.y(), oldBounds.width(), oldBounds.height(), + m_check_domtree_version ? "true" : "false", + latestVersion, m_domtree_version); + if (m_lastFocused == oldFocusNode && m_lastFocusedBounds == oldBounds + && !m_findIsUp + && (!m_check_domtree_version || latestVersion == m_domtree_version)) + { + return; } + m_lastFocused = oldFocusNode; + m_lastFocusedBounds = oldBounds; + m_domtree_version = latestVersion; + DBG_NAV_LOG("call updateFrameCache"); + updateFrameCache(); } void WebViewCore::updateButtonList(WTF::Vector<Container>* buttons) @@ -477,7 +584,7 @@ void WebViewCore::copyContentToPicture(SkPicture* picture) m_contentMutex.lock(); PictureSet copyContent = PictureSet(m_content); m_contentMutex.unlock(); - + int w = copyContent.width(); int h = copyContent.height(); copyContent.draw(picture->beginRecording(w, h, PICT_RECORD_FLAGS)); @@ -508,6 +615,18 @@ bool WebViewCore::drawContent(SkCanvas* canvas, SkColor color) return tookTooLong; } +bool WebViewCore::pictureReady() +{ + bool done; + m_contentMutex.lock(); + PictureSet copyContent = PictureSet(m_content); + done = m_progressDone; + m_contentMutex.unlock(); + DBG_NAV_LOGD("done=%s empty=%s", done ? "true" : "false", + copyContent.isEmpty() ? "true" : "false"); + return done || !copyContent.isEmpty(); +} + SkPicture* WebViewCore::rebuildPicture(const SkIRect& inval) { WebCore::FrameView* view = m_mainFrame->view(); @@ -558,12 +677,13 @@ void WebViewCore::rebuildPictureSet(PictureSet* pictureSet) bool WebViewCore::recordContent(SkRegion* region, SkIPoint* point) { DBG_SET_LOG("start"); + float progress = (float) m_mainFrame->page()->progress()->estimatedProgress(); m_contentMutex.lock(); PictureSet contentCopy(m_content); + m_progressDone = progress <= 0.0f || progress >= 1.0f; m_contentMutex.unlock(); recordPictureSet(&contentCopy); - float progress = (float) m_mainFrame->page()->progress()->estimatedProgress(); - if (progress > 0.0f && progress < 1.0f && contentCopy.isEmpty()) { + if (!m_progressDone && contentCopy.isEmpty()) { DBG_SET_LOGD("empty (progress=%g)", progress); return false; } @@ -609,22 +729,6 @@ void WebViewCore::scrollTo(int x, int y, bool animate) checkException(env); } -void WebViewCore::sendMarkNodeInvalid(WebCore::Node* node) -{ - LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_sendMarkNodeInvalid, (int) node); - checkException(env); -} - -void WebViewCore::sendNotifyFocusSet() -{ - LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_sendNotifyFocusSet); - checkException(env); -} - void WebViewCore::sendNotifyProgressFinished() { LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); @@ -633,16 +737,8 @@ void WebViewCore::sendNotifyProgressFinished() checkException(env); } -void WebViewCore::sendRecomputeFocus() -{ - LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_sendRecomputeFocus); - checkException(env); -} - void WebViewCore::viewInvalidate(const WebCore::IntRect& rect) -{ +{ LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); env->CallVoidMethod(m_javaGlue->object(env).get(), @@ -656,7 +752,7 @@ 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, + env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_scrollBy, dx, dy, animate); checkException(env); } @@ -671,10 +767,8 @@ void WebViewCore::contentDraw() void WebViewCore::contentInvalidate(const WebCore::IntRect &r) { DBG_SET_LOGD("rect={%d,%d,w=%d,h=%d}", r.x(), r.y(), r.width(), r.height()); - SkIRect rect, max; - android_setrect(&rect, r); - max.set(0, 0, INT_MAX, INT_MAX); - if (!rect.intersect(max)) + SkIRect rect(r); + if (!rect.intersect(0, 0, INT_MAX, INT_MAX)) return; m_addInval.op(rect, SkRegion::kUnion_Op); DBG_SET_LOGD("m_addInval={%d,%d,r=%d,b=%d}", @@ -706,13 +800,17 @@ void WebViewCore::didFirstLayout() DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); - const WebCore::KURL& url = m_mainFrame->loader()->url(); + WebCore::FrameLoader* loader = m_mainFrame->loader(); + const WebCore::KURL& url = loader->url(); if (url.isEmpty()) return; LOGV("::WebCore:: didFirstLayout %s", url.string().ascii().data()); + WebCore::FrameLoadType loadType = loader->loadType(); + JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_didFirstLayout); + env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_didFirstLayout, + loadType == WebCore::FrameLoadTypeStandard); checkException(env); DBG_NAV_LOG("call updateFrameCache"); @@ -743,9 +841,14 @@ void WebViewCore::needTouchEvents(bool need) #endif } -void WebViewCore::notifyFocusSet() +void WebViewCore::requestKeyboard(bool showKeyboard) { - sendNotifyFocusSet(); + DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); + LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); + + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_requestKeyboard, showKeyboard); + checkException(env); } void WebViewCore::notifyProgressFinished() @@ -780,9 +883,10 @@ void WebViewCore::doMaxScroll(CacheBuilder::Direction dir) this->scrollBy(dx, dy, true); } -void WebViewCore::setScrollOffset(int dx, int dy) +void WebViewCore::setScrollOffset(int moveGeneration, int dx, int dy) { - DBG_NAV_LOGD("{%d,%d}", dx, dy); + DBG_NAV_LOGD("{%d,%d} m_scrollOffset=(%d,%d)", dx, dy, + m_scrollOffsetX, m_scrollOffsetY); if (m_scrollOffsetX != dx || m_scrollOffsetY != dy) { m_scrollOffsetX = dx; m_scrollOffsetY = dy; @@ -791,8 +895,19 @@ void WebViewCore::setScrollOffset(int dx, int dy) // testing work correctly. m_mainFrame->view()->platformWidget()->setLocation(m_scrollOffsetX, m_scrollOffsetY); - m_mainFrame->sendScrollEvent(); + m_mainFrame->eventHandler()->sendScrollEvent(); + + // update the currently visible screen + sendPluginVisibleScreen(); } + gCursorBoundsMutex.lock(); + bool hasCursorBounds = m_hasCursorBounds; + Frame* frame = (Frame*) m_cursorFrame; + IntPoint location = m_cursorLocation; + gCursorBoundsMutex.unlock(); + if (!hasCursorBounds) + return; + moveMouseIfLatest(moveGeneration, frame, location.x(), location.y()); } void WebViewCore::setGlobalBounds(int x, int y, int h, int v) @@ -801,23 +916,25 @@ void WebViewCore::setGlobalBounds(int x, int y, int h, int v) m_mainFrame->view()->platformWidget()->setWindowBounds(x, y, h, v); } -void WebViewCore::setSizeScreenWidthAndScale(int width, int height, - int screenWidth, int scale, int realScreenWidth, int screenHeight) +void WebViewCore::setSizeScreenWidthAndScale(int width, int height, + int screenWidth, float scale, int realScreenWidth, int screenHeight) { WebCoreViewBridge* window = m_mainFrame->view()->platformWidget(); int ow = window->width(); int oh = window->height(); window->setSize(width, height); int osw = m_screenWidth; - DBG_NAV_LOGD("old:(w=%d,h=%d,sw=%d,scale=%d) new:(w=%d,h=%d,sw=%d,scale=%d)", + DBG_NAV_LOGD("old:(w=%d,h=%d,sw=%d,scale=%d) new:(w=%d,h=%d,sw=%d,scale=%g)", ow, oh, osw, m_scale, width, height, screenWidth, scale); m_screenWidth = screenWidth; - m_scale = scale; + m_screenHeight = screenHeight; + if (scale >= 0) // negative means ignore + m_scale = scale; m_maxXScroll = screenWidth >> 2; m_maxYScroll = (screenWidth * height / width) >> 2; if (ow != width || oh != height || osw != screenWidth) { WebCore::RenderObject *r = m_mainFrame->contentRenderer(); - DBG_NAV_LOGD("renderer=%p view=(w=%d,h=%d)", r, + DBG_NAV_LOGD("renderer=%p view=(w=%d,h=%d)", r, realScreenWidth, screenHeight); if (r) { // get current screen center position @@ -836,7 +953,7 @@ void WebViewCore::setSizeScreenWidthAndScale(int width, int height, offset = WebCore::IntPoint(screenCenter.x() - bounds.x(), screenCenter.y() - bounds.y()); if (offset.x() < 0 || offset.x() > realScreenWidth || - offset.y() < 0 || offset.y() > screenHeight) + offset.y() < 0 || offset.y() > screenHeight) { DBG_NAV_LOGD("offset out of bounds:(x=%d,y=%d)", offset.x(), offset.y()); @@ -844,18 +961,21 @@ void WebViewCore::setSizeScreenWidthAndScale(int width, int height, } } r->setNeedsLayoutAndPrefWidthsRecalc(); - m_mainFrame->forceLayout(); + m_mainFrame->view()->forceLayout(); // scroll to restore current screen center if (!node) return; const WebCore::IntRect& newBounds = node->getRect(); DBG_NAV_LOGD("nb:(x=%d,y=%d,w=%d," - "h=%d,ns=%d)", newBounds.x(), newBounds.y(), + "h=%d,ns=%d)", newBounds.x(), newBounds.y(), newBounds.width(), newBounds.height()); scrollBy(newBounds.x() - bounds.x(), newBounds.y() - bounds.y(), false); } } + + // update the currently visible screen + sendPluginVisibleScreen(); } void WebViewCore::dumpDomTree(bool useFile) @@ -901,14 +1021,13 @@ void WebViewCore::dumpRenderTree(bool useFile) void WebViewCore::dumpNavTree() { #if DUMP_NAV_CACHE - FrameLoaderClientAndroid::get(m_mainFrame)->getCacheBuilder().mDebug.print(); + cacheBuilder().mDebug.print(); #endif } WebCore::String WebViewCore::retrieveHref(WebCore::Frame* frame, WebCore::Node* node) { - CacheBuilder& builder = FrameLoaderClientAndroid::get(m_mainFrame)->getCacheBuilder(); - if (!builder.validNode(frame, node)) + if (!CacheBuilder::validNode(m_mainFrame, frame, node)) return WebCore::String(); if (!node->hasTagName(WebCore::HTMLNames::aTag)) return WebCore::String(); @@ -916,24 +1035,50 @@ WebCore::String WebViewCore::retrieveHref(WebCore::Frame* frame, WebCore::Node* return anchor->href(); } -bool WebViewCore::prepareFrameCache() +void WebViewCore::updateCacheOnNodeChange() +{ + gCursorBoundsMutex.lock(); + bool hasCursorBounds = m_hasCursorBounds; + Frame* frame = (Frame*) m_cursorFrame; + Node* node = (Node*) m_cursorNode; + IntRect bounds = m_cursorHitBounds; + gCursorBoundsMutex.unlock(); + if (!hasCursorBounds || !node) + return; + if (CacheBuilder::validNode(m_mainFrame, frame, node)) { + RenderObject* renderer = node->renderer(); + if (renderer) { + IntRect absBox = renderer->absoluteBoundingBoxRect(); + int globalX, globalY; + CacheBuilder::GetGlobalOffset(frame, &globalX, &globalY); + absBox.move(globalX, globalY); + if (absBox == bounds) + return; + DBG_NAV_LOGD("absBox=(%d,%d,%d,%d) bounds=(%d,%d,%d,%d)", + absBox.x(), absBox.y(), absBox.width(), absBox.height(), + bounds.x(), bounds.y(), bounds.width(), bounds.height()); + } + } + DBG_NAV_LOGD("updateFrameCache node=%p", node); + updateFrameCache(); +} + +void WebViewCore::updateFrameCache() { if (!m_frameCacheOutOfDate) { DBG_NAV_LOG("!m_frameCacheOutOfDate"); - return false; + return; } #ifdef ANDROID_INSTRUMENT TimeCounterAuto counter(TimeCounter::WebViewCoreBuildNavTimeCounter); #endif m_frameCacheOutOfDate = false; #if DEBUG_NAV_UI - DBG_NAV_LOG("m_frameCacheOutOfDate was true"); m_now = SkTime::GetMSecs(); #endif m_temp = new CachedRoot(); m_temp->init(m_mainFrame, &m_history); - m_temp->setGeneration(++m_buildGeneration); - CacheBuilder& builder = FrameLoaderClientAndroid::get(m_mainFrame)->getCacheBuilder(); + CacheBuilder& builder = cacheBuilder(); WebCore::Settings* settings = m_mainFrame->page()->settings(); builder.allowAllTextDetection(); #ifdef ANDROID_META_SUPPORT @@ -951,15 +1096,9 @@ bool WebViewCore::prepareFrameCache() recordPicture(m_tempPict); m_temp->setPicture(m_tempPict); m_temp->setTextGeneration(m_textGeneration); - return true; -} - -void WebViewCore::releaseFrameCache(bool newCache) -{ - if (!newCache) { - DBG_NAV_LOG("!newCache"); - return; - } + WebCoreViewBridge* window = m_mainFrame->view()->platformWidget(); + m_temp->setVisibleRect(WebCore::IntRect(m_scrollOffsetX, + m_scrollOffsetY, window->width(), window->height())); gFrameCacheMutex.lock(); delete m_frameCacheKit; delete m_navPictureKit; @@ -973,70 +1112,6 @@ void WebViewCore::releaseFrameCache(bool newCache) cachedFocusNode ? cachedFocusNode->nodePointer() : 0); #endif gFrameCacheMutex.unlock(); - notifyFocusSet(); - // it's tempting to send an invalidate here, but it's a bad idea - // the cache is now up to date, but the focus is not -- the event - // may need to be recomputed from the prior history. An invalidate - // will draw the stale location causing the ring to flash at the wrong place. -} - -void WebViewCore::updateFrameCache() -{ - m_useReplay = false; - releaseFrameCache(prepareFrameCache()); -} - -void WebViewCore::removeFrameGeneration(WebCore::Frame* frame) -{ - DBG_NAV_LOGD("frame=%p m_generation=%d", frame, m_generation); - gFrameGenerationMutex.lock(); - int last = m_frameGenerations.size() - 1; - for (int index = 0; index <= last; index++) { - if (m_frameGenerations[index].m_frame == frame) { - DBG_NAV_LOGD("index=%d last=%d", index, last); - if (index != last) - m_frameGenerations[index] = m_frameGenerations[last]; - m_frameGenerations.removeLast(); - break; - } - } - gFrameGenerationMutex.unlock(); -} - -void WebViewCore::updateFrameGeneration(WebCore::Frame* frame) -{ - DBG_NAV_LOGD("frame=%p m_generation=%d", frame, m_generation); - gFrameGenerationMutex.lock(); - ++m_buildGeneration; - for (size_t index = 0; index < m_frameGenerations.size(); index++) { - if (m_frameGenerations[index].m_frame == frame) { - DBG_NAV_LOG("replace"); - m_frameGenerations[index].m_generation = m_buildGeneration; - goto done; - } - } - { - FrameGen frameGen = {frame, m_buildGeneration}; - m_frameGenerations.append(frameGen); - DBG_NAV_LOG("append"); - } -done: - gFrameGenerationMutex.unlock(); -} - -int WebViewCore::retrieveFrameGeneration(WebCore::Frame* frame) -{ - int result = INT_MAX; - gFrameGenerationMutex.lock(); - for (size_t index = 0; index < m_frameGenerations.size(); index++) { - if (m_frameGenerations[index].m_frame == frame) { - result = m_frameGenerations[index].m_generation; - break; - } - } - gFrameGenerationMutex.unlock(); - DBG_NAV_LOGD("frame=%p m_generation=%d result=%d", frame, m_generation, result); - return result; } /////////////////////////////////////////////////////////////////////////////// @@ -1060,7 +1135,7 @@ void WebViewCore::removePlugin(PluginWidgetAndroid* w) void WebViewCore::invalPlugin(PluginWidgetAndroid* w) { - const double PLUGIN_INVAL_DELAY = 0; // should this be non-zero? + const double PLUGIN_INVAL_DELAY = 1.0 / 60; if (!m_pluginInvalTimer.isActive()) { m_pluginInvalTimer.startOneShot(PLUGIN_INVAL_DELAY); @@ -1092,89 +1167,113 @@ void WebViewCore::drawPlugins() } } -/////////////////////////////////////////////////////////////////////////////// +void WebViewCore::sendPluginVisibleScreen() +{ + ANPRectI visibleRect; + visibleRect.left = m_scrollOffsetX; + visibleRect.top = m_scrollOffsetY; + visibleRect.right = m_scrollOffsetX + m_screenWidth; + visibleRect.bottom = m_scrollOffsetY + m_screenHeight; + + PluginWidgetAndroid** iter = m_plugins.begin(); + PluginWidgetAndroid** stop = m_plugins.end(); + for (; iter < stop; ++iter) { + (*iter)->setVisibleScreen(visibleRect, m_scale); + } +} + +void WebViewCore::sendPluginEvent(const ANPEvent& evt, ANPEventFlag flag) +{ + PluginWidgetAndroid** iter = m_plugins.begin(); + PluginWidgetAndroid** stop = m_plugins.end(); + for (; iter < stop; ++iter) { + if((*iter)->isAcceptingEvent(flag)) + (*iter)->sendEvent(evt); + } +} -void WebViewCore::setFinalFocus(WebCore::Frame* frame, WebCore::Node* node, - int x, int y, bool block) +void WebViewCore::sendPluginEvent(const ANPEvent& evt) { - DBG_NAV_LOGD("frame=%p node=%p x=%d y=%d", frame, node, x, y); - bool result = finalKitFocus(frame, node, x, y, false); - if (block) { - m_blockFocusChange = true; - if (!result && node) - touchUp(m_touchGeneration, 0, 0, 0, x, y, 0, true, true); + PluginWidgetAndroid** iter = m_plugins.begin(); + PluginWidgetAndroid** stop = m_plugins.end(); + for (; iter < stop; ++iter) { + (*iter)->sendEvent(evt); + } +} + +static PluginView* nodeIsPlugin(Node* node) { + RenderObject* renderer = node->renderer(); + if (renderer && renderer->isWidget()) { + Widget* widget = static_cast<RenderWidget*>(renderer)->widget(); + if (widget && widget->isPluginView()) + return static_cast<PluginView*>(widget); + } + return 0; +} + +Node* WebViewCore::cursorNodeIsPlugin() { + gCursorBoundsMutex.lock(); + bool hasCursorBounds = m_hasCursorBounds; + Frame* frame = (Frame*) m_cursorFrame; + Node* node = (Node*) m_cursorNode; + gCursorBoundsMutex.unlock(); + if (hasCursorBounds && CacheBuilder::validNode(m_mainFrame, frame, node) + && nodeIsPlugin(node)) { + return node; } + return 0; +} + + +void WebViewCore::updatePluginState(Frame* frame, Node* node, PluginState state) { + + // check that the node and frame pointers are (still) valid + if (!frame || !node || !CacheBuilder::validNode(m_mainFrame, frame, node)) + return; + + // check that the node is a plugin view + PluginView* pluginView = nodeIsPlugin(node); + if (!pluginView) + return; + + // create the event + ANPEvent event; + SkANP::InitEvent(&event, kLifecycle_ANPEventType); + + if (state == kLoseFocus_PluginState) + event.data.lifecycle.action = kLoseFocus_ANPLifecycleAction; + else if (state == kGainFocus_PluginState) + event.data.lifecycle.action = kGainFocus_ANPLifecycleAction; + else + return; + + // send the event + pluginView->platformPluginWidget()->sendEvent(event); } -void WebViewCore::setKitFocus(int moveGeneration, int buildGeneration, - WebCore::Frame* frame, WebCore::Node* node, int x, int y, - bool ignoreNullFocus) +/////////////////////////////////////////////////////////////////////////////// +void WebViewCore::moveMouseIfLatest(int moveGeneration, + WebCore::Frame* frame, int x, int y) { DBG_NAV_LOGD("m_moveGeneration=%d moveGeneration=%d" - " buildGeneration=%d frame=%p node=%p x=%d y=%d", - m_moveGeneration, moveGeneration, buildGeneration, frame, node, x, y); - if (m_blockFocusChange) { - DBG_NAV_LOG("m_blockFocusChange"); - return; - } + " frame=%p x=%d y=%d", + m_moveGeneration, moveGeneration, frame, x, y); if (m_moveGeneration > moveGeneration) { DBG_NAV_LOGD("m_moveGeneration=%d > moveGeneration=%d", m_moveGeneration, moveGeneration); return; // short-circuit if a newer move has already been generated } - if (!commonKitFocus(moveGeneration, buildGeneration, frame, node, x, y, - ignoreNullFocus)) - return; m_lastGeneration = moveGeneration; -} - -bool WebViewCore::commonKitFocus(int generation, int buildGeneration, - WebCore::Frame* frame, WebCore::Node* node, int x, int y, - bool ignoreNullFocus) -{ - DBG_NAV_LOGD("generation=%d buildGeneration=%d frame=%p" - " node=%p x=%d y=%d", generation, buildGeneration, frame, node, x, y); - m_useReplay = true; - bool newCache = prepareFrameCache(); // must wait for possible recompute before using - if (m_moveGeneration > generation) { - DBG_NAV_LOGD("m_moveGeneration=%d > generation=%d", - m_moveGeneration, generation); - releaseFrameCache(newCache); - return false; // short-circuit if a newer move has already been generated - } - // if the nav cache has been rebuilt since this focus request was generated, - // send a request back to the UI side to recompute the kit-side focus - if (m_buildGeneration > buildGeneration || (node && !FrameLoaderClientAndroid::get(m_mainFrame)->getCacheBuilder().validNode(frame, node))) { - DBG_NAV_LOGD("m_buildGeneration=%d > buildGeneration=%d", - m_buildGeneration, buildGeneration); - gRecomputeFocusMutex.lock(); - bool first = !m_recomputeEvents.size(); - m_recomputeEvents.append(generation); - gRecomputeFocusMutex.unlock(); - releaseFrameCache(newCache); - if (first) - sendRecomputeFocus(); - return false; - } - releaseFrameCache(newCache); - if (!node && ignoreNullFocus) - return true; - finalKitFocus(frame, node, x, y, false); - return true; + moveMouse(frame, x, y); } // Update mouse position and may change focused node. -// If donotChangeDOMFocus is true, the function does not changed focused node -// in the DOM tree. Changing the focus in DOM may trigger onblur event -// handler on the current focused node before firing mouse up and down events. -bool WebViewCore::finalKitFocus(WebCore::Frame* frame, WebCore::Node* node, - int x, int y, bool donotChangeDOMFocus) -{ - CacheBuilder& builder = FrameLoaderClientAndroid:: - get(m_mainFrame)->getCacheBuilder(); - if (!frame || builder.validNode(frame, NULL) == false) +void WebViewCore::moveMouse(WebCore::Frame* frame, int x, int y) +{ + DBG_NAV_LOGD("frame=%p x=%d y=%d scrollOffset=(%d,%d)", frame, + x, y, m_scrollOffsetX, m_scrollOffsetY); + if (!frame || CacheBuilder::validNode(m_mainFrame, frame, NULL) == false) frame = m_mainFrame; - WebCore::Node* oldFocusNode = builder.currentFocus(); // mouse event expects the position in the window coordinate m_mousePos = WebCore::IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY); // validNode will still return true if the node is null, as long as we have @@ -1183,86 +1282,7 @@ bool WebViewCore::finalKitFocus(WebCore::Frame* frame, WebCore::Node* node, WebCore::NoButton, WebCore::MouseEventMoved, 1, false, false, false, false, WTF::currentTime()); frame->eventHandler()->handleMouseMoveEvent(mouseEvent); - bool valid = builder.validNode(frame, node); - if (!donotChangeDOMFocus) { - WebCore::Document* oldDoc = oldFocusNode ? oldFocusNode->document() : 0; - if (!node) { - if (oldFocusNode) - oldDoc->setFocusedNode(0); - return false; - } else if (!valid) { - DBG_NAV_LOGD("sendMarkNodeInvalid node=%p", node); - sendMarkNodeInvalid(node); - if (oldFocusNode) - oldDoc->setFocusedNode(0); - return false; - } - // If we jump frames (docs), kill the focus on the old doc - if (oldFocusNode && node->document() != oldDoc) { - oldDoc->setFocusedNode(0); - } - if (!node->isTextNode()) - static_cast<WebCore::Element*>(node)->focus(false); - if (node->document()->focusedNode() != node) { - // This happens when Element::focus() fails as we may try to set the - // focus to a node which WebCore doesn't recognize as a focusable node. - // So we need to do some extra work, as it does in Element::focus(), - // besides calling Document::setFocusedNode. - if (oldFocusNode) { - // copied from clearSelectionIfNeeded in FocusController.cpp - WebCore::SelectionController* s = oldDoc->frame()->selection(); - if (!s->isNone()) - s->clear(); - } - //setFocus on things that WebCore doesn't recognize as supporting focus - //for instance, if there is an onclick element that does not support focus - node->document()->setFocusedNode(node); - } - } else { // !donotChangeDOMFocus - if (!node || !valid) - return false; - } - - DBG_NAV_LOGD("setFocusedNode node=%p", node); - builder.setLastFocus(node); - m_lastFocused = node; - m_lastFocusedBounds = node->getRect(); - return true; -} - -// helper function to find the frame that has focus -static WebCore::Frame* FocusedFrame(WebCore::Frame* frame) -{ - if (!frame) - return 0; - WebCore::Node* focusNode = FrameLoaderClientAndroid::get(frame)->getCacheBuilder().currentFocus(); - if (!focusNode) - return 0; - WebCore::Document* doc = focusNode->document(); - if (!doc) - return 0; - return doc->frame(); -} - -static WebCore::RenderTextControl* FocusedTextControl(WebCore::Frame* frame) -{ - WebCore::Node* focusNode = FrameLoaderClientAndroid::get(frame)->getCacheBuilder().currentFocus(); - WebCore::RenderObject* renderer = focusNode->renderer(); - if (renderer && (renderer->isTextField() || renderer->isTextArea())) { - return static_cast<WebCore::RenderTextControl*>(renderer); - } - return 0; -} - -WebCore::Frame* WebViewCore::changedKitFocus(WebCore::Frame* frame, - WebCore::Node* node, int x, int y) -{ - if (!frame || !node) - return m_mainFrame; - WebCore::Node* current = FrameLoaderClientAndroid::get(m_mainFrame)->getCacheBuilder().currentFocus(); - if (current == node) - return frame; - return finalKitFocus(frame, node, x, y, false) ? frame : m_mainFrame; + updateCacheOnNodeChange(); } static int findTextBoxIndex(WebCore::Node* node, const WebCore::IntPoint& pt) @@ -1300,7 +1320,7 @@ static int findTextBoxIndex(WebCore::Node* node, const WebCore::IntPoint& pt) "offset=%d pt.x=%d globalX=%d renderX=%d x=%d " "textBox->x()=%d textBox->start()=%d prior=%d current=%d next=%d", offset, pt.x(), globalX, absPt.x(), x, - textBox->xPos(), textBox->start(), prior, current, next + textBox->x(), textBox->start(), prior, current, next ); #endif return textBox->start() + offset; @@ -1420,114 +1440,91 @@ WebCore::String WebViewCore::getSelection(SkRegion* selRgn) return result; } -static void selectInFrame(WebCore::Frame* frame, int start, int end) +void WebViewCore::setSelection(int start, int end) { - WebCore::Document* doc = frame->document(); - if (!doc) - return; - - WebCore::Node* focus = doc->focusedNode(); + WebCore::Node* focus = currentFocus(); if (!focus) return; - WebCore::RenderObject* renderer = focus->renderer(); - if (renderer && (renderer->isTextField() || renderer->isTextArea())) { - WebCore::RenderTextControl* rtc = static_cast<WebCore::RenderTextControl*>(renderer); - if (start > end) { - int temp = start; - start = end; - end = temp; - } - rtc->setSelectionRange(start, end); - frame->revealSelection(); + if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) + return; + WebCore::RenderTextControl* rtc = static_cast<WebCore::RenderTextControl*>(renderer); + if (start > end) { + int temp = start; + start = end; + end = temp; } + rtc->setSelectionRange(start, end); + focus->document()->frame()->revealSelection(); + setFocusControllerActive(true); } -WebCore::Frame* WebViewCore::setSelection(WebCore::Frame* frame, WebCore::Node* node, - int x, int y, int start, int end) -{ - // FIXME: Consider using a generation number to avoid doing this many more times than necessary. - frame = changedKitFocus(frame, node, x, y); - if (!frame) - return 0; - selectInFrame(frame, start, end); - return frame; -} - -// Shortcut for no modifier keys -#define NO_MODIFIER_KEYS (static_cast<WebCore::PlatformKeyboardEvent::ModifierKey>(0)) - -WebCore::Frame* WebViewCore::deleteSelection(WebCore::Frame* frame, WebCore::Node* node, - int x, int y, int start, int end) +void WebViewCore::deleteSelection(int start, int end, int textGeneration) { - frame = setSelection(frame, node, x, y, start, end); - if (start != end) { - WebCore::PlatformKeyboardEvent downEvent(kKeyCodeDel, WebCore::VK_BACK, - WebCore::PlatformKeyboardEvent::KeyDown, 0, NO_MODIFIER_KEYS); - frame->eventHandler()->keyEvent(downEvent); - WebCore::PlatformKeyboardEvent upEvent(kKeyCodeDel, WebCore::VK_BACK, - WebCore::PlatformKeyboardEvent::KeyUp, 0, NO_MODIFIER_KEYS); - frame->eventHandler()->keyEvent(upEvent); - } - return frame; + setSelection(start, end); + if (start == end) + return; + WebCore::Node* focus = currentFocus(); + if (!focus) + return; + WebCore::TypingCommand::deleteSelection(focus->document()); + m_textGeneration = textGeneration; } -void WebViewCore::replaceTextfieldText(WebCore::Frame* frame, WebCore::Node* node, int x, int y, - int oldStart, int oldEnd, jstring replace, int start, int end) +void WebViewCore::replaceTextfieldText(int oldStart, + int oldEnd, const WebCore::String& replace, int start, int end, + int textGeneration) { - JNIEnv* env = JSC::Bindings::getJNIEnv(); - - WebCore::String webcoreString = to_string(env, replace); - frame = setSelection(frame, node, x, y, oldStart, oldEnd); - WebCore::TypingCommand::insertText(frame->document(), webcoreString, false); - selectInFrame(frame, start, end); + WebCore::Node* focus = currentFocus(); + if (!focus) + return; + setSelection(oldStart, oldEnd); + WebCore::TypingCommand::insertText(focus->document(), replace, + false); + setSelection(start, end); + m_textGeneration = textGeneration; } -void WebViewCore::passToJs(WebCore::Frame* frame, WebCore::Node* node, int x, int y, int generation, - jstring currentText, int keyCode, int keyValue, bool down, bool cap, bool fn, bool sym) +void WebViewCore::passToJs(int generation, const WebCore::String& current, + const PlatformKeyboardEvent& event) { - frame = changedKitFocus(frame, node, x, y); - // Construct the ModifierKey value - int mods = 0; - if (cap) { - mods |= WebCore::PlatformKeyboardEvent::ShiftKey; - } - if (fn) { - mods |= WebCore::PlatformKeyboardEvent::AltKey; + WebCore::Node* focus = currentFocus(); + if (!focus) { + DBG_NAV_LOG("!focus"); + clearTextEntry(); + return; } - if (sym) { - mods |= WebCore::PlatformKeyboardEvent::CtrlKey; + WebCore::RenderObject* renderer = focus->renderer(); + if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) { + DBG_NAV_LOGD("renderer==%p || not text", renderer); + clearTextEntry(); + return; } - WebCore::PlatformKeyboardEvent event(keyCode, keyValue, - down ? WebCore::PlatformKeyboardEvent::KeyDown : - WebCore::PlatformKeyboardEvent::KeyUp, - 0, static_cast<WebCore::PlatformKeyboardEvent::ModifierKey>(mods)); // Block text field updates during a key press. m_blockTextfieldUpdates = true; - frame->eventHandler()->keyEvent(event); + key(event); m_blockTextfieldUpdates = false; m_textGeneration = generation; - - WebCore::Node* currentFocus = FrameLoaderClientAndroid::get(m_mainFrame)->getCacheBuilder().currentFocus(); - // Make sure we have the same focus and it is a text field. - if (node == currentFocus && currentFocus) { - WebCore::RenderObject* renderer = currentFocus->renderer(); - if (renderer && (renderer->isTextField() || renderer->isTextArea())) { - WebCore::RenderTextControl* renderText = static_cast<WebCore::RenderTextControl*>(renderer); - JNIEnv* env = JSC::Bindings::getJNIEnv(); - WebCore::String current = to_string(env, currentText); - WebCore::String test = renderText->text(); - // If the text changed during the key event, update the UI text field. - if (test != current) - updateTextfield(currentFocus, false, test); - } + setFocusControllerActive(true); + WebCore::RenderTextControl* renderText = + static_cast<WebCore::RenderTextControl*>(renderer); + WebCore::String test = renderText->text(); + if (test == current) { + DBG_NAV_LOG("test == current"); + return; } + // If the text changed during the key event, update the UI text field. + updateTextfield(focus, false, test); +} + +void WebViewCore::setFocusControllerActive(bool active) +{ + m_mainFrame->page()->focusController()->setActive(active); } void WebViewCore::saveDocumentState(WebCore::Frame* frame) { - if (!FrameLoaderClientAndroid::get(m_mainFrame)->getCacheBuilder() - .validNode(frame, 0)) + if (!CacheBuilder::validNode(m_mainFrame, frame, 0)) frame = m_mainFrame; WebCore::HistoryItem *item = frame->loader()->currentHistoryItem(); @@ -1568,45 +1565,57 @@ public: // Special value for cancel. Do nothing. return; } - // If the select element no longer exists, do to a page change, etc, silently return. - if (!m_select || !FrameLoaderClientAndroid::get(m_viewImpl->m_mainFrame)->getCacheBuilder().validNode(m_frame, m_select)) - return; - if (-1 == index) { - if (m_select->selectedIndex() != -1) { -#ifdef ANDROID_DESELECT_SELECT - m_select->deselectItems(); -#endif - m_select->onChange(); - m_viewImpl->contentInvalidate(m_select->getRect()); - } + // 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; - } - WebCore::HTMLOptionElement* option = static_cast<WebCore::HTMLOptionElement*>( - m_select->item(m_select->listToOptionIndex(index))); - if (!option->selected()) { - option->setSelected(true); - m_select->onChange(); - m_viewImpl->contentInvalidate(m_select->getRect()); - } + // 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, false); + 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, do to a page change, etc, silently return. - if (!m_select || !FrameLoaderClientAndroid::get(m_viewImpl->m_mainFrame)->getCacheBuilder().validNode(m_frame, m_select)) + // 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; -#ifdef ANDROID_DESELECT_SELECT - m_select->deselectItems(); -#endif + + // If count is 1 or 0, use replyInt. + SkASSERT(count > 1); + + 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 i = 0; i < count; i++) { - option = static_cast<WebCore::HTMLOptionElement*>( - m_select->item(m_select->listToOptionIndex(array[i]))); - option->setSelected(true); + 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_viewImpl->contentInvalidate(m_select->getRect()); + m_select->dispatchFormControlChangeEvent(); + m_viewImpl->contentInvalidate(m_select->getRect()); } private: // The select element associated with this listbox. @@ -1685,40 +1694,32 @@ void WebViewCore::listBoxRequest(WebCoreReply* reply, const uint16_t** labels, s m_popupReply = reply; } -bool WebViewCore::key(int keyCode, UChar32 unichar, int repeatCount, bool isShift, bool isAlt, bool isDown) +bool WebViewCore::key(const PlatformKeyboardEvent& event) { - DBG_NAV_LOGD("key: keyCode=%d", keyCode); - WebCore::EventHandler* eventHandler = m_mainFrame->eventHandler(); - WebCore::Node* focusNode = FrameLoaderClientAndroid::get(m_mainFrame)->getCacheBuilder().currentFocus(); - if (focusNode) { + WebCore::Node* focusNode = currentFocus(); + if (focusNode) eventHandler = focusNode->document()->frame()->eventHandler(); - } - - int mods = 0; // PlatformKeyboardEvent::ModifierKey - if (isShift) { - mods |= WebCore::PlatformKeyboardEvent::ShiftKey; - } - if (isAlt) { - mods |= WebCore::PlatformKeyboardEvent::AltKey; - } - WebCore::PlatformKeyboardEvent evt(keyCode, unichar, - isDown ? WebCore::PlatformKeyboardEvent::KeyDown : WebCore::PlatformKeyboardEvent::KeyUp, - repeatCount, static_cast<WebCore::PlatformKeyboardEvent::ModifierKey> (mods)); - return eventHandler->keyEvent(evt); + DBG_NAV_LOGD("keyCode=%s unichar=%d focusNode=%p", + event.keyIdentifier().utf8().data(), event.unichar(), focusNode); + return eventHandler->keyEvent(event); } -bool WebViewCore::click() { - bool keyHandled = false; - WebCore::Node* focusNode = FrameLoaderClientAndroid::get(m_mainFrame)->getCacheBuilder().currentFocus(); - if (focusNode) { - WebFrame::getWebFrame(m_mainFrame)->setUserInitiatedClick(true); - keyHandled = handleMouseClick(focusNode->document()->frame(), focusNode); - WebFrame::getWebFrame(m_mainFrame)->setUserInitiatedClick(false); +// For when the user clicks the trackball +void WebViewCore::click(WebCore::Frame* frame, WebCore::Node* node) { + if (!node) { + WebCore::IntPoint pt = m_mousePos; + pt.move(m_scrollOffsetX, m_scrollOffsetY); + WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()-> + hitTestResultAtPoint(pt, false); + node = hitTestResult.innerNode(); + frame = node->document()->frame(); + DBG_NAV_LOGD("m_mousePos=(%d,%d) m_scrollOffset=(%d,%d) pt=(%d,%d)" + " node=%p", m_mousePos.x(), m_mousePos.y(), + m_scrollOffsetX, m_scrollOffsetY, pt.x(), pt.y(), node); } - // match in setFinalFocus() - m_blockFocusChange = false; - return keyHandled; + if (node) + handleMouseClick(frame, node); } bool WebViewCore::handleTouchEvent(int action, int x, int y) @@ -1749,27 +1750,17 @@ bool WebViewCore::handleTouchEvent(int action, int x, int y) return preventDefault; } -void WebViewCore::touchUp(int touchGeneration, int buildGeneration, - WebCore::Frame* frame, WebCore::Node* node, int x, int y, int size, - bool isClick, bool retry) +void WebViewCore::touchUp(int touchGeneration, + WebCore::Frame* frame, WebCore::Node* node, int x, int y, int size) { if (m_touchGeneration > touchGeneration) { DBG_NAV_LOGD("m_touchGeneration=%d > touchGeneration=%d" " x=%d y=%d", m_touchGeneration, touchGeneration, x, y); return; // short circuit if a newer touch has been generated } - if (retry || isClick) - finalKitFocus(frame, node, x, y, true); // don't change DOM focus - else if (!commonKitFocus(touchGeneration, buildGeneration, - frame, node, x, y, false)) { - return; - } + moveMouse(frame, x, y); m_lastGeneration = touchGeneration; - // If this is just a touch and not a click, we have already done the change in focus, - // so just leave the function now. - if (!isClick) - return; - if (frame && FrameLoaderClientAndroid::get(m_mainFrame)->getCacheBuilder().validNode(frame, 0)) { + if (frame && CacheBuilder::validNode(m_mainFrame, frame, 0)) { frame->loader()->resetMultipleFormSubmissionProtection(); } EditorClientAndroid* client = static_cast<EditorClientAndroid*>(m_mainFrame->editor()->client()); @@ -1780,25 +1771,26 @@ void WebViewCore::touchUp(int touchGeneration, int buildGeneration, client->setFromClick(false); } +// Common code for both clicking with the trackball and touchUp bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* nodePtr) { - bool valid = framePtr == NULL || FrameLoaderClientAndroid::get( - m_mainFrame)->getCacheBuilder().validNode(framePtr, nodePtr); + bool valid = framePtr == NULL + || CacheBuilder::validNode(m_mainFrame, framePtr, nodePtr); WebFrame* webFrame = WebFrame::getWebFrame(m_mainFrame); if (valid && nodePtr) { // Need to special case area tags because an image map could have an area element in the middle // so when attempting to get the default, the point chosen would be follow the wrong link. if (nodePtr->hasTagName(WebCore::HTMLNames::areaTag)) { webFrame->setUserInitiatedClick(true); - WebCore::EventTargetNodeCast(nodePtr)->dispatchSimulatedClick(0, - true, true); + nodePtr->dispatchSimulatedClick(0, true, true); webFrame->setUserInitiatedClick(false); + DBG_NAV_LOG("area"); return true; } WebCore::RenderObject* renderer = nodePtr->renderer(); - if (renderer && renderer->isMenuList()) { + if (renderer && (renderer->isMenuList() || renderer->isListBox())) { WebCore::HTMLSelectElement* select = static_cast<WebCore::HTMLSelectElement*>(nodePtr); - const WTF::Vector<WebCore::HTMLElement*>& listItems = select->listItems(); + const WTF::Vector<WebCore::Element*>& listItems = select->listItems(); SkTDArray<const uint16_t*> names; SkTDArray<int> enabledArray; SkTDArray<int> selectedArray; @@ -1807,7 +1799,7 @@ bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* node 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->text()); + *names.append() = stringConverter(option->textIndentedToRespectGroupLabel()); *enabledArray.append() = option->disabled() ? 0 : 1; if (multiple && option->selected()) *selectedArray.append() = i; @@ -1815,21 +1807,22 @@ bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* node WebCore::HTMLOptGroupElement* optGroup = static_cast<WebCore::HTMLOptGroupElement*>(listItems[i]); *names.append() = stringConverter(optGroup->groupLabelText()); *enabledArray.append() = 0; - if (multiple) - *selectedArray.append() = 0; } } 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() : - select->optionToListIndex(select->selectedIndex())); + selectElement->optionToListIndex(select->selectedIndex())); + DBG_NAV_LOG("menu list"); return true; } } if (!valid || !framePtr) framePtr = m_mainFrame; webFrame->setUserInitiatedClick(true); - DBG_NAV_LOGD("m_mousePos={%d,%d}", m_mousePos.x(), m_mousePos.y()); WebCore::PlatformMouseEvent mouseDown(m_mousePos, m_mousePos, WebCore::LeftButton, WebCore::MouseEventPressed, 1, false, false, false, false, WTF::currentTime()); @@ -1840,6 +1833,17 @@ bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* node WTF::currentTime()); bool handled = framePtr->eventHandler()->handleMouseReleaseEvent(mouseUp); webFrame->setUserInitiatedClick(false); + + // If the user clicked on a textfield, make the focusController active + // so we show the blinking cursor. + WebCore::Node* focusNode = currentFocus(); + DBG_NAV_LOGD("m_mousePos={%d,%d} focusNode=%p handled=%s", m_mousePos.x(), + m_mousePos.y(), focusNode, handled ? "true" : "false"); + if (focusNode) { + WebCore::RenderObject* renderer = focusNode->renderer(); + if (renderer && (renderer->isTextField() || renderer->isTextArea())) + setFocusControllerActive(true); + } return handled; } @@ -1861,6 +1865,16 @@ void WebViewCore::popupReply(const int* array, int count) } } +void WebViewCore::addMessageToConsole(const WebCore::String& message, unsigned int lineNumber, const WebCore::String& sourceID) { + JNIEnv* env = JSC::Bindings::getJNIEnv(); + jstring jMessageStr = env->NewString((unsigned short *)message.characters(), message.length()); + jstring jSourceIDStr = env->NewString((unsigned short *)sourceID.characters(), sourceID.length()); + env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_addMessageToConsole, jMessageStr, lineNumber, jSourceIDStr); + env->DeleteLocalRef(jMessageStr); + env->DeleteLocalRef(jSourceIDStr); + checkException(env); +} + void WebViewCore::jsAlert(const WebCore::String& url, const WebCore::String& text) { JNIEnv* env = JSC::Bindings::getJNIEnv(); @@ -1872,6 +1886,19 @@ void WebViewCore::jsAlert(const WebCore::String& url, const WebCore::String& tex checkException(env); } +void WebViewCore::exceededDatabaseQuota(const WebCore::String& url, const WebCore::String& databaseIdentifier, const unsigned long long currentQuota) +{ +#if ENABLE(DATABASE) + JNIEnv* env = JSC::Bindings::getJNIEnv(); + jstring jDatabaseIdentifierStr = env->NewString((unsigned short *)databaseIdentifier.characters(), databaseIdentifier.length()); + jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length()); + env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_exceededDatabaseQuota, jUrlStr, jDatabaseIdentifierStr, currentQuota); + env->DeleteLocalRef(jDatabaseIdentifierStr); + env->DeleteLocalRef(jUrlStr); + checkException(env); +#endif +} + bool WebViewCore::jsConfirm(const WebCore::String& url, const WebCore::String& text) { JNIEnv* env = JSC::Bindings::getJNIEnv(); @@ -1956,6 +1983,13 @@ void WebViewCore::updateTextfield(WebCore::Node* ptr, bool changeToPassword, checkException(env); } +void WebViewCore::clearTextEntry() +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue->object(env).get(), + m_javaGlue->m_clearTextEntry); +} + void WebViewCore::setSnapAnchor(int x, int y) { m_snapAnchorNode = 0; @@ -2003,6 +2037,32 @@ void WebViewCore::setBackgroundColor(SkColor c) view->setBaseBackgroundColor(bcolor); } +jobject WebViewCore::createSurface(SurfaceCallback* cb) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + jobject surface = env->CallObjectMethod(m_javaGlue->object(env).get(), + m_javaGlue->m_createSurface, (int) cb); + checkException(env); + return surface; +} + +void WebViewCore::destroySurface(jobject surface) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue->object(env).get(), + m_javaGlue->m_destroySurface, surface); + checkException(env); +} + +void WebViewCore::attachSurface(jobject surface, int x, int y, int width, + int height) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue->object(env).get(), + m_javaGlue->m_attachSurface, surface, x, y, width, height); + checkException(env); +} + //---------------------------------------------------------------------- // Native JNI methods //---------------------------------------------------------------------- @@ -2025,17 +2085,11 @@ static void SetSize(JNIEnv *env, jobject obj, jint width, jint height, WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); LOGV("webviewcore::nativeSetSize(%u %u)\n viewImpl: %p", (unsigned)width, (unsigned)height, viewImpl); LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetSize"); - // convert the scale to an int - int s = (int) (scale * 100); - // a negative value indicates that we should not change the scale - if (scale < 0) - s = viewImpl->scale(); - - viewImpl->setSizeScreenWidthAndScale(width, height, screenWidth, s, + viewImpl->setSizeScreenWidthAndScale(width, height, screenWidth, scale, realScreenWidth, screenHeight); } -static void SetScrollOffset(JNIEnv *env, jobject obj, jint dx, jint dy) +static void SetScrollOffset(JNIEnv *env, jobject obj, jint gen, jint x, jint y) { #ifdef ANDROID_INSTRUMENT TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); @@ -2043,7 +2097,7 @@ static void SetScrollOffset(JNIEnv *env, jobject obj, jint dx, jint dy) WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); LOG_ASSERT(viewImpl, "need viewImpl"); - viewImpl->setScrollOffset(dx, dy); + viewImpl->setScrollOffset(gen, x, y); } static void SetGlobalBounds(JNIEnv *env, jobject obj, jint x, jint y, jint h, @@ -2059,18 +2113,17 @@ static void SetGlobalBounds(JNIEnv *env, jobject obj, jint x, jint y, jint h, } static jboolean Key(JNIEnv *env, jobject obj, jint keyCode, jint unichar, - jint repeatCount, jboolean isShift, jboolean isAlt, jboolean isDown) + jint repeatCount, jboolean isShift, jboolean isAlt, jboolean isSym, + jboolean isDown) { #ifdef ANDROID_INSTRUMENT TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); #endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in Key"); - - return viewImpl->key(keyCode, unichar, repeatCount, isShift, isAlt, isDown); + return GET_NATIVE_VIEW(env, obj)->key(PlatformKeyboardEvent(keyCode, + unichar, repeatCount, isDown, isShift, isAlt, isSym)); } -static jboolean Click(JNIEnv *env, jobject obj) +static void Click(JNIEnv *env, jobject obj, int framePtr, int nodePtr) { #ifdef ANDROID_INSTRUMENT TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); @@ -2078,62 +2131,64 @@ static jboolean Click(JNIEnv *env, jobject obj) WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); LOG_ASSERT(viewImpl, "viewImpl not set in Click"); - return viewImpl->click(); + viewImpl->click(reinterpret_cast<WebCore::Frame*>(framePtr), + reinterpret_cast<WebCore::Node*>(nodePtr)); } -static void DeleteSelection(JNIEnv *env, jobject obj, - jint frame, jint node, jint x, jint y, jint start, jint end) +static void DeleteSelection(JNIEnv *env, jobject obj, jint start, jint end, + jint textGeneration) { #ifdef ANDROID_INSTRUMENT TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); #endif - LOGV("webviewcore::nativeDeleteSelection()\n"); WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in nativeDeleteSelection"); - viewImpl->deleteSelection((WebCore::Frame*) frame, (WebCore::Node*) node, - x, y, start, end); + viewImpl->deleteSelection(start, end, textGeneration); } -static void SetSelection(JNIEnv *env, jobject obj, - jint frame, jint node, jint x, jint y, jint start, jint end) +static void SetSelection(JNIEnv *env, jobject obj, jint start, jint end) { #ifdef ANDROID_INSTRUMENT TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); #endif - LOGV("webviewcore::nativeSetSelection()\n"); WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in nativeDeleteSelection"); - viewImpl->setSelection((WebCore::Frame*) frame, (WebCore::Node*) node, - x, y, start, end); + viewImpl->setSelection(start, end); } static void ReplaceTextfieldText(JNIEnv *env, jobject obj, - jint framePtr, jint nodePtr, jint x, jint y, jint oldStart, jint oldEnd, - jstring replace, jint start, jint end) + jint oldStart, jint oldEnd, jstring replace, jint start, jint end, + jint textGeneration) { #ifdef ANDROID_INSTRUMENT TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); #endif - LOGV("webviewcore::nativeReplaceTextfieldText()\n"); WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in nativeReplaceTextfieldText"); - viewImpl->replaceTextfieldText((WebCore::Frame*) framePtr, (WebCore::Node*) nodePtr, x, y, oldStart, - oldEnd, replace, start, end); + WebCore::String webcoreString = to_string(env, replace); + viewImpl->replaceTextfieldText(oldStart, + oldEnd, webcoreString, start, end, textGeneration); } -static void PassToJs(JNIEnv *env, jobject obj, jint frame, jint node, - jint x, jint y, jint generation, jstring currentText, jint keyCode, +static void PassToJs(JNIEnv *env, jobject obj, + jint generation, jstring currentText, jint keyCode, jint keyValue, jboolean down, jboolean cap, jboolean fn, jboolean sym) { #ifdef ANDROID_INSTRUMENT TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); #endif - LOGV("webviewcore::nativePassToJs()\n"); + WebCore::String current = to_string(env, currentText); + GET_NATIVE_VIEW(env, obj)->passToJs(generation, current, + PlatformKeyboardEvent(keyCode, keyValue, 0, down, cap, fn, sym)); +} + +static void SetFocusControllerActive(JNIEnv *env, jobject obj, jboolean active) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); +#endif + LOGV("webviewcore::nativeSetFocusControllerActive()\n"); WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in nativePassToJs"); - viewImpl->passToJs((WebCore::Frame*) frame, (WebCore::Node*) node, - x, y, generation, currentText, keyCode, keyValue, down, cap, fn, sym); + LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetFocusControllerActive"); + viewImpl->setFocusControllerActive(active); } static void SaveDocumentState(JNIEnv *env, jobject obj, jint frame) @@ -2206,7 +2261,8 @@ static void SendListBoxChoices(JNIEnv* env, jobject obj, jbooleanArray jArray, viewImpl->popupReply(array, count); } -static jstring FindAddress(JNIEnv *env, jobject obj, jstring addr) +static jstring FindAddress(JNIEnv *env, jobject obj, jstring addr, + jboolean caseInsensitive) { #ifdef ANDROID_INSTRUMENT TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); @@ -2219,7 +2275,7 @@ static jstring FindAddress(JNIEnv *env, jobject obj, jstring addr) const jchar* addrChars = env->GetStringChars(addr, 0); int start, end; bool success = CacheBuilder::FindAddress(addrChars, length, - &start, &end) == CacheBuilder::FOUND_COMPLETE; + &start, &end, caseInsensitive) == CacheBuilder::FOUND_COMPLETE; jstring ret = 0; if (success) { ret = env->NewString((jchar*) addrChars + start, end - start); @@ -2240,16 +2296,15 @@ static jboolean HandleTouchEvent(JNIEnv *env, jobject obj, jint action, jint x, } static void TouchUp(JNIEnv *env, jobject obj, jint touchGeneration, - jint buildGeneration, jint frame, jint node, jint x, jint y, jint size, - jboolean isClick, jboolean retry) + jint frame, jint node, jint x, jint y, jint size) { #ifdef ANDROID_INSTRUMENT TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); #endif WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); - viewImpl->touchUp(touchGeneration, buildGeneration, - (WebCore::Frame*) frame, (WebCore::Node*) node, x, y, size, isClick, retry); + viewImpl->touchUp(touchGeneration, + (WebCore::Frame*) frame, (WebCore::Node*) node, x, y, size); } static jstring RetrieveHref(JNIEnv *env, jobject obj, jint frame, @@ -2267,40 +2322,27 @@ static jstring RetrieveHref(JNIEnv *env, jobject obj, jint frame, return 0; } -static void SetFinalFocus(JNIEnv *env, jobject obj, jint frame, jint node, - jint x, jint y, jboolean block) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); - viewImpl->setFinalFocus((WebCore::Frame*) frame, (WebCore::Node*) node, x, - y, block); -} - -static void SetKitFocus(JNIEnv *env, jobject obj, jint moveGeneration, - jint buildGeneration, jint frame, jint node, jint x, jint y, - jboolean ignoreNullFocus) +static void MoveMouse(JNIEnv *env, jobject obj, jint frame, + jint x, jint y) { #ifdef ANDROID_INSTRUMENT TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); #endif WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); - viewImpl->setKitFocus(moveGeneration, buildGeneration, - (WebCore::Frame*) frame, (WebCore::Node*) node, x, y, - ignoreNullFocus); + viewImpl->moveMouse((WebCore::Frame*) frame, x, y); } -static void UnblockFocus(JNIEnv *env, jobject obj) +static void MoveMouseIfLatest(JNIEnv *env, jobject obj, jint moveGeneration, + jint frame, jint x, jint y) { #ifdef ANDROID_INSTRUMENT TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); #endif WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); - viewImpl->unblockFocus(); + viewImpl->moveMouseIfLatest(moveGeneration, + (WebCore::Frame*) frame, x, y); } static void UpdateFrameCache(JNIEnv *env, jobject obj) @@ -2427,16 +2469,28 @@ static void DumpNavTree(JNIEnv *env, jobject obj) viewImpl->dumpNavTree(); } -static void RefreshPlugins(JNIEnv *env, - jobject obj, - jboolean reloadOpenPages) +static void SetJsFlags(JNIEnv *env, jobject obj, jstring flags) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); +#if USE(V8) + WebCore::String flagsString = to_string(env, flags); + WebCore::CString utf8String = flagsString.utf8(); + WebCore::ScriptController::setFlags(utf8String.data(), utf8String.length()); +#endif +} + + +// Called from the Java side to set a new quota for the origin in response. +// to a notification that the original quota was exceeded. +static void SetDatabaseQuota(JNIEnv* env, jobject obj, jlong quota) { +#if ENABLE(DATABASE) + WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + Frame* frame = viewImpl->mainFrame(); + + // The main thread is blocked awaiting this response, so now we can wake it + // up. + ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client()); + chromeC->wakeUpMainThreadWithNewQuota(quota); #endif - // Refresh the list of plugins, optionally reloading all open - // pages. - WebCore::refreshPlugins(reloadOpenPages); } static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jstring scheme) { @@ -2475,6 +2529,68 @@ static bool DrawContent(JNIEnv *env, jobject obj, jobject canv, jint color) return viewImpl->drawContent(canvas, color); } +static bool PictureReady(JNIEnv* env, jobject obj) +{ + return GET_NATIVE_VIEW(env, obj)->pictureReady(); +} + +static void UpdatePluginState(JNIEnv* env, jobject obj, jint framePtr, jint nodePtr, jint state) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); +#endif + WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(viewImpl, "viewImpl not set in nativeUpdatePluginState"); + viewImpl->updatePluginState((WebCore::Frame*) framePtr, (WebCore::Node*) nodePtr, + (PluginState) state); +} + +static void SurfaceChanged(JNIEnv* env, jobject obj, jint pointer, jint state, + jint format, jint width, jint height) +{ + // Be safe and check for a valid callback + if (!pointer) + return; + SurfaceCallback* cb = reinterpret_cast<SurfaceCallback*>(pointer); + switch (state) { + case 0: + cb->surfaceCreated(); + break; + case 1: + cb->surfaceChanged(format, width, height); + break; + case 2: + cb->surfaceDestroyed(); + break; + default: + break; + } +} + +static void Pause(JNIEnv* env, jobject obj) +{ + ANPEvent event; + SkANP::InitEvent(&event, kLifecycle_ANPEventType); + event.data.lifecycle.action = kPause_ANPLifecycleAction; + GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event); +} + +static void Resume(JNIEnv* env, jobject obj) +{ + ANPEvent event; + SkANP::InitEvent(&event, kLifecycle_ANPEventType); + event.data.lifecycle.action = kResume_ANPLifecycleAction; + GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event); +} + +static void FreeMemory(JNIEnv* env, jobject obj) +{ + ANPEvent event; + SkANP::InitEvent(&event, kLifecycle_ANPEventType); + event.data.lifecycle.action = kFreeMemory_ANPLifecycleAction; + GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event); +} + // ---------------------------------------------------------------------------- /* @@ -2487,44 +2603,46 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = { (void*) CopyContentToPicture }, { "nativeDrawContent", "(Landroid/graphics/Canvas;I)Z", (void*) DrawContent } , - { "nativeKey", "(IIIZZZ)Z", + { "nativeKey", "(IIIZZZZ)Z", (void*) Key }, - { "nativeClick", "()Z", + { "nativeClick", "(II)V", (void*) Click }, + { "nativePictureReady", "()Z", + (void*) PictureReady } , { "nativeSendListBoxChoices", "([ZI)V", (void*) SendListBoxChoices }, { "nativeSendListBoxChoice", "(I)V", (void*) SendListBoxChoice }, { "nativeSetSize", "(IIIFII)V", (void*) SetSize }, - { "nativeSetScrollOffset", "(II)V", + { "nativeSetScrollOffset", "(III)V", (void*) SetScrollOffset }, { "nativeSetGlobalBounds", "(IIII)V", (void*) SetGlobalBounds }, - { "nativeSetSelection", "(IIIIII)V", + { "nativeSetSelection", "(II)V", (void*) SetSelection } , - { "nativeDeleteSelection", "(IIIIII)V", + { "nativeDeleteSelection", "(III)V", (void*) DeleteSelection } , - { "nativeReplaceTextfieldText", "(IIIIIILjava/lang/String;II)V", + { "nativeReplaceTextfieldText", "(IILjava/lang/String;III)V", (void*) ReplaceTextfieldText } , - { "passToJs", "(IIIIILjava/lang/String;IIZZZZ)V", + { "nativeMoveMouse", "(III)V", + (void*) MoveMouse }, + { "nativeMoveMouseIfLatest", "(IIII)V", + (void*) MoveMouseIfLatest }, + { "passToJs", "(ILjava/lang/String;IIZZZZ)V", (void*) PassToJs } , + { "nativeSetFocusControllerActive", "(Z)V", + (void*) SetFocusControllerActive }, { "nativeSaveDocumentState", "(I)V", (void*) SaveDocumentState }, - { "nativeFindAddress", "(Ljava/lang/String;)Ljava/lang/String;", + { "nativeFindAddress", "(Ljava/lang/String;Z)Ljava/lang/String;", (void*) FindAddress }, { "nativeHandleTouchEvent", "(III)Z", (void*) HandleTouchEvent }, - { "nativeTouchUp", "(IIIIIIIZZ)V", + { "nativeTouchUp", "(IIIIII)V", (void*) TouchUp }, { "nativeRetrieveHref", "(II)Ljava/lang/String;", (void*) RetrieveHref }, - { "nativeSetFinalFocus", "(IIIIZ)V", - (void*) SetFinalFocus }, - { "nativeSetKitFocus", "(IIIIIIZ)V", - (void*) SetKitFocus }, - { "nativeUnblockFocus", "()V", - (void*) UnblockFocus }, { "nativeUpdateFrameCache", "()V", (void*) UpdateFrameCache }, { "nativeGetContentMinPrefWidth", "()I", @@ -2543,8 +2661,6 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = { (void*) SetBackgroundColor }, { "nativeGetSelection", "(Landroid/graphics/Region;)Ljava/lang/String;", (void*) GetSelection }, - { "nativeRefreshPlugins", "(Z)V", - (void*) RefreshPlugins }, { "nativeRegisterURLSchemeAsLocal", "(Ljava/lang/String;)V", (void*) RegisterURLSchemeAsLocal }, { "nativeDumpDomTree", "(Z)V", @@ -2552,7 +2668,16 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = { { "nativeDumpRenderTree", "(Z)V", (void*) DumpRenderTree }, { "nativeDumpNavTree", "()V", - (void*) DumpNavTree } + (void*) DumpNavTree }, + { "nativeSetDatabaseQuota", "(J)V", + (void*) SetDatabaseQuota }, + { "nativeSurfaceChanged", "(IIIII)V", + (void*) SurfaceChanged }, + { "nativePause", "()V", (void*) Pause }, + { "nativeResume", "()V", (void*) Resume }, + { "nativeFreeMemory", "()V", (void*) FreeMemory }, + { "nativeSetJsFlags", "(Ljava/lang/String;)V", (void*) SetJsFlags }, + { "nativeUpdatePluginState", "(III)V", (void*) UpdatePluginState }, }; int register_webviewcore(JNIEnv* env) diff --git a/WebKit/android/jni/WebViewCore.h b/WebKit/android/jni/WebViewCore.h index 8f035f2..66ef470 100644 --- a/WebKit/android/jni/WebViewCore.h +++ b/WebKit/android/jni/WebViewCore.h @@ -26,6 +26,7 @@ #ifndef WEBVIEWCORE_H #define WEBVIEWCORE_H +#include "android_npapi.h" #include "CacheBuilder.h" #include "CachedHistory.h" #include "PictureSet.h" @@ -47,6 +48,7 @@ namespace WebCore { class RenderPart; class RenderText; class Node; + class PlatformKeyboardEvent; class RenderTextControl; class ScrollView; class TimerBase; @@ -57,9 +59,15 @@ class SkPicture; class SkIRect; namespace android { - + + enum PluginState { + kGainFocus_PluginState = 0, + kLoseFocus_PluginState = 1, + }; + class CachedRoot; class ListBoxReply; + class SurfaceCallback; class WebCoreReply : public WebCoreRefObject { public: @@ -132,12 +140,6 @@ namespace android { void offInvalidate(const WebCore::IntRect &rect); /** - * Called by webcore when the focus was set after returning to prior page - * used to rebuild and display any changes in focus - */ - void notifyFocusSet(); - - /** * Called by webcore when the progress indicator is done * used to rebuild and display any changes in focus */ @@ -149,7 +151,7 @@ namespace android { void didFirstLayout(); /** - * Notify the view to restore the screen width, which in turn restores + * Notify the view to restore the screen width, which in turn restores * the scale. */ void restoreScale(int); @@ -164,7 +166,7 @@ namespace android { */ void updateTextfield(WebCore::Node* pointer, bool changeToPassword, const WebCore::String& text); - + void clearTextEntry(); // JavaScript support void jsAlert(const WebCore::String& url, const WebCore::String& text); bool jsConfirm(const WebCore::String& url, const WebCore::String& text); @@ -173,6 +175,19 @@ namespace android { bool jsUnload(const WebCore::String& url, const WebCore::String& message); bool jsInterrupt(); + /** + * Tell the Java side that the origin has exceeded it's database quota. + * @param url The URL of the page that caused the quota overflow + * @param databaseIdentifier the id of the database that caused the + * quota overflow. + * @param currentQuota The current quota for the origin. + */ + void exceededDatabaseQuota(const WebCore::String& url, + const WebCore::String& databaseIdentifier, + const unsigned long long currentQuota); + + void addMessageToConsole(const String& message, unsigned int lineNumber, const String& sourceID); + // // Followings support calls from Java to native WebCore // @@ -180,37 +195,35 @@ namespace android { WebCore::String retrieveHref(WebCore::Frame* frame, WebCore::Node* node); WebCore::String getSelection(SkRegion* ); - + // Create a single picture to represent the drawn DOM (used by navcache) void recordPicture(SkPicture* picture); - + // Create a set of pictures to represent the drawn DOM, driven by // the invalidated region and the time required to draw (used to draw) void recordPictureSet(PictureSet* master); - void setFinalFocus(WebCore::Frame* frame, WebCore::Node* node, - int x, int y, bool block); - void setKitFocus(int moveGeneration, int buildGeneration, - WebCore::Frame* frame, WebCore::Node* node, int x, int y, - bool ignoreNullFocus); + void moveMouse(WebCore::Frame* frame, int x, int y); + void moveMouseIfLatest(int moveGeneration, + WebCore::Frame* frame, int x, int y); // set the scroll amount that webview.java is currently showing - void setScrollOffset(int dx, int dy); + void setScrollOffset(int moveGeneration, int dx, int dy); void setGlobalBounds(int x, int y, int h, int v); - void setSizeScreenWidthAndScale(int width, int height, int screenWidth, - int scale, int realScreenWidth, int screenHeight); + void setSizeScreenWidthAndScale(int width, int height, int screenWidth, + float scale, int realScreenWidth, int screenHeight); /** * Handle key events from Java. * @return Whether keyCode was handled by this class. */ - bool key(int keyCode, UChar32 unichar, int repeatCount, bool isShift, bool isAlt, bool isDown); + bool key(const WebCore::PlatformKeyboardEvent& event); /** - * Handle (mouse) click event from Java + * Handle (trackball) click event from Java */ - bool click(); + void click(WebCore::Frame* frame, WebCore::Node* node); /** * Handle touch event @@ -221,10 +234,9 @@ namespace android { * Handle motionUp event from the UI thread (called touchUp in the * WebCore thread). */ - void touchUp(int touchGeneration, int buildGeneration, - WebCore::Frame* frame, WebCore::Node* node, int x, int y, - int size, bool isClick, bool retry); - + void touchUp(int touchGeneration, + WebCore::Frame* frame, WebCore::Node* node, int x, int y, int size); + /** * Sets the index of the label from a popup */ @@ -232,33 +244,29 @@ namespace android { void popupReply(const int* array, int count); /** - * Delete text from start to end in the focused textfield. If there is no - * focus, or if start == end, silently fail, but set selection to that value. + * Delete text from start to end in the focused textfield. + * If start == end, set the selection, but perform no deletion. + * If there is no focus, silently fail. * If start and end are out of order, swap them. - * Use the frame, node, x, and y to ensure that the correct node is focused. - * Return a frame. Convenience so replaceTextfieldText can use this function. */ - WebCore::Frame* deleteSelection(WebCore::Frame* frame, WebCore::Node* node, int x, - int y,int start, int end); + void deleteSelection(int start, int end, int textGeneration); /** * Set the selection of the currently focused textfield to (start, end). * If start and end are out of order, swap them. - * Use the frame, node, x, and y to ensure that the correct node is focused. - * Return a frame. Convenience so deleteSelection can use this function. */ - WebCore::Frame* setSelection(WebCore::Frame* frame, WebCore::Node* node, int x, - int y,int start, int end); + void setSelection(int start, int end); /** - * In the currenlty focused textfield, represented by frame, node, x, and y (which - * are used to ensure it has focus), replace the characters from oldStart to oldEnd + * In the currently focused textfield, replace the characters from oldStart to oldEnd * (if oldStart == oldEnd, this will be an insert at that position) with replace, * and set the selection to (start, end). */ - void replaceTextfieldText(WebCore::Frame* frame, WebCore::Node* node, int x, int y, - int oldStart, int oldEnd, jstring replace, int start, int end); - void passToJs(WebCore::Frame* frame, WebCore::Node* node, int x, int y, int generation, - jstring currentText, int jKeyCode, int keyVal, bool down, bool cap, bool fn, bool sym); + void replaceTextfieldText(int oldStart, + int oldEnd, const WebCore::String& replace, int start, int end, + int textGeneration); + void passToJs(int generation, + const WebCore::String& , const WebCore::PlatformKeyboardEvent& ); + void setFocusControllerActive(bool active); void saveDocumentState(WebCore::Frame* frame); @@ -273,8 +281,8 @@ namespace android { void setBackgroundColor(SkColor c); void setSnapAnchor(int x, int y); void snapToAnchor(); - void unblockFocus() { m_blockFocusChange = false; } void updateFrameCache(); + void updateCacheOnNodeChange(); void dumpDomTree(bool); void dumpRenderTree(bool); void dumpNavTree(); @@ -288,34 +296,58 @@ namespace android { void invalPlugin(PluginWidgetAndroid*); void drawPlugins(); + // send the current screen size/zoom to all of the plugins in our list + void sendPluginVisibleScreen(); + + // send this event to all of the plugins in our list + void sendPluginEvent(const ANPEvent&); + + // send this event to all of the plugins who have the given flag set + void sendPluginEvent(const ANPEvent& evt, ANPEventFlag flag); + + // return the cursorNode if it is a plugin + Node* cursorNodeIsPlugin(); + + // notify the plugin of an update in state + void updatePluginState(Frame* frame, Node* node, PluginState state); + // Notify the Java side whether it needs to pass down the touch events void needTouchEvents(bool); + // Notify the Java side that webkit is requesting a keyboard + void requestKeyboard(bool); + + // Creates a SurfaceView for a plugin + jobject createSurface(SurfaceCallback* cb); + + // Destroys the SurfaceView after removing from the view system. + void destroySurface(jobject surface); + + // Positions the SurfaceView at x,y with dimensions width x height + void attachSurface(jobject surface, int x, int y, int width, int height); + // other public functions public: - void removeFrameGeneration(WebCore::Frame* ); - void updateFrameGeneration(WebCore::Frame* ); - // reset the picture set to empty void clearContent(); - + // flatten the picture set to a picture void copyContentToPicture(SkPicture* ); - + // draw the picture set with the specified background color bool drawContent(SkCanvas* , SkColor ); - + bool pictureReady(); + // record the inval area, and the picture size bool recordContent(SkRegion* , SkIPoint* ); int screenWidth() const { return m_screenWidth; } - int scale() const { return m_scale; } + float scale() const { return m_scale; } WebCore::Frame* mainFrame() const { return m_mainFrame; } - + // utility to split slow parts of the picture set void splitContent(); - + // these members are shared with webview.cpp - int retrieveFrameGeneration(WebCore::Frame* ); static Mutex gFrameCacheMutex; CachedRoot* m_frameCacheKit; // nav data being built by webcore SkPicture* m_navPictureKit; @@ -324,10 +356,14 @@ namespace android { int m_touchGeneration; // copy of state in WebViewNative triggered by touch int m_lastGeneration; // last action using up to date cache bool m_updatedFrameCache; - bool m_useReplay; bool m_findIsUp; - static Mutex gRecomputeFocusMutex; - WTF::Vector<int> m_recomputeEvents; + bool m_hasCursorBounds; + WebCore::IntRect m_cursorBounds; + WebCore::IntRect m_cursorHitBounds; + void* m_cursorFrame; + IntPoint m_cursorLocation; + void* m_cursorNode; + static Mutex gCursorBoundsMutex; // These two fields go together: we use the mutex to protect access to // m_buttons, so that we, and webview.cpp can look/modify the m_buttons // field safely from our respective threads @@ -337,6 +373,8 @@ namespace android { // internal functions private: + CacheBuilder& cacheBuilder(); + WebCore::Node* currentFocus(); // Compare the new set of buttons to the old one. All of the new // buttons either replace our old ones or should be added to our list. // Then check the old buttons to see if any are no longer needed. @@ -348,18 +386,13 @@ namespace android { bool multiple, const int selected[], size_t selectedCountOrSelection); friend class ListBoxReply; - struct FrameGen { - const WebCore::Frame* m_frame; - int m_generation; - }; - WTF::Vector<FrameGen> m_frameGenerations; - static Mutex gFrameGenerationMutex; struct JavaGlue; struct JavaGlue* m_javaGlue; WebCore::Frame* m_mainFrame; WebCoreReply* m_popupReply; WebCore::Node* m_lastFocused; WebCore::IntRect m_lastFocusedBounds; + int m_lastMoveGeneration; static Mutex m_contentMutex; // protects ui/core thread pictureset access PictureSet m_content; // the set of pictures to draw (accessed by UI too) SkRegion m_addInval; // the accumulated inval region (not yet drawn) @@ -373,45 +406,34 @@ namespace android { int m_textGeneration; CachedRoot* m_temp; SkPicture* m_tempPict; - int m_buildGeneration; int m_maxXScroll; int m_maxYScroll; int m_scrollOffsetX; // webview.java's current scroll in X int m_scrollOffsetY; // webview.java's current scroll in Y WebCore::IntPoint m_mousePos; bool m_frameCacheOutOfDate; - bool m_blockFocusChange; + bool m_progressDone; int m_lastPassed; int m_lastVelocity; CachedHistory m_history; WebCore::Node* m_snapAnchorNode; - int m_screenWidth; - int m_scale; + int m_screenWidth; // width of the visible rect in document coordinates + int m_screenHeight;// height of the visible rect in document coordinates + float m_scale; unsigned m_domtree_version; bool m_check_domtree_version; - + SkTDArray<PluginWidgetAndroid*> m_plugins; WebCore::Timer<WebViewCore> m_pluginInvalTimer; void pluginInvalTimerFired(WebCore::Timer<WebViewCore>*) { this->drawPlugins(); } - WebCore::Frame* changedKitFocus(WebCore::Frame* frame, - WebCore::Node* node, int x, int y); - bool commonKitFocus(int generation, int buildGeneration, - WebCore::Frame* frame, WebCore::Node* node, int x, int y, - bool ignoreNullFocus); - bool finalKitFocus(WebCore::Frame* frame, WebCore::Node* node, int x, int y, bool donotChangeDOMFocus); void doMaxScroll(CacheBuilder::Direction dir); SkPicture* rebuildPicture(const SkIRect& inval); void rebuildPictureSet(PictureSet* ); - void sendMarkNodeInvalid(WebCore::Node* ); - void sendNotifyFocusSet(); void sendNotifyProgressFinished(); - void sendRecomputeFocus(); bool handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* nodePtr); - bool prepareFrameCache(); - void releaseFrameCache(bool newCache); #if DEBUG_NAV_UI uint32_t m_now; #endif diff --git a/WebKit/android/nav/CacheBuilder.cpp b/WebKit/android/nav/CacheBuilder.cpp index a49c614..56cb2ae 100644 --- a/WebKit/android/nav/CacheBuilder.cpp +++ b/WebKit/android/nav/CacheBuilder.cpp @@ -27,8 +27,8 @@ #include "CachedNode.h" #include "CachedRoot.h" #include "Document.h" +#include "EventListener.h" #include "EventNames.h" -#include "EventTargetNode.h" #include "Frame.h" #include "FrameLoader.h" #include "FrameLoaderClientAndroid.h" @@ -45,6 +45,7 @@ #include "InlineTextBox.h" #include "KURL.h" #include "PluginView.h" +#include "RegisteredEventListener.h" #include "RenderImage.h" #include "RenderInline.h" #include "RenderListBox.h" @@ -88,8 +89,20 @@ Frame* CacheBuilder::FrameAnd(const CacheBuilder* cacheBuilder) { return loader->getFrame(); } + #if DUMP_NAV_CACHE +static bool hasEventListener(Node* node, const AtomicString& eventType) { + const RegisteredEventListenerVector& listeners = node->eventListeners(); + size_t size = listeners.size(); + for (size_t i = 0; i < size; ++i) { + const RegisteredEventListener& r = *listeners[i]; + if (r.eventType() == eventType) + return true; + } + return false; +} + #define DEBUG_BUFFER_SIZE 256 #define DEBUG_WRAP_SIZE 150 #define DEBUG_WRAP_MAX 170 @@ -345,24 +358,20 @@ void CacheBuilder::Debug::groups() { DUMP_NAV_LOGD("static DebugTestNode TEST%s_RECTS[] = {\n", name); do { String properties; - EventTargetNode* elementTarget = node->isEventTargetNode() ? - (EventTargetNode*) node : NULL; - if (elementTarget) { - if (elementTarget->getEventListener(eventNames().clickEvent)) - properties.append("ONCLICK | "); - if (elementTarget->getEventListener(eventNames().mousedownEvent)) - properties.append("MOUSEDOWN | "); - if (elementTarget->getEventListener(eventNames().mouseupEvent)) - properties.append("MOUSEUP | "); - if (elementTarget->getEventListener(eventNames().mouseoverEvent)) - properties.append("MOUSEOVER | "); - if (elementTarget->getEventListener(eventNames().mouseoutEvent)) - properties.append("MOUSEOUT | "); - if (elementTarget->getEventListener(eventNames().keydownEvent)) - properties.append("KEYDOWN | "); - if (elementTarget->getEventListener(eventNames().keyupEvent)) - properties.append("KEYUP | "); - } + if (hasEventListener(node, eventNames().clickEvent)) + properties.append("ONCLICK | "); + if (hasEventListener(node, eventNames().mousedownEvent)) + properties.append("MOUSEDOWN | "); + if (hasEventListener(node, eventNames().mouseupEvent)) + properties.append("MOUSEUP | "); + if (hasEventListener(node, eventNames().mouseoverEvent)) + properties.append("MOUSEOVER | "); + if (hasEventListener(node, eventNames().mouseoutEvent)) + properties.append("MOUSEOUT | "); + if (hasEventListener(node, eventNames().keydownEvent)) + properties.append("KEYDOWN | "); + if (hasEventListener(node, eventNames().keyupEvent)) + properties.append("KEYUP | "); if (CacheBuilder::HasFrame(node)) properties.append("FRAME | "); if (focus == node) { @@ -381,7 +390,7 @@ void CacheBuilder::Debug::groups() { properties.truncate(properties.length() - 3); IntRect rect = node->getRect(); if (node->hasTagName(HTMLNames::areaTag)) - rect = Builder(frame)->getAreaRect(static_cast<HTMLAreaElement*>(node)); + rect = getAreaRect(static_cast<HTMLAreaElement*>(node)); char buffer[DEBUG_BUFFER_SIZE]; memset(buffer, 0, sizeof(buffer)); mBuffer = buffer; @@ -437,7 +446,7 @@ void CacheBuilder::Debug::groups() { //print(renderer ? renderer->information().ascii() : "NO_RENDER_INFO"); if (node->isElementNode()) { Element* element = static_cast<Element*>(node); - NamedAttrMap* attrs = element->attributes(); + NamedNodeMap* attrs = element->attributes(); unsigned length = attrs->length(); if (length > 0) { newLine(); @@ -448,8 +457,6 @@ void CacheBuilder::Debug::groups() { } } } - if (renderer) - renderTree(renderer, 0, node, count); count++; newLine(); } while ((node = node->traverseNextNode()) != NULL); @@ -520,9 +527,10 @@ void CacheBuilder::Debug::groups() { mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, ", %d, %d, %d", 0 /*textBox->spaceAdd()*/, textBox->start(), 0 /*textBox->textPos()*/); mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, ", %d, %d, %d, %d", - textBox->xPos(), textBox->yPos(), textBox->width(), textBox->height()); + textBox->x(), textBox->y(), textBox->width(), textBox->height()); + int baseline = textBox->renderer()->style(textBox->isFirstLineStyle())->font().ascent(); mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, ", %d }, // %d ", - textBox->baseline(), ++rectIndex); + baseline, ++rectIndex); wideString(node->textContent().characters() + textBox->start(), textBox->len(), true); DUMP_NAV_LOGD("%.*s\n", mIndex, mBuffer); textBox = textBox->nextTextBox(); @@ -553,8 +561,6 @@ bool CacheBuilder::Debug::isFocusable(Node* node) { return true; if (node->isFocusable()) return true; - if (node->isEventTargetNode()) - return true; if (CacheBuilder::AnyIsClick(node)) return false; if (CacheBuilder::HasTriggerEvent(node)) @@ -645,64 +651,6 @@ void CacheBuilder::Debug::setIndent(int indent) print(scratch); } -void CacheBuilder::Debug::renderTree(RenderObject* renderer, int indent, - Node* child, int count) -{ - char scratch[256]; - Node* node = renderer->node(); - if (node != child) { - count = ParentIndex(child, count, node); - if (renderer->isRenderBlock() == false) - goto tryParent; - RenderBlock* renderBlock = (RenderBlock*) renderer; - if (renderBlock->hasColumns() == false) - goto tryParent; - Vector<IntRect>* rects = renderBlock->columnRects(); - newLine(indent); - snprintf(scratch, sizeof(scratch), "// render parent=%d", count); - print(scratch); - for (size_t x = 0; x < rects->size(); x++) { - const IntRect& rect = rects->at(x); - snprintf(scratch, sizeof(scratch), "(%d,%d,%d,%d) ", rect.x(), - rect.y(), rect.width(), rect.height()); - print(scratch); - } - } - { - newLine(indent); - RenderStyle* style = renderer->style(); - EVisibility vis = style->visibility(); - ASSERT(vis == VISIBLE || vis == HIDDEN || vis == COLLAPSE); - snprintf(scratch, sizeof(scratch), - "// render style visible:%s opacity:%g width:%d height:%d" - " hasBackground:%s isInlineFlow:%s isBlockFlow:%s" - " textOverflow:%s", - vis == VISIBLE ? "visible" : vis == HIDDEN ? "hidden" : "collapse", - style->opacity(), 0 /*renderer->width()*/, 0 /*renderer->height()*/, - style->hasBackground() ? "true" : "false", - 0 /*renderer->isInlineFlow()*/ ? "true" : "false", - renderer->isBlockFlow() ? "true" : "false", - style->textOverflow() ? "true" : "false" - ); - print(scratch); - newLine(indent); - const IntRect& oRect = renderer->absoluteClippedOverflowRect(); - const IntRect& cRect = renderer->getOverflowClipRect(0,0); - snprintf(scratch, sizeof(scratch), - "// render xPos:%d yPos:%d overflowRect:{%d, %d, %d, %d} " - " getOverflowClipRect:{%d, %d, %d, %d} ", - 0 /*renderer->xPos()*/, 0 /*renderer->yPos()*/, - oRect.x(), oRect.y(), oRect.width(), oRect.height(), - cRect.x(), cRect.y(), cRect.width(), cRect.height() - ); - print(scratch); - } -tryParent: - RenderObject* parent = renderer->parent(); - if (parent) - renderTree(parent, indent + 2, node, count); -} - void CacheBuilder::Debug::uChar(const UChar* name, unsigned len, bool hex) { const UChar* end = name + len; bool wroteHex = false; @@ -773,7 +721,6 @@ void CacheBuilder::Debug::wideString(const String& str) { CacheBuilder::CacheBuilder() { - mLastKnownFocus = NULL; mAllowableTypes = ALL_CACHEDNODETYPES; #ifdef DUMP_NAV_CACHE_USING_PRINTF gNavCacheLogFile = NULL; @@ -807,20 +754,35 @@ void CacheBuilder::adjustForColumns(const ClipColumnTracker& track, } } +// Checks if a node has one of event listener types. +bool CacheBuilder::NodeHasEventListeners(Node* node, AtomicString* eventTypes, int length) { + const RegisteredEventListenerVector& listeners = node->eventListeners(); + size_t size = listeners.size(); + for (size_t i = 0; i < size; ++i) { + const RegisteredEventListener& r = *listeners[i]; + for (int j = 0; j < length; ++j) { + if (r.eventType() == eventTypes[j]) + return true; + } + } + return false; +} + bool CacheBuilder::AnyChildIsClick(Node* node) { + AtomicString eventTypes[5] = { + eventNames().clickEvent, + eventNames().mousedownEvent, + eventNames().mouseupEvent, + eventNames().keydownEvent, + eventNames().keyupEvent + }; + Node* child = node->firstChild(); while (child != NULL) { - if (child->isEventTargetNode()) { - EventTargetNode* target = (EventTargetNode*) child; - if (target->isFocusable() || - target->getEventListener(eventNames().clickEvent) || - target->getEventListener(eventNames().mousedownEvent) || - target->getEventListener(eventNames().mouseupEvent) || - target->getEventListener(eventNames().keydownEvent) || - target->getEventListener(eventNames().keyupEvent)) + if (child->isFocusable() || + NodeHasEventListeners(child, eventTypes, 5)) return true; - } if (AnyChildIsClick(child)) return true; child = child->nextSibling(); @@ -832,26 +794,32 @@ bool CacheBuilder::AnyIsClick(Node* node) { if (node->hasTagName(HTMLNames::bodyTag)) return AnyChildIsClick(node); - EventTargetNode* target = (EventTargetNode*) node; - if (target->getEventListener(eventNames().mouseoverEvent) == NULL && - target->getEventListener(eventNames().mouseoutEvent) == NULL && - target->getEventListener(eventNames().keydownEvent) == NULL && - target->getEventListener(eventNames().keyupEvent) == NULL) - return false; - if (target->getEventListener(eventNames().clickEvent)) - return false; - if (target->getEventListener(eventNames().mousedownEvent)) + + AtomicString eventTypeSetOne[4] = { + eventNames().mouseoverEvent, + eventNames().mouseoutEvent, + eventNames().keydownEvent, + eventNames().keyupEvent + }; + + if (!NodeHasEventListeners(node, eventTypeSetOne, 4)) return false; - if (target->getEventListener(eventNames().mouseupEvent)) + + AtomicString eventTypeSetTwo[3] = { + eventNames().clickEvent, + eventNames().mousedownEvent, + eventNames().mouseupEvent + }; + + if (NodeHasEventListeners(node, eventTypeSetTwo, 3)) return false; + return AnyChildIsClick(node); } void CacheBuilder::buildCache(CachedRoot* root) { Frame* frame = FrameAnd(this); - mLastKnownFocus = NULL; - m_areaBoundsMap.clear(); BuildFrame(frame, frame, root, (CachedFrame*) root); root->finishInit(); // set up frame parent pointers, child pointers setData((CachedFrame*) root); @@ -933,10 +901,8 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, Node* node = parent; int cacheIndex = 1; Node* focused = doc->focusedNode(); - if (focused) { - setLastFocus(focused); - cachedRoot->setFocusBounds(mLastKnownFocusBounds); - } + if (focused) + cachedRoot->setFocusBounds(focused->getRect()); int globalOffsetX, globalOffsetY; GetGlobalOffset(frame, &globalOffsetX, &globalOffsetY); while (walk.mMore || (node = node->traverseNextNode()) != NULL) { @@ -1004,39 +970,24 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, } RenderObject* nodeRenderer = node->renderer(); bool isTransparent = false; - bool hasFocusRing = true; + bool hasCursorRing = true; if (nodeRenderer != NULL) { RenderStyle* style = nodeRenderer->style(); if (style->visibility() == HIDDEN) continue; - if (nodeRenderer->isImage()) { // set all the area elements to have a link to their images - RenderImage* image = static_cast<RenderImage*>(nodeRenderer); - HTMLMapElement* map = image->imageMap(); - if (map) { - Node* node; - for (node = map->firstChild(); node; - node = node->traverseNextNode(map)) { - if (!node->hasTagName(HTMLNames::areaTag)) - continue; - HTMLAreaElement* area = static_cast<HTMLAreaElement*>(node); - m_areaBoundsMap.set(area, image); - } - } - } isTransparent = style->hasBackground() == false; #ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR - hasFocusRing = style->tapHighlightColor().alpha() > 0; + hasCursorRing = style->tapHighlightColor().alpha() > 0; #endif } bool more = walk.mMore; walk.reset(); // GetGlobalBounds(node, &bounds, false); - bool computeFocusRings = false; + bool computeCursorRings = false; bool hasClip = false; bool hasMouseOver = false; bool isAnchor = false; bool isArea = node->hasTagName(HTMLNames::areaTag); - bool isInput = false; bool isPassword = false; bool isTextArea = false; bool isTextField = false; @@ -1055,8 +1006,6 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, IntRect bounds; IntRect absBounds; WTF::Vector<IntRect>* columns = NULL; - int minimumFocusableWidth = MINIMUM_FOCUSABLE_WIDTH; - int minimumFocusableHeight = MINIMUM_FOCUSABLE_HEIGHT; if (isArea) { HTMLAreaElement* area = static_cast<HTMLAreaElement*>(node); bounds = getAreaRect(area); @@ -1131,7 +1080,7 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, IntRect(0, 0, INT_MAX, INT_MAX); if (ConstructTextRects((WebCore::Text*) node, walk.mStart, (WebCore::Text*) walk.mFinalNode, walk.mEnd, globalOffsetX, - globalOffsetY, &bounds, clip, &cachedNode.focusRings()) == false) + globalOffsetY, &bounds, clip, &cachedNode.cursorRings()) == false) continue; absBounds = bounds; cachedNode.setBounds(bounds); @@ -1139,7 +1088,7 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, continue; if (bounds.height() < MINIMUM_FOCUSABLE_HEIGHT) continue; - computeFocusRings = true; + computeCursorRings = true; isUnclipped = true; // FIXME: to hide or partially occlude synthesized links, each // focus ring will also need the offset and length of characters // used to produce it @@ -1149,23 +1098,23 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, HTMLInputElement* input = (HTMLInputElement*) node; if (input->inputType() == HTMLInputElement::FILE) continue; - isInput = true; isTextField = input->isTextField(); + if (isTextField) + wantsKeyEvents = true; isPassword = input->inputType() == HTMLInputElement::PASSWORD; maxLength = input->maxLength(); name = input->name().string().copy(); isUnclipped = isTransparent; // can't detect if this is drawn on top (example: deviant.com login parts) } else if (node->hasTagName(HTMLNames::textareaTag)) - isTextArea = true; + isTextArea = wantsKeyEvents = true; else if (node->hasTagName(HTMLNames::aTag)) { const HTMLAnchorElement* anchorNode = (const HTMLAnchorElement*) node; if (!anchorNode->isFocusable() && !HasTriggerEvent(node)) continue; - EventTargetNode* target = (EventTargetNode*) node; - if (target->disabled()) + if (node->disabled()) continue; - hasMouseOver = target->getEventListener(eventNames().mouseoverEvent); + hasMouseOver = NodeHasEventListeners(node, &eventNames().mouseoverEvent, 1); isAnchor = true; KURL href = anchorNode->href(); if (!href.isEmpty() && !href.protocolIs("javascript")) @@ -1188,20 +1137,14 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, style->textAlign() == WebCore::RIGHT || style->textAlign() == WebCore::WEBKIT_RIGHT; } - minimumFocusableWidth += 4; - minimumFocusableHeight += 4; } takesFocus = true; - if (isAnchor) { - bounds = absBounds; - } else { + bounds = absBounds; + if (!isAnchor) { bool isFocusable = node->isKeyboardFocusable(NULL) || node->isMouseFocusable() || node->isFocusable(); if (isFocusable == false) { - if (node->isEventTargetNode() == false) - continue; - EventTargetNode* eventTargetNode = (EventTargetNode*) node; - if (eventTargetNode->disabled()) + if (node->disabled()) continue; bool overOrOut = HasOverOrOut(node); bool hasTrigger = HasTriggerEvent(node); @@ -1209,32 +1152,15 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, continue; takesFocus = hasTrigger; } - bounds = node->getRect(); - // For Bank of America site - if (isTextField && ((RenderBox*)nodeRenderer)->paddingLeft() > 100) { - int paddingLeft = ((RenderBox*)nodeRenderer)->paddingLeft(); - int paddingTop = ((RenderBox*)nodeRenderer)->paddingTop(); - int x = bounds.x() + paddingLeft; - int y = bounds.y() + paddingTop; - int width = bounds.width() - paddingLeft - ((RenderBox*)nodeRenderer)->paddingRight(); - int height = bounds.height() - paddingTop - ((RenderBox*)nodeRenderer)->paddingBottom(); - bounds.setLocation(IntPoint(x, y)); - bounds.setSize(IntSize(width, height)); - } - if (bounds.width() < minimumFocusableWidth) - continue; - if (bounds.height() < minimumFocusableHeight) - continue; - bounds.move(globalOffsetX, globalOffsetY); } - computeFocusRings = true; + computeCursorRings = true; keepNode: cachedNode.init(node); - if (computeFocusRings == false) { + if (computeCursorRings == false) { cachedNode.setBounds(bounds); - cachedNode.focusRings().append(bounds); + cachedNode.cursorRings().append(bounds); } else if (ConstructPartRects(node, bounds, cachedNode.boundsPtr(), - globalOffsetX, globalOffsetY, &cachedNode.focusRings()) == false) + globalOffsetX, globalOffsetY, &cachedNode.cursorRings()) == false) continue; keepTextNode: IntRect clip = hasClip ? bounds : absBounds; @@ -1254,22 +1180,21 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, clip.intersect(parentClip); hasClip = true; } - if (hasClip && cachedNode.clip(clip) == false) { + if (hasClip && !clip.isEmpty() && cachedNode.clip(clip) == false) { cachedNode.setBounds(clip); - cachedNode.focusRings().append(clip); + cachedNode.cursorRings().append(clip); isUnclipped = true; } cachedNode.setNavableRects(); cachedNode.setChildFrameIndex(-1); cachedNode.setExport(exported); - cachedNode.setHasFocusRing(hasFocusRing); + cachedNode.setHasCursorRing(hasCursorRing); cachedNode.setHasMouseOver(hasMouseOver); cachedNode.setHitBounds(absBounds); cachedNode.setIndex(cacheIndex); cachedNode.setIsAnchor(isAnchor); cachedNode.setIsArea(isArea); cachedNode.setIsFocus(isFocus); - cachedNode.setIsInput(isInput); cachedNode.setIsPassword(isPassword); cachedNode.setIsRtlText(isRtlText); cachedNode.setIsTextArea(isTextArea); @@ -1335,7 +1260,7 @@ bool CacheBuilder::CleanUpContainedNodes(CachedFrame* cachedFrame, lastNode->hasTagName(HTMLNames::bodyTag) || lastNode->hasTagName(HTMLNames::formTag)) { lastCached->setBounds(IntRect(0, 0, 0, 0)); - lastCached->focusRings().clear(); + lastCached->cursorRings().clear(); lastCached->setNavableRects(); return false; } @@ -1345,11 +1270,8 @@ bool CacheBuilder::CleanUpContainedNodes(CachedFrame* cachedFrame, lastNode->isKeyboardFocusable(NULL) == false && lastNode->isMouseFocusable() == false && lastNode->isFocusable() == false && - lastNode->isEventTargetNode() == true && HasOverOrOut(lastNode) == true && HasTriggerEvent(lastNode) == false; - if (cachedFrame->focusIndex() == lastChildIndex) - cachedFrame->setFocusIndex(last->mCachedNodeIndex); if (onlyChildCached->parent() == lastCached) onlyChildCached->setParentIndex(lastCached->parentIndex()); if (outerIsMouseMoveOnly || onlyChild->isKeyboardFocusable(NULL)) @@ -1535,11 +1457,13 @@ static bool validZip(int stateIndex, const UChar* zipPtr) #define MAX_PLACE_NAME_LENGTH 25 // the longest allowable one word place name -CacheBuilder::FoundState CacheBuilder::FindAddress(const UChar* chars, unsigned length, int* start, int* end) +CacheBuilder::FoundState CacheBuilder::FindAddress(const UChar* chars, + unsigned length, int* start, int* end, bool caseInsensitive) { FindState addressState; FindReset(&addressState); addressState.mWords[0] = addressState.mStarts[0] = chars; + addressState.mCaseInsensitive = caseInsensitive; FoundState state = FindPartialAddress(chars, chars, length, &addressState); if (state == FOUND_PARTIAL && addressState.mProgress == ZIP_CODE && addressState.mNumberCount == 0) { @@ -1760,6 +1684,8 @@ CacheBuilder::FoundState CacheBuilder::FindPartialAddress(const UChar* baseChars } else if (s->mLetterCount >= MAX_PLACE_NAME_LENGTH) { break; } else if (s->mFirstLower != NULL) { + if (s->mCaseInsensitive) + goto resetWord; size_t length = chars - s->mFirstLower; if (length > 3) break; @@ -2381,14 +2307,28 @@ void CacheBuilder::FindResetNumber(FindState* state) state->mStorePtr = state->mStore; } -IntRect CacheBuilder::getAreaRect(const HTMLAreaElement* area) const +IntRect CacheBuilder::getAreaRect(const HTMLAreaElement* area) { - RenderImage* map = m_areaBoundsMap.get(area); - if (!map) - return IntRect(); - if (area->isDefault()) - return map->absoluteBoundingBoxRect(); - return area->getRect(map); + Node* node = area->document(); + while ((node = node->traverseNextNode()) != NULL) { + RenderObject* renderer = node->renderer(); + if (renderer && renderer->isRenderImage()) { + RenderImage* image = static_cast<RenderImage*>(renderer); + HTMLMapElement* map = image->imageMap(); + if (map) { + Node* n; + for (n = map->firstChild(); n; + n = n->traverseNextNode(map)) { + if (n == area) { + if (area->isDefault()) + return image->absoluteBoundingBoxRect(); + return area->getRect(image); + } + } + } + } + } + return IntRect(); } void CacheBuilder::GetGlobalOffset(Node* node, int* x, int * y) @@ -2432,20 +2372,26 @@ Frame* CacheBuilder::HasFrame(Node* node) bool CacheBuilder::HasOverOrOut(Node* node) { - EventTargetNode* target = (EventTargetNode*) node; - return target->getEventListener(eventNames().mouseoverEvent) || - target->getEventListener(eventNames().mouseoutEvent); + // eventNames are thread-local data, I avoid using 'static' variable here. + AtomicString eventTypes[2] = { + eventNames().mouseoverEvent, + eventNames().mouseoutEvent + }; + return NodeHasEventListeners(node, eventTypes, 2); } bool CacheBuilder::HasTriggerEvent(Node* node) { - EventTargetNode* target = (EventTargetNode*) node; - return target->getEventListener(eventNames().clickEvent) || - target->getEventListener(eventNames().mousedownEvent) || - target->getEventListener(eventNames().mouseupEvent) || - target->getEventListener(eventNames().keydownEvent) || - target->getEventListener(eventNames().keyupEvent); + AtomicString eventTypes[5] = { + eventNames().clickEvent, + eventNames().mousedownEvent, + eventNames().mouseupEvent, + eventNames().keydownEvent, + eventNames().keyupEvent + }; + + return NodeHasEventListeners(node, eventTypes, 5); } // #define EMAIL_PATTERN "x@y.d" // where 'x' is letters, numbers, and '-', '.', '_' ; 'y' is 'x' without the underscore, and 'd' is a valid domain @@ -2460,61 +2406,6 @@ bool CacheBuilder::IsDomainChar(UChar ch) return (body[ch >> 5] & 1 << (ch & 0x1f)) != 0; } -// does not find text to keep it fast -// (this assume text nodes are more rarely moved than other nodes) -Node* CacheBuilder::findByCenter(int x, int y) const -{ - DBG_NAV_LOGD("x=%d y=%d\n", x, y); - Frame* frame = FrameAnd(this); - Node* node = frame->document(); - ASSERT(node != NULL); - int globalOffsetX, globalOffsetY; - GetGlobalOffset(frame, &globalOffsetX, &globalOffsetY); - while ((node = node->traverseNextNode()) != NULL) { - Frame* child = HasFrame(node); - if (child != NULL) { - if (child->document() == NULL) - continue; - CacheBuilder* cacheBuilder = Builder(child); - // if (cacheBuilder->mViewBounds.isEmpty()) - // continue; - Node* result = cacheBuilder->findByCenter(x, y); - if (result != NULL) - return result; - } - if (node->isTextNode()) - continue; - IntRect bounds; - if (node->hasTagName(HTMLNames::areaTag)) { - HTMLAreaElement* area = static_cast<HTMLAreaElement*>(node); - bounds = getAreaRect(area); - bounds.move(globalOffsetX, globalOffsetY); - } else - bounds = node->getRect(); - if (bounds.isEmpty()) - continue; - bounds.move(globalOffsetX, globalOffsetY); - if (x != bounds.x() + (bounds.width() >> 1)) - continue; - if (y != bounds.y() + (bounds.height() >> 1)) - continue; - if (node->isKeyboardFocusable(NULL)) - return node; - if (node->isMouseFocusable()) - return node; - if (node->isFocusable()) - return node; - if (node->isEventTargetNode() == false) - continue; - if (AnyIsClick(node)) - continue; - if (HasTriggerEvent(node) == false) - continue; - return node; - } - return NULL; -} - bool CacheBuilder::isFocusableText(NodeWalk* walk, bool more, Node* node, CachedNodeType* type, String* exported) const { @@ -2733,29 +2624,6 @@ bool CacheBuilder::IsMailboxChar(UChar ch) return (body[ch >> 5] & 1 << (ch & 0x1f)) != 0; } -bool CacheBuilder::outOfDate() -{ - Node* kitFocusNode = currentFocus(); - if (mLastKnownFocus != kitFocusNode) { - DBG_NAV_LOGD("%s\n", "mLastKnownFocus != kitFocusNode"); - return true; - } - if (kitFocusNode == NULL) - return false; - IntRect kitBounds = kitFocusNode->getRect(); - bool result = kitBounds != mLastKnownFocusBounds; - if (result == true) - DBG_NAV_LOGD("%s\n", "kitBounds != mLastKnownFocusBounds"); - return result; -} - -void CacheBuilder::setLastFocus(Node* node) -{ - ASSERT(node); - mLastKnownFocus = node; - mLastKnownFocusBounds = node->getRect(); -} - bool CacheBuilder::setData(CachedFrame* cachedFrame) { Frame* frame = FrameAnd(this); @@ -2790,13 +2658,13 @@ bool CacheBuilder::setData(CachedFrame* cachedFrame) return true; } -bool CacheBuilder::validNode(void* matchFrame, void* matchNode) const +bool CacheBuilder::validNode(Frame* startFrame, void* matchFrame, + void* matchNode) { - Frame* frame = FrameAnd(this); - if (matchFrame == frame) { + if (matchFrame == startFrame) { if (matchNode == NULL) return true; - Node* node = frame->document(); + Node* node = startFrame->document(); while (node != NULL) { if (node == matchNode) { const IntRect& rect = node->hasTagName(HTMLNames::areaTag) ? @@ -2812,15 +2680,15 @@ bool CacheBuilder::validNode(void* matchFrame, void* matchNode) const DBG_NAV_LOGD("frame=%p valid node=%p invalid\n", matchFrame, matchNode); return false; } - Frame* child = frame->tree()->firstChild(); + Frame* child = startFrame->tree()->firstChild(); while (child) { - bool result = Builder(child)->validNode(matchFrame, matchNode); + bool result = validNode(child, matchFrame, matchNode); if (result) return result; child = child->tree()->nextSibling(); } #if DEBUG_NAV_UI - if (frame->tree()->parent() == NULL) + if (startFrame->tree()->parent() == NULL) DBG_NAV_LOGD("frame=%p node=%p false\n", matchFrame, matchNode); #endif return false; @@ -3020,7 +2888,7 @@ bool CacheBuilder::ConstructTextRects(Text* node, int start, if ((int) textBox->end() >= start) break; } while ((textBox = textBox->nextTextBox()) != NULL); - if (ConstructTextRect(node, textBox, start, relEnd, + if (textBox && ConstructTextRect(node, textBox, start, relEnd, x, y, focusBounds, clipBounds, result) == false) return false; } diff --git a/WebKit/android/nav/CacheBuilder.h b/WebKit/android/nav/CacheBuilder.h index 32ae0af..35bd623 100644 --- a/WebKit/android/nav/CacheBuilder.h +++ b/WebKit/android/nav/CacheBuilder.h @@ -31,7 +31,6 @@ #include "IntRect.h" #include "PlatformString.h" #include "TextDirection.h" -#include "wtf/HashMap.h" #include "wtf/Vector.h" #define NAVIGATION_MAX_PHONE_LENGTH 14 @@ -39,7 +38,8 @@ using namespace WebCore; namespace WebCore { - + +class AtomicString; class Document; class Frame; class HTMLAreaElement; @@ -47,7 +47,6 @@ class InlineTextBox; class Node; class PlatformGraphicsContext; class RenderFlow; -class RenderImage; class RenderObject; class RenderLayer; class Text; @@ -89,13 +88,11 @@ public: mAllowableTypes & ~EMAIL_CACHEDNODETYPE); } void disallowPhoneDetection() { mAllowableTypes = (CachedNodeType) ( mAllowableTypes & ~PHONE_CACHEDNODETYPE); } - static FoundState FindAddress(const UChar* , unsigned length, int* start, int* end); - Node* findByCenter(int x, int y) const; + static FoundState FindAddress(const UChar* , unsigned length, int* start, + int* end, bool caseInsensitive); static void GetGlobalOffset(Frame* , int* x, int * y); static void GetGlobalOffset(Node* , int* x, int * y); - bool outOfDate(); - void setLastFocus(Node* ); - bool validNode(void* framePtr, void* nodePtr) const; + static bool validNode(Frame* startFrame, void* framePtr, void* nodePtr); private: enum AddressProgress { NO_ADDRESS, @@ -167,6 +164,7 @@ private: bool mOpenParen; bool mInitialized; bool mContinuationNode; + bool mCaseInsensitive; }; struct ClipColumnTracker { IntRect mBounds; @@ -194,6 +192,7 @@ private: WTF::Vector<IntRect>* result, IntRect* focusBounds); static bool AnyIsClick(Node* node); static bool AnyChildIsClick(Node* node); + static bool NodeHasEventListeners(Node* node, AtomicString* eventTypes, int length); void BuildFrame(Frame* root, Frame* frame, CachedRoot* cachedRoot, CachedFrame* cachedFrame); bool CleanUpContainedNodes(CachedFrame* cachedFrame, @@ -213,7 +212,7 @@ private: static Frame* FrameAnd(CacheBuilder* focusNav); static Frame* FrameAnd(const CacheBuilder* focusNav); static CacheBuilder* Builder(Frame* ); - IntRect getAreaRect(const HTMLAreaElement* area) const; + static IntRect getAreaRect(const HTMLAreaElement* area); static Frame* HasFrame(Node* ); static bool HasOverOrOut(Node* ); static bool HasTriggerEvent(Node* ); @@ -226,10 +225,7 @@ private: bool setData(CachedFrame* ); Node* tryFocus(Direction direction); Node* trySegment(Direction direction, int mainStart, int mainEnd); - Node* mLastKnownFocus; - IntRect mLastKnownFocusBounds; CachedNodeType mAllowableTypes; - WTF::HashMap<const HTMLAreaElement* , RenderImage* > m_areaBoundsMap; #if DUMP_NAV_CACHE public: class Debug { @@ -251,7 +247,6 @@ private: void localName(Node* node); void newLine(int indent = 0); void print(const char* name, unsigned len); - void renderTree(RenderObject* , int indent, Node* , int count); void setIndent(int ); void uChar(const UChar* name, unsigned len, bool hex); void validateFrame(); diff --git a/WebKit/android/nav/CachedFrame.cpp b/WebKit/android/nav/CachedFrame.cpp index 0eefad1..4bf9805 100644 --- a/WebKit/android/nav/CachedFrame.cpp +++ b/WebKit/android/nav/CachedFrame.cpp @@ -36,7 +36,7 @@ namespace android { -bool CachedFrame::CheckBetween(Direction direction, const WebCore::IntRect& bestRect, +bool CachedFrame::CheckBetween(Direction direction, const WebCore::IntRect& bestRect, const WebCore::IntRect& prior, WebCore::IntRect* result) { int left, top, width, height; @@ -86,7 +86,7 @@ bool CachedFrame::checkBetween(BestData* best, Direction direction) do { WebCore::IntRect edges; Direction check = (Direction) (index & DIRECTION_MASK); - if (CheckBetween(check, bestRect, + if (CheckBetween(check, bestRect, history()->priorBounds(), &edges) == false) continue; WebCore::IntRect clip = mRoot->scrolledBounds(); @@ -96,7 +96,7 @@ bool CachedFrame::checkBetween(BestData* best, Direction direction) findClosest(&test, direction, check, &clip); if (test.mNode == NULL) continue; - if (direction == check) + if (direction == check) break; } while (++index < limit); if (test.mNode == NULL) @@ -105,47 +105,46 @@ bool CachedFrame::checkBetween(BestData* best, Direction direction) return true; } -bool CachedFrame::checkVisited(const CachedNode* node, Direction direction) const -{ - return history()->checkVisited(node, direction); +bool CachedFrame::checkVisited(const CachedNode* node, Direction direction) const +{ + return history()->checkVisited(node, direction); } -void CachedFrame::clearFocus() +void CachedFrame::clearCursor() { - if (mFocus < 0) + DBG_NAV_LOGD("mCursorIndex=%d", mCursorIndex); + if (mCursorIndex < CURSOR_SET) return; - CachedNode& focus = mCachedNodes[mFocus]; - focus.clearFocus(this); - mFocus = -1; + CachedNode& cursor = mCachedNodes[mCursorIndex]; + cursor.clearCursor(this); + mCursorIndex = CURSOR_CLEARED; // initialized and explicitly cleared } -// the thing that sucks is that when you're on a link, you want to navigate next door to a link just like this one, but can't make it -// so with all my other sucky compares, maybe there needs to be one that prefers links that are aligned with the current focus... - // returns 0 if test is preferable to best, 1 if not preferable, or -1 if unknown -int CachedFrame::compare(BestData& testData, const BestData& bestData, const CachedNode* focus) const +int CachedFrame::compare(BestData& testData, const BestData& bestData, + const CachedNode* cursor) const { if (testData.mNode->tabIndex() != bestData.mNode->tabIndex()) { if (testData.mNode->tabIndex() < bestData.mNode->tabIndex() - || (focus && focus->tabIndex() < bestData.mNode->tabIndex())) { + || (cursor && cursor->tabIndex() < bestData.mNode->tabIndex())) { testData.mNode->setCondition(CachedNode::HIGHER_TAB_INDEX); return REJECT_TEST; } return TEST_IS_BEST; } -// start here; - // if the test minor axis line intersects the line segment between focus center and best center, choose it + // if the test minor axis line intersects the line segment between cursor + // center and best center, choose it // give more weight to exact major axis alignment (rows, columns) if (testData.mInNav != bestData.mInNav) { if (bestData.mInNav) { - testData.mNode->setCondition(CachedNode::IN_FOCUS); + testData.mNode->setCondition(CachedNode::IN_CURSOR); return REJECT_TEST; } return TEST_IS_BEST; } if (testData.mInNav) { if (bestData.mMajorDelta < testData.mMajorDelta) { - testData.mNode->setCondition(CachedNode::CLOSER_IN_FOCUS); + testData.mNode->setCondition(CachedNode::CLOSER_IN_CURSOR); return REJECT_TEST; } if (testData.mMajorDelta < bestData.mMajorDelta) @@ -157,13 +156,6 @@ int CachedFrame::compare(BestData& testData, const BestData& bestData, const Cac } if ((testData.mMajorDelta ^ bestData.mMajorDelta) < 0) // one above, one below (or one left, one right) return TEST_IS_BEST; -// SkFixed focusMultiplier = SK_Fixed1; -// if (focus != NULL) { -// if (testData.mMajorDelta < bestData.mMajorDelta) { -// // use bestData.mMajorDelta, -// } else if (bestData.mMajorDelta < testData.mMajorDelta) { -// -// } bool bestInWorking = bestData.inOrSubsumesWorking(); bool testInWorking = testData.inOrSubsumesWorking(); if (bestInWorking && testData.mWorkingOutside && testData.mNavOutside) { @@ -183,9 +175,9 @@ int CachedFrame::compare(BestData& testData, const BestData& bestData, const Cac return TEST_IS_BEST; } #if 01 // hopefully butt test will remove need for this - if (testData.mFocusChild != bestData.mFocusChild) { - if (bestData.mFocusChild) { - testData.mNode->setCondition(CachedNode::IN_FOCUS_CHILDREN); + if (testData.mCursorChild != bestData.mCursorChild) { + if (bestData.mCursorChild) { + testData.mNode->setCondition(CachedNode::IN_CURSOR_CHILDREN); return REJECT_TEST; } return TEST_IS_BEST; @@ -210,7 +202,7 @@ int CachedFrame::compare(BestData& testData, const BestData& bestData, const Cac } if (testOverlap && testData.mMajorDelta < bestData.mMajorDelta) return TEST_IS_BEST; - if (bestOverlap && bestData.mMajorDelta2 < testData.mMajorDelta2) { + if (bestOverlap && bestData.mMajorDelta2 < testData.mMajorDelta2) { testData.mNode->setCondition(CachedNode::CLOSER_TOP); return REJECT_TEST; } @@ -218,7 +210,7 @@ int CachedFrame::compare(BestData& testData, const BestData& bestData, const Cac return TEST_IS_BEST; #if 01 if (bestOverlap && ((bestData.mSideDistance <= 0 && testData.mSideDistance > 0) || - abs(bestData.mSideDistance) < abs(testData.mSideDistance))) { + abs(bestData.mSideDistance) < abs(testData.mSideDistance))) { testData.mNode->setCondition(CachedNode::LEFTMOST); return REJECT_TEST; } @@ -240,7 +232,7 @@ int CachedFrame::compare(BestData& testData, const BestData& bestData, const Cac // and off by a lot causes sideDistance to have little or no effect // try elliptical distance -- lengthen side contribution // these ASSERTs should not fire, but do fire on mail.google.com - // can't debug yet, won't reproduce + // can't debug yet, won't reproduce ASSERT(testDistance >= 0); ASSERT(bestDistance >= 0); testDistance += testDistance; // multiply by 2 @@ -295,23 +287,36 @@ int CachedFrame::compare(BestData& testData, const BestData& bestData, const Cac return UNDECIDED; } -const CachedNode* CachedFrame::currentFocus(const CachedFrame** framePtr) const +const CachedNode* CachedFrame::currentCursor(const CachedFrame** framePtr) const { if (framePtr) *framePtr = this; - if (mFocus < 0) + if (mCursorIndex < CURSOR_SET) return NULL; - const CachedNode* result = &mCachedNodes[mFocus]; + const CachedNode* result = &mCachedNodes[mCursorIndex]; + const CachedFrame* frame = hasFrame(result); + if (frame != NULL) + return frame->currentCursor(framePtr); + (const_cast<CachedNode*>(result))->fixUpCursorRects(mRoot); + return result; +} + +const CachedNode* CachedFrame::currentFocus(const CachedFrame** framePtr) const +{ + if (framePtr) + *framePtr = this; + if (mFocusIndex < 0) + return NULL; + const CachedNode* result = &mCachedNodes[mFocusIndex]; const CachedFrame* frame = hasFrame(result); if (frame != NULL) return frame->currentFocus(framePtr); - (const_cast<CachedNode*>(result))->fixUpFocusRects(); return result; } -bool CachedFrame::directionChange() const -{ - return history()->directionChange(); +bool CachedFrame::directionChange() const +{ + return history()->directionChange(); } #ifdef BROWSER_DEBUG @@ -320,18 +325,20 @@ CachedNode* CachedFrame::find(WebCore::Node* node) // !!! probably debugging onl for (CachedNode* test = mCachedNodes.begin(); test != mCachedNodes.end(); test++) if (node == test->webCoreNode()) return test; - for (CachedFrame* frame = mCachedFrames.begin(); frame != mCachedFrames.end(); + for (CachedFrame* frame = mCachedFrames.begin(); frame != mCachedFrames.end(); frame++) { CachedNode* result = frame->find(node); if (result != NULL) return result; } - return NULL; + return NULL; } #endif -const CachedNode* CachedFrame::findBestAt(const WebCore::IntRect& rect, int* best, - bool* inside, const CachedNode** directHit, const CachedFrame** framePtr, int* x, int* y) const +const CachedNode* CachedFrame::findBestAt(const WebCore::IntRect& rect, + int* best, bool* inside, const CachedNode** directHit, + const CachedFrame** framePtr, int* x, int* y, + bool checkForHiddenStart) const { const CachedNode* result = NULL; int rectWidth = rect.width(); @@ -345,13 +352,13 @@ const CachedNode* CachedFrame::findBestAt(const WebCore::IntRect& rect, int* bes BestData testData; testData.mNode = test; testData.mMouseBounds = testData.mNodeBounds = test->getBounds(); - bool checkForHidden = true; + bool checkForHidden = checkForHiddenStart; for (size_t part = 0; part < parts; part++) { - if (test->focusRings().at(part).intersects(rect)) { + if (test->cursorRings().at(part).intersects(rect)) { if (checkForHidden && mRoot->maskIfHidden(&testData) == true) break; checkForHidden = false; - WebCore::IntRect testRect = test->focusRings().at(part); + WebCore::IntRect testRect = test->cursorRings().at(part); testRect.intersect(testData.mMouseBounds); if (testRect.contains(center)) { // We have a direct hit. @@ -372,12 +379,12 @@ const CachedNode* CachedFrame::findBestAt(const WebCore::IntRect& rect, int* bes } } if (NULL != *directHit) { - // If we have a direct hit already, there is no need to - // calculate the distances, or check the other focusring parts + // If we have a direct hit already, there is no need to + // calculate the distances, or check the other parts break; } WebCore::IntRect both = rect; - int smaller = testRect.width() < testRect.height() ? + int smaller = testRect.width() < testRect.height() ? testRect.width() : testRect.height(); smaller -= rectWidth; int inset = smaller < rectWidth ? smaller : rectWidth; @@ -390,7 +397,7 @@ const CachedNode* CachedFrame::findBestAt(const WebCore::IntRect& rect, int* bes bool testInside = testRect.contains(center); if (*inside && !testInside) continue; - WebCore::IntPoint testCenter = WebCore::IntPoint(testRect.x() + + WebCore::IntPoint testCenter = WebCore::IntPoint(testRect.x() + (testRect.width() >> 1), testRect.y() + (testRect.height() >> 1)); int dx = testCenter.x() - center.x(); int dy = testCenter.y() - center.y(); @@ -406,10 +413,10 @@ const CachedNode* CachedFrame::findBestAt(const WebCore::IntRect& rect, int* bes } } } - for (const CachedFrame* frame = mCachedFrames.begin(); + for (const CachedFrame* frame = mCachedFrames.begin(); frame != mCachedFrames.end(); frame++) { - const CachedNode* frameResult = frame->findBestAt(rect, best, inside, directHit, - framePtr, x, y); + const CachedNode* frameResult = frame->findBestAt(rect, best, inside, + directHit, framePtr, x, y, checkForHiddenStart); if (NULL != frameResult) result = frameResult; } @@ -424,7 +431,7 @@ const CachedFrame* CachedFrame::findBestFrameAt(int x, int y) const if (mLocalViewBounds.contains(x, y) == false) return NULL; const CachedFrame* result = this; - for (const CachedFrame* frame = mCachedFrames.begin(); + for (const CachedFrame* frame = mCachedFrames.begin(); frame != mCachedFrames.end(); frame++) { const CachedFrame* frameResult = frame->findBestFrameAt(x, y); if (NULL != frameResult) @@ -433,7 +440,7 @@ const CachedFrame* CachedFrame::findBestFrameAt(int x, int y) const return result; } -const CachedNode* CachedFrame::findBestHitAt(const WebCore::IntRect& rect, +const CachedNode* CachedFrame::findBestHitAt(const WebCore::IntRect& rect, int* best, const CachedFrame** framePtr, int* x, int* y) const { const CachedNode* result = NULL; @@ -453,21 +460,21 @@ const CachedNode* CachedFrame::findBestHitAt(const WebCore::IntRect& rect, if (mRoot->maskIfHidden(&testData) == true) continue; const WebCore::IntRect& bounds = testData.mMouseBounds; - WebCore::IntPoint testCenter = WebCore::IntPoint(bounds.x() + + WebCore::IntPoint testCenter = WebCore::IntPoint(bounds.x() + (bounds.width() >> 1), bounds.y() + (bounds.height() >> 1)); int dx = testCenter.x() - center.x(); int dy = testCenter.y() - center.y(); int distance = dx * dx + dy * dy; - if (*best <= distance) + if (*best <= distance) continue; *best = distance; result = test; *framePtr = this; - const WebCore::IntRect& focusRect = test->focusRings().at(0); - *x = focusRect.x() + (focusRect.width() >> 1); - *y = focusRect.y() + (focusRect.height() >> 1); + const WebCore::IntRect& cursorRect = test->cursorRings().at(0); + *x = cursorRect.x() + (cursorRect.width() >> 1); + *y = cursorRect.y() + (cursorRect.height() >> 1); } - for (const CachedFrame* frame = mCachedFrames.begin(); + for (const CachedFrame* frame = mCachedFrames.begin(); frame != mCachedFrames.end(); frame++) { const CachedNode* frameResult = frame->findBestHitAt(rect, best, framePtr, x, y); @@ -478,7 +485,7 @@ const CachedNode* CachedFrame::findBestHitAt(const WebCore::IntRect& rect, } void CachedFrame::findClosest(BestData* bestData, Direction originalDirection, - Direction direction, WebCore::IntRect* clip) const + Direction direction, WebCore::IntRect* clip) const { const CachedNode* test = mCachedNodes.begin(); while ((test = test->traverseNextNode()) != NULL) { @@ -491,13 +498,13 @@ void CachedFrame::findClosest(BestData* bestData, Direction originalDirection, } if (test->noSecondChance()) continue; - if (test->isFocusable(*clip) == false) + if (test->isNavable(*clip) == false) continue; if (checkVisited(test, originalDirection) == false) continue; size_t partMax = test->navableRects(); for (size_t part = 0; part < partMax; part++) { - WebCore::IntRect testBounds = test->focusRings().at(part); + WebCore::IntRect testBounds = test->cursorRings().at(part); if (clip->intersects(testBounds) == false) continue; if (clip->contains(testBounds) == false) { @@ -516,7 +523,7 @@ void CachedFrame::findClosest(BestData* bestData, Direction originalDirection, continue; } int distance; - // seems like distance for UP for instance needs to be 'test top closest to + // seems like distance for UP for instance needs to be 'test top closest to // clip bottom' -- keep the old code but try this instead switch (direction) { #if 0 @@ -530,74 +537,72 @@ void CachedFrame::findClosest(BestData* bestData, Direction originalDirection, case UP: distance = clip->bottom() - testBounds.y(); break; case DOWN: distance = testBounds.bottom() - clip->y(); break; #endif - default: + default: distance = 0; ASSERT(0); } if (distance < bestData->mDistance) { bestData->mNode = test; bestData->mFrame = this; bestData->mDistance = distance; - bestData->mMouseBounds = bestData->mNodeBounds = - test->focusRings().at(part); + bestData->mMouseBounds = bestData->mNodeBounds = + test->cursorRings().at(part); CachedHistory* cachedHistory = history(); switch (direction) { - case LEFT: - bestData->setLeftDirection(cachedHistory); + case LEFT: + bestData->setLeftDirection(cachedHistory); break; - case RIGHT: - bestData->setRightDirection(cachedHistory); + case RIGHT: + bestData->setRightDirection(cachedHistory); break; - case UP: - bestData->setUpDirection(cachedHistory); + case UP: + bestData->setUpDirection(cachedHistory); break; - case DOWN: - bestData->setDownDirection(cachedHistory); + case DOWN: + bestData->setDownDirection(cachedHistory); break; - default: - ASSERT(0); + default: + ASSERT(0); } } } } } -bool CachedFrame::finishInit() +void CachedFrame::finishInit() { CachedNode* lastCached = lastNode(); lastCached->setLast(); CachedFrame* child = mCachedFrames.begin(); while (child != mCachedFrames.end()) { child->mParent = this; - if (child->finishInit()) - setFocusIndex(child->indexInParent()); + child->finishInit(); child++; } - return focusIndex() > 0; } -const CachedNode* CachedFrame::frameDown(const CachedNode* test, const CachedNode* limit, BestData* bestData, - const CachedNode* focus) const +const CachedNode* CachedFrame::frameDown(const CachedNode* test, const CachedNode* limit, BestData* bestData, + const CachedNode* cursor) const { BestData originalData = *bestData; do { - if (moveInFrame(&CachedFrame::frameDown, test, bestData, focus)) + if (moveInFrame(&CachedFrame::frameDown, test, bestData, cursor)) continue; BestData testData; - if (frameNodeCommon(testData, test, bestData, &originalData, focus) == REJECT_TEST) + if (frameNodeCommon(testData, test, bestData, &originalData, cursor) == REJECT_TEST) continue; if (checkVisited(test, DOWN) == false) continue; size_t parts = test->navableRects(); for (size_t part = 0; part < parts; part++) { - testData.mNodeBounds = test->focusRings().at(part); + testData.mNodeBounds = test->cursorRings().at(part); if (testData.setDownDirection(history())) continue; - int result = framePartCommon(testData, test, bestData, focus); + int result = framePartCommon(testData, test, bestData, cursor); if (result == REJECT_TEST) continue; if (result == 0 && limit == NULL) { // retry all data up to this point, since smaller may have replaced node preferable to larger BestData innerData = testData; - frameDown(document(), test, &innerData, focus); + frameDown(document(), test, &innerData, cursor); if (checkVisited(innerData.mNode, DOWN)) { *bestData = innerData; continue; @@ -607,37 +612,37 @@ const CachedNode* CachedFrame::frameDown(const CachedNode* test, const CachedNod *bestData = testData; } } while ((test = test->traverseNextNode()) != limit); - ASSERT(focus == NULL || bestData->mNode != focus); - // does the best contain something (or, is it contained by an area which is not the focus?) + ASSERT(cursor == NULL || bestData->mNode != cursor); + // does the best contain something (or, is it contained by an area which is not the cursor?) // if so, is the conainer/containee should have been chosen, but wasn't -- so there's a better choice // in the doc list prior to this choice - // + // return bestData->mNode; } -const CachedNode* CachedFrame::frameLeft(const CachedNode* test, const CachedNode* limit, BestData* bestData, - const CachedNode* focus) const +const CachedNode* CachedFrame::frameLeft(const CachedNode* test, const CachedNode* limit, BestData* bestData, + const CachedNode* cursor) const { BestData originalData = *bestData; do { - if (moveInFrame(&CachedFrame::frameLeft, test, bestData, focus)) + if (moveInFrame(&CachedFrame::frameLeft, test, bestData, cursor)) continue; BestData testData; - if (frameNodeCommon(testData, test, bestData, &originalData, focus) == REJECT_TEST) + if (frameNodeCommon(testData, test, bestData, &originalData, cursor) == REJECT_TEST) continue; if (checkVisited(test, LEFT) == false) continue; size_t parts = test->navableRects(); for (size_t part = 0; part < parts; part++) { - testData.mNodeBounds = test->focusRings().at(part); + testData.mNodeBounds = test->cursorRings().at(part); if (testData.setLeftDirection(history())) continue; - int result = framePartCommon(testData, test, bestData, focus); + int result = framePartCommon(testData, test, bestData, cursor); if (result == REJECT_TEST) continue; if (result == 0 && limit == NULL) { // retry all data up to this point, since smaller may have replaced node preferable to larger BestData innerData = testData; - frameLeft(document(), test, &innerData, focus); + frameLeft(document(), test, &innerData, cursor); if (checkVisited(innerData.mNode, LEFT)) { *bestData = innerData; continue; @@ -647,12 +652,12 @@ const CachedNode* CachedFrame::frameLeft(const CachedNode* test, const CachedNod *bestData = testData; } } while ((test = test->traverseNextNode()) != limit); // FIXME ??? left and up should use traversePreviousNode to choose reverse document order - ASSERT(focus == NULL || bestData->mNode != focus); + ASSERT(cursor == NULL || bestData->mNode != cursor); return bestData->mNode; } int CachedFrame::frameNodeCommon(BestData& testData, const CachedNode* test, BestData* bestData, BestData* originalData, - const CachedNode* focus) const + const CachedNode* cursor) const { testData.mFrame = this; testData.mNode = test; @@ -662,34 +667,34 @@ int CachedFrame::frameNodeCommon(BestData& testData, const CachedNode* test, Bes return REJECT_TEST; } if (mRoot->scrolledBounds().intersects(test->bounds()) == false) { - testData.mNode->setCondition(CachedNode::FOCUSABLE); + testData.mNode->setCondition(CachedNode::NAVABLE); return REJECT_TEST; } -// if (isFocusable(test, &testData.mNodeBounds, walk) == false) { -// testData.mNode->setCondition(CachedNode::FOCUSABLE); +// if (isNavable(test, &testData.mNodeBounds, walk) == false) { +// testData.mNode->setCondition(CachedNode::NAVABLE); // return REJECT_TEST; // } // - if (test == focus) { - testData.mNode->setCondition(CachedNode::NOT_FOCUS_NODE); + if (test == cursor) { + testData.mNode->setCondition(CachedNode::NOT_CURSOR_NODE); return REJECT_TEST; } -// if (test->bounds().contains(mRoot->focusBounds())) { -// testData.mNode->setCondition(CachedNode::NOT_ENCLOSING_FOCUS); +// if (test->bounds().contains(mRoot->cursorBounds())) { +// testData.mNode->setCondition(CachedNode::NOT_ENCLOSING_CURSOR); // return REJECT_TEST; // } - void* par = focus ? focus->parentGroup() : NULL; - testData.mFocusChild = test->parentGroup() == par; + void* par = cursor ? cursor->parentGroup() : NULL; + testData.mCursorChild = test->parentGroup() == par; #if 0 // not debugged - if (focus && focus->hasMouseOver() && test->hasMouseOver() == false && - focus->bounds().contains(test->bounds())) + if (cursor && cursor->hasMouseOver() && test->hasMouseOver() == false && + cursor->bounds().contains(test->bounds())) return REJECT_TEST; #endif - if (bestData->mNode == NULL) + if (bestData->mNode == NULL) return TEST_IS_BEST; #if 0 // not debugged - if (focus && focus->hasMouseOver() && test->hasMouseOver() == false && - focus->bounds().contains(test->bounds())) + if (cursor && cursor->hasMouseOver() && test->hasMouseOver() == false && + cursor->bounds().contains(test->bounds())) return REJECT_TEST; if (test->hasMouseOver() != bestData->mNode->hasMouseOver()) { if (test->hasMouseOver()) { @@ -703,15 +708,15 @@ int CachedFrame::frameNodeCommon(BestData& testData, const CachedNode* test, Bes test->setCondition(CachedNode::ANCHOR_IN_ANCHOR); return REJECT_TEST; } - } - } + } + } #endif - if (focus && testData.mNode->parentIndex() != bestData->mNode->parentIndex()) { - int focusParentIndex = focus->parentIndex(); - if (focusParentIndex >= 0) { - if (bestData->mNode->parentIndex() == focusParentIndex) + if (cursor && testData.mNode->parentIndex() != bestData->mNode->parentIndex()) { + int cursorParentIndex = cursor->parentIndex(); + if (cursorParentIndex >= 0) { + if (bestData->mNode->parentIndex() == cursorParentIndex) return REJECT_TEST; - if (testData.mNode->parentIndex() == focusParentIndex) + if (testData.mNode->parentIndex() == cursorParentIndex) return TEST_IS_BEST; } } @@ -743,15 +748,15 @@ int CachedFrame::frameNodeCommon(BestData& testData, const CachedNode* test, Bes } int CachedFrame::framePartCommon(BestData& testData, - const CachedNode* test, BestData* bestData, const CachedNode* focus) const + const CachedNode* test, BestData* bestData, const CachedNode* cursor) const { - if (testData.mNodeBounds.contains(mRoot->focusBounds())) { - testData.mNode->setCondition(CachedNode::NOT_ENCLOSING_FOCUS); + if (cursor && testData.mNodeBounds.contains(cursor->bounds())) { + testData.mNode->setCondition(CachedNode::NOT_ENCLOSING_CURSOR); return REJECT_TEST; } testData.setDistances(); if (bestData->mNode != NULL) { - int compared = compare(testData, *bestData, focus); + int compared = compare(testData, *bestData, cursor); if (compared == 0 && test->isArea() == false && bestData->mNode->isArea() == false) goto pickTest; if (compared >= 0) @@ -761,29 +766,29 @@ pickTest: return -1; // pick test } -const CachedNode* CachedFrame::frameRight(const CachedNode* test, const CachedNode* limit, BestData* bestData, - const CachedNode* focus) const +const CachedNode* CachedFrame::frameRight(const CachedNode* test, const CachedNode* limit, BestData* bestData, + const CachedNode* cursor) const { BestData originalData = *bestData; do { - if (moveInFrame(&CachedFrame::frameRight, test, bestData, focus)) + if (moveInFrame(&CachedFrame::frameRight, test, bestData, cursor)) continue; BestData testData; - if (frameNodeCommon(testData, test, bestData, &originalData, focus) == REJECT_TEST) + if (frameNodeCommon(testData, test, bestData, &originalData, cursor) == REJECT_TEST) continue; if (checkVisited(test, RIGHT) == false) continue; size_t parts = test->navableRects(); for (size_t part = 0; part < parts; part++) { - testData.mNodeBounds = test->focusRings().at(part); + testData.mNodeBounds = test->cursorRings().at(part); if (testData.setRightDirection(history())) continue; - int result = framePartCommon(testData, test, bestData, focus); + int result = framePartCommon(testData, test, bestData, cursor); if (result == REJECT_TEST) continue; if (result == 0 && limit == NULL) { // retry all data up to this point, since smaller may have replaced node preferable to larger BestData innerData = testData; - frameRight(document(), test, &innerData, focus); + frameRight(document(), test, &innerData, cursor); if (checkVisited(innerData.mNode, RIGHT)) { *bestData = innerData; continue; @@ -793,33 +798,33 @@ const CachedNode* CachedFrame::frameRight(const CachedNode* test, const CachedNo *bestData = testData; } } while ((test = test->traverseNextNode()) != limit); - ASSERT(focus == NULL || bestData->mNode != focus); + ASSERT(cursor == NULL || bestData->mNode != cursor); return bestData->mNode; } -const CachedNode* CachedFrame::frameUp(const CachedNode* test, const CachedNode* limit, BestData* bestData, - const CachedNode* focus) const +const CachedNode* CachedFrame::frameUp(const CachedNode* test, const CachedNode* limit, BestData* bestData, + const CachedNode* cursor) const { BestData originalData = *bestData; do { - if (moveInFrame(&CachedFrame::frameUp, test, bestData, focus)) + if (moveInFrame(&CachedFrame::frameUp, test, bestData, cursor)) continue; BestData testData; - if (frameNodeCommon(testData, test, bestData, &originalData, focus) == REJECT_TEST) + if (frameNodeCommon(testData, test, bestData, &originalData, cursor) == REJECT_TEST) continue; if (checkVisited(test, UP) == false) continue; size_t parts = test->navableRects(); for (size_t part = 0; part < parts; part++) { - testData.mNodeBounds = test->focusRings().at(part); + testData.mNodeBounds = test->cursorRings().at(part); if (testData.setUpDirection(history())) continue; - int result = framePartCommon(testData, test, bestData, focus); + int result = framePartCommon(testData, test, bestData, cursor); if (result == REJECT_TEST) continue; if (result == 0 && limit == NULL) { // retry all data up to this point, since smaller may have replaced node preferable to larger BestData innerData = testData; - frameUp(document(), test, &innerData, focus); + frameUp(document(), test, &innerData, cursor); if (checkVisited(innerData.mNode, UP)) { *bestData = innerData; continue; @@ -829,56 +834,66 @@ const CachedNode* CachedFrame::frameUp(const CachedNode* test, const CachedNode* *bestData = testData; } } while ((test = test->traverseNextNode()) != limit); // FIXME ??? left and up should use traversePreviousNode to choose reverse document order - ASSERT(focus == NULL || bestData->mNode != focus); + ASSERT(cursor == NULL || bestData->mNode != cursor); return bestData->mNode; } const CachedFrame* CachedFrame::hasFrame(const CachedNode* node) const -{ - return node->isFrame() ? &mCachedFrames[node->childFrameIndex()] : NULL; +{ + return node->isFrame() ? &mCachedFrames[node->childFrameIndex()] : NULL; +} + +void CachedFrame::hideCursor() +{ + DBG_NAV_LOGD("mCursorIndex=%d", mCursorIndex); + if (mCursorIndex < CURSOR_SET) + return; + CachedNode& cursor = mCachedNodes[mCursorIndex]; + cursor.hideCursor(this); } -CachedHistory* CachedFrame::history() const -{ - return mRoot->rootHistory(); +CachedHistory* CachedFrame::history() const +{ + return mRoot->rootHistory(); } -void CachedFrame::init(const CachedRoot* root, int childFrameIndex, +void CachedFrame::init(const CachedRoot* root, int childFrameIndex, WebCore::Frame* frame) { mContents = WebCore::IntRect(0, 0, 0, 0); // fixed up for real in setData() mLocalViewBounds = WebCore::IntRect(0, 0, 0, 0); mViewBounds = WebCore::IntRect(0, 0, 0, 0); mRoot = root; - mFocus = -1; + mCursorIndex = CURSOR_UNINITIALIZED; // not explicitly cleared + mFocusIndex = -1; mFrame = frame; mParent = NULL; // set up parents after stretchy arrays are set up - mIndex = childFrameIndex; + mIndexInParent = childFrameIndex; } -int CachedFrame::minWorkingHorizontal() const -{ - return history()->minWorkingHorizontal(); +int CachedFrame::minWorkingHorizontal() const +{ + return history()->minWorkingHorizontal(); } -int CachedFrame::minWorkingVertical() const -{ +int CachedFrame::minWorkingVertical() const +{ return history()->minWorkingVertical(); } - -int CachedFrame::maxWorkingHorizontal() const -{ - return history()->maxWorkingHorizontal(); + +int CachedFrame::maxWorkingHorizontal() const +{ + return history()->maxWorkingHorizontal(); } - -int CachedFrame::maxWorkingVertical() const -{ - return history()->maxWorkingVertical(); + +int CachedFrame::maxWorkingVertical() const +{ + return history()->maxWorkingVertical(); } -bool CachedFrame::moveInFrame(MoveInDirection moveInDirection, +bool CachedFrame::moveInFrame(MoveInDirection moveInDirection, const CachedNode* test, BestData* bestData, - const CachedNode* focus) const + const CachedNode* cursor) const { const CachedFrame* frame = hasFrame(test); if (frame == NULL) @@ -886,25 +901,25 @@ bool CachedFrame::moveInFrame(MoveInDirection moveInDirection, const CachedNode* childDoc = frame->validDocument(); if (childDoc == NULL) return true; - (frame->*moveInDirection)(childDoc, NULL, bestData, focus); + (frame->*moveInDirection)(childDoc, NULL, bestData, cursor); return true; } const WebCore::IntRect& CachedFrame::_navBounds() const -{ - return history()->navBounds(); +{ + return history()->navBounds(); } void CachedFrame::resetClippedOut() { - for (CachedNode* test = mCachedNodes.begin(); test != mCachedNodes.end(); test++) + for (CachedNode* test = mCachedNodes.begin(); test != mCachedNodes.end(); test++) { if (test->clippedOut()) { test->setDisabled(false); test->setClippedOut(false); } } - for (CachedFrame* frame = mCachedFrames.begin(); frame != mCachedFrames.end(); + for (CachedFrame* frame = mCachedFrames.begin(); frame != mCachedFrames.end(); frame++) { frame->resetClippedOut(); } @@ -913,14 +928,14 @@ void CachedFrame::resetClippedOut() bool CachedFrame::sameFrame(const CachedFrame* test) const { ASSERT(test); - if (mIndex != test->mIndex) + if (mIndexInParent != test->mIndexInParent) return false; - if (mIndex == -1) // index within parent's array of children, or -1 if root + if (mIndexInParent == -1) // index within parent's array of children, or -1 if root return true; return mParent->sameFrame(test->mParent); } -void CachedFrame::setData() +void CachedFrame::setData() { if (this != mRoot) { mViewBounds = mLocalViewBounds; @@ -942,17 +957,17 @@ void CachedFrame::setData() } } -bool CachedFrame::setFocus(WebCore::Frame* frame, WebCore::Node* node, +bool CachedFrame::setCursor(WebCore::Frame* frame, WebCore::Node* node, int x, int y) { if (NULL == node) { - const_cast<CachedRoot*>(mRoot)->setCachedFocus(NULL, NULL); + const_cast<CachedRoot*>(mRoot)->setCursor(NULL, NULL); return true; } if (mFrame != frame) { - for (CachedFrame* testF = mCachedFrames.begin(); testF != mCachedFrames.end(); + for (CachedFrame* testF = mCachedFrames.begin(); testF != mCachedFrames.end(); testF++) { - if (testF->setFocus(frame, node, x, y)) + if (testF->setCursor(frame, node, x, y)) return true; } DBG_NAV_LOGD("no frame frame=%p node=%p", frame, node); @@ -965,17 +980,17 @@ bool CachedFrame::setFocus(WebCore::Frame* frame, WebCore::Node* node, if (test->nodePointer() != node && first) continue; size_t partMax = test->navableRects(); - WTF::Vector<WebCore::IntRect>& focusRings = test->focusRings(); + WTF::Vector<WebCore::IntRect>& cursorRings = test->cursorRings(); for (size_t part = 0; part < partMax; part++) { - const WebCore::IntRect& testBounds = focusRings.at(part); + const WebCore::IntRect& testBounds = cursorRings.at(part); if (testBounds.contains(x, y) == false) continue; - if (test->isFocus()) { - DBG_NAV_LOGD("already set? test=%d frame=%p node=%p x=%d y=%d", + if (test->isCursor()) { + DBG_NAV_LOGD("already set? test=%d frame=%p node=%p x=%d y=%d", test->index(), frame, node, x, y); - return true; + return false; } - const_cast<CachedRoot*>(mRoot)->setCachedFocus(this, test); + const_cast<CachedRoot*>(mRoot)->setCursor(this, test); return true; } } @@ -1034,11 +1049,11 @@ int CachedFrame::BestData::isContainer(CachedFrame::BestData* other) // mMouseOver = other->mNode; return other->mNode->isArea() ? -1 : 1; } - return 0; + return 0; } // distance scale factor factor as a 16.16 scalar -SkFixed CachedFrame::BestData::Overlap(int span, int left, int right) +SkFixed CachedFrame::BestData::Overlap(int span, int left, int right) { unsigned result; if (left > 0 && left < span && right > span) @@ -1077,11 +1092,11 @@ void CachedFrame::BestData::setDistances() bool CachedFrame::BestData::setDownDirection(const CachedHistory* history) { - const WebCore::IntRect& navBounds = history->navBounds(); + const WebCore::IntRect& navBounds = history->navBounds(); mMajorButt = mNodeBounds.y() - navBounds.bottom(); int testX = mNodeBounds.x(); int testRight = mNodeBounds.right(); - setNavOverlap(navBounds.width(), navBounds.right() - testX, + setNavOverlap(navBounds.width(), navBounds.right() - testX, testRight - navBounds.x()); if (canBeReachedByAnotherDirection()) { mNode->setCondition(CachedNode::BEST_DIRECTION); @@ -1089,7 +1104,7 @@ bool CachedFrame::BestData::setDownDirection(const CachedHistory* history) } int inNavTop = mNodeBounds.y() - navBounds.y(); mMajorDelta2 = inNavTop; - mMajorDelta = mMajorDelta2 + ((mNodeBounds.height() - + mMajorDelta = mMajorDelta2 + ((mNodeBounds.height() - navBounds.height()) >> 1); if (mMajorDelta2 <= 1 && mMajorDelta <= 1) { mNode->setCondition(CachedNode::CENTER_FURTHER); // never move up or sideways @@ -1099,7 +1114,7 @@ bool CachedFrame::BestData::setDownDirection(const CachedHistory* history) setNavInclusion(testRight - navBounds.right(), navBounds.x() - testX); bool subsumes = navBounds.height() > 0 && inOrSubsumesNav(); if (inNavTop <= 0 && inNavBottom <= 0 && subsumes) { - mNode->setCondition(CachedNode::NOT_ENCLOSING_FOCUS); + mNode->setCondition(CachedNode::NOT_ENCLOSING_CURSOR); return REJECT_TEST; } int maxV = history->maxWorkingVertical(); @@ -1110,18 +1125,18 @@ bool CachedFrame::BestData::setDownDirection(const CachedHistory* history) mNode->setCondition(CachedNode::OVERLAP_OR_EDGE_FURTHER); return REJECT_TEST; } - mInNav = history->directionChange() && inNavTop >= 0 && - inNavBottom > 0 && subsumes; + mInNav = history->directionChange() && inNavTop >= 0 && + inNavBottom > 0 && subsumes; return false; } bool CachedFrame::BestData::setLeftDirection(const CachedHistory* history) { - const WebCore::IntRect& navBounds = history->navBounds(); + const WebCore::IntRect& navBounds = history->navBounds(); mMajorButt = navBounds.x() - mNodeBounds.right(); int testY = mNodeBounds.y(); int testBottom = mNodeBounds.bottom(); - setNavOverlap(navBounds.height(), navBounds.bottom() - testY, + setNavOverlap(navBounds.height(), navBounds.bottom() - testY, testBottom - navBounds.y()); if (canBeReachedByAnotherDirection()) { mNode->setCondition(CachedNode::BEST_DIRECTION); @@ -1129,7 +1144,7 @@ bool CachedFrame::BestData::setLeftDirection(const CachedHistory* history) } int inNavRight = navBounds.right() - mNodeBounds.right(); mMajorDelta2 = inNavRight; - mMajorDelta = mMajorDelta2 - ((navBounds.width() - + mMajorDelta = mMajorDelta2 - ((navBounds.width() - mNodeBounds.width()) >> 1); if (mMajorDelta2 <= 1 && mMajorDelta <= 1) { mNode->setCondition(CachedNode::CENTER_FURTHER); // never move right or sideways @@ -1139,7 +1154,7 @@ bool CachedFrame::BestData::setLeftDirection(const CachedHistory* history) setNavInclusion(navBounds.y() - testY, testBottom - navBounds.bottom()); bool subsumes = navBounds.width() > 0 && inOrSubsumesNav(); if (inNavLeft <= 0 && inNavRight <= 0 && subsumes) { - mNode->setCondition(CachedNode::NOT_ENCLOSING_FOCUS); + mNode->setCondition(CachedNode::NOT_ENCLOSING_CURSOR); return REJECT_TEST; } int maxH = history->maxWorkingHorizontal(); @@ -1150,18 +1165,18 @@ bool CachedFrame::BestData::setLeftDirection(const CachedHistory* history) mNode->setCondition(CachedNode::OVERLAP_OR_EDGE_FURTHER); return REJECT_TEST; } - mInNav = history->directionChange() && inNavLeft >= 0 && + mInNav = history->directionChange() && inNavLeft >= 0 && inNavRight > 0 && subsumes; /* both L/R in or out */ return false; } bool CachedFrame::BestData::setRightDirection(const CachedHistory* history) { - const WebCore::IntRect& navBounds = history->navBounds(); + const WebCore::IntRect& navBounds = history->navBounds(); mMajorButt = mNodeBounds.x() - navBounds.right(); int testY = mNodeBounds.y(); int testBottom = mNodeBounds.bottom(); - setNavOverlap(navBounds.height(), navBounds.bottom() - testY, + setNavOverlap(navBounds.height(), navBounds.bottom() - testY, testBottom - navBounds.y()); if (canBeReachedByAnotherDirection()) { mNode->setCondition(CachedNode::BEST_DIRECTION); @@ -1169,7 +1184,7 @@ bool CachedFrame::BestData::setRightDirection(const CachedHistory* history) } int inNavLeft = mNodeBounds.x() - navBounds.x(); mMajorDelta2 = inNavLeft; - mMajorDelta = mMajorDelta2 + ((mNodeBounds.width() - + mMajorDelta = mMajorDelta2 + ((mNodeBounds.width() - navBounds.width()) >> 1); if (mMajorDelta2 <= 1 && mMajorDelta <= 1) { mNode->setCondition(CachedNode::CENTER_FURTHER); // never move left or sideways @@ -1179,7 +1194,7 @@ bool CachedFrame::BestData::setRightDirection(const CachedHistory* history) setNavInclusion(testBottom - navBounds.bottom(), navBounds.y() - testY); bool subsumes = navBounds.width() > 0 && inOrSubsumesNav(); if (inNavLeft <= 0 && inNavRight <= 0 && subsumes) { - mNode->setCondition(CachedNode::NOT_ENCLOSING_FOCUS); + mNode->setCondition(CachedNode::NOT_ENCLOSING_CURSOR); return REJECT_TEST; } int maxH = history->maxWorkingHorizontal(); @@ -1190,18 +1205,18 @@ bool CachedFrame::BestData::setRightDirection(const CachedHistory* history) mNode->setCondition(CachedNode::OVERLAP_OR_EDGE_FURTHER); return REJECT_TEST; } - mInNav = history->directionChange() && inNavLeft >= 0 && + mInNav = history->directionChange() && inNavLeft >= 0 && inNavRight > 0 && subsumes; /* both L/R in or out */ return false; } bool CachedFrame::BestData::setUpDirection(const CachedHistory* history) { - const WebCore::IntRect& navBounds = history->navBounds(); + const WebCore::IntRect& navBounds = history->navBounds(); mMajorButt = navBounds.y() - mNodeBounds.bottom(); int testX = mNodeBounds.x(); int testRight = mNodeBounds.right(); - setNavOverlap(navBounds.width(), navBounds.right() - testX, + setNavOverlap(navBounds.width(), navBounds.right() - testX, testRight - navBounds.x()); if (canBeReachedByAnotherDirection()) { mNode->setCondition(CachedNode::BEST_DIRECTION); @@ -1209,7 +1224,7 @@ bool CachedFrame::BestData::setUpDirection(const CachedHistory* history) } int inNavBottom = navBounds.bottom() - mNodeBounds.bottom(); mMajorDelta2 = inNavBottom; - mMajorDelta = mMajorDelta2 - ((navBounds.height() - + mMajorDelta = mMajorDelta2 - ((navBounds.height() - mNodeBounds.height()) >> 1); if (mMajorDelta2 <= 1 && mMajorDelta <= 1) { mNode->setCondition(CachedNode::CENTER_FURTHER); // never move down or sideways @@ -1219,7 +1234,7 @@ bool CachedFrame::BestData::setUpDirection(const CachedHistory* history) setNavInclusion(navBounds.x() - testX, testRight - navBounds.right()); bool subsumes = navBounds.height() > 0 && inOrSubsumesNav(); if (inNavTop <= 0 && inNavBottom <= 0 && subsumes) { - mNode->setCondition(CachedNode::NOT_ENCLOSING_FOCUS); + mNode->setCondition(CachedNode::NOT_ENCLOSING_CURSOR); return REJECT_TEST; } int maxV = history->maxWorkingVertical(); @@ -1230,36 +1245,38 @@ bool CachedFrame::BestData::setUpDirection(const CachedHistory* history) mNode->setCondition(CachedNode::OVERLAP_OR_EDGE_FURTHER); return REJECT_TEST; } - mInNav = history->directionChange() && inNavTop >= 0 && + mInNav = history->directionChange() && inNavTop >= 0 && inNavBottom > 0 && subsumes; /* both L/R in or out */ return false; } void CachedFrame::BestData::setNavInclusion(int left, int right) { - // if left and right <= 0, test node is completely in umbra of focus + // if left and right <= 0, test node is completely in umbra of cursor // prefer leftmost center - // if left and right > 0, test node subsumes focus + // if left and right > 0, test node subsumes cursor mNavDelta = left; mNavDelta2 = right; } void CachedFrame::BestData::setNavOverlap(int span, int left, int right) { - mNavOutside = left < MIN_OVERLAP || right < MIN_OVERLAP; // if left or right < 0, test node is not in umbra of focus + // if left or right < 0, test node is not in umbra of cursor + mNavOutside = left < MIN_OVERLAP || right < MIN_OVERLAP; mNavOverlap = Overlap(span, left, right); // prefer smallest negative left } -void CachedFrame::BestData::setWorkingInclusion(int left, int right) +void CachedFrame::BestData::setWorkingInclusion(int left, int right) { mWorkingDelta = left; mWorkingDelta2 = right; } // distance scale factor factor as a 16.16 scalar -void CachedFrame::BestData::setWorkingOverlap(int span, int left, int right) +void CachedFrame::BestData::setWorkingOverlap(int span, int left, int right) { - mWorkingOutside = left < MIN_OVERLAP || right < MIN_OVERLAP; // if left or right < 0, test node is not in umbra of focus + // if left or right < 0, test node is not in umbra of cursor + mWorkingOutside = left < MIN_OVERLAP || right < MIN_OVERLAP; mWorkingOverlap = Overlap(span, left, right); mPreferred = left <= 0 ? 0 : left; } @@ -1273,7 +1290,7 @@ void CachedFrame::BestData::setWorkingOverlap(int span, int left, int right) CachedFrame* CachedFrame::Debug::base() const { CachedFrame* nav = (CachedFrame*) ((char*) this - OFFSETOF(CachedFrame, mDebug)); - return nav; + return nav; } void CachedFrame::Debug::print() const @@ -1283,12 +1300,12 @@ void CachedFrame::Debug::print() const DEBUG_PRINT_RECT("", BOUNDS, mLocalViewBounds); DEBUG_PRINT_RECT("//", VIEW, mViewBounds); DUMP_NAV_LOGD("// CachedNode mCachedNodes={ // count=%d\n", b->mCachedNodes.size()); - for (CachedNode* node = b->mCachedNodes.begin(); + for (CachedNode* node = b->mCachedNodes.begin(); node != b->mCachedNodes.end(); node++) node->mDebug.print(); DUMP_NAV_LOGD("// }; // end of nodes\n"); DUMP_NAV_LOGD("// CachedFrame mCachedFrames={ // count=%d\n", b->mCachedFrames.size()); - for (CachedFrame* child = b->mCachedFrames.begin(); + for (CachedFrame* child = b->mCachedFrames.begin(); child != b->mCachedFrames.end(); child++) { child->mDebug.print(); @@ -1296,9 +1313,10 @@ void CachedFrame::Debug::print() const DUMP_NAV_LOGD("// }; // end of child frames\n"); DUMP_NAV_LOGD("// void* mFrame=(void*) %p;\n", b->mFrame); DUMP_NAV_LOGD("// CachedFrame* mParent=%p;\n", b->mParent); - DUMP_NAV_LOGD("// int mIndex=%d;\n", b->mIndex); + DUMP_NAV_LOGD("// int mIndexInParent=%d;\n", b->mIndexInParent); DUMP_NAV_LOGD("// const CachedRoot* mRoot=%p;\n", b->mRoot); - DUMP_NAV_LOGD("// int mFocus=%d;\n", b->mFocus); + DUMP_NAV_LOGD("// int mCursorIndex=%d;\n", b->mCursorIndex); + DUMP_NAV_LOGD("// int mFocusIndex=%d;\n", b->mFocusIndex); } bool CachedFrame::Debug::validate(const CachedNode* node) const @@ -1308,7 +1326,7 @@ bool CachedFrame::Debug::validate(const CachedNode* node) const return false; if (node >= b->mCachedNodes.begin() && node < b->mCachedNodes.end()) return true; - for (const CachedFrame* child = b->mCachedFrames.begin(); + for (const CachedFrame* child = b->mCachedFrames.begin(); child != b->mCachedFrames.end(); child++) if (child->mDebug.validate(node)) return true; diff --git a/WebKit/android/nav/CachedFrame.h b/WebKit/android/nav/CachedFrame.h index dc20e15..0df5489 100644 --- a/WebKit/android/nav/CachedFrame.h +++ b/WebKit/android/nav/CachedFrame.h @@ -60,31 +60,39 @@ public: TEST_IS_BEST, REJECT_TEST }; + enum CursorInit { + CURSOR_UNINITIALIZED = -2, + CURSOR_CLEARED = -1, + CURSOR_SET = 0 + }; CachedFrame() {} void add(CachedNode& node) { mCachedNodes.append(node); } void addFrame(CachedFrame& child) { mCachedFrames.append(child); } bool checkVisited(const CachedNode* , CachedFrame::Direction ) const; size_t childCount() { return mCachedFrames.size(); } - void clearFocus(); + void clearCursor(); + const CachedNode* currentCursor() const { return currentCursor(NULL); } + const CachedNode* currentCursor(const CachedFrame** ) const; const CachedNode* currentFocus() const { return currentFocus(NULL); } const CachedNode* currentFocus(const CachedFrame** ) const; bool directionChange() const; const CachedNode* document() const { return mCachedNodes.begin(); } bool empty() const { return mCachedNodes.size() < 2; } // must have 1 past doc - const CachedNode* findBestAt(const WebCore::IntRect& , int* best, bool* inside, - const CachedNode** , const CachedFrame** , int* x, int* y) const; + const CachedNode* findBestAt(const WebCore::IntRect& , int* best, + bool* inside, const CachedNode** , const CachedFrame** , int* x, + int* y, bool checkForHidden) const; const CachedFrame* findBestFrameAt(int x, int y) const; const CachedNode* findBestHitAt(const WebCore::IntRect& , int* best, const CachedFrame** , int* x, int* y) const; - bool finishInit(); + void finishInit(); CachedFrame* firstChild() { return mCachedFrames.begin(); } const CachedFrame* firstChild() const { return mCachedFrames.begin(); } - int focusIndex() const { return mFocus; } void* framePointer() const { return mFrame; } CachedNode* getIndex(int index) { return index >= 0 ? &mCachedNodes[index] : NULL; } const CachedFrame* hasFrame(const CachedNode* node) const; - int indexInParent() const { return mIndex; } + void hideCursor(); + int indexInParent() const { return mIndexInParent; } void init(const CachedRoot* root, int index, WebCore::Frame* frame); const CachedFrame* lastChild() const { return &mCachedFrames.last(); } CachedNode* lastNode() { return &mCachedNodes.last(); } @@ -96,9 +104,11 @@ public: void resetClippedOut(); void setContentsSize(int width, int height) { mContents.setWidth(width); mContents.setHeight(height); } + bool setCursor(WebCore::Frame* , WebCore::Node* , int x, int y); + void setCursorIndex(int index) { mCursorIndex = index; } void setData(); bool setFocus(WebCore::Frame* , WebCore::Node* , int x, int y); - void setFocusIndex(int focusIndex) const { mFocus = focusIndex; } + void setFocusIndex(int index) { mFocusIndex = index; } void setLocalViewBounds(const WebCore::IntRect& bounds) { mLocalViewBounds = bounds; } int size() { return mCachedNodes.size(); } const CachedNode* validDocument() const; @@ -121,7 +131,7 @@ protected: SkFixed mWorkingOverlap; // this and below are fuzzy answers instead of bools SkFixed mNavOverlap; SkFixed mPreferred; - bool mFocusChild; + bool mCursorChild; bool mInNav; bool mNavOutside; bool mWorkingOutside; @@ -186,9 +196,10 @@ protected: WTF::Vector<CachedFrame> mCachedFrames; void* mFrame; // WebCore::Frame*, used only to compare pointers CachedFrame* mParent; - int mIndex; // index within parent's array of children, or -1 if root + int mCursorIndex; + int mFocusIndex; + int mIndexInParent; // index within parent's array of children, or -1 if root const CachedRoot* mRoot; - mutable int mFocus; private: CachedHistory* history() const; #ifdef BROWSER_DEBUG diff --git a/WebKit/android/nav/CachedHistory.cpp b/WebKit/android/nav/CachedHistory.cpp index f75f237..7aca1ad 100644 --- a/WebKit/android/nav/CachedHistory.cpp +++ b/WebKit/android/nav/CachedHistory.cpp @@ -84,8 +84,6 @@ void CachedHistory::reset() // mLastScroll = 0; mPriorBounds = WebCore::IntRect(0, 0, 0, 0); mDirectionChange = false; - mFocusIsInput = false; - mPriorIsInput = false; mDidFirstLayout = false; mPriorMove = mLastMove = CachedFrame::UNINITIALIZED; mMinWorkingHorizontal = mMinWorkingVertical = INT_MIN; @@ -93,24 +91,22 @@ void CachedHistory::reset() } void CachedHistory::setWorking(CachedFrame::Direction newMove, - const CachedNode* focus, const WebCore::IntRect& viewBounds) + const CachedNode* cursor, const WebCore::IntRect& viewBounds) { CachedFrame::Direction lastAxis = (CachedFrame::Direction) (mLastMove & ~CachedFrame::RIGHT_DOWN); // up, left or uninitialized CachedFrame::Direction newAxis = (CachedFrame::Direction) (newMove & ~CachedFrame::RIGHT_DOWN); bool change = newAxis != lastAxis; mDirectionChange = change && mLastMove != CachedFrame::UNINITIALIZED; - if (focus != NULL || mLastMove != CachedFrame::UNINITIALIZED) { + if (cursor != NULL || mLastMove != CachedFrame::UNINITIALIZED) { mPriorMove = mLastMove; mLastMove = newMove; } const WebCore::IntRect* navBounds = &mNavBounds; - if (focus != NULL) { - WebCore::IntRect focusBounds; - focus->getBounds(&focusBounds); - if (focusBounds.isEmpty() == false) - mNavBounds = focusBounds; - mPriorIsInput = mFocusIsInput; - mFocusIsInput = focus->isInput(); // focus->localName() == "input"; + if (cursor != NULL) { + WebCore::IntRect cursorBounds; + cursor->getBounds(&cursorBounds); + if (cursorBounds.isEmpty() == false) + mNavBounds = cursorBounds; } if (change) { // uninitialized or change in direction if (lastAxis != CachedFrame::LEFT && navBounds->height() > 0) { @@ -121,18 +117,6 @@ void CachedHistory::setWorking(CachedFrame::Direction newMove, mMinWorkingVertical = navBounds->x(); mMaxWorkingVertical = navBounds->right(); } - } else if (mPriorIsInput) { - if (newAxis == CachedFrame::UP_DOWN) { - if (mPriorBounds.x() == mMinWorkingVertical && mPriorBounds.right() == mMaxWorkingVertical) { - mMinWorkingVertical = navBounds->x(); - mMaxWorkingVertical = navBounds->right(); - } - } else { - if (mPriorBounds.y() == mMinWorkingHorizontal && mPriorBounds.bottom() == mMaxWorkingHorizontal) { - mMinWorkingHorizontal = navBounds->y(); - mMaxWorkingHorizontal = navBounds->bottom(); - } - } } pinMaxMin(viewBounds); } @@ -176,11 +160,11 @@ void CachedHistory::Debug::print(CachedRoot* root) const } DUMP_NAV_LOGD("// };\n"); // DUMP_NAV_LOGD("// int mLastScroll=%d;\n", b->mLastScroll); + DEBUG_PRINT_RECT(mMouseBounds); DEBUG_PRINT_RECT(mNavBounds); DEBUG_PRINT_RECT(mPriorBounds); DEBUG_PRINT_BOOL(mDirectionChange); - DEBUG_PRINT_BOOL(mFocusIsInput); - DEBUG_PRINT_BOOL(mPriorIsInput); + DEBUG_PRINT_BOOL(mDidFirstLayout); DUMP_NAV_LOGD("// CachedFrame::Direction mLastMove=%s, mPriorMove=%s;\n", direction(b->mLastMove), direction(b->mPriorMove)); int max = b->mMaxWorkingHorizontal; diff --git a/WebKit/android/nav/CachedHistory.h b/WebKit/android/nav/CachedHistory.h index e48d44b..1ae62b9 100644 --- a/WebKit/android/nav/CachedHistory.h +++ b/WebKit/android/nav/CachedHistory.h @@ -50,6 +50,7 @@ public: const WebCore::IntRect& navBounds() const { return mNavBounds; } const WebCore::IntRect& priorBounds() const { return mPriorBounds; } void setDidFirstLayout(bool did) { mDidFirstLayout = did; } + void setMouseBounds(const WebCore::IntRect& loc) { mMouseBounds = loc; } void setNavBounds(const WebCore::IntRect& loc) { mNavBounds = loc; } void setWorking(CachedFrame::Direction , const CachedNode* focus, const WebCore::IntRect& viewBounds); @@ -60,12 +61,10 @@ private: const CachedNode* mNode; CachedFrame::Direction mDirection; } mVisited[NAVIGATION_VISIT_DEPTH]; - WebCore::IntRect mMouseBounds; // constricted bounds, if focus ring is partially visible - WebCore::IntRect mNavBounds; // focus ring bounds plus optional keystroke movement - WebCore::IntRect mPriorBounds; // prior chosen focus ring (for reversing narrowing) + WebCore::IntRect mMouseBounds; // constricted bounds, if cursor ring is partially visible + WebCore::IntRect mNavBounds; // cursor ring bounds plus optional keystroke movement + WebCore::IntRect mPriorBounds; // prior chosen cursor ring (for reversing narrowing) bool mDirectionChange; - bool mFocusIsInput; // defer max/min to non-focus node if focus is too broad - bool mPriorIsInput; // defer max/min to non-focus node if focus is too broad bool mDidFirstLayout; // set true when page is newly laid out CachedFrame::Direction mLastMove; CachedFrame::Direction mPriorMove; diff --git a/WebKit/android/nav/CachedNode.cpp b/WebKit/android/nav/CachedNode.cpp index b786677..cab1f15 100644 --- a/WebKit/android/nav/CachedNode.cpp +++ b/WebKit/android/nav/CachedNode.cpp @@ -24,8 +24,8 @@ */ #include "CachedPrefix.h" -#include "CachedFrame.h" #include "CachedHistory.h" +#include "CachedRoot.h" #include "Node.h" #include "PlatformString.h" @@ -34,13 +34,13 @@ namespace android { -void CachedNode::clearFocus(CachedFrame* parent) +void CachedNode::clearCursor(CachedFrame* parent) { if (isFrame()) { CachedFrame* child = const_cast<CachedFrame*>(parent->hasFrame(this)); - child->clearFocus(); + child->clearCursor(); } - mIsFocus = false; + mIsCursor = false; } bool CachedNode::Clip(const WebCore::IntRect& outer, WebCore::IntRect* inner, @@ -73,24 +73,40 @@ bool CachedNode::Clip(const WebCore::IntRect& outer, WebCore::IntRect* inner, bool CachedNode::clip(const WebCore::IntRect& bounds) { - return Clip(bounds, &mBounds, &mFocusRing); + return Clip(bounds, &mBounds, &mCursorRing); } #define OVERLAP 3 -void CachedNode::fixUpFocusRects() +void CachedNode::fixUpCursorRects(const CachedRoot* root) { - if (mFixedUpFocusRects) + if (mFixedUpCursorRects) return; - mFixedUpFocusRects = true; + mFixedUpCursorRects = true; + // if the hit-test rect doesn't intersect any other rect, use it + if (mHitBounds != mBounds && mHitBounds.contains(mBounds) && + root->checkRings(mCursorRing, mHitBounds)) { + DBG_NAV_LOGD("use mHitBounds (%d,%d,%d,%d)", mHitBounds.x(), + mHitBounds.y(), mHitBounds.width(), mHitBounds.height()); + mUseHitBounds = true; + return; + } if (mNavableRects <= 1) return; + // if there is more than 1 rect, and the bounds doesn't intersect + // any other cursor ring bounds, use it + if (root->checkRings(mCursorRing, mBounds)) { + DBG_NAV_LOGD("use mBounds (%d,%d,%d,%d)", mBounds.x(), + mBounds.y(), mBounds.width(), mBounds.height()); + mUseBounds = true; + return; + } #if DEBUG_NAV_UI { - WebCore::IntRect* boundsPtr = mFocusRing.begin() - 1; - const WebCore::IntRect* const boundsEnd = mFocusRing.begin() + mFocusRing.size(); + WebCore::IntRect* boundsPtr = mCursorRing.begin() - 1; + const WebCore::IntRect* const boundsEnd = mCursorRing.begin() + mCursorRing.size(); while (++boundsPtr < boundsEnd) - LOGD("%s %d:(%d, %d, %d, %d)\n", __FUNCTION__, boundsPtr - mFocusRing.begin(), + LOGD("%s %d:(%d, %d, %d, %d)\n", __FUNCTION__, boundsPtr - mCursorRing.begin(), boundsPtr->x(), boundsPtr->y(), boundsPtr->width(), boundsPtr->height()); } #endif @@ -98,16 +114,16 @@ void CachedNode::fixUpFocusRects() bool again; do { again = false; - size_t size = mFocusRing.size(); - WebCore::IntRect* unitBoundsPtr = mFocusRing.begin() - 1; - const WebCore::IntRect* const unitBoundsEnd = mFocusRing.begin() + size; + size_t size = mCursorRing.size(); + WebCore::IntRect* unitBoundsPtr = mCursorRing.begin() - 1; + const WebCore::IntRect* const unitBoundsEnd = mCursorRing.begin() + size; while (++unitBoundsPtr < unitBoundsEnd) { // any other unitBounds to the left or right of this one? int unitTop = unitBoundsPtr->y(); int unitBottom = unitBoundsPtr->bottom(); int unitLeft = unitBoundsPtr->x(); int unitRight = unitBoundsPtr->right(); - WebCore::IntRect* testBoundsPtr = mFocusRing.begin() - 1; + WebCore::IntRect* testBoundsPtr = mCursorRing.begin() - 1; while (++testBoundsPtr < unitBoundsEnd) { if (unitBoundsPtr == testBoundsPtr) continue; @@ -135,7 +151,7 @@ void CachedNode::fixUpFocusRects() WebCore::IntRect candidate = WebCore::IntRect(candidateLeft, candidateTop, candidateRight - candidateLeft, candidateBottom - candidateTop); // does a different unit bounds intersect the candidate? if so, don't add - WebCore::IntRect* checkBoundsPtr = mFocusRing.begin() - 1; + WebCore::IntRect* checkBoundsPtr = mCursorRing.begin() - 1; while (++checkBoundsPtr < unitBoundsEnd) { if (checkBoundsPtr->intersects(candidate) == false) continue; @@ -163,10 +179,10 @@ void CachedNode::fixUpFocusRects() candidateRight - candidateLeft, candidateBottom - candidateTop); ASSERT(candidate.isEmpty() == false); #if DEBUG_NAV_UI - LOGD("%s %d:(%d, %d, %d, %d)\n", __FUNCTION__, mFocusRing.size(), + LOGD("%s %d:(%d, %d, %d, %d)\n", __FUNCTION__, mCursorRing.size(), candidate.x(), candidate.y(), candidate.width(), candidate.height()); #endif - mFocusRing.append(candidate); + mCursorRing.append(candidate); again = true; goto tryAgain; nextCheck: @@ -179,14 +195,23 @@ tryAgain: } -void CachedNode::focusRingBounds(WebCore::IntRect* bounds) const +void CachedNode::cursorRingBounds(WebCore::IntRect* bounds) const { int partMax = mNavableRects; ASSERT(partMax > 0); - *bounds = mFocusRing[0]; + *bounds = mCursorRing[0]; for (int partIndex = 1; partIndex < partMax; partIndex++) - bounds->unite(mFocusRing[partIndex]); - bounds->inflate(FOCUS_RING_HIT_TEST_RADIUS); + bounds->unite(mCursorRing[partIndex]); + bounds->inflate(CURSOR_RING_HIT_TEST_RADIUS); +} + +void CachedNode::hideCursor(CachedFrame* parent) +{ + if (isFrame()) { + CachedFrame* child = const_cast<CachedFrame*>(parent->hasFrame(this)); + child->hideCursor(); + } + mIsHidden = true; } void CachedNode::init(WebCore::Node* node) @@ -203,8 +228,8 @@ void CachedNode::move(int x, int y) { mBounds.move(x, y); // mHitTestBounds will be moved by caller - WebCore::IntRect* first = mFocusRing.begin(); - WebCore::IntRect* last = first + mFocusRing.size(); + WebCore::IntRect* first = mCursorRing.begin(); + WebCore::IntRect* last = first + mCursorRing.size(); --first; while (++first != last) first->move(x, y); @@ -216,10 +241,10 @@ bool CachedNode::partRectsContains(const CachedNode* other) const int outerMax = mNavableRects; int innerMax = other->mNavableRects; do { - const WebCore::IntRect& outerBounds = mFocusRing[outerIndex]; + const WebCore::IntRect& outerBounds = mCursorRing[outerIndex]; int innerIndex = 0; do { - const WebCore::IntRect& innerBounds = other->mFocusRing[innerIndex]; + const WebCore::IntRect& innerBounds = other->mCursorRing[innerIndex]; if (innerBounds.contains(outerBounds)) return true; } while (++innerIndex < innerMax); @@ -249,10 +274,10 @@ const char* CachedNode::Debug::condition(Condition t) const case BUTTED_UP: return "BUTTED_UP"; break; case CENTER_FURTHER: return "CENTER_FURTHER"; break; case CLOSER: return "CLOSER"; break; - case CLOSER_IN_FOCUS: return "CLOSER_IN_FOCUS"; break; + case CLOSER_IN_CURSOR: return "CLOSER_IN_CURSOR"; break; case CLOSER_OVERLAP: return "CLOSER_OVERLAP"; break; case CLOSER_TOP: return "CLOSER_TOP"; break; - case FOCUSABLE: return "FOCUSABLE"; break; + case NAVABLE: return "NAVABLE"; break; case FURTHER: return "FURTHER"; break; case IN_UMBRA: return "IN_UMBRA"; break; case IN_WORKING: return "IN_WORKING"; break; @@ -264,11 +289,10 @@ const char* CachedNode::Debug::condition(Condition t) const case CHILD: return "CHILD"; break; case DISABLED: return "DISABLED"; break; case HIGHER_TAB_INDEX: return "HIGHER_TAB_INDEX"; break; - case IN_FOCUS: return "IN_FOCUS"; break; - case IN_FOCUS_CHILDREN: return "IN_FOCUS_CHILDREN"; break; - case NOT_ENCLOSING_FOCUS: return "NOT_ENCLOSING_FOCUS"; break; - // case NOT_FOCUS_CHILD: return "NOT_FOCUS_CHILD"; break; - case NOT_FOCUS_NODE: return "NOT_FOCUS_NODE"; break; + case IN_CURSOR: return "IN_CURSOR"; break; + case IN_CURSOR_CHILDREN: return "IN_CURSOR_CHILDREN"; break; + case NOT_ENCLOSING_CURSOR: return "NOT_ENCLOSING_CURSOR"; break; + case NOT_CURSOR_NODE: return "NOT_CURSOR_NODE"; break; case OUTSIDE_OF_BEST: return "OUTSIDE_OF_BEST"; break; case OUTSIDE_OF_ORIGINAL: return "OUTSIDE_OF_ORIGINAL"; break; default: return "???"; @@ -302,9 +326,9 @@ void CachedNode::Debug::print() const DUMP_NAV_LOGD("%.*s\"\n", index, scratch); DEBUG_PRINT_RECT(mBounds); DEBUG_PRINT_RECT(mHitBounds); - const WTF::Vector<WebCore::IntRect>& rects = b->focusRings(); + const WTF::Vector<WebCore::IntRect>& rects = b->cursorRings(); size_t size = rects.size(); - DUMP_NAV_LOGD("// IntRect focusRings={ // size=%d\n", size); + DUMP_NAV_LOGD("// IntRect cursorRings={ // size=%d\n", size); for (size_t i = 0; i < size; i++) DUMP_NAV_LOGD(" // {%d, %d, %d, %d}, // %d\n", rects[i].x(), rects[i].y(), rects[i].width(), rects[i].height(), i); @@ -322,13 +346,14 @@ void CachedNode::Debug::print() const DUMP_NAV_LOGD("// Type mType=%s;\n", type(b->mType)); DEBUG_PRINT_BOOL(mClippedOut); DEBUG_PRINT_BOOL(mDisabled); - DEBUG_PRINT_BOOL(mFixedUpFocusRects); - DEBUG_PRINT_BOOL(mHasFocusRing); + DEBUG_PRINT_BOOL(mFixedUpCursorRects); + DEBUG_PRINT_BOOL(mHasCursorRing); DEBUG_PRINT_BOOL(mHasMouseOver); DEBUG_PRINT_BOOL(mIsAnchor); DEBUG_PRINT_BOOL(mIsArea); + DEBUG_PRINT_BOOL(mIsCursor); DEBUG_PRINT_BOOL(mIsFocus); - DEBUG_PRINT_BOOL(mIsInput); + DEBUG_PRINT_BOOL(mIsHidden); DEBUG_PRINT_BOOL(mIsParentAnchor); DEBUG_PRINT_BOOL(mIsPassword); DEBUG_PRINT_BOOL(mIsRtlText); @@ -337,6 +362,8 @@ void CachedNode::Debug::print() const DEBUG_PRINT_BOOL(mIsTransparent); DEBUG_PRINT_BOOL(mIsUnclipped); DEBUG_PRINT_BOOL(mLast); + DEBUG_PRINT_BOOL(mUseBounds); + DEBUG_PRINT_BOOL(mUseHitBounds); DEBUG_PRINT_BOOL(mWantsKeyEvents); DUMP_NAV_LOGD("\n"); } diff --git a/WebKit/android/nav/CachedNode.h b/WebKit/android/nav/CachedNode.h index aa64982..2efbaf7 100644 --- a/WebKit/android/nav/CachedNode.h +++ b/WebKit/android/nav/CachedNode.h @@ -40,6 +40,7 @@ namespace WebCore { namespace android { class CachedFrame; +class CachedRoot; class CachedNode { public: @@ -53,10 +54,10 @@ public: BUTTED_UP, CENTER_FURTHER, CLOSER, - CLOSER_IN_FOCUS, + CLOSER_IN_CURSOR, CLOSER_OVERLAP, CLOSER_TOP, - FOCUSABLE, + NAVABLE, FURTHER, IN_UMBRA, IN_WORKING, @@ -70,11 +71,10 @@ public: CHILD, DISABLED, HIGHER_TAB_INDEX, - IN_FOCUS, - IN_FOCUS_CHILDREN, - NOT_ENCLOSING_FOCUS, - // NOT_FOCUS_CHILD, - NOT_FOCUS_NODE, + IN_CURSOR, + IN_CURSOR_CHILDREN, + NOT_ENCLOSING_CURSOR, + NOT_CURSOR_NODE, OUTSIDE_OF_BEST, // containership OUTSIDE_OF_ORIGINAL, // containership CONDITION_SIZE // FIXME: test that CONDITION_SIZE fits in mCondition @@ -88,41 +88,43 @@ public: WebCore::IntRect* boundsPtr() { return &mBounds; } int childFrameIndex() const { return mChildFrameIndex; } void clearCondition() const { mCondition = NOT_REJECTED; } - void clearFocus(CachedFrame* ); + void clearCursor(CachedFrame* ); static bool Clip(const WebCore::IntRect& outer, WebCore::IntRect* inner, WTF::Vector<WebCore::IntRect>* rings); bool clip(const WebCore::IntRect& ); bool clippedOut() { return mClippedOut; } + void cursorRingBounds(WebCore::IntRect* ) const; bool disabled() const { return mDisabled; } const CachedNode* document() const { return &this[-mIndex]; } - void fixUpFocusRects(); - void focusRingBounds(WebCore::IntRect* ) const; - WTF::Vector<WebCore::IntRect>& focusRings() { return mFocusRing; } - const WTF::Vector<WebCore::IntRect>& focusRings() const { return mFocusRing; } + void fixUpCursorRects(const CachedRoot* root); + WTF::Vector<WebCore::IntRect>& cursorRings() { return mCursorRing; } + const WTF::Vector<WebCore::IntRect>& cursorRings() const { return mCursorRing; } const WebCore::IntRect& getBounds() const { return mBounds; } void getBounds(WebCore::IntRect* bounds) const { *bounds = mBounds; } const WebCore::String& getExport() const { return mExport; } - bool hasFocusRing() const { return mHasFocusRing; } + bool hasCursorRing() const { return !mIsHidden && mHasCursorRing; } bool hasMouseOver() const { return mHasMouseOver; } + void hideCursor(CachedFrame* ); const WebCore::IntRect& hitBounds() const { return mHitBounds; } int index() const { return mIndex; } void init(WebCore::Node* node); bool isAnchor() const { return mIsAnchor; } + bool isCursor() const { return mIsCursor; } bool isArea() const { return mIsArea; } bool isFocus() const { return mIsFocus; } - bool isFocusable(const WebCore::IntRect& clip) const { + bool isFrame() const { return mChildFrameIndex >= 0 ; } + bool isNavable(const WebCore::IntRect& clip) const { return clip.intersects(mBounds); } - bool isFrame() const { return mChildFrameIndex >= 0 ; } - bool isInput() const { return mIsInput; } bool isPassword() const { return mIsPassword; } + bool isPlugin() const { + return mWantsKeyEvents && !mIsTextArea && !mIsTextField; + } bool isRtlText() const { return mIsRtlText; } bool isTextArea() const { return mIsTextArea; } bool isTextField() const { return mIsTextField; } bool isTransparent() const { return mIsTransparent; } bool isUnclipped() const { return mIsUnclipped; } - bool isWantsKeyEvents() const { return mWantsKeyEvents; } - int maxLength() const { return mMaxLength; }; void move(int x, int y); const WebCore::String& name() const { return mName; } @@ -140,14 +142,14 @@ public: void setCondition(Condition condition) const { mCondition = condition; } void setDisabled(bool disabled) { mDisabled = disabled; } void setExport(const WebCore::String& exported) { mExport = exported; } - void setHasFocusRing(bool hasFocusRing) { mHasFocusRing = hasFocusRing; } + void setHasCursorRing(bool hasRing) { mHasCursorRing = hasRing; } void setHasMouseOver(bool hasMouseOver) { mHasMouseOver = hasMouseOver; } void setHitBounds(const WebCore::IntRect& bounds) { mHitBounds = bounds; } void setIndex(int index) { mIndex = index; } void setIsAnchor(bool isAnchor) { mIsAnchor = isAnchor; } void setIsArea(bool isArea) { mIsArea = isArea; } + void setIsCursor(bool isCursor) { mIsCursor = isCursor; } void setIsFocus(bool isFocus) { mIsFocus = isFocus; } - void setIsInput(bool isInput) { mIsInput = isInput; } void setIsParentAnchor(bool isAnchor) { mIsParentAnchor = isAnchor; } void setIsPassword(bool isPassword) { mIsPassword = isPassword; } void setIsRtlText(bool isRtlText) { mIsRtlText = isRtlText; } @@ -158,23 +160,27 @@ public: void setLast() { mLast = true; } void setMaxLength(int maxLength) { mMaxLength = maxLength; } void setName(const WebCore::String& name) { mName = name; } - void setNavableRects() { mNavableRects = mFocusRing.size(); } + void setNavableRects() { mNavableRects = mCursorRing.size(); } void setParentGroup(void* group) { mParentGroup = group; } void setParentIndex(int parent) { mParentIndex = parent; } void setTabIndex(int index) { mTabIndex = index; } void setTextSize(int textSize) { mTextSize = textSize; } void setType(CachedNodeType type) { mType = type; } void setWantsKeyEvents(bool wantsKeys) { mWantsKeyEvents = wantsKeys; } + void show() { mIsHidden = false; } int tabIndex() const { return mTabIndex; } const CachedNode* traverseNextNode() const { return mLast ? NULL : &this[1]; } int textSize() const { return mTextSize; } CachedNodeType type() const { return mType; } + bool useBounds() const { return mUseBounds; } + bool useHitBounds() const { return mUseHitBounds; } + bool wantsKeyEvents() const { return mWantsKeyEvents; } private: WebCore::String mExport; WebCore::String mName; WebCore::IntRect mBounds; WebCore::IntRect mHitBounds; - WTF::Vector<WebCore::IntRect> mFocusRing; + WTF::Vector<WebCore::IntRect> mCursorRing; void* mNode; // WebCore::Node*, only used to match pointers void* mParentGroup; // WebCore::Node*, only used to match pointers int mChildFrameIndex; // set to -1 if node is not a frame @@ -188,13 +194,14 @@ private: CachedNodeType mType : 3; bool mClippedOut : 1; bool mDisabled : 1; - bool mFixedUpFocusRects : 1; - bool mHasFocusRing : 1; + bool mFixedUpCursorRects : 1; + bool mHasCursorRing : 1; bool mHasMouseOver : 1; bool mIsAnchor : 1; bool mIsArea : 1; + bool mIsCursor : 1; bool mIsFocus : 1; - bool mIsInput : 1; + bool mIsHidden : 1; bool mIsParentAnchor : 1; bool mIsPassword : 1; bool mIsRtlText : 1; @@ -203,6 +210,8 @@ private: bool mIsTransparent : 1; bool mIsUnclipped : 1; bool mLast : 1; // true if this is the last node in a group + bool mUseBounds : 1; + bool mUseHitBounds : 1; bool mWantsKeyEvents : 1; // true for nodes like plugins #ifdef BROWSER_DEBUG public: diff --git a/WebKit/android/nav/CachedRoot.cpp b/WebKit/android/nav/CachedRoot.cpp index a123e55..7da4bd3 100644 --- a/WebKit/android/nav/CachedRoot.cpp +++ b/WebKit/android/nav/CachedRoot.cpp @@ -24,6 +24,7 @@ */ #include "CachedPrefix.h" +#include "android_graphics.h" #include "CachedHistory.h" #include "CachedNode.h" #include "SkBitmap.h" @@ -57,18 +58,18 @@ public: kDrawText_Type, kDrawTextOnPath_Type }; - + static bool isTextType(Type t) { return t == kDrawPosTextH_Type || t == kDrawText_Type; } - + CommonCheck() : mType(kNo_Type), mAllOpaque(true), mIsOpaque(true) { setEmpty(); } - bool doRect(Type type) { + bool doRect(Type type) { mType = type; - return doIRect(mUnion); + return doIRect(mUnion); } bool joinGlyphs(const SkIRect& rect) { @@ -77,7 +78,7 @@ public: mUnion.join(rect); return isGlyph; } - + void setAllOpaque(bool opaque) { mAllOpaque = opaque; } void setEmpty() { mUnion.setEmpty(); } void setIsOpaque(bool opaque) { mIsOpaque = opaque; } @@ -112,16 +113,16 @@ public: class BoundsCheck : public CommonCheck { public: - BoundsCheck() { + BoundsCheck() { mAllDrawnIn.setEmpty(); mLastAll.setEmpty(); mLastOver.setEmpty(); } - + static int Area(SkIRect test) { return test.width() * test.height(); } - + void checkLast() { if (mAllDrawnIn.isEmpty()) return; @@ -131,16 +132,16 @@ public: } 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 || + bool interestingType = mType == kDrawBitmap_Type || mType == kDrawRect_Type || isTextType(mType); if (SkIRect::Intersects(mBounds, rect) == false) { #if DEBUG_NAV_UI && !defined BROWSER_DEBUG @@ -154,7 +155,7 @@ public: } if (interestingType == false) return false; - if (mBoundsSlop.contains(rect) || + if (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 && @@ -176,15 +177,15 @@ public: // 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 + (mIsOpaque && mAllOpaque)) && +#endif mLastAll.isEmpty() == false) mDrawnOver.op(rect, SkRegion::kUnion_Op); } else { // FIXME -// sometimes the text is not drawn entirely inside the focus area, even though +// 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 focusable link +// 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 ) @@ -201,7 +202,7 @@ public: } return false; } - + SkIRect mBounds; SkIRect mBoundsSlop; SkRegion mDrawnOver; @@ -257,7 +258,7 @@ public: SkCanvas::drawSprite(bitmap, left, top, paint); } - virtual void drawText(const void* text, size_t byteLength, SkScalar x, + virtual void drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint) { mBounder.setEmpty(); mBounder.setType(CommonCheck::kDrawGlyph_Type); @@ -265,7 +266,7 @@ public: mBounder.doRect(CommonCheck::kDrawText_Type); } - virtual void drawPosText(const void* text, size_t byteLength, + virtual void drawPosText(const void* text, size_t byteLength, const SkPoint pos[], const SkPaint& paint) { mBounder.setEmpty(); mBounder.setType(CommonCheck::kDrawGlyph_Type); @@ -294,8 +295,8 @@ public: mBounder.doRect(CommonCheck::kDrawPosTextH_Type); } - virtual void drawTextOnPath(const void* text, size_t byteLength, - const SkPath& path, const SkMatrix* matrix, + virtual void drawTextOnPath(const void* text, size_t byteLength, + const SkPath& path, const SkMatrix* matrix, const SkPaint& paint) { mBounder.setEmpty(); mBounder.setType(CommonCheck::kDrawGlyph_Type); @@ -307,7 +308,7 @@ public: mBounder.setType(CommonCheck::kDrawPicture_Type); SkCanvas::drawPicture(picture); } - + virtual int saveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags) { int depth = SkCanvas::saveLayer(bounds, paint, flags); @@ -326,7 +327,7 @@ public: } SkCanvas::restore(); } - + int mTransparentLayer; CommonCheck& mBounder; }; @@ -337,20 +338,20 @@ and returns via center() the optimal amount to scroll in x to display the paragraph of text. The caller of CenterCheck has configured (but not allocated) a bitmap -the height and three times the width of the view. The picture is drawn centered -in the bitmap, so text that would be revealed, if the view was scrolled up to +the height and three times the width of the view. The picture is drawn centered +in the bitmap, so text that would be revealed, if the view was scrolled up to a view-width to the left or right, is considered. */ class CenterCheck : public CommonCheck { public: - CenterCheck(int x, int y, int width) : mX(x), mY(y), + CenterCheck(int x, int y, int width) : mX(x), mY(y), mHitLeft(x), mHitRight(x), mMostLeft(INT_MAX), mMostRight(-INT_MAX), mViewLeft(width), mViewRight(width << 1) { - mHit.set(x - CENTER_SLOP, y - CENTER_SLOP, + mHit.set(x - CENTER_SLOP, y - CENTER_SLOP, x + CENTER_SLOP, y + CENTER_SLOP); mPartial.setEmpty(); } - + int center() { doRect(); // process the final line of text /* If the touch coordinates aren't near any text, return 0 */ @@ -381,12 +382,12 @@ public: center = 0; // paragraph is already fully visible #endif } - DBG_NAV_LOGD("scroll: leftOver=%d rightOver=%d center=%d", + DBG_NAV_LOGD("scroll: leftOver=%d rightOver=%d center=%d", leftOver, rightOver, center); return center; } - -protected: + +protected: virtual bool onIRect(const SkIRect& rect) { if (joinGlyphs(rect)) // assembles glyphs into a text string return false; @@ -394,9 +395,9 @@ protected: return false; /* Text on one line may be broken into several parts. Reassemble the text into a rectangle before considering it. */ - if (rect.fTop < mPartial.fBottom && rect.fBottom > + if (rect.fTop < mPartial.fBottom && rect.fBottom > mPartial.fTop && mPartial.fRight + CENTER_SLOP >= rect.fLeft) { - DBG_NAV_LOGD("join mPartial=(%d, %d, %d, %d) rect=(%d, %d, %d, %d)", + DBG_NAV_LOGD("join mPartial=(%d, %d, %d, %d) rect=(%d, %d, %d, %d)", mPartial.fLeft, mPartial.fTop, mPartial.fRight, mPartial.fBottom, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom); mPartial.join(rect); @@ -406,11 +407,11 @@ protected: doRect(); // process the previous line of text mPartial = rect; return false; - } - + } + void doRect() { - /* Record the outer bounds of the lines of text that was 'hit' by the + /* Record the outer bounds of the lines of text that was 'hit' by the touch coordinates, given some slop */ if (SkIRect::Intersects(mPartial, mHit)) { if (mHitLeft > mPartial.fLeft) @@ -439,10 +440,10 @@ protected: mMostLeft = leftOver; if (mMostRight < rightOver) mMostRight = rightOver; - DBG_NAV_LOGD("leftOver=%d rightOver=%d mMostLeft=%d mMostRight=%d", + DBG_NAV_LOGD("leftOver=%d rightOver=%d mMostLeft=%d mMostRight=%d", leftOver, rightOver, mMostLeft, mMostRight); } - + static const int CENTER_SLOP = 10; // space between text parts and lines /* const */ SkIRect mHit; // sloppy hit rectangle SkIRect mPartial; // accumulated text bounds, per line @@ -463,7 +464,7 @@ public: } // 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 +// 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, const SkMatrix& , const SkPaint& ) { @@ -490,14 +491,14 @@ public: mMinX = mMinJiggle = abs(delta); mMaxWidth = width + mMinX; } - + int jiggle() { if (mMinJiggle > mMaxJiggle) return mDelta; int avg = (mMinJiggle + mMaxJiggle + 1) >> 1; return mDelta < 0 ? -avg : avg; } - + virtual bool onIRect(const SkIRect& rect) { if (joinGlyphs(rect)) return false; @@ -530,14 +531,45 @@ public: int mMaxWidth; }; -bool CachedRoot::adjustForScroll(BestData* best, CachedFrame::Direction direction, +class RingCheck : public CommonCheck { +public: + RingCheck(const WTF::Vector<WebCore::IntRect>& rings, + const WebCore::IntPoint& location) : mSuccess(true) { + const WebCore::IntRect* r; + for (r = rings.begin(); r != rings.end(); r++) { + SkIRect fatter = {r->x(), r->y(), r->right(), r->bottom()}; + fatter.inset(-CURSOR_RING_HIT_TEST_RADIUS, -CURSOR_RING_HIT_TEST_RADIUS); + DBG_NAV_LOGD("fat=(%d,%d,r=%d,b=%d)", fatter.fLeft, fatter.fTop, + fatter.fRight, fatter.fBottom); + mRings.op(fatter, SkRegion::kUnion_Op); + } + DBG_NAV_LOGD("translate=(%d,%d)", -location.x(), -location.y()); + mRings.translate(-location.x(), -location.y()); + } + + virtual bool onIRect(const SkIRect& rect) { + if (mSuccess && mType == kDrawGlyph_Type) { + DBG_NAV_LOGD("contains (%d,%d,r=%d,b=%d) == %s", rect.fLeft, rect.fTop, + rect.fRight, rect.fBottom, mRings.contains(rect) ? "true" : + "false"); + mSuccess &= mRings.contains(rect); + } + return false; + } + + bool success() { return mSuccess; } + SkRegion mRings; + bool mSuccess; +}; + +bool CachedRoot::adjustForScroll(BestData* best, CachedFrame::Direction direction, WebCore::IntPoint* scrollPtr, bool findClosest) -{ +{ WebCore::IntRect newOutset; const CachedNode* newNode = best->mNode; // see if there's a middle node - // if the middle node is in the visited list, - // or if none was computed and the newNode is in the visited list, + // if the middle node is in the visited list, + // or if none was computed and the newNode is in the visited list, // treat result as NULL if (newNode != NULL && findClosest) { if (best->bounds().intersects(mHistory->mPriorBounds) == false && @@ -547,13 +579,13 @@ bool CachedRoot::adjustForScroll(BestData* best, CachedFrame::Direction directio innerMove(document(), best, direction, scrollPtr, false); return true; } - newNode->focusRingBounds(&newOutset); + newNode->cursorRingBounds(&newOutset); } int delta; bool newNodeInView = scrollDelta(newOutset, direction, &delta); - if (delta && scrollPtr && (newNode == NULL || newNodeInView == false || + if (delta && scrollPtr && (newNode == NULL || newNodeInView == false || (best->mNavOutside && best->mWorkingOutside))) - *scrollPtr = WebCore::IntPoint(direction & UP_DOWN ? 0 : delta, + *scrollPtr = WebCore::IntPoint(direction & UP_DOWN ? 0 : delta, direction & UP_DOWN ? delta : 0); return false; } @@ -562,14 +594,14 @@ bool CachedRoot::adjustForScroll(BestData* best, CachedFrame::Direction directio int CachedRoot::checkForCenter(int x, int y) const { int width = mViewBounds.width(); - CenterCheck centerCheck(x + width - mViewBounds.x(), y - mViewBounds.y(), + CenterCheck centerCheck(x + width - mViewBounds.x(), y - mViewBounds.y(), width); BoundsCanvas checker(¢erCheck); SkBitmap bitmap; bitmap.setConfig(SkBitmap::kARGB_8888_Config, width * 3, mViewBounds.height()); checker.setBitmapDevice(bitmap); - checker.translate(SkIntToScalar(width - mViewBounds.x()), + checker.translate(SkIntToScalar(width - mViewBounds.x()), SkIntToScalar(-mViewBounds.y())); checker.drawPicture(*mPicture); return centerCheck.center(); @@ -585,25 +617,45 @@ void CachedRoot::checkForJiggle(int* xDeltaPtr) const bitmap.setConfig(SkBitmap::kARGB_8888_Config, mViewBounds.width() + absDelta, mViewBounds.height()); checker.setBitmapDevice(bitmap); - checker.translate(SkIntToScalar(-mViewBounds.x() - + checker.translate(SkIntToScalar(-mViewBounds.x() - (xDelta < 0 ? xDelta : 0)), SkIntToScalar(-mViewBounds.y())); checker.drawPicture(*mPicture); *xDeltaPtr = jiggleCheck.jiggle(); } +bool CachedRoot::checkRings(const WTF::Vector<WebCore::IntRect>& rings, + const WebCore::IntRect& bounds) const +{ + if (!mPicture) + return false; + RingCheck ringCheck(rings, bounds.location()); + BoundsCanvas checker(&ringCheck); + SkBitmap bitmap; + bitmap.setConfig(SkBitmap::kARGB_8888_Config, bounds.width(), + bounds.height()); + checker.setBitmapDevice(bitmap); + checker.translate(SkIntToScalar(-bounds.x()), SkIntToScalar(-bounds.y())); + checker.drawPicture(*mPicture); + DBG_NAV_LOGD("bounds=(%d,%d,r=%d,b=%d) success=%s", + bounds.x(), bounds.y(), bounds.right(), bounds.bottom(), + ringCheck.success() ? "true" : "false"); + return ringCheck.success(); +} + const CachedNode* CachedRoot::findAt(const WebCore::IntRect& rect, - const CachedFrame** framePtr, int* x, int* y) const + const CachedFrame** framePtr, int* x, int* y, bool checkForHidden) const { int best = INT_MAX; bool inside = false; (const_cast<CachedRoot*>(this))->resetClippedOut(); const CachedNode* directHit = NULL; - const CachedNode* node = findBestAt(rect, &best, &inside, &directHit, framePtr, x, y); - DBG_NAV_LOGD("node=%d (%p)", node == NULL ? 0 : node->index(), + const CachedNode* node = findBestAt(rect, &best, &inside, &directHit, + framePtr, x, y, checkForHidden); + DBG_NAV_LOGD("node=%d (%p)", node == NULL ? 0 : node->index(), node == NULL ? NULL : node->nodePointer()); if (node == NULL) { node = findBestHitAt(rect, &best, framePtr, x, y); - DBG_NAV_LOGD("node=%d (%p)", node == NULL ? 0 : node->index(), + DBG_NAV_LOGD("node=%d (%p)", node == NULL ? 0 : node->index(), node == NULL ? NULL : node->nodePointer()); } if (node == NULL) { @@ -613,13 +665,19 @@ const CachedNode* CachedRoot::findAt(const WebCore::IntRect& rect, return node; } -WebCore::IntPoint CachedRoot::focusLocation() const +WebCore::IntPoint CachedRoot::cursorLocation() const { const WebCore::IntRect& bounds = mHistory->mNavBounds; - return WebCore::IntPoint(bounds.x() + (bounds.width() >> 1), + return WebCore::IntPoint(bounds.x() + (bounds.width() >> 1), bounds.y() + (bounds.height() >> 1)); } +WebCore::IntPoint CachedRoot::focusLocation() const +{ + return WebCore::IntPoint(mFocusBounds.x() + (mFocusBounds.width() >> 1), + mFocusBounds.y() + (mFocusBounds.height() >> 1)); +} + // These reset the values because we only want to get the selection the first time. // After that, the selection is no longer accurate. int CachedRoot::getAndResetSelectionEnd() @@ -636,14 +694,27 @@ int CachedRoot::getAndResetSelectionStart() return start; } -void CachedRoot::getSimulatedMousePosition(WebCore::IntPoint* point) +void CachedRoot::getSimulatedMousePosition(WebCore::IntPoint* point) const { #ifndef NDEBUG ASSERT(CachedFrame::mDebug.mInUse); #endif const WebCore::IntRect& mouseBounds = mHistory->mMouseBounds; - point->setX(mouseBounds.x() + (mouseBounds.width() >> 1)); - point->setY(mouseBounds.y() + (mouseBounds.height() >> 1)); + int x = mouseBounds.x(); + int y = mouseBounds.y(); + int width = mouseBounds.width(); + int height = mouseBounds.height(); + point->setX(x + (width >> 1)); // default to box center + point->setY(y + (height >> 1)); + const CachedNode* cursor = currentCursor(); + if (cursor && cursor->bounds().contains(mHistory->mMouseBounds)) { + if (cursor->isTextField()) // if text field, return end of line + point->setX(x + width - 1); + else if (cursor->isTextArea()) { // if text area, return start + point->setX(x + 1); + point->setY(y + 1); + } + } #if DEBUG_NAV_UI && !defined BROWSER_DEBUG const WebCore::IntRect& navBounds = mHistory->mNavBounds; LOGD("%s mHistory->mNavBounds={%d,%d,%d,%d} " @@ -654,7 +725,7 @@ void CachedRoot::getSimulatedMousePosition(WebCore::IntPoint* point) #endif } -void CachedRoot::init(WebCore::Frame* frame, CachedHistory* history) +void CachedRoot::init(WebCore::Frame* frame, CachedHistory* history) { CachedFrame::init(this, -1, frame); reset(); @@ -671,18 +742,19 @@ bool CachedRoot::innerDown(const CachedNode* test, BestData* bestData) const mScrolledBounds.setHeight(mScrolledBounds.height() + mMaxYScroll); int testTop = mScrolledBounds.y(); int viewBottom = mViewBounds.bottom(); - if (mFocusBounds.isEmpty() == false && - mFocusBounds.bottom() > viewBottom && viewBottom < mContents.height()) + const WebCore::IntRect& navBounds = mHistory->mNavBounds; + if (navBounds.isEmpty() == false && + navBounds.bottom() > viewBottom && viewBottom < mContents.height()) return false; - if (mHistory->mNavBounds.isEmpty() == false) { - int navTop = mHistory->mNavBounds.y(); + if (navBounds.isEmpty() == false) { + int navTop = navBounds.y(); int scrollBottom; if (testTop < navTop && navTop < (scrollBottom = mScrolledBounds.bottom())) { mScrolledBounds.setHeight(scrollBottom - navTop); mScrolledBounds.setY(navTop); } } - frameDown(test, NULL, bestData, currentFocus()); + frameDown(test, NULL, bestData, currentCursor()); return true; } @@ -695,62 +767,60 @@ bool CachedRoot::innerLeft(const CachedNode* test, BestData* bestData) const mScrolledBounds.setWidth(mScrolledBounds.width() + mMaxXScroll); int testRight = mScrolledBounds.right(); int viewLeft = mViewBounds.x(); - if (mFocusBounds.isEmpty() == false && - mFocusBounds.x() < viewLeft && viewLeft > mContents.x()) + const WebCore::IntRect& navBounds = mHistory->mNavBounds; + if (navBounds.isEmpty() == false && + navBounds.x() < viewLeft && viewLeft > mContents.x()) return false; - if (mHistory->mNavBounds.isEmpty() == false) { - int navRight = mHistory->mNavBounds.right(); + if (navBounds.isEmpty() == false) { + int navRight = navBounds.right(); int scrollLeft; if (testRight > navRight && navRight > (scrollLeft = mScrolledBounds.x())) mScrolledBounds.setWidth(navRight - scrollLeft); } - frameLeft(test, NULL, bestData, currentFocus()); + frameLeft(test, NULL, bestData, currentCursor()); return true; } -void CachedRoot::innerMove(const CachedNode* node, BestData* bestData, +void CachedRoot::innerMove(const CachedNode* node, BestData* bestData, Direction direction, WebCore::IntPoint* scroll, bool firstCall) { bestData->reset(); - mFocusChild = false; - bool outOfFocus = mFocus < 0; - bool firstTime = mHistory->didFirstLayout() && outOfFocus; + bool outOfCursor = mCursorIndex == CURSOR_CLEARED; #if DEBUG_NAV_UI && !defined BROWSER_DEBUG - LOGD("%s mHistory->didFirstLayout()=%s && mFocus=%d\n", __FUNCTION__, - mHistory->didFirstLayout() ? "true" : "false", mFocus); + LOGD("%s mHistory->didFirstLayout()=%s && mCursorIndex=%d\n", __FUNCTION__, + mHistory->didFirstLayout() ? "true" : "false", mCursorIndex); #endif - if (firstTime) + if (mHistory->didFirstLayout() && mCursorIndex < CURSOR_SET) { mHistory->reset(); - const CachedNode* focus = currentFocus(); - mHistory->setWorking(direction, focus, mViewBounds); - mFocusBounds = WebCore::IntRect(0, 0, 0, 0); - if (focus != NULL) - focus->getBounds(&mFocusBounds); + outOfCursor = true; + } + const CachedNode* cursor = currentCursor(); + mHistory->setWorking(direction, cursor, mViewBounds); bool findClosest = false; if (mScrollOnly == false) { switch (direction) { case LEFT: - if (outOfFocus) - mHistory->mNavBounds = WebCore::IntRect(mViewBounds.right(), + if (outOfCursor) + mHistory->mNavBounds = WebCore::IntRect(mViewBounds.right(), mViewBounds.y(), 1, mViewBounds.height()); findClosest = innerLeft(node, bestData); break; - case RIGHT: - if (outOfFocus) + case RIGHT: + if (outOfCursor) mHistory->mNavBounds = WebCore::IntRect(mViewBounds.x() - 1, mViewBounds.y(), 1, mViewBounds.height()); findClosest = innerRight(node, bestData); break; case UP: - if (outOfFocus) - mHistory->mNavBounds = WebCore::IntRect(mViewBounds.x(), + if (outOfCursor) + mHistory->mNavBounds = WebCore::IntRect(mViewBounds.x(), mViewBounds.bottom(), mViewBounds.width(), 1); findClosest = innerUp(node, bestData); break; case DOWN: - if (outOfFocus) - mHistory->mNavBounds = WebCore::IntRect(mViewBounds.x(), + if (outOfCursor) + mHistory->mNavBounds = WebCore::IntRect(mViewBounds.x(), mViewBounds.y() - 1, mViewBounds.width(), 1); findClosest = innerDown(node, bestData); break; @@ -766,7 +836,7 @@ void CachedRoot::innerMove(const CachedNode* node, BestData* bestData, return; if (bestData->mNode != NULL) { mHistory->addToVisited(bestData->mNode, direction); - mHistory->mNavBounds = mFocusBounds = bestData->mNodeBounds; + mHistory->mNavBounds = bestData->mNodeBounds; mHistory->mMouseBounds = bestData->mMouseBounds; } else if (scroll->x() != 0 || scroll->y() != 0) { WebCore::IntRect newBounds = mHistory->mNavBounds; @@ -795,18 +865,19 @@ bool CachedRoot::innerRight(const CachedNode* test, BestData* bestData) const mScrolledBounds.setWidth(mScrolledBounds.width() + mMaxXScroll); int testLeft = mScrolledBounds.x(); int viewRight = mViewBounds.right(); - if (mFocusBounds.isEmpty() == false && - mFocusBounds.right() > viewRight && viewRight < mContents.width()) + const WebCore::IntRect& navBounds = mHistory->mNavBounds; + if (navBounds.isEmpty() == false && + navBounds.right() > viewRight && viewRight < mContents.width()) return false; - if (mHistory->mNavBounds.isEmpty() == false) { - int navLeft = mHistory->mNavBounds.x(); + if (navBounds.isEmpty() == false) { + int navLeft = navBounds.x(); int scrollRight; if (testLeft < navLeft && navLeft < (scrollRight = mScrolledBounds.right())) { mScrolledBounds.setWidth(scrollRight - navLeft); mScrolledBounds.setX(navLeft); } } - frameRight(test, NULL, bestData, currentFocus()); + frameRight(test, NULL, bestData, currentCursor()); return true; } @@ -819,16 +890,17 @@ bool CachedRoot::innerUp(const CachedNode* test, BestData* bestData) const mScrolledBounds.setHeight(mScrolledBounds.height() + mMaxYScroll); int testBottom = mScrolledBounds.bottom(); int viewTop = mViewBounds.y(); - if (mFocusBounds.isEmpty() == false && - mFocusBounds.y() < viewTop && viewTop > mContents.y()) + const WebCore::IntRect& navBounds = mHistory->mNavBounds; + if (navBounds.isEmpty() == false && + navBounds.y() < viewTop && viewTop > mContents.y()) return false; - if (mHistory->mNavBounds.isEmpty() == false) { - int navBottom = mHistory->mNavBounds.bottom(); + if (navBounds.isEmpty() == false) { + int navBottom = navBounds.bottom(); int scrollTop; if (testBottom > navBottom && navBottom > (scrollTop = mScrolledBounds.y())) mScrolledBounds.setHeight(navBottom - scrollTop); } - frameUp(test, NULL, bestData, currentFocus()); + frameUp(test, NULL, bestData, currentCursor()); return true; } @@ -856,7 +928,7 @@ bool CachedRoot::maskIfHidden(BestData* best) const if (bestNode->isUnclipped()) return false; // given the picture matching this nav cache - // create an SkBitmap with dimensions of the focus intersected w/ extended view + // create an SkBitmap with dimensions of the cursor intersected w/ extended view const WebCore::IntRect& nodeBounds = bestNode->getBounds(); WebCore::IntRect bounds = nodeBounds; bounds.intersect(mScrolledBounds); @@ -870,7 +942,7 @@ bool CachedRoot::maskIfHidden(BestData* best) const marginBounds.intersect(mScrolledBounds); BoundsCheck boundsCheck; BoundsCanvas checker(&boundsCheck); - boundsCheck.mBounds.set(leftMargin, topMargin, + boundsCheck.mBounds.set(leftMargin, topMargin, leftMargin + bounds.width(), topMargin + bounds.height()); boundsCheck.mBoundsSlop = boundsCheck.mBounds; boundsCheck.mBoundsSlop.inset(-kSlop, -kSlop); @@ -878,8 +950,8 @@ bool CachedRoot::maskIfHidden(BestData* best) const bitmap.setConfig(SkBitmap::kARGB_8888_Config, marginBounds.width(), marginBounds.height()); checker.setBitmapDevice(bitmap); - // insert probes to be called when the data corresponding to this focus ring is drawn - // need to know if focus ring was generated by text, image, or parent (like div) + // insert probes to be called when the data corresponding to this ring is drawn + // need to know if ring was generated by text, image, or parent (like div) // ? need to know (like imdb menu bar) to give up sometimes (when?) checker.translate(SkIntToScalar(leftMargin - bounds.x()), SkIntToScalar(topMargin - bounds.y())); @@ -938,17 +1010,17 @@ bool CachedRoot::maskIfHidden(BestData* best) const #if DEBUG_NAV_UI && !defined BROWSER_DEBUG const SkIRect& modded = boundsCheck.mBounds; LOGD("%s partially occluded node:%p (%d) old:{%d,%d,%d,%d} new:{%d,%d,%d,%d}\n", - __FUNCTION__, best->mNode, best->mNode->index(), + __FUNCTION__, best->mNode, best->mNode->index(), orig.fLeft, orig.fTop, orig.fRight, orig.fBottom, base.fLeft, base.fTop, base.fRight, base.fBottom); #endif - best->mMouseBounds = WebCore::IntRect(bounds.x() + base.fLeft - kMargin, + best->mMouseBounds = WebCore::IntRect(bounds.x() + base.fLeft - kMargin, bounds.y() + base.fTop - kMargin, base.width(), base.height()); } return false; } -const CachedNode* CachedRoot::moveFocus(Direction direction, const CachedFrame** framePtr, +const CachedNode* CachedRoot::moveCursor(Direction direction, const CachedFrame** framePtr, WebCore::IntPoint* scroll) { #ifndef NDEBUG @@ -977,7 +1049,6 @@ void CachedRoot::reset() mMaxXScroll = mMaxYScroll = 0; mSelectionStart = mSelectionEnd = -1; mScrollOnly = false; - mFocusBounds = WebCore::IntRect(0, 0, 0, 0); } bool CachedRoot::scrollDelta(WebCore::IntRect& newOutset, Direction direction, int* delta) @@ -986,13 +1057,13 @@ bool CachedRoot::scrollDelta(WebCore::IntRect& newOutset, Direction direction, i case LEFT: *delta = -mMaxXScroll; return newOutset.x() >= mViewBounds.x(); - case RIGHT: + case RIGHT: *delta = mMaxXScroll; return newOutset.right() <= mViewBounds.right(); case UP: *delta = -mMaxYScroll; return newOutset.y() >= mViewBounds.y(); - case DOWN: + case DOWN: *delta = mMaxYScroll; return newOutset.bottom() <= mViewBounds.bottom(); default: @@ -1004,46 +1075,62 @@ bool CachedRoot::scrollDelta(WebCore::IntRect& newOutset, Direction direction, i void CachedRoot::setCachedFocus(CachedFrame* frame, CachedNode* node) { -#if !defined NDEBUG - ASSERT(CachedFrame::mDebug.mInUse); -#endif -#if DEBUG_NAV_UI && !defined BROWSER_DEBUG - const CachedNode* focus = currentFocus(); - WebCore::IntRect bounds; - if (focus) - bounds = focus->bounds(); - LOGD("%s old focus %d (nodePointer=%p) bounds={%d,%d,%d,%d}\n", __FUNCTION__, - focus ? focus->index() : 0, - focus ? focus->nodePointer() : NULL, bounds.x(), bounds.y(), - bounds.width(), bounds.height()); -#endif - clearFocus(); + mFocusBounds = WebCore::IntRect(0, 0, 0, 0); if (node == NULL) return; node->setIsFocus(true); - ASSERT(node->isFrame() == false); + mFocusBounds = node->bounds(); frame->setFocusIndex(node - frame->document()); - ASSERT(frame->focusIndex() > 0 && frame->focusIndex() < (int) frame->size()); CachedFrame* parent; while ((parent = frame->parent()) != NULL) { parent->setFocusIndex(frame->indexInParent()); frame = parent; } #if DEBUG_NAV_UI && !defined BROWSER_DEBUG - focus = currentFocus(); - bounds = WebCore::IntRect(0, 0, 0, 0); + const CachedNode* focus = currentFocus(); + WebCore::IntRect bounds = WebCore::IntRect(0, 0, 0, 0); if (focus) bounds = focus->bounds(); LOGD("%s new focus %d (nodePointer=%p) bounds={%d,%d,%d,%d}\n", __FUNCTION__, focus ? focus->index() : 0, - focus ? focus->nodePointer() : NULL, bounds.x(), bounds.y(), + focus ? focus->nodePointer() : NULL, bounds.x(), bounds.y(), bounds.width(), bounds.height()); #endif } -void CachedRoot::setupScrolledBounds() const +void CachedRoot::setCursor(CachedFrame* frame, CachedNode* node) { - mScrolledBounds = mViewBounds; +#if DEBUG_NAV_UI && !defined BROWSER_DEBUG + const CachedNode* cursor = currentCursor(); + WebCore::IntRect bounds; + if (cursor) + bounds = cursor->bounds(); + LOGD("%s old cursor %d (nodePointer=%p) bounds={%d,%d,%d,%d}\n", __FUNCTION__, + cursor ? cursor->index() : 0, + cursor ? cursor->nodePointer() : NULL, bounds.x(), bounds.y(), + bounds.width(), bounds.height()); +#endif + clearCursor(); + if (node == NULL) + return; + node->setIsCursor(true); + node->show(); + frame->setCursorIndex(node - frame->document()); + CachedFrame* parent; + while ((parent = frame->parent()) != NULL) { + parent->setCursorIndex(frame->indexInParent()); + frame = parent; + } +#if DEBUG_NAV_UI && !defined BROWSER_DEBUG + cursor = currentCursor(); + bounds = WebCore::IntRect(0, 0, 0, 0); + if (cursor) + bounds = cursor->bounds(); + LOGD("%s new cursor %d (nodePointer=%p) bounds={%d,%d,%d,%d}\n", __FUNCTION__, + cursor ? cursor->index() : 0, + cursor ? cursor->nodePointer() : NULL, bounds.x(), bounds.y(), + bounds.width(), bounds.height()); +#endif } #if DUMP_NAV_CACHE @@ -1058,7 +1145,7 @@ void CachedRoot::setupScrolledBounds() const CachedRoot* CachedRoot::Debug::base() const { CachedRoot* nav = (CachedRoot*) ((char*) this - OFFSETOF(CachedRoot, mDebug)); - return nav; + return nav; } void CachedRoot::Debug::print() const @@ -1071,10 +1158,8 @@ void CachedRoot::Debug::print() const CachedRoot* b = base(); b->CachedFrame::mDebug.print(); b->mHistory->mDebug.print(b); - DEBUG_PRINT_RECT(mFocusBounds); - DUMP_NAV_LOGD("// int mMaxXScroll=%d, mMaxYScroll=%d;\n", + DUMP_NAV_LOGD("// int mMaxXScroll=%d, mMaxYScroll=%d;\n", b->mMaxXScroll, b->mMaxYScroll); - DEBUG_PRINT_BOOL(mFocusChild); #ifdef DUMP_NAV_CACHE_USING_PRINTF if (gNavCacheLogFile) fclose(gNavCacheLogFile); diff --git a/WebKit/android/nav/CachedRoot.h b/WebKit/android/nav/CachedRoot.h index ab1b823..38ab2d8 100644 --- a/WebKit/android/nav/CachedRoot.h +++ b/WebKit/android/nav/CachedRoot.h @@ -27,8 +27,9 @@ #define CachedRoot_H #include "CachedFrame.h" -#include "IntPoint.h" +#include "IntRect.h" #include "SkPicture.h" +#include "wtf/Vector.h" class SkRect; @@ -43,20 +44,19 @@ public: bool findClosest); int checkForCenter(int x, int y) const; void checkForJiggle(int* ) const; + bool checkRings(const WTF::Vector<WebCore::IntRect>& rings, + const WebCore::IntRect& bounds) const; + WebCore::IntPoint cursorLocation() const; int documentHeight() { return mContents.height(); } int documentWidth() { return mContents.width(); } const CachedNode* findAt(const WebCore::IntRect& , const CachedFrame** , - int* x, int* y) const; + int* x, int* y, bool checkForHidden) const; const WebCore::IntRect& focusBounds() const { return mFocusBounds; } - bool focusChild() const { return mFocusChild; } WebCore::IntPoint focusLocation() const; - int generation() const { return mGeneration; } SkPicture* getPicture() { return mPicture; } int getAndResetSelectionEnd(); int getAndResetSelectionStart(); -// const WebCore::IntRect& navClipBounds() const { return mClippedBounds; } - void getSimulatedMousePosition(WebCore::IntPoint* ); -// bool hasNavClipBounds() { return mClippedBounds.isEmpty() == false; } + void getSimulatedMousePosition(WebCore::IntPoint* ) const; void init(WebCore::Frame* , CachedHistory* ); bool innerDown(const CachedNode* , BestData* ) const; bool innerLeft(const CachedNode* , BestData* ) const; @@ -66,39 +66,34 @@ public: bool innerUp(const CachedNode* , BestData* ) const; WebCore::String imageURI(int x, int y) const; bool maskIfHidden(BestData* ) const; - const CachedNode* moveFocus(Direction , const CachedFrame** , WebCore::IntPoint* scroll); + const CachedNode* moveCursor(Direction , const CachedFrame** , WebCore::IntPoint* scroll); void reset(); -// void resetNavClipBounds() { mClippedBounds = WebCore::IntRect(-1, -1, 0, 0); } CachedHistory* rootHistory() const { return mHistory; } - bool scrollDelta(WebCore::IntRect& focusRingBounds, Direction , int* delta); + bool scrollDelta(WebCore::IntRect& cursorRingBounds, Direction , int* delta); const WebCore::IntRect& scrolledBounds() const { return mScrolledBounds; } + void setCursor(CachedFrame* , CachedNode* ); void setCachedFocus(CachedFrame* , CachedNode* ); void setFocusBounds(const WebCore::IntRect& r) { mFocusBounds = r; } - void setGeneration(int generation) { mGeneration = generation; } void setTextGeneration(int textGeneration) { mTextGeneration = textGeneration; } - void setFocusChild(bool state) const { mFocusChild = state; } void setMaxScroll(int x, int y) { mMaxXScroll = x; mMaxYScroll = y; } -// void setNavClipBounds(const WebCore::IntRect& r) { mClippedBounds = r; } void setPicture(SkPicture* picture) { mPicture = picture; } void setScrollOnly(bool state) { mScrollOnly = state; } void setSelection(int start, int end) { mSelectionStart = start; mSelectionEnd = end; } - void setupScrolledBounds() const; + void setupScrolledBounds() const { mScrolledBounds = mViewBounds; } void setVisibleRect(const WebCore::IntRect& r) { mViewBounds = r; } int textGeneration() const { return mTextGeneration; } int width() const { return mPicture ? mPicture->width() : 0; } private: CachedHistory* mHistory; SkPicture* mPicture; - WebCore::IntRect mFocusBounds; // chosen focus ring + WebCore::IntRect mFocusBounds; // dom text input focus node bounds mutable WebCore::IntRect mScrolledBounds; // view bounds + amount visible as result of scroll - int mGeneration; int mTextGeneration; int mMaxXScroll; int mMaxYScroll; // These two are ONLY used when the tree is rebuilt and the focus is a textfield/area int mSelectionStart; int mSelectionEnd; - mutable bool mFocusChild; // temporary state set if walked nodes are children of focus bool mScrollOnly; #if DUMP_NAV_CACHE public: diff --git a/WebKit/android/nav/WebView.cpp b/WebKit/android/nav/WebView.cpp index 0657a81..cf1e486 100644 --- a/WebKit/android/nav/WebView.cpp +++ b/WebKit/android/nav/WebView.cpp @@ -69,265 +69,8 @@ #include <JNIHelp.h> #include <jni.h> -#define REPLAY_BUFFER_SIZE 4096 - namespace android { -struct CommonParams { - enum Trigger { - NoData, - ClearFocusParams, - FirstMoveFocusParams, - MoveFocusParams, - MotionUpParams - } m_trigger; - int m_generation; -}; - -struct CacheParams { - void setFocus(const CachedNode* node, - const CachedFrame* frame, const CachedRoot* root, - const WebCore::IntPoint& focusLocation) - { - m_node = (WebCore::Node*) (node ? node->nodePointer() : 0); - m_frame = (WebCore::Frame*) (node ? frame->framePointer() : 0); - m_x = focusLocation.x(); - m_y = focusLocation.y(); - } - - WebCore::Node* m_node; - WebCore::Frame* m_frame; - int m_x; - int m_y; -}; - -struct ClearFocusParams { - CommonParams d; - CacheParams c; - int m_x; - int m_y; -}; - -struct MotionUpParams { - CommonParams d; - int m_x; - int m_y; - int m_slop; - bool m_isClick; -}; - -struct FirstMoveFocusParams { - CommonParams d; - int m_keyCode; - int m_count; - bool m_ignoreScroll; -}; - -struct MoveFocusParams { - FirstMoveFocusParams d; - CacheParams c; - void* m_sentFocus; - WebCore::IntRect m_sentBounds; - WebCore::IntRect m_visibleRect; - CachedHistory m_history; // FIXME: make this a subset - int m_xMax; - int m_yMax; -}; - -typedef MoveFocusParams LargestParams; - -#if DEBUG_NAV_UI -static const char* TriggerNames[] = { - "*** no data ! ***", - "clearFocus", - "firstMoveFocus", - "moveFocus", - "motionUp" -}; -#endif - -class FocusReplay { -public: -FocusReplay() : m_start(m_buffer), m_end(m_buffer), m_lastGeneration(0) -{ -} - -// find the most recent common data -void add(const CommonParams& data, size_t len) -{ - DBG_NAV_LOGD("m_start=%d m_end=%d trigger=%s moveGeneration=%d", m_start - m_buffer, - m_end - m_buffer, TriggerNames[data.m_trigger], data.m_generation); - m_lastGeneration = data.m_generation; - char* limit = m_buffer + sizeof(m_buffer); - int used = m_end - m_start; - if (used < 0) - used += sizeof(m_buffer); - int needed = (int) len - ((int) sizeof(m_buffer) - used); - if (needed >= 0) - reclaim(++needed); - if (m_end + len <= limit) { - memcpy(m_end, (void*) &data, len); - m_end += len; - DBG_NAV_LOGD("m_start=%d m_end=%d", m_start - m_buffer, m_end - m_buffer); - return; - } - size_t partial = limit - m_end; - memcpy(m_end, (void*) &data, partial); - const void* remainder = (const void*) ((const char*) &data + partial); - partial = len - partial; - memcpy(m_buffer, remainder, partial); - m_end = m_buffer + partial; - DBG_NAV_LOGD("wrap m_start=%d m_end=%d", - m_start - m_buffer, m_end - m_buffer); -} - -int count() -{ - DBG_NAV_LOGD("m_start=%d m_end=%d", - m_start - m_buffer, m_end - m_buffer); - if (m_start == m_end) - return 0; - char* limit = m_buffer + sizeof(m_buffer); - char* saveStart = m_start; - int result = 0; - while (true) { - ++result; - m_start += triggerSize(); - if (m_start == m_end) - break; - if (m_start < limit) - continue; - m_start -= sizeof(m_buffer); - if (m_start == m_end) - break; - } - m_start = saveStart; - DBG_NAV_LOGD("count=%d", result); - return result; -} - -void discard(int generation) -{ - DBG_NAV_LOGD("generation=%d", generation); - LargestParams storage; - const CommonParams& params = storage.d.d; - char* pos = position(); - retrieve(&storage.d.d); - if (params.m_generation > generation) { - DBG_NAV_LOGD("params.m_generation=%d > generation=%d", - params.m_generation, generation); - rewind(pos); - DBG_NAV_LOGD("m_start=%d m_end=%d", m_start - m_buffer, m_end - m_buffer); - return; - } - LOG_ASSERT(params.m_generation == generation, "params.m_generation != generation"); - DBG_NAV_LOGD("m_start=%d m_end=%d", m_start - m_buffer, m_end - m_buffer); -} - -int lastAdd() -{ - return m_lastGeneration; -} - -char* position() -{ - return m_start; -} - -int retrieve(CommonParams* data) -{ - if (m_end == m_start) { - // changed from LOGD to LOGV, as it always fires when I click to center - // text (mrr) - LOGV("%s *** no data to retrieve (error condition) ***", __FUNCTION__); - data->m_trigger = CommonParams::NoData; - return data->m_generation = INT_MAX; - } - DBG_NAV_LOGD("m_start=%d m_end=%d", - m_start - m_buffer, m_end - m_buffer); - char* limit = m_buffer + sizeof(m_buffer); - size_t size = triggerSize(); - if (m_start < m_end) { - LOG_ASSERT((size_t) (m_end - m_start) >= size, "m_end - m_start < size"); - memcpy(data, m_start, size); - m_start += size; - } else { - int partial = limit - m_start; - if (partial > (int) size) - partial = size; - memcpy(data, m_start, partial); - m_start += partial; - void* remainder = (void*) ((char*) data + partial); - partial = size - partial; - if (partial > 0) { - memcpy(remainder, m_buffer, partial); - m_start = m_buffer + partial; - LOG_ASSERT(m_start <= m_end, "m_start > m_end"); - } - } - if (m_start == limit) { - m_start = m_buffer; - if (m_end == limit) - m_end = m_buffer; - } - DBG_NAV_LOGD("m_start=%d m_end=%d trigger=%s moveGeneration=%d", - m_start - m_buffer, m_end - m_buffer, TriggerNames[data->m_trigger], - data->m_generation); - return data->m_generation; -} - -void rewind(char* pos) -{ - m_start = pos; -} - -private: -void reclaim(int needed) -{ - DBG_NAV_LOGD("needed=%d", needed); - char* limit = m_buffer + sizeof(m_buffer); - do { - size_t size = triggerSize(); - m_start += size; - needed -= size; - if (m_start >= limit) { - m_start = m_buffer + (m_start - limit); - if (m_end == limit) - m_end = m_buffer; - } - } while (needed > 0 && m_start != m_end); - DBG_NAV_LOGD("m_start=%d m_end=%d", - m_start - m_buffer, m_end - m_buffer); -} - -size_t triggerSize() -{ - LOG_ASSERT(m_start != m_end, "m_start == m_end"); - char* limit = m_buffer + sizeof(m_buffer); - LOG_ASSERT(m_start + sizeof(CommonParams::Trigger) <= limit, "trigger not in limit"); - CommonParams::Trigger trigger; - memcpy(&trigger, m_start, sizeof(trigger)); - switch (trigger) { - case CommonParams::ClearFocusParams: - return sizeof(ClearFocusParams); - case CommonParams::FirstMoveFocusParams: - return sizeof(FirstMoveFocusParams); - case CommonParams::MoveFocusParams: - return sizeof(MoveFocusParams); - case CommonParams::MotionUpParams: - return sizeof(MotionUpParams); - default: - LOG_ASSERT(0, "trigger undefined"); - } - return 0; -} - -char m_buffer[REPLAY_BUFFER_SIZE]; -char* m_start; -char* m_end; -int m_lastGeneration; -}; // end of helper class ReplayFocus - static jfieldID gWebViewField; //------------------------------------- @@ -351,25 +94,19 @@ enum FrameCachePermission { AllowNewest }; -enum OutOfFocusFix { - DoNothing, - ClearTextEntry, - UpdateTextEntry -}; - struct JavaGlue { jobject m_obj; jmethodID m_clearTextEntry; jmethodID m_overrideLoading; + jmethodID m_sendPluginState; jmethodID m_scrollBy; - jmethodID m_sendFinalFocus; - jmethodID m_sendKitFocus; + jmethodID m_sendMoveMouse; + jmethodID m_sendMoveMouseIfLatest; jmethodID m_sendMotionUp; - jmethodID m_setFocusData; jmethodID m_getScaledMaxXScroll; jmethodID m_getScaledMaxYScroll; jmethodID m_getVisibleRect; - jmethodID m_updateTextEntry; + jmethodID m_rebuildWebTextView; jmethodID m_displaySoftKeyboard; jmethodID m_viewInvalidate; jmethodID m_viewInvalidateRect; @@ -378,8 +115,6 @@ struct JavaGlue { jfieldID m_rectTop; jmethodID m_rectWidth; jmethodID m_rectHeight; - jfieldID m_focusNode; - jmethodID m_setAll; AutoJObject object(JNIEnv* env) { return getRealObject(env, m_obj); } @@ -393,15 +128,15 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl) m_javaGlue.m_scrollBy = GetJMethod(env, clazz, "setContentScrollBy", "(IIZ)V"); m_javaGlue.m_clearTextEntry = GetJMethod(env, clazz, "clearTextEntry", "()V"); m_javaGlue.m_overrideLoading = GetJMethod(env, clazz, "overrideLoading", "(Ljava/lang/String;)V"); - m_javaGlue.m_sendFinalFocus = GetJMethod(env, clazz, "sendFinalFocus", "(IIII)V"); - m_javaGlue.m_sendKitFocus = GetJMethod(env, clazz, "sendKitFocus", "()V"); - m_javaGlue.m_sendMotionUp = GetJMethod(env, clazz, "sendMotionUp", "(IIIIIIIZZ)V"); - m_javaGlue.m_setFocusData = GetJMethod(env, clazz, "setFocusData", "(IIIIIIZ)V"); + m_javaGlue.m_sendPluginState = GetJMethod(env, clazz, "sendPluginState", "(I)V"); + m_javaGlue.m_sendMoveMouse = GetJMethod(env, clazz, "sendMoveMouse", "(IIII)V"); + m_javaGlue.m_sendMoveMouseIfLatest = GetJMethod(env, clazz, "sendMoveMouseIfLatest", "(Z)V"); + m_javaGlue.m_sendMotionUp = GetJMethod(env, clazz, "sendMotionUp", "(IIIIII)V"); m_javaGlue.m_getScaledMaxXScroll = GetJMethod(env, clazz, "getScaledMaxXScroll", "()I"); m_javaGlue.m_getScaledMaxYScroll = GetJMethod(env, clazz, "getScaledMaxYScroll", "()I"); m_javaGlue.m_getVisibleRect = GetJMethod(env, clazz, "sendOurVisibleRect", "()Landroid/graphics/Rect;"); - m_javaGlue.m_updateTextEntry = GetJMethod(env, clazz, "updateTextEntry", "()V"); - m_javaGlue.m_displaySoftKeyboard = GetJMethod(env, clazz, "displaySoftKeyboard", "()V"); + m_javaGlue.m_rebuildWebTextView = GetJMethod(env, clazz, "rebuildWebTextView", "()V"); + m_javaGlue.m_displaySoftKeyboard = GetJMethod(env, clazz, "displaySoftKeyboard", "(Z)V"); m_javaGlue.m_viewInvalidate = GetJMethod(env, clazz, "viewInvalidate", "()V"); m_javaGlue.m_viewInvalidateRect = GetJMethod(env, clazz, "viewInvalidate", "(IIII)V"); m_javaGlue.m_postInvalidateDelayed = GetJMethod(env, clazz, @@ -413,18 +148,10 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl) m_javaGlue.m_rectWidth = GetJMethod(env, rectClass, "width", "()I"); m_javaGlue.m_rectHeight = GetJMethod(env, rectClass, "height", "()I"); - // Set up class for updateFocusNode - jclass focusnodeClass = env->FindClass("android/webkit/WebView$FocusNode"); - LOG_ASSERT(focusnodeClass, "Could not find FocusNode class!"); - m_javaGlue.m_focusNode = env->GetFieldID(clazz, "mFocusNode", "Landroid/webkit/WebView$FocusNode;"); - m_javaGlue.m_setAll = GetJMethod(env, focusnodeClass, "setAll", "(ZZZZZIIIIIIIILjava/lang/String;Ljava/lang/String;I)V"); - env->DeleteLocalRef(focusnodeClass); - env->SetIntField(javaWebView, gWebViewField, (jint)this); m_viewImpl = (WebViewCore*) viewImpl; m_frameCacheUI = 0; m_navPictureUI = 0; - m_invalidNode = 0; m_generation = 0; m_heightCanMeasure = false; m_followedLink = false; @@ -436,6 +163,10 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl) m_matches = 0; m_hasCurrentLocation = false; m_isFindPaintSetUp = false; + m_pluginReceivesEvents = false; // initialization is the only time this + // variable should be set directly, all + // other changes should be made through + // setPluginReceivesEvents(bool) } ~WebView() @@ -452,33 +183,32 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl) delete m_matches; } -void clearFocus(int x, int y, bool inval) +WebViewCore* getWebViewCore() const { + return m_viewImpl; +} + +// removes the cursor altogether (e.g., when going to a new page) +void clearCursor() { - DBG_NAV_LOGD("x=%d y=%d inval=%s", x, y, - inval ? "true" : "false"); - clearTextEntry(); CachedRoot* root = getFrameCache(AllowNewer); if (!root) return; - const CachedFrame* oldFrame = 0; - const CachedNode* oldFocusNode = root->currentFocus(&oldFrame); - WebCore::IntPoint focusLocation = WebCore::IntPoint(0, 0); - setFocusData(root->generation(), 0, 0, x, y, !oldFocusNode); - sendKitFocus(); - if (oldFocusNode) { - DBG_NAV_LOG("oldFocusNode"); - focusLocation = root->focusLocation(); - root->setCachedFocus(0, 0); - if (inval) - viewInvalidate(); - } - ClearFocusParams params; - params.d.m_trigger = CommonParams::ClearFocusParams; - params.d.m_generation = m_generation; - params.c.setFocus(oldFocusNode, oldFrame, root, focusLocation); - params.m_x = x; - params.m_y = y; - m_replay.add(params.d, sizeof(params)); + DBG_NAV_LOG(""); + m_viewImpl->m_hasCursorBounds = false; + root->clearCursor(); + viewInvalidate(); +} + +// leaves the cursor where it is, but suppresses drawing it +void hideCursor() +{ + CachedRoot* root = getFrameCache(AllowNewer); + if (!root) + return; + DBG_NAV_LOG(""); + m_viewImpl->m_hasCursorBounds = false; + root->hideCursor(); + viewInvalidate(); } void clearTextEntry() @@ -499,40 +229,38 @@ void debugDump() #endif // Traverse our stored array of buttons that are in our picture, and update -// their subpictures according to their current focus state. +// their subpictures according to their current state. // Called from the UI thread. This is the one place in the UI thread where we // access the buttons stored in the WebCore thread. // hasFocus keeps track of whether the WebView has focus && windowFocus. -// If not, we do not want to draw the button in a focused or pressed state +// If not, we do not want to draw the button in a selected or pressed state void nativeRecordButtons(bool hasFocus, bool pressed, bool invalidate) { - bool focusIsButton = false; - const CachedNode* cachedFocus = 0; + bool cursorIsOnButton = false; + const CachedNode* cachedCursor = 0; // Lock the mutex, since we now share with the WebCore thread. m_viewImpl->gButtonMutex.lock(); if (m_viewImpl->m_buttons.size()) { - // Find the focused node so we can determine which node has focus, and - // therefore which state to paint them in. - // FIXME: In a future change, we should keep track of whether the focus + // FIXME: In a future change, we should keep track of whether the selection // has changed to short circuit (note that we would still need to update // if we received new buttons from the WebCore thread). - WebCore::Node* focus = 0; + WebCore::Node* cursor = 0; CachedRoot* root = getFrameCache(DontAllowNewer); if (root) { - cachedFocus = root->currentFocus(); - if (cachedFocus) - focus = (WebCore::Node*) cachedFocus->nodePointer(); + cachedCursor = root->currentCursor(); + if (cachedCursor) + cursor = (WebCore::Node*) cachedCursor->nodePointer(); } // Traverse the array, and update each button, depending on whether it - // is focused. + // is selected. Container* end = m_viewImpl->m_buttons.end(); for (Container* ptr = m_viewImpl->m_buttons.begin(); ptr != end; ptr++) { WebCore::RenderSkinAndroid::State state; - if (ptr->matches(focus)) { - focusIsButton = true; + if (ptr->matches(cursor)) { + cursorIsOnButton = true; // If the WebView is out of focus/window focus, set the state to - // normal, but still keep track of the fact that the focus is a + // normal, but still keep track of the fact that the selected is a // button if (!hasFocus) { state = WebCore::RenderSkinAndroid::kNormal; @@ -548,8 +276,8 @@ void nativeRecordButtons(bool hasFocus, bool pressed, bool invalidate) } } m_viewImpl->gButtonMutex.unlock(); - if (invalidate && cachedFocus && focusIsButton) { - const WebCore::IntRect& b = cachedFocus->getBounds(); + if (invalidate && cachedCursor && cursorIsOnButton) { + const WebCore::IntRect& b = cachedCursor->getBounds(); viewInvalidateRect(b.x(), b.y(), b.right(), b.bottom()); } } @@ -577,7 +305,7 @@ void setUpFindPaint() m_isFindPaintSetUp = true; } -// Draw the match specified by region to the canvas. +// Draw the match specified by region to the canvas. void drawMatch(const SkRegion& region, SkCanvas* canvas, bool focused) { // For the match which has focus, use a filled paint. For the others, use @@ -666,8 +394,7 @@ void drawMatches(SkCanvas* canvas) unsigned numberOfMatches = m_matches->size(); if (numberOfMatches > 1 && numberOfMatches < MAX_NUMBER_OF_MATCHES_TO_DRAW) { - SkIRect visibleIRect; - android_setrect(&visibleIRect, visible); + SkIRect visibleIRect(visible); for(unsigned i = 0; i < numberOfMatches; i++) { // The current match has already been drawn if (i == m_findIndex) @@ -683,41 +410,50 @@ void drawMatches(SkCanvas* canvas) } } -void drawFocusRing(SkCanvas* canvas) +void resetCursorRing() +{ + m_followedLink = false; + setPluginReceivesEvents(false); + m_viewImpl->m_hasCursorBounds = false; +} + +void drawCursorRing(SkCanvas* canvas) { const CachedRoot* root = getFrameCache(AllowNewer); if (!root) { DBG_NAV_LOG("!root"); - m_followedLink = false; + resetCursorRing(); return; } - const CachedNode* node = root->currentFocus(); + const CachedFrame* frame; + const CachedNode* node = root->currentCursor(&frame); if (!node) { DBG_NAV_LOG("!node"); - m_followedLink = false; + resetCursorRing(); return; } - if (!node->hasFocusRing()) { - DBG_NAV_LOG("!node->hasFocusRing()"); + if (!node->hasCursorRing()) { + DBG_NAV_LOG("!node->hasCursorRing()"); + m_viewImpl->m_hasCursorBounds = false; return; } - const WTF::Vector<WebCore::IntRect>& rings = node->focusRings(); - if (!rings.size()) { - DBG_NAV_LOG("!rings.size()"); + const WTF::Vector<WebCore::IntRect>* rings = &node->cursorRings(); + if (!rings->size()) { + DBG_NAV_LOG("!rings->size()"); + m_viewImpl->m_hasCursorBounds = false; return; } - bool isButton = false; m_viewImpl->gButtonMutex.lock(); // If this is a button drawn by us (rather than webkit) do not draw the - // focus ring, since its focus will be shown by a change in what we draw. + // cursor ring, since its cursor will be shown by a change in what we draw. // Should be in sync with recordButtons, since that will be called // before this. if (m_viewImpl->m_buttons.size() > 0) { - WebCore::Node* focusPointer = (WebCore::Node*) 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(focusPointer)) { + if (ptr->matches(cursorPointer)) { isButton = true; break; } @@ -725,153 +461,93 @@ void drawFocusRing(SkCanvas* canvas) } m_viewImpl->gButtonMutex.unlock(); WebCore::IntRect bounds = node->bounds(); - bounds.inflate(SkScalarCeil(FOCUS_RING_OUTER_DIAMETER)); - SkRect sbounds; - android_setrect(&sbounds, bounds); - if (canvas->quickReject(sbounds, SkCanvas::kAA_EdgeType)) { - DBG_NAV_LOG("canvas->quickReject"); + updateCursorBounds(root, frame, node); + + WTF::Vector<WebCore::IntRect> oneRing; + bool useHitBounds = node->useHitBounds(); + if (useHitBounds) { + bounds = node->hitBounds(); + } + if (useHitBounds || node->useBounds()) { + oneRing.append(bounds); + rings = &oneRing; + } + bounds.inflate(SkScalarCeil(CURSOR_RING_OUTER_DIAMETER)); + if (canvas->quickReject(bounds, SkCanvas::kAA_EdgeType)) { + DBG_NAV_LOGD("canvas->quickReject cursorNode=%d (nodePointer=%p)" + " bounds=(%d,%d,w=%d,h=%d)", node->index(), node->nodePointer(), + bounds.x(), bounds.y(), bounds.width(), bounds.height()); m_followedLink = false; + setPluginReceivesEvents(false); return; } - FocusRing::Flavor flavor = FocusRing::NORMAL_FLAVOR; + CursorRing::Flavor flavor = CursorRing::NORMAL_FLAVOR; if (!isButton) { flavor = node->type() != NORMAL_CACHEDNODETYPE ? - FocusRing::FAKE_FLAVOR : node->nodePointer() == m_invalidNode ? - FocusRing::INVALID_FLAVOR : FocusRing::NORMAL_FLAVOR; - if (flavor != FocusRing::INVALID_FLAVOR && m_followedLink) { - flavor = (FocusRing::Flavor) (flavor + FocusRing::NORMAL_ANIMATING); + CursorRing::FAKE_FLAVOR : CursorRing::NORMAL_FLAVOR; + if (m_pluginReceivesEvents && node->isPlugin()) { + return; + } + if (m_followedLink) { + flavor = static_cast<CursorRing::Flavor> + (flavor + CursorRing::NORMAL_ANIMATING); } #if DEBUG_NAV_UI - const WebCore::IntRect& ring = rings[0]; - DBG_NAV_LOGD("cachedFocusNode=%d (nodePointer=%p) flavor=%s rings=%d" - " (%d, %d, %d, %d)", node->index(), node->nodePointer(), - flavor == FocusRing::FAKE_FLAVOR ? "FAKE_FLAVOR" : - flavor == FocusRing::INVALID_FLAVOR ? "INVALID_FLAVOR" : - flavor == FocusRing::NORMAL_ANIMATING ? "NORMAL_ANIMATING" : - flavor == FocusRing::FAKE_ANIMATING ? "FAKE_ANIMATING" : "NORMAL_FLAVOR", - rings.size(), ring.x(), ring.y(), ring.width(), ring.height()); + const WebCore::IntRect& ring = (*rings)[0]; + DBG_NAV_LOGD("cursorNode=%d (nodePointer=%p) flavor=%s rings=%d" + " (%d, %d, %d, %d) pluginReceivesEvents=%s isPlugin=%s", + node->index(), node->nodePointer(), + flavor == CursorRing::FAKE_FLAVOR ? "FAKE_FLAVOR" : + flavor == CursorRing::NORMAL_ANIMATING ? "NORMAL_ANIMATING" : + flavor == CursorRing::FAKE_ANIMATING ? "FAKE_ANIMATING" : "NORMAL_FLAVOR", + rings->size(), ring.x(), ring.y(), ring.width(), ring.height(), + m_pluginReceivesEvents ? "true" : "false", + node->isPlugin() ? "true" : "false"); #endif } - if (isButton || flavor >= FocusRing::NORMAL_ANIMATING) { + if (isButton || flavor >= CursorRing::NORMAL_ANIMATING) { SkMSec time = SkTime::GetMSecs(); if (time < m_ringAnimationEnd) { // views assume that inval bounds coordinates are non-negative bounds.intersect(WebCore::IntRect(0, 0, INT_MAX, INT_MAX)); postInvalidateDelayed(m_ringAnimationEnd - time, bounds); } else { + if (m_followedLink) + hideCursor(); m_followedLink = false; - flavor = (FocusRing::Flavor) (flavor - FocusRing::NORMAL_ANIMATING); + flavor = static_cast<CursorRing::Flavor> + (flavor - CursorRing::NORMAL_ANIMATING); } } if (!isButton) - FocusRing::DrawRing(canvas, rings, flavor); -} - -OutOfFocusFix fixOutOfDateFocus(bool useReplay) -{ - if (!m_frameCacheUI) { - DBG_NAV_LOG("!m_frameCacheUI"); - return DoNothing; - } - const CachedFrame* cachedFrame = 0; - const CachedNode* cachedFocusNode = m_frameCacheUI->currentFocus(&cachedFrame); - if (!cachedFocusNode) { - DBG_NAV_LOG("!cachedFocusNode"); - return DoNothing; - } - CachedRoot* webRoot = m_viewImpl->m_frameCacheKit; - if (!webRoot) { - DBG_NAV_LOG("!webRoot"); - return DoNothing; - } - int uiWidth = m_frameCacheUI->width(); - int webWidth = webRoot->width(); - if (uiWidth != webWidth) { - DBG_NAV_LOGD("uiWidth=%d webWidth=%d", uiWidth, webWidth); - return DoNothing; // allow text inputs to preserve their state - } else { - const WebCore::IntRect& cachedBounds = m_frameCacheUI->focusBounds(); - const CachedFrame* webFrame = 0; - const CachedNode* webFocusNode = webRoot->currentFocus(&webFrame); - DBG_NAV_LOGD("cachedBounds=(%d,%d,w=%d,h=%d) cachedFrame=%p (%d)" - " webFocusNode=%p (%d) webFrame=%p (%d)", - cachedBounds.x(), cachedBounds.y(), - cachedBounds.width(), cachedBounds.height(), - cachedFrame, cachedFrame ? cachedFrame->indexInParent() : -1, - webFocusNode, webFocusNode ? webFocusNode->index() : -1, - webFrame, webFrame ? webFrame->indexInParent() : -1); - if (webFocusNode && webFrame && webFrame->sameFrame(cachedFrame)) { - if (useReplay && !m_replay.count()) { - DBG_NAV_LOG("!m_replay.count()"); - return DoNothing; - } - if (webFocusNode->index() == cachedFocusNode->index()) { - DBG_NAV_LOG("index =="); - return DoNothing; - } - const WebCore::IntRect& webBounds = webRoot->focusBounds(); - DBG_NAV_LOGD("webBounds=(%d,%d,w=%d,h=%d)", - webBounds.x(), webBounds.y(), - webBounds.width(), webBounds.height()); - if (cachedBounds.contains(webBounds)) { - DBG_NAV_LOG("contains"); - return DoNothing; - } - if (webBounds.contains(cachedBounds)) { - DBG_NAV_LOG("webBounds contains"); - return DoNothing; - } - } - const CachedFrame* foundFrame = 0; - int x, y; - const CachedNode* found = findAt(webRoot, cachedBounds, &foundFrame, &x, &y); -#if DEBUG_NAV_UI - DBG_NAV_LOGD("found=%p (%d) frame=%p (%d)", - found, found ? found->index() : -1, - foundFrame, foundFrame ? foundFrame->indexInParent() : -1); - if (found) { - WebCore::IntRect newBounds = found->bounds(); - DBG_NAV_LOGD("found=(%d,%d,w=%d,h=%d) x=%d y=%d", - newBounds.x(), newBounds.y(), newBounds.width(), - newBounds.height(), x, y); - } -#endif - webRoot->setCachedFocus(const_cast<CachedFrame*>(foundFrame), - const_cast<CachedNode*>(found)); - if (found) - webRoot->rootHistory()->setNavBounds(found->bounds()); - WebCore::Frame* framePointer = foundFrame ? (WebCore::Frame*) foundFrame->framePointer() : 0; - WebCore::Node* nodePointer = found ? (WebCore::Node*) found->nodePointer() : 0; - setFocusData(webRoot->generation(), framePointer, nodePointer, x, y, !found); - sendFinalFocus(framePointer, nodePointer, x, y); - if (found && (found->isTextArea() || found->isTextField())) - return UpdateTextEntry; - } -checkOldFocus: - return cachedFocusNode->isTextArea() || cachedFocusNode->isTextField() ? ClearTextEntry : DoNothing; + CursorRing::DrawRing(canvas, *rings, flavor); } -bool focusIsTextArea(FrameCachePermission allowNewer) +bool cursorIsTextInput(FrameCachePermission allowNewer) { CachedRoot* root = getFrameCache(allowNewer); if (!root) { DBG_NAV_LOG("!root"); return false; } - const CachedNode* focus = root->currentFocus(); - if (!focus) + const CachedNode* cursor = root->currentCursor(); + if (!cursor) { + DBG_NAV_LOG("!cursor"); return false; - return focus->isTextArea() || focus->isTextField(); + } + DBG_NAV_LOGD("%s", + cursor->isTextArea() || cursor->isTextField() ? "true" : "false"); + return cursor->isTextArea() || cursor->isTextField(); } -void focusRingBounds(WebCore::IntRect* bounds) +void cursorRingBounds(WebCore::IntRect* bounds) { DBG_NAV_LOGD("%s", ""); CachedRoot* root = getFrameCache(DontAllowNewer); if (root) { - const CachedNode* cachedNode = root->currentFocus(); + const CachedNode* cachedNode = root->currentCursor(); if (cachedNode) { - cachedNode->focusRingBounds(bounds); + cachedNode->cursorRingBounds(bounds); DBG_NAV_LOGD("bounds={%d,%d,%d,%d}", bounds->x(), bounds->y(), bounds->width(), bounds->height()); return; @@ -880,23 +556,64 @@ void focusRingBounds(WebCore::IntRect* bounds) *bounds = WebCore::IntRect(0, 0, 0, 0); } +void fixCursor() +{ + m_viewImpl->gCursorBoundsMutex.lock(); + bool hasCursorBounds = m_viewImpl->m_hasCursorBounds; + IntRect bounds = m_viewImpl->m_cursorBounds; + m_viewImpl->gCursorBoundsMutex.unlock(); + if (!hasCursorBounds) + return; + int x, y; + const CachedFrame* frame; + const CachedNode* node = m_frameCacheUI->findAt(bounds, &frame, &x, &y, false); + if (!node) + return; + // require that node have approximately the same bounds (+/- 4) and the same + // center (+/- 2) + IntPoint oldCenter = IntPoint(bounds.x() + (bounds.width() >> 1), + bounds.y() + (bounds.height() >> 1)); + IntRect newBounds = node->bounds(); + IntPoint newCenter = IntPoint(newBounds.x() + (newBounds.width() >> 1), + newBounds.y() + (newBounds.height() >> 1)); + DBG_NAV_LOGD("oldCenter=(%d,%d) newCenter=(%d,%d)" + " bounds=(%d,%d,w=%d,h=%d) newBounds=(%d,%d,w=%d,h=%d)", + oldCenter.x(), oldCenter.y(), newCenter.x(), newCenter.y(), + bounds.x(), bounds.y(), bounds.width(), bounds.height(), + newBounds.x(), newBounds.y(), newBounds.width(), newBounds.height()); + if (abs(oldCenter.x() - newCenter.x()) > 2) + return; + if (abs(oldCenter.y() - newCenter.y()) > 2) + return; + if (abs(bounds.x() - newBounds.x()) > 4) + return; + if (abs(bounds.y() - newBounds.y()) > 4) + return; + if (abs(bounds.right() - newBounds.right()) > 4) + return; + if (abs(bounds.bottom() - newBounds.bottom()) > 4) + return; + DBG_NAV_LOGD("node=%p frame=%p x=%d y=%d bounds=(%d,%d,w=%d,h=%d)", + node, frame, x, y, bounds.x(), bounds.y(), bounds.width(), + bounds.height()); + m_frameCacheUI->setCursor(const_cast<CachedFrame*>(frame), + const_cast<CachedNode*>(node)); +} + CachedRoot* getFrameCache(FrameCachePermission allowNewer) { - if (!m_viewImpl->m_updatedFrameCache) - return m_frameCacheUI; - m_viewImpl->gRecomputeFocusMutex.lock(); - bool recomputeInProgress = m_viewImpl->m_recomputeEvents.size() > 0; - m_viewImpl->gRecomputeFocusMutex.unlock(); - if (allowNewer != AllowNewest && recomputeInProgress) + if (!m_viewImpl->m_updatedFrameCache) { + DBG_NAV_LOG("!m_viewImpl->m_updatedFrameCache"); return m_frameCacheUI; - if (allowNewer == DontAllowNewer && m_viewImpl->m_lastGeneration < m_generation) + } + if (allowNewer == DontAllowNewer && m_viewImpl->m_lastGeneration < m_generation) { + DBG_NAV_LOGD("allowNewer==DontAllowNewer m_viewImpl->m_lastGeneration=%d" + " < m_generation=%d", m_viewImpl->m_lastGeneration, m_generation); return m_frameCacheUI; + } DBG_NAV_LOGD("%s", "m_viewImpl->m_updatedFrameCache == true"); - bool hadFocus = m_frameCacheUI && m_frameCacheUI->currentFocus(); + bool hadCursor = m_frameCacheUI && m_frameCacheUI->currentCursor(); m_viewImpl->gFrameCacheMutex.lock(); - OutOfFocusFix fix = DoNothing; - if (allowNewer != DontAllowNewer) - fix = fixOutOfDateFocus(m_viewImpl->m_useReplay); delete m_frameCacheUI; delete m_navPictureUI; m_viewImpl->m_updatedFrameCache = false; @@ -905,12 +622,9 @@ CachedRoot* getFrameCache(FrameCachePermission allowNewer) m_viewImpl->m_frameCacheKit = 0; m_viewImpl->m_navPictureKit = 0; m_viewImpl->gFrameCacheMutex.unlock(); - if (hadFocus && (!m_frameCacheUI || !m_frameCacheUI->currentFocus())) - viewInvalidate(); // redraw in case focus ring is still visible - if (fix == UpdateTextEntry) - updateTextEntry(); - else if (fix == ClearTextEntry) - clearTextEntry(); + fixCursor(); + if (hadCursor && (!m_frameCacheUI || !m_frameCacheUI->currentCursor())) + viewInvalidate(); // redraw in case cursor ring is still visible return m_frameCacheUI; } @@ -970,64 +684,74 @@ static CachedFrame::Direction KeyToDirection(KeyCode keyCode) DBG_NAV_LOGD("keyCode=%s", "up"); return CachedFrame::UP; default: - LOGD("------- bad key sent to WebView::moveFocus"); + DBG_NAV_LOGD("bad key %d sent", keyCode); return CachedFrame::UNINITIALIZED; } } -bool invalidFrame(WebCore::Frame* frame, const CachedRoot* root) -{ - if (!frame) - return false; - int frameBuild = m_viewImpl->retrieveFrameGeneration(frame); - int rootBuild = root->generation(); - return frameBuild > rootBuild; -} - WebCore::String imageURI(int x, int y) { const CachedRoot* root = getFrameCache(DontAllowNewer); return root ? root->imageURI(x, y) : WebCore::String(); } -bool focusNodeWantsKeyEvents() +bool cursorWantsKeyEvents() { const CachedRoot* root = getFrameCache(DontAllowNewer); if (root) { - const CachedNode* focus = root->currentFocus(); - if (focus) { - return focus->isWantsKeyEvents(); - } + const CachedNode* focus = root->currentCursor(); + if (focus) + return focus->wantsKeyEvents(); } return false; } -/* returns true if the key had no effect (neither scrolled nor changed focus) */ -bool moveFocus(int keyCode, int count, bool ignoreScroll, bool inval, - void* lastSentFocus, const WebCore::IntRect* lastSentBounds) -{ +// This needs to be called each time we call CachedRoot::setCursor() with +// non-null CachedNode/CachedFrame, since otherwise the WebViewCore's data +// about the cursor is incorrect. When we call setCursor(0,0), we need +// to set m_viewImpl->hasCursorBounds to false. +void updateCursorBounds(const CachedRoot* root, const CachedFrame* cachedFrame, + const CachedNode* cachedNode) +{ + LOG_ASSERT(root, "updateCursorBounds: root cannot be null"); + LOG_ASSERT(cachedNode, "updateCursorBounds: cachedNode cannot be null"); + LOG_ASSERT(cachedFrame, "updateCursorBounds: cachedFrame cannot be null"); + m_viewImpl->gCursorBoundsMutex.lock(); + m_viewImpl->m_hasCursorBounds = cachedNode->hasCursorRing(); + // If m_viewImpl->m_hasCursorBounds is false, we never look at the other + // values, so do not bother setting them. + if (m_viewImpl->m_hasCursorBounds) { + WebCore::IntRect bounds = cachedNode->bounds(); + if (m_viewImpl->m_cursorBounds != bounds) + DBG_NAV_LOGD("new cursor bounds=(%d,%d,w=%d,h=%d)", + bounds.x(), bounds.y(), bounds.width(), bounds.height()); + m_viewImpl->m_cursorBounds = cachedNode->bounds(); + m_viewImpl->m_cursorHitBounds = cachedNode->hitBounds(); + m_viewImpl->m_cursorFrame = cachedFrame->framePointer(); + root->getSimulatedMousePosition(&m_viewImpl->m_cursorLocation); + m_viewImpl->m_cursorNode = cachedNode->nodePointer(); + } + m_viewImpl->gCursorBoundsMutex.unlock(); +} + +/* returns true if the key had no effect (neither scrolled nor changed cursor) */ +bool moveCursor(int keyCode, int count, bool ignoreScroll) +{ + setPluginReceivesEvents(false); CachedRoot* root = getFrameCache(AllowNewer); if (!root) { DBG_NAV_LOG("!root"); - setFocusData(0, 0, 0, 0, 0, true); - sendKitFocus(); // will build cache and retry - FirstMoveFocusParams params; - params.d.m_trigger = CommonParams::FirstMoveFocusParams; - params.d.m_generation = m_generation; - params.m_keyCode = keyCode; - params.m_count = count; - params.m_ignoreScroll = ignoreScroll; - m_replay.add(params.d, sizeof(params)); return true; } + m_viewImpl->m_moveGeneration++; CachedFrame::Direction direction = KeyToDirection((KeyCode) keyCode); const CachedFrame* cachedFrame, * oldFrame = 0; - const CachedNode* focus = root->currentFocus(&oldFrame); - WebCore::IntPoint focusLocation = root->focusLocation(); - DBG_NAV_LOGD("old focus %d (nativeNode=%p) focusLocation={%d, %d}", - focus ? focus->index() : 0, - focus ? focus->nodePointer() : 0, focusLocation.x(), focusLocation.y()); + const CachedNode* cursor = root->currentCursor(&oldFrame); + WebCore::IntPoint cursorLocation = root->cursorLocation(); + DBG_NAV_LOGD("old cursor %d (nativeNode=%p) cursorLocation={%d, %d}", + cursor ? cursor->index() : 0, + cursor ? cursor->nodePointer() : 0, cursorLocation.x(), cursorLocation.y()); WebCore::IntRect visibleRect; getVisibleRect(&visibleRect); DBG_NAV_LOGD("getVisibleRect %d,%d,%d,%d", @@ -1036,29 +760,31 @@ bool moveFocus(int keyCode, int count, bool ignoreScroll, bool inval, int xMax = getScaledMaxXScroll(); int yMax = getScaledMaxYScroll(); root->setMaxScroll(xMax, yMax); - CachedHistory savedHistory = *root->rootHistory(); - bool oldNodeIsTextArea = focusIsTextArea(DontAllowNewer); const CachedNode* cachedNode = 0; int dx = 0; int dy = 0; int counter = count; - if (!focus || !focus->isInput() || !m_followedLink) + if (!cursor || !m_followedLink) root->setScrollOnly(m_followedLink); while (--counter >= 0) { WebCore::IntPoint scroll = WebCore::IntPoint(0, 0); - cachedNode = root->moveFocus(direction, &cachedFrame, &scroll); + cachedNode = root->moveCursor(direction, &cachedFrame, &scroll); dx += scroll.x(); dy += scroll.y(); } - DBG_NAV_LOGD("new focus %d (nativeNode=%p) focusLocation={%d, %d}", - cachedNode ? cachedNode->index() : 0, - cachedNode ? cachedNode->nodePointer() : 0, root->focusLocation().x(), - root->focusLocation().y()); + DBG_NAV_LOGD("new cursor %d (nativeNode=%p) cursorLocation={%d, %d}" + "bounds={%d,%d,w=%d,h=%d}", cachedNode ? cachedNode->index() : 0, + cachedNode ? cachedNode->nodePointer() : 0, + root->cursorLocation().x(), root->cursorLocation().y(), + cachedNode ? cachedNode->bounds().x() : 0, + cachedNode ? cachedNode->bounds().y() : 0, + cachedNode ? cachedNode->bounds().width() : 0, + cachedNode ? cachedNode->bounds().height() : 0); // If !m_heightCanMeasure (such as in the browser), we want to scroll no // matter what if (!ignoreScroll && (!m_heightCanMeasure || !cachedNode || - (focus && focus->nodePointer() == cachedNode->nodePointer()))) + (cursor && cursor->nodePointer() == cachedNode->nodePointer()))) { if (count == 1 && dx != 0 && dy == 0 && -m_lastDx == dx && SkTime::GetMSecs() - m_lastDxTime < 1000) @@ -1068,55 +794,17 @@ bool moveFocus(int keyCode, int count, bool ignoreScroll, bool inval, this->scrollBy(dx, dy); m_lastDx = dx; m_lastDxTime = SkTime::GetMSecs(); - ignoreScroll = true; // if move re-executes, don't scroll the second time } bool result = false; if (cachedNode) { - WebCore::IntPoint pos; - root->setCachedFocus((CachedFrame*) cachedFrame, (CachedNode*) cachedNode); - root->getSimulatedMousePosition(&pos); - if (lastSentFocus == cachedNode->nodePointer() && lastSentBounds && - *lastSentBounds == cachedNode->bounds()) - { - sendFinalFocus((WebCore::Frame*) cachedFrame->framePointer(), - (WebCore::Node*) cachedNode->nodePointer(), pos.x(), pos.y()); - } else { - setFocusData(root->generation(), - (WebCore::Frame*) cachedFrame->framePointer(), - (WebCore::Node*) cachedNode->nodePointer(), pos.x(), pos.y(), - true); - sendKitFocus(); - if (inval) - viewInvalidate(); - MoveFocusParams params; - params.d.d.m_trigger = CommonParams::MoveFocusParams; - params.d.d.m_generation = m_generation; - params.c.setFocus(focus, oldFrame, root, focusLocation); - params.m_sentFocus = cachedNode->nodePointer(); - params.m_sentBounds = cachedNode->bounds(); - params.m_visibleRect = visibleRect; - params.m_history = savedHistory; - DBG_NAV_LOGD("history.mDidFirstLayout=%s", - params.m_history.didFirstLayout() ? "true" : "false"); - params.m_xMax = xMax; - params.m_yMax = yMax; - params.d.m_keyCode = keyCode; - params.d.m_count = count; - params.d.m_ignoreScroll = ignoreScroll; - m_replay.add(params.d.d, sizeof(params)); - } + updateCursorBounds(root, cachedFrame, cachedNode); + root->setCursor(const_cast<CachedFrame*>(cachedFrame), + const_cast<CachedNode*>(cachedNode)); + bool disableFocusController = cachedNode != root->currentFocus() + && cachedNode->wantsKeyEvents(); + sendMoveMouseIfLatest(disableFocusController); + viewInvalidate(); } else { - if (visibleRect.intersects(root->focusBounds()) == false) { - setFocusData(root->generation(), 0, 0, 0, 0, true); - sendKitFocus(); // will build cache and retry - } - FirstMoveFocusParams params; - params.d.m_trigger = CommonParams::FirstMoveFocusParams; - params.d.m_generation = m_generation; - params.m_keyCode = keyCode; - params.m_count = count; - params.m_ignoreScroll = ignoreScroll; - m_replay.add(params.d, sizeof(params)); int docHeight = root->documentHeight(); int docWidth = root->documentWidth(); if (visibleRect.bottom() + dy > docHeight) @@ -1131,45 +819,28 @@ bool moveFocus(int keyCode, int count, bool ignoreScroll, bool inval, direction == CachedFrame::RIGHT ? dx <= 0 : direction == CachedFrame::UP ? dy >= 0 : dy <= 0; } - if (focusIsTextArea(DontAllowNewer)) - updateTextEntry(); - else if (oldNodeIsTextArea) - clearTextEntry(); return result; } -void notifyFocusSet(FrameCachePermission inEditingMode) +bool pluginEatsNavKey() { CachedRoot* root = getFrameCache(DontAllowNewer); - if (root) { - // make sure the mFocusData in WebView.java is in sync with WebView.cpp - const CachedFrame* frame = 0; - const CachedNode* node = root->currentFocus(&frame); - const WebCore::IntPoint& focusLocation = root->focusLocation(); - setFocusData(root->generation(), - frame ? (WebCore::Frame*) frame->framePointer() : 0, - node ? (WebCore::Node*) node->nodePointer() : 0, - focusLocation.x(), focusLocation.y(), false); - } - - if (focusIsTextArea(inEditingMode)) - updateTextEntry(); - else if (inEditingMode) - clearTextEntry(); -#if DEBUG_NAV_UI - if (m_frameCacheUI) { - const CachedNode* focus = m_frameCacheUI->currentFocus(); - DBG_NAV_LOGD("focus %d (nativeNode=%p)", - focus ? focus->index() : 0, - focus ? focus->nodePointer() : 0); + if (!root) { + DBG_NAV_LOG("!root"); + return false; } -#endif + const CachedNode* cursor = root->currentCursor(); + DBG_NAV_LOGD("cursor=%p isPlugin=%s pluginReceivesEvents=%s", + cursor, cursor && cursor->isPlugin() ? "true" : "false", + m_pluginReceivesEvents ? "true" : "false"); + // FIXME: check to see if plugin wants keys + return cursor && cursor->isPlugin() && m_pluginReceivesEvents; } void notifyProgressFinished() { - DBG_NAV_LOGD("focusIsTextArea=%d", focusIsTextArea(DontAllowNewer)); - updateTextEntry(); + DBG_NAV_LOGD("cursorIsTextInput=%d", cursorIsTextInput(DontAllowNewer)); + rebuildWebTextView(); #if DEBUG_NAV_UI if (m_frameCacheUI) { const CachedNode* focus = m_frameCacheUI->currentFocus(); @@ -1180,121 +851,6 @@ void notifyProgressFinished() #endif } -void recomputeFocus() -{ - int generation; - do { - m_viewImpl->gRecomputeFocusMutex.lock(); - if (!m_viewImpl->m_recomputeEvents.size()) { - m_viewImpl->gRecomputeFocusMutex.unlock(); - return; - } - generation = m_viewImpl->m_recomputeEvents.first(); - m_viewImpl->m_recomputeEvents.remove(0); - m_viewImpl->gRecomputeFocusMutex.unlock(); - DBG_NAV_LOGD("generation=%d", generation); - CachedRoot* root = getFrameCache(AllowNewest); - if (!root) { - DBG_NAV_LOG("!root"); - return; - } - LargestParams storage; - const CommonParams& params = storage.d.d; - char* pos = m_replay.position(); - while (m_replay.retrieve(&storage.d.d) < generation) - DBG_NAV_LOGD("dropped ", params.m_generation); - if (params.m_generation > generation) { - DBG_NAV_LOGD("params.m_generation=%d > generation=%d", - params.m_generation, generation); - m_replay.rewind(pos); - return; - } - int lastAdd = m_replay.lastAdd(); - do { - LOG_ASSERT(params.m_trigger != CommonParams::NoData, "expected data"); - bool inval = generation == m_generation; - switch (params.m_trigger) { - case CommonParams::ClearFocusParams: { - const ClearFocusParams& sParams = *(ClearFocusParams*) &storage; - const CacheParams& cParams = sParams.c; - if (invalidFrame(cParams.m_frame, root)) { - DBG_NAV_LOGD("dropped %s generation=%d", - TriggerNames[params.m_trigger], generation); - return; - } - root->setFocus(cParams.m_frame, cParams.m_node, cParams.m_x, cParams.m_y); - clearFocus(sParams.m_x, sParams.m_y, inval); - DBG_NAV_LOGD("clearFocus(x,y)={%d,%d}", sParams.m_x, sParams.m_y); - } break; - case CommonParams::MotionUpParams: { - const MotionUpParams& mParams = *(MotionUpParams*) &storage; - // const CacheParams& cParams = mParams.c; - // if (invalidFrame(cParams.m_frame, root) == false) - // root->setFocus(cParams.m_frame, cParams.m_node, - // cParams.m_x, cParams.m_y); - motionUp(mParams.m_x, mParams.m_y, mParams.m_slop, mParams.m_isClick, inval, true); - DBG_NAV_LOGD("motionUp m_x=%d m_y=%d", mParams.m_x, mParams.m_y); - } break; - case CommonParams::FirstMoveFocusParams: { - if (invalidFrame((WebCore::Frame*) root->framePointer(), root)) { - DBG_NAV_LOGD("dropped %s generation=%d", - TriggerNames[params.m_trigger], generation); - return; - } - const FirstMoveFocusParams& fParams = *(FirstMoveFocusParams*) &storage; - DBG_NAV_LOGD("first moveFocus keyCode=%d count=%d" - " ignoreScroll=%s", fParams.m_keyCode, fParams.m_count, - fParams.m_ignoreScroll ? "true" : "false"); - moveFocus(fParams.m_keyCode, fParams.m_count, - fParams.m_ignoreScroll, inval, 0, 0); - } break; - case CommonParams::MoveFocusParams: { - const MoveFocusParams& mParams = *(MoveFocusParams*) &storage; - const CacheParams& cParams = mParams.c; - if (invalidFrame(cParams.m_frame, root)) { - DBG_NAV_LOGD("dropped %s generation=%d", - TriggerNames[params.m_trigger], generation); - return; - } - DBG_NAV_LOGD("moveFocus keyCode=%d count=%d ignoreScroll=%s " - "history.mDidFirstLayout=%s", mParams.d.m_keyCode, - mParams.d.m_count, mParams.d.m_ignoreScroll ? "true" : "false", - mParams.m_history.didFirstLayout() ? "true" : "false"); - if (!root->setFocus(cParams.m_frame, cParams.m_node, - cParams.m_x, cParams.m_y)) { - DBG_NAV_LOGD("can't restore focus frame=%p node=%p", - "x=%d y=%d %s", cParams.m_frame, cParams.m_node, - cParams.m_x, cParams.m_y, TriggerNames[params.m_trigger]); - return; - } - root->setVisibleRect(mParams.m_visibleRect); - root->setMaxScroll(mParams.m_xMax, mParams.m_yMax); - *root->rootHistory() = mParams.m_history; - moveFocus(mParams.d.m_keyCode, mParams.d.m_count, - mParams.d.m_ignoreScroll, inval, - mParams.m_sentFocus, &mParams.m_sentBounds); - } break; - default: - LOG_ASSERT(0, "unknown trigger"); - } - if (params.m_generation >= lastAdd) - break; - root = getFrameCache(DontAllowNewer); // re-execution may have retrieved newer cache - m_replay.retrieve(&storage.d.d); - DBG_NAV_LOGD("continuation m_generation %d", params.m_generation); - } while (true); - } while (true); -} - -void resetFocus() -{ - DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); - CachedRoot* root = getFrameCache(AllowNewer); - if (!root) - return; - root->setCachedFocus(0, 0); -} - const CachedNode* findAt(CachedRoot* root, const WebCore::IntRect& rect, const CachedFrame** framePtr, int* rxPtr, int* ryPtr) { @@ -1306,49 +862,42 @@ const CachedNode* findAt(CachedRoot* root, const WebCore::IntRect& rect, WebCore::IntRect visibleRect; getVisibleRect(&visibleRect); root->setVisibleRect(visibleRect); - return root->findAt(rect, framePtr, rxPtr, ryPtr); + return root->findAt(rect, framePtr, rxPtr, ryPtr, true); } void selectBestAt(const WebCore::IntRect& rect) { const CachedFrame* frame; int rx, ry; + bool disableFocusController = false; CachedRoot* root = getFrameCache(DontAllowNewer); const CachedNode* node = findAt(root, rect, &frame, &rx, &ry); - int rootGeneration = root ? root->generation() : 0; - setFocusData(rootGeneration, - frame ? (WebCore::Frame*) frame->framePointer() : 0, - node ? (WebCore::Node*) node->nodePointer() : 0, rx, ry, false); + if (!node) { DBG_NAV_LOGD("no nodes found root=%p", root); - if (root) { - root->clearFocus(); - root->setCachedFocus(0, 0); + disableFocusController = true; + m_viewImpl->m_hasCursorBounds = false; + if (root) + root->setCursor(0, 0); + } else { + DBG_NAV_LOGD("CachedNode:%p (%d)", node, node->index()); + root->rootHistory()->setMouseBounds(node->bounds()); + updateCursorBounds(root, frame, node); + root->setCursor(const_cast<CachedFrame*>(frame), + const_cast<CachedNode*>(node)); + if (!node->wantsKeyEvents()) { + disableFocusController = true; } - sendKitFocus(); - viewInvalidate(); - clearTextEntry(); - return; } - DBG_NAV_LOGD("CachedNode:%p (%d)", node, node->index()); - const CachedFrame* oldFrame = 0; - const CachedNode* oldFocusNode = root->currentFocus(&oldFrame); - bool oldNodeIsTextArea = focusIsTextArea(DontAllowNewer); - root->setCachedFocus(const_cast<CachedFrame*>(frame), - const_cast<CachedNode*>(node)); + sendMoveMouseIfLatest(disableFocusController); viewInvalidate(); - if (focusIsTextArea(DontAllowNewer)) - updateTextEntry(); - else if (oldNodeIsTextArea) - clearTextEntry(); } WebCore::IntRect getNavBounds() { CachedRoot* root = getFrameCache(DontAllowNewer); - if (!root) - return WebCore::IntRect(0, 0, 0, 0); - return root->rootHistory()->navBounds(); + return root ? root->rootHistory()->navBounds() : + WebCore::IntRect(0, 0, 0, 0); } void setNavBounds(const WebCore::IntRect& rect) @@ -1359,14 +908,7 @@ void setNavBounds(const WebCore::IntRect& rect) root->rootHistory()->setNavBounds(rect); } -void markNodeInvalid(WebCore::Node* node) -{ - DBG_NAV_LOGD("node=%p", node); - m_invalidNode = node; - viewInvalidate(); -} - -bool motionUp(int x, int y, int slop, bool isClick, bool inval, bool retry) +bool motionUp(int x, int y, int slop) { bool pageScrolled = false; m_followedLink = false; @@ -1374,82 +916,48 @@ bool motionUp(int x, int y, int slop, bool isClick, bool inval, bool retry) WebCore::IntRect rect = WebCore::IntRect(x - slop, y - slop, slop * 2, slop * 2); int rx, ry; CachedRoot* root = getFrameCache(AllowNewer); + if (!root) + return false; const CachedNode* result = findAt(root, rect, &frame, &rx, &ry); if (!result) { DBG_NAV_LOGD("no nodes found root=%p", root); - int rootGeneration = 0; - if (root) { - root->clearFocus(); - rootGeneration = root->generation(); - if (!retry) { // scroll first time only - int dx = root->checkForCenter(x, y); - if (dx) { - scrollBy(dx, 0); - retry = true; // don't recompute later since we scrolled - pageScrolled = true; - } - } - } - sendMotionUp(rootGeneration, frame ? - (WebCore::Frame*) frame->framePointer() : 0, - 0, x, y, slop, isClick, retry); - if (inval) - viewInvalidate(); - if (!retry) { - MotionUpParams params; - params.d.m_trigger = CommonParams::MotionUpParams; - params.d.m_generation = m_generation; - params.m_x = x; - params.m_y = y; - params.m_slop = slop; - params.m_isClick = isClick; - m_replay.add(params.d, sizeof(params)); + setNavBounds(rect); + m_viewImpl->m_hasCursorBounds = false; + root->hideCursor(); + int dx = root->checkForCenter(x, y); + if (dx) { + scrollBy(dx, 0); + pageScrolled = true; } + sendMotionUp(frame ? (WebCore::Frame*) frame->framePointer() : 0, + 0, x, y, slop); + viewInvalidate(); clearTextEntry(); + setPluginReceivesEvents(false); return pageScrolled; } DBG_NAV_LOGD("CachedNode:%p (%d) x=%d y=%d rx=%d ry=%d", result, result->index(), x, y, rx, ry); - // const CachedFrame* oldFrame = 0; - // const CachedNode* oldFocusNode = root->currentFocus(&oldFrame); - // WebCore::IntPoint focusLocation = root->focusLocation(); - bool oldNodeIsTextArea = !retry && focusIsTextArea(DontAllowNewer); - root->setCachedFocus(const_cast<CachedFrame*>(frame), + setNavBounds(WebCore::IntRect(rx, ry, 1, 1)); + updateCursorBounds(root, frame, result); + root->setCursor(const_cast<CachedFrame*>(frame), const_cast<CachedNode*>(result)); - bool newNodeIsTextArea = focusIsTextArea(DontAllowNewer); + updatePluginReceivesEvents(); CachedNodeType type = result->type(); - if (type == NORMAL_CACHEDNODETYPE || newNodeIsTextArea) { - sendMotionUp(root->generation(), + if (type == NORMAL_CACHEDNODETYPE) { + sendMotionUp( frame ? (WebCore::Frame*) frame->framePointer() : 0, result ? (WebCore::Node*) result->nodePointer() : 0, rx, ry, - slop, isClick, retry); - if (inval) - viewInvalidate(); - if (!retry) { - MotionUpParams params; - params.d.m_trigger = CommonParams::MotionUpParams; - params.d.m_generation = m_generation; - params.m_x = x; - params.m_y = y; - params.m_slop = slop; - params.m_isClick = isClick; - // params.c.setFocus(oldFocusNode, oldFrame, root, focusLocation); - m_replay.add(params.d, sizeof(params)); - } - } else if (inval) - viewInvalidate(); - if (newNodeIsTextArea) { - updateTextEntry(); - displaySoftKeyboard(); + slop); + } + viewInvalidate(); + if (result->isTextField() || result->isTextArea()) { + rebuildWebTextView(); + displaySoftKeyboard(true); } else { - if (isClick) { - setFollowedLink(true); - if (type != NORMAL_CACHEDNODETYPE) { - overrideUrlLoading(result->getExport()); - } - } - if (oldNodeIsTextArea) - clearTextEntry(); + setFollowedLink(true); + if (type != NORMAL_CACHEDNODETYPE) + overrideUrlLoading(result->getExport()); } return pageScrolled; } @@ -1470,6 +978,32 @@ void setFindIsUp(bool up) m_hasCurrentLocation = false; } +void setPluginReceivesEvents(bool value) +{ + if (value == m_pluginReceivesEvents) + return; + + //send message to plugin in webkit + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue.object(env).get(), + m_javaGlue.m_sendPluginState, + value ? kGainFocus_PluginState : kLoseFocus_PluginState); + checkException(env); + + m_pluginReceivesEvents = value; +} + +void updatePluginReceivesEvents() +{ + CachedRoot* root = getFrameCache(DontAllowNewer); + if (!root) + return; + const CachedNode* cursor = root->currentCursor(); + setPluginReceivesEvents(cursor && cursor->isPlugin()); + DBG_NAV_LOGD("m_pluginReceivesEvents=%s cursor=%p", m_pluginReceivesEvents + ? "true" : "false", cursor); +} + void setFollowedLink(bool followed) { if ((m_followedLink = followed) != false) { @@ -1614,49 +1148,34 @@ void getSelectionCaret(SkPath* path) path->lineTo(0, height); } -void sendFinalFocus(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y) +void sendMoveMouse(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y) { DBG_NAV_LOGD("framePtr=%p nodePtr=%p x=%d y=%d", framePtr, nodePtr, x, y); - 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_sendFinalFocus, + env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_sendMoveMouse, (jint) framePtr, (jint) nodePtr, x, y); checkException(env); } -void sendKitFocus() +void sendMoveMouseIfLatest(bool disableFocusController) { 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_sendKitFocus); + env->CallVoidMethod(m_javaGlue.object(env).get(), + m_javaGlue.m_sendMoveMouseIfLatest, disableFocusController); checkException(env); } -void sendMotionUp(int buildGeneration, - WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y, int slop, - bool isClick, bool retry) +void sendMotionUp( + WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y, int slop) { m_viewImpl->m_touchGeneration = m_viewImpl->m_generation = ++m_generation; - DBG_NAV_LOGD("buildGeneration=%d m_generation=%d framePtr=%p nodePtr=%p" - " x=%d y=%d slop=%d", buildGeneration, + DBG_NAV_LOGD("m_generation=%d framePtr=%p nodePtr=%p x=%d y=%d slop=%d", m_generation, framePtr, nodePtr, x, y, slop); LOG_ASSERT(m_javaGlue.m_obj, "A WebView was not associated with this WebViewNative!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_sendMotionUp, m_generation, - buildGeneration, (jint) framePtr, (jint) nodePtr, x, y, slop, isClick, retry); - checkException(env); -} - -void setFocusData(int buildGeneration, WebCore::Frame* framePtr, - WebCore::Node* nodePtr, int x, int y, bool ignoreNullFocus) -{ - m_viewImpl->m_moveGeneration = m_viewImpl->m_generation = ++m_generation; - DBG_NAV_LOGD("moveGeneration=%d buildGeneration=%d framePtr=%p nodePtr=%p" - " x=%d y=%d", m_generation, buildGeneration, framePtr, nodePtr, x, y); - 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_setFocusData, m_generation, - buildGeneration, (jint) framePtr, (jint) nodePtr, x, y, ignoreNullFocus); + env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_sendMotionUp, + m_generation, (jint) framePtr, (jint) nodePtr, x, y, slop); checkException(env); } @@ -1724,68 +1243,52 @@ void scrollBy(int dx, int dy) 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_scrollBy, + env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_scrollBy, dx, dy, true); checkException(env); } -bool updateFocusNode(JNIEnv* env) +bool hasCursorNode() { CachedRoot* root = getFrameCache(DontAllowNewer); if (!root) { DBG_NAV_LOG("!root"); return false; } - const CachedFrame* cachedFrame = 0; - const CachedNode* cachedFocusNode = root->currentFocus(&cachedFrame); - if (!cachedFocusNode) { - DBG_NAV_LOG("!cachedFocusNode"); + const CachedNode* cursorNode = root->currentCursor(); + DBG_NAV_LOGD("cursorNode=%d (nodePointer=%p)", + cursorNode ? cursorNode->index() : -1, + cursorNode ? cursorNode->nodePointer() : 0); + return cursorNode; +} + +bool hasFocusNode() +{ + CachedRoot* root = getFrameCache(DontAllowNewer); + if (!root) { + DBG_NAV_LOG("!root"); return false; } - DBG_NAV_LOGD("cachedFocusNode=%d (nodePointer=%p)", - cachedFocusNode->index(), - cachedFocusNode->nodePointer()); - jobject focusnode = env->GetObjectField(m_javaGlue.object(env).get(), m_javaGlue.m_focusNode); - LOG_ASSERT(focusnode, "Could not find WebView's FocusNode"); - - bool isTextArea = cachedFocusNode->isTextArea(); - bool isTextField = cachedFocusNode->isTextField(); - int maxLength; - jstring jName; - if (isTextField) { - maxLength = cachedFocusNode->maxLength(); - const WebCore::String& name = cachedFocusNode->name(); - jName = env->NewString((jchar*)name.characters(), name.length()); - } else { - maxLength = -1; - jName = 0; - } - WebCore::IntRect bounds = cachedFocusNode->bounds(); - WebCore::String value = cachedFocusNode->getExport(); - jstring val = !value.isEmpty() ? env->NewString((jchar *)value.characters(), value.length()) : 0; - env->CallVoidMethod(focusnode, m_javaGlue.m_setAll, isTextField, isTextArea, cachedFocusNode->isPassword(), - cachedFocusNode->isAnchor(), cachedFocusNode->isRtlText(), maxLength, cachedFocusNode->textSize(), - bounds.x(), bounds.y(), bounds.right(), bounds.bottom(), (int)(cachedFocusNode->nodePointer()), - (int)(cachedFrame->framePointer()), val, jName, root->textGeneration()); - env->DeleteLocalRef(val); - env->DeleteLocalRef(focusnode); - if (isTextField) - env->DeleteLocalRef(jName); - return true; -} - -void updateTextEntry() + const CachedNode* focusNode = root->currentFocus(); + DBG_NAV_LOGD("focusNode=%d (nodePointer=%p)", + focusNode ? focusNode->index() : -1, + focusNode ? focusNode->nodePointer() : 0); + return focusNode; +} + +void rebuildWebTextView() { JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_updateTextEntry); + env->CallVoidMethod(m_javaGlue.object(env).get(), + m_javaGlue.m_rebuildWebTextView); checkException(env); } -void displaySoftKeyboard() +void displaySoftKeyboard(bool isTextView) { JNIEnv* env = JSC::Bindings::getJNIEnv(); env->CallVoidMethod(m_javaGlue.object(env).get(), - m_javaGlue.m_displaySoftKeyboard); + m_javaGlue.m_displaySoftKeyboard, isTextView); checkException(env); } @@ -1811,15 +1314,19 @@ void postInvalidateDelayed(int64_t delay, const WebCore::IntRect& bounds) checkException(env); } +int moveGeneration() +{ + return m_viewImpl->m_moveGeneration; +} + private: // local state for WebView // private to getFrameCache(); other functions operate in a different thread CachedRoot* m_frameCacheUI; // navigation data ready for use - FocusReplay m_replay; WebViewCore* m_viewImpl; - WebCore::Node* m_invalidNode; int m_generation; // associate unique ID with sent kit focus to match with ui SkPicture* m_navPictureUI; bool m_followedLink; + bool m_pluginReceivesEvents; SkMSec m_ringAnimationEnd; // Corresponds to the same-named boolean on the java side. bool m_heightCanMeasure; @@ -1852,11 +1359,11 @@ static jstring WebCoreStringToJString(JNIEnv *env, WebCore::String string) return ret; } -static void nativeClearFocus(JNIEnv *env, jobject obj, int x, int y) +static void nativeClearCursor(JNIEnv *env, jobject obj) { WebView* view = GET_NATIVE_VIEW(env, obj); LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - view->clearFocus(x, y, true); + view->clearCursor(); } static void nativeCreate(JNIEnv *env, jobject obj, int viewImpl) @@ -1866,6 +1373,123 @@ static void nativeCreate(JNIEnv *env, jobject obj, int viewImpl) //Release(obj); } +static jint nativeCursorFramePointer(JNIEnv *env, jobject obj) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); + if (!root) + return 0; + const CachedFrame* frame = 0; + (void) root->currentCursor(&frame); + return reinterpret_cast<int>(frame ? frame->framePointer() : 0); +} + +static const CachedNode* getCursorNode(JNIEnv *env, jobject obj) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); + return root ? root->currentCursor() : 0; +} + +static const CachedNode* getFocusCandidate(JNIEnv *env, jobject obj) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); + if (!root) + return 0; + const CachedNode* cursor = root->currentCursor(); + if (cursor && cursor->wantsKeyEvents()) + return cursor; + return root->currentFocus(); +} + +static const CachedNode* getFocusNode(JNIEnv *env, jobject obj) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); + return root ? root->currentFocus() : 0; +} + +static jboolean nativeCursorMatchesFocus(JNIEnv *env, jobject obj) +{ + const CachedNode* cursor = getCursorNode(env, obj); + const CachedNode* focus = getFocusNode(env, obj); + return cursor && focus && cursor->nodePointer() == focus->nodePointer(); +} + +static jobject nativeCursorNodeBounds(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getCursorNode(env, obj); + WebCore::IntRect bounds = node ? node->getBounds() + : WebCore::IntRect(0, 0, 0, 0); + jclass rectClass = env->FindClass("android/graphics/Rect"); + jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V"); + jobject rect = env->NewObject(rectClass, init, bounds.x(), + bounds.y(), bounds.right(), bounds.bottom()); + return rect; +} + +static jint nativeCursorNodePointer(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getCursorNode(env, obj); + return reinterpret_cast<int>(node ? node->nodePointer() : 0); +} + +static jobject nativeCursorPosition(JNIEnv *env, jobject obj) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + const CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); + WebCore::IntPoint pos = WebCore::IntPoint(0, 0); + if (root) + root->getSimulatedMousePosition(&pos); + jclass pointClass = env->FindClass("android/graphics/Point"); + jmethodID init = env->GetMethodID(pointClass, "<init>", "(II)V"); + jobject point = env->NewObject(pointClass, init, pos.x(), pos.y()); + return point; +} + +static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj) +{ + int L, T, R, B; + GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B); + return WebCore::IntRect(L, T, R - L, B - T); +} + +static bool nativeCursorIntersects(JNIEnv *env, jobject obj, jobject visRect) +{ + const CachedNode* node = getCursorNode(env, obj); + return node ? node->getBounds().intersects(jrect_to_webrect(env, visRect)) + : false; +} + +static bool nativeCursorIsAnchor(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getCursorNode(env, obj); + return node ? node->isAnchor() : false; +} + +static bool nativeCursorIsPlugin(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getCursorNode(env, obj); + return node ? node->isPlugin() : false; +} + +static bool nativeCursorIsTextInput(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getCursorNode(env, obj); + return node ? node->isTextField() || node->isTextArea() : false; +} + +static jobject nativeCursorText(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getCursorNode(env, obj); + if (!node) + return 0; + WebCore::String value = node->getExport(); + return !value.isEmpty() ? env->NewString((jchar *)value.characters(), + value.length()) : 0; +} + static void nativeDebugDump(JNIEnv *env, jobject obj) { #if DUMP_NAV_CACHE @@ -1890,8 +1514,7 @@ static void nativeDrawMatches(JNIEnv *env, jobject obj, jobject canv) view->drawMatches(canvas); } -static void nativeDrawFocusRing(JNIEnv *env, jobject obj, - jobject canv) +static void nativeDrawCursorRing(JNIEnv *env, jobject obj, jobject canv) { SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv); if (!canv) { @@ -1903,7 +1526,7 @@ static void nativeDrawFocusRing(JNIEnv *env, jobject obj, DBG_NAV_LOG("!view"); return; } - view->drawFocusRing(canvas); + view->drawCursorRing(canvas); } static void nativeDrawSelection(JNIEnv *env, jobject obj, @@ -1951,10 +1574,96 @@ static jobject nativeImageURI(JNIEnv *env, jobject obj, jint x, jint y) return ret; } -static bool nativeFocusNodeWantsKeyEvents(JNIEnv* env, jobject jwebview) { +static bool nativeFocusCandidateIsPassword(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getFocusCandidate(env, obj); + return node ? node->isPassword() : false; +} + +static bool nativeFocusCandidateIsRtlText(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getFocusCandidate(env, obj); + return node ? node->isRtlText() : false; +} + +static bool nativeFocusCandidateIsTextField(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getFocusCandidate(env, obj); + return node ? node->isTextField() : false; +} + +static bool nativeFocusCandidateIsTextInput(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getFocusCandidate(env, obj); + return node ? node->isTextField() || node->isTextArea() : false; +} + +static jint nativeFocusCandidateMaxLength(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getFocusCandidate(env, obj); + return node ? node->maxLength() : false; +} + +static jobject nativeFocusCandidateName(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getFocusCandidate(env, obj); + if (!node) + return 0; + const WebCore::String& name = node->name(); + return env->NewString((jchar*)name.characters(), name.length()); +} + +static jobject nativeFocusCandidateNodeBounds(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getFocusCandidate(env, obj); + WebCore::IntRect bounds = node ? node->getBounds() + : WebCore::IntRect(0, 0, 0, 0); + jclass rectClass = env->FindClass("android/graphics/Rect"); + jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V"); + jobject rect = env->NewObject(rectClass, init, bounds.x(), + bounds.y(), bounds.right(), bounds.bottom()); + return rect; +} + +static jint nativeFocusCandidatePointer(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getFocusCandidate(env, obj); + return reinterpret_cast<int>(node ? node->nodePointer() : 0); +} + +static jobject nativeFocusCandidateText(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getFocusCandidate(env, obj); + if (!node) + return 0; + WebCore::String value = node->getExport(); + return !value.isEmpty() ? env->NewString((jchar *)value.characters(), + value.length()) : 0; +} + +static jint nativeFocusCandidateTextSize(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getFocusCandidate(env, obj); + return node ? node->textSize() : 0; +} + +static jint nativeFocusNodePointer(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getFocusNode(env, obj); + return node ? reinterpret_cast<int>(node->nodePointer()) : 0; +} + +static bool nativeCursorWantsKeyEvents(JNIEnv* env, jobject jwebview) { WebView* view = GET_NATIVE_VIEW(env, jwebview); LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - return view->focusNodeWantsKeyEvents(); + return view->cursorWantsKeyEvents(); +} + +static void nativeHideCursor(JNIEnv *env, jobject obj) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(view, "view not set in %s", __FUNCTION__); + view->hideCursor(); } static void nativeInstrumentReport(JNIEnv *env, jobject obj) @@ -1964,13 +1673,6 @@ static void nativeInstrumentReport(JNIEnv *env, jobject obj) #endif } -static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj) -{ - int L, T, R, B; - GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B); - return WebCore::IntRect(L, T, R - L, B - T); -} - static void nativeSelectBestAt(JNIEnv *env, jobject obj, jobject jrect) { WebView* view = GET_NATIVE_VIEW(env, obj); @@ -1979,49 +1681,38 @@ static void nativeSelectBestAt(JNIEnv *env, jobject obj, jobject jrect) view->selectBestAt(rect); } -static void nativeMarkNodeInvalid(JNIEnv *env, jobject obj, int node) +static jint nativeTextGeneration(JNIEnv *env, jobject obj) { WebView* view = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - view->markNodeInvalid((WebCore::Node*) node); + CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); + return root ? root->textGeneration() : 0; } static bool nativeMotionUp(JNIEnv *env, jobject obj, - int x, int y, int slop, bool isClick) + int x, int y, int slop) { WebView* view = GET_NATIVE_VIEW(env, obj); LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - return view->motionUp(x, y, slop, isClick, true, false); + return view->motionUp(x, y, slop); } -static bool nativeUpdateFocusNode(JNIEnv *env, jobject obj) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - return view->updateFocusNode(env); -} - -static bool nativeMoveFocus(JNIEnv *env, jobject obj, - int key, int count, bool ignoreScroll) +static bool nativeHasCursorNode(JNIEnv *env, jobject obj) { - WebView* view = GET_NATIVE_VIEW(env, obj); - DBG_NAV_LOGD("env=%p obj=%p view=%p", env, obj, view); - LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - return view->moveFocus(key, count, ignoreScroll, true, 0, 0); + return GET_NATIVE_VIEW(env, obj)->hasCursorNode(); } -static void nativeNotifyFocusSet(JNIEnv *env, jobject obj, bool inEditingMode) +static bool nativeHasFocusNode(JNIEnv *env, jobject obj) { - WebView* view = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - view->notifyFocusSet((WebView::FrameCachePermission) inEditingMode); + return GET_NATIVE_VIEW(env, obj)->hasFocusNode(); } -static void nativeRecomputeFocus(JNIEnv *env, jobject obj) +static bool nativeMoveCursor(JNIEnv *env, jobject obj, + int key, int count, bool ignoreScroll) { WebView* view = GET_NATIVE_VIEW(env, obj); + DBG_NAV_LOGD("env=%p obj=%p view=%p", env, obj, view); LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - view->recomputeFocus(); + return view->moveCursor(key, count, ignoreScroll); } static void nativeRecordButtons(JNIEnv* env, jobject obj, bool hasFocus, @@ -2032,18 +1723,16 @@ static void nativeRecordButtons(JNIEnv* env, jobject obj, bool hasFocus, view->nativeRecordButtons(hasFocus, pressed, invalidate); } -static void nativeResetFocus(JNIEnv *env, jobject obj) +static void nativeSetFindIsDown(JNIEnv *env, jobject obj) { WebView* view = GET_NATIVE_VIEW(env, obj); LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - view->resetFocus(); + view->setFindIsUp(false); } -static void nativeSetFindIsDown(JNIEnv *env, jobject obj) +static void nativeUpdatePluginReceivesEvents(JNIEnv *env, jobject obj) { - WebView* view = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - view->setFindIsUp(false); + GET_NATIVE_VIEW(env, obj)->updatePluginReceivesEvents(); } static void nativeSetFollowedLink(JNIEnv *env, jobject obj, bool followed) @@ -2060,7 +1749,7 @@ static void nativeSetHeightCanMeasure(JNIEnv *env, jobject obj, bool measure) view->setHeightCanMeasure(measure); } -static jobject nativeGetFocusRingBounds(JNIEnv *env, jobject obj) +static jobject nativeGetCursorRingBounds(JNIEnv *env, jobject obj) { WebView* view = GET_NATIVE_VIEW(env, obj); LOG_ASSERT(view, "view not set in %s", __FUNCTION__); @@ -2069,34 +1758,12 @@ static jobject nativeGetFocusRingBounds(JNIEnv *env, jobject obj) jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V"); LOG_ASSERT(init, "Could not find constructor for Rect"); WebCore::IntRect webRect; - view->focusRingBounds(&webRect); + view->cursorRingBounds(&webRect); jobject rect = env->NewObject(rectClass, init, webRect.x(), webRect.y(), webRect.right(), webRect.bottom()); return rect; } -static jobject nativeGetNavBounds(JNIEnv *env, jobject obj) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - jclass rectClass = env->FindClass("android/graphics/Rect"); - LOG_ASSERT(rectClass, "Could not find Rect class!"); - jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V"); - LOG_ASSERT(init, "Could not find constructor for Rect"); - WebCore::IntRect webRect = view->getNavBounds(); - jobject rect = env->NewObject(rectClass, init, webRect.x(), - webRect.y(), webRect.right(), webRect.bottom()); - return rect; -} - -static void nativeSetNavBounds(JNIEnv *env, jobject obj, jobject jrect) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - WebCore::IntRect rect = jrect_to_webrect(env, jrect); - view->setNavBounds(rect); -} - static int nativeFindAll(JNIEnv *env, jobject obj, jstring findLower, jstring findUpper) { @@ -2135,11 +1802,8 @@ static int nativeFindAll(JNIEnv *env, jobject obj, jstring findLower, checkException(env); return 0; } - static const int MAX_16_BIT_INT = 65535; int width = root->documentWidth(); - if (width > MAX_16_BIT_INT) width = MAX_16_BIT_INT; int height = root->documentHeight(); - if (height > MAX_16_BIT_INT) height = MAX_16_BIT_INT; // Create a FindCanvas, which allows us to fake draw into it so we can // figure out where our search string is rendered (and how many times). FindCanvas canvas(width, height, (const UChar*) findLowerChars, @@ -2189,6 +1853,14 @@ static void nativeDestroy(JNIEnv *env, jobject obj) delete view; } +static int nativeMoveGeneration(JNIEnv *env, jobject obj) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + if (!view) + return 0; + return view->moveGeneration(); +} + static void nativeMoveSelection(JNIEnv *env, jobject obj, int x, int y, bool ex) { WebView* view = GET_NATIVE_VIEW(env, obj); @@ -2196,6 +1868,11 @@ static void nativeMoveSelection(JNIEnv *env, jobject obj, int x, int y, bool ex) view->moveSelection(x, y, ex); } +static bool nativePluginEatsNavKey(JNIEnv *env, jobject obj) +{ + return GET_NATIVE_VIEW(env, obj)->pluginEatsNavKey(); +} + static jobject nativeGetSelection(JNIEnv *env, jobject obj) { WebView* view = GET_NATIVE_VIEW(env, obj); @@ -2216,29 +1893,25 @@ static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl) WebView* view = GET_NATIVE_VIEW(env, jwebview); LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); - if (root) { - SkPicture* picture = root->getPicture(); - if (picture) { - FILE* file = fopen(DISPLAY_TREE_LOG_FILE, "w"); - if (file) { - SkFormatDumper dumper(dumpToFile, file); - // dump the URL - if (jurl) { - const char* str = env->GetStringUTFChars(jurl, 0); - SkDebugf("Dumping %s to %s\n", str, DISPLAY_TREE_LOG_FILE); - dumpToFile(str, file); - env->ReleaseStringUTFChars(jurl, str); - } - // now dump the display tree - SkDumpCanvas canvas(&dumper); - // this will playback the picture into the canvas, which will - // spew its contents to the dumper - picture->draw(&canvas); - // we're done with the file now - fwrite("\n", 1, 1, file); - fclose(file); + if (view && view->getWebViewCore()) { + FILE* file = fopen(DISPLAY_TREE_LOG_FILE, "w"); + if (file) { + SkFormatDumper dumper(dumpToFile, file); + // dump the URL + if (jurl) { + const char* str = env->GetStringUTFChars(jurl, 0); + SkDebugf("Dumping %s to %s\n", str, DISPLAY_TREE_LOG_FILE); + dumpToFile(str, file); + env->ReleaseStringUTFChars(jurl, str); } + // now dump the display tree + SkDumpCanvas canvas(&dumper); + // this will playback the picture into the canvas, which will + // spew its contents to the dumper + view->getWebViewCore()->drawContent(&canvas, 0); + // we're done with the file now + fwrite("\n", 1, 1, file); + fclose(file); } } #endif @@ -2248,48 +1921,98 @@ static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl) * JNI registration */ static JNINativeMethod gJavaWebViewMethods[] = { - { "nativeFindAll", "(Ljava/lang/String;Ljava/lang/String;)I", - (void*) nativeFindAll }, - { "nativeFindNext", "(Z)V", - (void*) nativeFindNext }, - { "nativeClearFocus", "(II)V", - (void*) nativeClearFocus }, + { "nativeClearCursor", "()V", + (void*) nativeClearCursor }, { "nativeCreate", "(I)V", (void*) nativeCreate }, + { "nativeCursorFramePointer", "()I", + (void*) nativeCursorFramePointer }, + { "nativeCursorMatchesFocus", "()Z", + (void*) nativeCursorMatchesFocus }, + { "nativeCursorNodeBounds", "()Landroid/graphics/Rect;", + (void*) nativeCursorNodeBounds }, + { "nativeCursorNodePointer", "()I", + (void*) nativeCursorNodePointer }, + { "nativeCursorIntersects", "(Landroid/graphics/Rect;)Z", + (void*) nativeCursorIntersects }, + { "nativeCursorIsAnchor", "()Z", + (void*) nativeCursorIsAnchor }, + { "nativeCursorIsPlugin", "()Z", + (void*) nativeCursorIsPlugin }, + { "nativeCursorIsTextInput", "()Z", + (void*) nativeCursorIsTextInput }, + { "nativeCursorPosition", "()Landroid/graphics/Point;", + (void*) nativeCursorPosition }, + { "nativeCursorText", "()Ljava/lang/String;", + (void*) nativeCursorText }, + { "nativeCursorWantsKeyEvents", "()Z", + (void*)nativeCursorWantsKeyEvents }, { "nativeDebugDump", "()V", (void*) nativeDebugDump }, { "nativeDestroy", "()V", (void*) nativeDestroy }, + { "nativeDrawCursorRing", "(Landroid/graphics/Canvas;)V", + (void*) nativeDrawCursorRing }, { "nativeDrawMatches", "(Landroid/graphics/Canvas;)V", (void*) nativeDrawMatches }, - { "nativeDrawFocusRing", "(Landroid/graphics/Canvas;)V", - (void*) nativeDrawFocusRing }, { "nativeDrawSelection", "(Landroid/graphics/Canvas;IIZ)V", (void*) nativeDrawSelection }, { "nativeDrawSelectionRegion", "(Landroid/graphics/Canvas;)V", (void*) nativeDrawSelectionRegion }, - { "nativeUpdateFocusNode", "()Z", - (void*) nativeUpdateFocusNode }, - { "nativeGetFocusRingBounds", "()Landroid/graphics/Rect;", - (void*) nativeGetFocusRingBounds }, - { "nativeGetNavBounds", "()Landroid/graphics/Rect;", - (void*) nativeGetNavBounds }, + { "nativeDumpDisplayTree", "(Ljava/lang/String;)V", + (void*) nativeDumpDisplayTree }, + { "nativeFindAll", "(Ljava/lang/String;Ljava/lang/String;)I", + (void*) nativeFindAll }, + { "nativeFindNext", "(Z)V", + (void*) nativeFindNext }, + { "nativeFocusCandidateIsPassword", "()Z", + (void*) nativeFocusCandidateIsPassword }, + { "nativeFocusCandidateIsRtlText", "()Z", + (void*) nativeFocusCandidateIsRtlText }, + { "nativeFocusCandidateIsTextField", "()Z", + (void*) nativeFocusCandidateIsTextField }, + { "nativeFocusCandidateIsTextInput", "()Z", + (void*) nativeFocusCandidateIsTextInput }, + { "nativeFocusCandidateMaxLength", "()I", + (void*) nativeFocusCandidateMaxLength }, + { "nativeFocusCandidateName", "()Ljava/lang/String;", + (void*) nativeFocusCandidateName }, + { "nativeFocusCandidateNodeBounds", "()Landroid/graphics/Rect;", + (void*) nativeFocusCandidateNodeBounds }, + { "nativeFocusCandidatePointer", "()I", + (void*) nativeFocusCandidatePointer }, + { "nativeFocusCandidateText", "()Ljava/lang/String;", + (void*) nativeFocusCandidateText }, + { "nativeFocusCandidateTextSize", "()I", + (void*) nativeFocusCandidateTextSize }, + { "nativeFocusNodePointer", "()I", + (void*) nativeFocusNodePointer }, + { "nativeGetCursorRingBounds", "()Landroid/graphics/Rect;", + (void*) nativeGetCursorRingBounds }, + { "nativeGetSelection", "()Landroid/graphics/Region;", + (void*) nativeGetSelection }, + { "nativeHasCursorNode", "()Z", + (void*) nativeHasCursorNode }, + { "nativeHasFocusNode", "()Z", + (void*) nativeHasFocusNode }, + { "nativeHideCursor", "()V", + (void*) nativeHideCursor }, + { "nativeImageURI", "(II)Ljava/lang/String;", + (void*) nativeImageURI }, { "nativeInstrumentReport", "()V", (void*) nativeInstrumentReport }, - { "nativeMarkNodeInvalid", "(I)V", - (void*) nativeMarkNodeInvalid }, - { "nativeMotionUp", "(IIIZ)Z", + { "nativeMotionUp", "(III)Z", (void*) nativeMotionUp }, - { "nativeMoveFocus", "(IIZ)Z", - (void*) nativeMoveFocus }, - { "nativeNotifyFocusSet", "(Z)V", - (void*) nativeNotifyFocusSet }, - { "nativeRecomputeFocus", "()V", - (void*) nativeRecomputeFocus }, + { "nativeMoveCursor", "(IIZ)Z", + (void*) nativeMoveCursor }, + { "nativeMoveGeneration", "()I", + (void*) nativeMoveGeneration }, + { "nativeMoveSelection", "(IIZ)V", + (void*) nativeMoveSelection }, + { "nativePluginEatsNavKey", "()Z", + (void*) nativePluginEatsNavKey }, { "nativeRecordButtons", "(ZZZ)V", (void*) nativeRecordButtons }, - { "nativeResetFocus", "()V", - (void*) nativeResetFocus }, { "nativeSelectBestAt", "(Landroid/graphics/Rect;)V", (void*) nativeSelectBestAt }, { "nativeSetFindIsDown", "()V", @@ -2298,20 +2021,12 @@ static JNINativeMethod gJavaWebViewMethods[] = { (void*) nativeSetFollowedLink }, { "nativeSetHeightCanMeasure", "(Z)V", (void*) nativeSetHeightCanMeasure }, - { "nativeSetNavBounds", "(Landroid/graphics/Rect;)V", - (void*) nativeSetNavBounds }, - { "nativeImageURI", "(II)Ljava/lang/String;", - (void*) nativeImageURI }, - { "nativeFocusNodeWantsKeyEvents", "()Z", - (void*)nativeFocusNodeWantsKeyEvents }, + { "nativeTextGeneration", "()I", + (void*) nativeTextGeneration }, { "nativeUpdateCachedTextfield", "(Ljava/lang/String;I)V", (void*) nativeUpdateCachedTextfield }, - { "nativeMoveSelection", "(IIZ)V", - (void*) nativeMoveSelection }, - { "nativeGetSelection", "()Landroid/graphics/Region;", - (void*) nativeGetSelection }, - { "nativeDumpDisplayTree", "(Ljava/lang/String;)V", - (void*) nativeDumpDisplayTree } + { "nativeUpdatePluginReceivesEvents", "()V", + (void*) nativeUpdatePluginReceivesEvents } }; int register_webview(JNIEnv* env) diff --git a/WebKit/android/plugins/ANPBitmapInterface.cpp b/WebKit/android/plugins/ANPBitmapInterface.cpp new file mode 100644 index 0000000..25d1e97 --- /dev/null +++ b/WebKit/android/plugins/ANPBitmapInterface.cpp @@ -0,0 +1,72 @@ +/* + * Copyright 2009, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// must include config.h first for webkit to fiddle with new/delete +#include "config.h" +#include "SkANP.h" +#include "SkColorPriv.h" + +static bool anp_getPixelPacking(ANPBitmapFormat fmt, ANPPixelPacking* packing) { + switch (fmt) { + case kRGBA_8888_ANPBitmapFormat: + if (packing) { + packing->AShift = SK_A32_SHIFT; + packing->ABits = SK_A32_BITS; + packing->RShift = SK_R32_SHIFT; + packing->RBits = SK_R32_BITS; + packing->GShift = SK_G32_SHIFT; + packing->GBits = SK_G32_BITS; + packing->BShift = SK_B32_SHIFT; + packing->BBits = SK_B32_BITS; + } + return true; + case kRGB_565_ANPBitmapFormat: + if (packing) { + packing->AShift = 0; + packing->ABits = 0; + packing->RShift = SK_R16_SHIFT; + packing->RBits = SK_R16_BITS; + packing->GShift = SK_G16_SHIFT; + packing->GBits = SK_G16_BITS; + packing->BShift = SK_B16_SHIFT; + packing->BBits = SK_B16_BITS; + } + return true; + default: + break; + } + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +#define ASSIGN(obj, name) (obj)->name = anp_##name + +void ANPBitmapInterfaceV0_Init(ANPInterface* value) { + ANPBitmapInterfaceV0* i = reinterpret_cast<ANPBitmapInterfaceV0*>(value); + + ASSIGN(i, getPixelPacking); +} + diff --git a/WebKit/android/plugins/ANPCanvasInterface.cpp b/WebKit/android/plugins/ANPCanvasInterface.cpp index ba79691..c985f64 100644 --- a/WebKit/android/plugins/ANPCanvasInterface.cpp +++ b/WebKit/android/plugins/ANPCanvasInterface.cpp @@ -68,6 +68,9 @@ static void anp_clipRect(ANPCanvas* canvas, const ANPRectF* rect) { static void anp_clipPath(ANPCanvas* canvas, const ANPPath* path) { canvas->skcanvas->clipPath(*path); } +static void anp_concat(ANPCanvas* canvas, const ANPMatrix* matrix) { + canvas->skcanvas->concat(*matrix); +} static void anp_getTotalMatrix(ANPCanvas* canvas, ANPMatrix* matrix) { const SkMatrix& src = canvas->skcanvas->getTotalMatrix(); @@ -102,6 +105,12 @@ static void anp_drawPaint(ANPCanvas* canvas, const ANPPaint* paint) { canvas->skcanvas->drawPaint(*paint); } +static void anp_drawLine(ANPCanvas* canvas, float x0, float y0, + float x1, float y1, const ANPPaint* paint) { + canvas->skcanvas->drawLine(SkFloatToScalar(x0), SkFloatToScalar(y0), + SkFloatToScalar(x1), SkFloatToScalar(y1), *paint); +} + static void anp_drawRect(ANPCanvas* canvas, const ANPRectF* rect, const ANPPaint* paint) { SkRect r; @@ -146,7 +155,7 @@ static void anp_drawBitmapRect(ANPCanvas* canvas, const ANPBitmap* bitmap, SkBitmap bm; SkRect dstR; SkIRect srcR, *srcPtr = NULL; - + if (src) { srcPtr = SkANP::SetRect(&srcR, *src); } @@ -160,7 +169,7 @@ static void anp_drawBitmapRect(ANPCanvas* canvas, const ANPBitmap* bitmap, void ANPCanvasInterfaceV0_Init(ANPInterface* value) { ANPCanvasInterfaceV0* i = reinterpret_cast<ANPCanvasInterfaceV0*>(value); - + ASSIGN(i, newCanvas); ASSIGN(i, deleteCanvas); ASSIGN(i, save); @@ -171,11 +180,13 @@ void ANPCanvasInterfaceV0_Init(ANPInterface* value) { ASSIGN(i, skew); ASSIGN(i, clipRect); ASSIGN(i, clipPath); + ASSIGN(i, concat); ASSIGN(i, getTotalMatrix); ASSIGN(i, getLocalClipBounds); ASSIGN(i, getDeviceClipBounds); ASSIGN(i, drawColor); ASSIGN(i, drawPaint); + ASSIGN(i, drawLine); ASSIGN(i, drawRect); ASSIGN(i, drawOval); ASSIGN(i, drawPath); diff --git a/WebKit/android/plugins/ANPPathInterface.cpp b/WebKit/android/plugins/ANPPathInterface.cpp new file mode 100644 index 0000000..468d866 --- /dev/null +++ b/WebKit/android/plugins/ANPPathInterface.cpp @@ -0,0 +1,113 @@ +/* + * Copyright 2009, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// must include config.h first for webkit to fiddle with new/delete +#include "config.h" +#include "SkANP.h" + +static ANPPath* anp_newPath() { + return new ANPPath; +} + +static void anp_deletePath(ANPPath* path) { + delete path; +} + +static void anp_copy(ANPPath* dst, const ANPPath* src) { + *dst = *src; +} + +static bool anp_equal(const ANPPath* p0, const ANPPath* p1) { + return *p0 == *p1; +} + +static void anp_reset(ANPPath* path) { + path->reset(); +} + +static bool anp_isEmpty(const ANPPath* path) { + return path->isEmpty(); +} + +static void anp_getBounds(const ANPPath* path, ANPRectF* bounds) { + SkANP::SetRect(bounds, path->getBounds()); +} + +static void anp_moveTo(ANPPath* path, float x, float y) { + path->moveTo(SkFloatToScalar(x), SkFloatToScalar(y)); +} + +static void anp_lineTo(ANPPath* path, float x, float y) { + path->lineTo(SkFloatToScalar(x), SkFloatToScalar(y)); +} + +static void anp_quadTo(ANPPath* path, float x0, float y0, float x1, float y1) { + path->quadTo(SkFloatToScalar(x0), SkFloatToScalar(y0), + SkFloatToScalar(x1), SkFloatToScalar(y1)); +} + +static void anp_cubicTo(ANPPath* path, float x0, float y0, + float x1, float y1, float x2, float y2) { + path->cubicTo(SkFloatToScalar(x0), SkFloatToScalar(y0), + SkFloatToScalar(x1), SkFloatToScalar(y1), + SkFloatToScalar(x2), SkFloatToScalar(y2)); +} + +static void anp_close(ANPPath* path) { + path->close(); +} + +static void anp_offset(ANPPath* path, float dx, float dy, ANPPath* dst) { + path->offset(SkFloatToScalar(dx), SkFloatToScalar(dy), dst); +} + +static void anp_transform(ANPPath* src, const ANPMatrix* matrix, + ANPPath* dst) { + src->transform(*matrix, dst); +} + +/////////////////////////////////////////////////////////////////////////////// + +#define ASSIGN(obj, name) (obj)->name = anp_##name + +void ANPPathInterfaceV0_Init(ANPInterface* value) { + ANPPathInterfaceV0* i = reinterpret_cast<ANPPathInterfaceV0*>(value); + + ASSIGN(i, newPath); + ASSIGN(i, deletePath); + ASSIGN(i, copy); + ASSIGN(i, equal); + ASSIGN(i, reset); + ASSIGN(i, isEmpty); + ASSIGN(i, getBounds); + ASSIGN(i, moveTo); + ASSIGN(i, lineTo); + ASSIGN(i, quadTo); + ASSIGN(i, cubicTo); + ASSIGN(i, close); + ASSIGN(i, offset); + ASSIGN(i, transform); +} + diff --git a/WebKit/android/plugins/ANPSurfaceInterface.cpp b/WebKit/android/plugins/ANPSurfaceInterface.cpp new file mode 100644 index 0000000..835f45a --- /dev/null +++ b/WebKit/android/plugins/ANPSurfaceInterface.cpp @@ -0,0 +1,97 @@ +/* + * Copyright 2009, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// must include config.h first for webkit to fiddle with new/delete +#include "config.h" + +#include "PluginSurface.h" +#include "PluginView.h" +#include "PluginWidgetAndroid.h" +#include "SkANP.h" + +using namespace WebCore; + +static ANPSurface* anp_newSurface(NPP instance, ANPSurfaceType type) { + if (instance && instance->ndata) { + PluginView* view = static_cast<PluginView*>(instance->ndata); + PluginWidgetAndroid* widget = view->platformPluginWidget(); + return widget->createSurface(type); + } + return NULL; +} + +static void anp_deleteSurface(ANPSurface* surface) { + if (surface) { + if (surface->data) { + android::PluginSurface* s = + static_cast<android::PluginSurface*>(surface->data); + s->destroy(); + } + delete surface; + } +} + +static bool anp_lock(ANPSurface* surface, ANPBitmap* bitmap, + ANPRectI* dirtyRect) { + if (bitmap && surface && surface->data) { + android::PluginSurface* s = + static_cast<android::PluginSurface*>(surface->data); + SkBitmap src; + bool res = false; + if (dirtyRect) { + SkIRect rect; + res = s->lock(SkANP::SetRect(&rect, *dirtyRect), &src); + } else { + res = s->lock(NULL, &src); + } + if (res) { + res &= SkANP::SetBitmap(bitmap, src); + } + return res; + } + return false; +} + +static void anp_unlock(ANPSurface* surface) { + if (surface && surface->data) { + android::PluginSurface* s = + static_cast<android::PluginSurface*>(surface->data); + s->unlock(); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +#define ASSIGN(obj, name) (obj)->name = anp_##name + +void ANPSurfaceInterfaceV0_Init(ANPInterface* value) { + ANPSurfaceInterfaceV0* i = reinterpret_cast<ANPSurfaceInterfaceV0*>(value); + + ASSIGN(i, newSurface); + ASSIGN(i, deleteSurface); + ASSIGN(i, lock); + ASSIGN(i, unlock); +} + diff --git a/WebKit/android/plugins/ANPTypefaceInterface.cpp b/WebKit/android/plugins/ANPTypefaceInterface.cpp index 17b3067..d560d3e 100644 --- a/WebKit/android/plugins/ANPTypefaceInterface.cpp +++ b/WebKit/android/plugins/ANPTypefaceInterface.cpp @@ -26,6 +26,7 @@ // must include config.h first for webkit to fiddle with new/delete #include "config.h" #include "SkANP.h" +#include "SkFontHost.h" static ANPTypeface* anp_createFromName(const char name[], ANPTypefaceStyle s) { SkTypeface* tf = SkTypeface::CreateFromName(name, @@ -57,6 +58,27 @@ static ANPTypefaceStyle anp_getStyle(const ANPTypeface* tf) { return static_cast<ANPTypefaceStyle>(s); } +static const char* gFontDir; +#define FONT_DIR_SUFFIX "/fonts/" + +static const char* anp_getFontDirectoryPath() { + if (NULL == gFontDir) { + const char* root = getenv("ANDROID_ROOT"); + size_t len = strlen(root); + char* storage = (char*)malloc(len + sizeof(FONT_DIR_SUFFIX)); + if (NULL == storage) { + return NULL; + } + memcpy(storage, root, len); + memcpy(storage + len, FONT_DIR_SUFFIX, sizeof(FONT_DIR_SUFFIX)); + // save this assignment for last, so that if multiple threads call us + // (which should never happen), we never return an incomplete global. + // At worst, we would allocate storage for the path twice. + gFontDir = storage; + } + return gFontDir; +} + /////////////////////////////////////////////////////////////////////////////// #define ASSIGN(obj, name) (obj)->name = anp_##name @@ -70,5 +92,6 @@ void ANPTypefaceInterfaceV0_Init(ANPInterface* v) { ASSIGN(i, ref); ASSIGN(i, unref); ASSIGN(i, getStyle); + ASSIGN(i, getFontDirectoryPath); } diff --git a/WebKit/android/plugins/ANPWindowInterface.cpp b/WebKit/android/plugins/ANPWindowInterface.cpp index 4aa862b..41e00e9 100644 --- a/WebKit/android/plugins/ANPWindowInterface.cpp +++ b/WebKit/android/plugins/ANPWindowInterface.cpp @@ -26,6 +26,9 @@ // must include config.h first for webkit to fiddle with new/delete #include "config.h" #include "SkANP.h" +#include "WebViewCore.h" +#include "PluginView.h" +#include "PluginWidgetAndroid.h" static bool anp_lockRect(void* window, const ANPRectI* inval, ANPBitmap* bitmap) { @@ -48,15 +51,40 @@ static bool anp_lockRegion(void* window, const ANPRegion* inval, static void anp_unlock(void* window) { } +static PluginView* pluginViewForInstance(NPP instance) { + if (instance && instance->ndata) + return static_cast<PluginView*>(instance->ndata); + return PluginView::currentPluginView(); +} + +static void anp_setVisibleRects(NPP instance, const ANPRectI rects[], int32_t count) { + PluginView* pluginView = pluginViewForInstance(instance); + PluginWidgetAndroid* pluginWidget = pluginView->platformPluginWidget(); + pluginWidget->setVisibleRects(rects, count); +} + +static void anp_clearVisibleRects(NPP instance) { + anp_setVisibleRects(instance, NULL, 0); +} + +static void anp_showKeyboard(NPP instance, bool value) { + ScrollView* scrollView = pluginViewForInstance(instance)->parent(); + android::WebViewCore* core = android::WebViewCore::getWebViewCore(scrollView); + core->requestKeyboard(value); +} + /////////////////////////////////////////////////////////////////////////////// #define ASSIGN(obj, name) (obj)->name = anp_##name void ANPWindowInterfaceV0_Init(ANPInterface* value) { ANPWindowInterfaceV0* i = reinterpret_cast<ANPWindowInterfaceV0*>(value); - + ASSIGN(i, lockRect); ASSIGN(i, lockRegion); + ASSIGN(i, setVisibleRects); + ASSIGN(i, clearVisibleRects); + ASSIGN(i, showKeyboard); ASSIGN(i, unlock); } diff --git a/WebKit/android/plugins/PluginSurface.cpp b/WebKit/android/plugins/PluginSurface.cpp new file mode 100644 index 0000000..aba0263 --- /dev/null +++ b/WebKit/android/plugins/PluginSurface.cpp @@ -0,0 +1,186 @@ +/* + * Copyright 2009, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "PluginSurface.h" + +#include "android_graphics.h" +#include "PluginWidgetAndroid.h" +#include "WebViewCore.h" +#include "jni_utility.h" + +#include <ui/Rect.h> +#include <ui/Region.h> +#include <ui/Surface.h> + +namespace android { + +// jni field offset for the native surface pointer. +static jfieldID gSurfaceField; +static jmethodID gGetHolder; +static jmethodID gGetSurface; + +static void initFields(JNIEnv* env) { + if (gSurfaceField) + return; + + jclass clazz = env->FindClass("android/view/Surface"); + gSurfaceField = env->GetFieldID(clazz, "mSurface", "I"); + + clazz = env->FindClass("android/view/SurfaceView"); + gGetHolder = env->GetMethodID(clazz, "getHolder", "()Landroid/view/SurfaceHolder;"); + + clazz = env->FindClass("android/view/SurfaceHolder"); + gGetSurface = env->GetMethodID(clazz, "getSurface", "()Landroid/view/Surface;"); +} + +static inline sp<Surface> getSurface(jobject view) { + if (!view) { + return NULL; + } + JNIEnv* env = JSC::Bindings::getJNIEnv(); + initFields(env); + jobject holder = env->CallObjectMethod(view, gGetHolder); + jobject surface = env->CallObjectMethod(holder, gGetSurface); + return sp<Surface>((Surface*) env->GetIntField(surface, gSurfaceField)); +} + +static inline SkBitmap::Config convertPixelFormat(PixelFormat format) { + switch (format) { + case PIXEL_FORMAT_RGBA_8888: return SkBitmap::kARGB_8888_Config; + case PIXEL_FORMAT_RGBA_4444: return SkBitmap::kARGB_4444_Config; + case PIXEL_FORMAT_RGB_565: return SkBitmap::kRGB_565_Config; + case PIXEL_FORMAT_A_8: return SkBitmap::kA8_Config; + default: return SkBitmap::kNo_Config; + } +} + +PluginSurface::PluginSurface(PluginWidgetAndroid* widget) + : m_jSurfaceView(0) + , m_widget(widget) { + // Create our java SurfaceView. + jobject obj = widget->webViewCore()->createSurface(this); + if (obj) { + JNIEnv* env = JSC::Bindings::getJNIEnv(); + m_jSurfaceView = env->NewGlobalRef(obj); + env->DeleteLocalRef(obj); + } +} + +void PluginSurface::attach(int x, int y, int width, int height) { + if (m_jSurfaceView) { + m_widget->webViewCore()->attachSurface(m_jSurfaceView, x, y, width, + height); + } +} + +void PluginSurface::destroy() { + m_surface.clear(); + if (m_jSurfaceView) { + m_widget->webViewCore()->destroySurface(m_jSurfaceView); + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->DeleteGlobalRef(m_jSurfaceView); + m_jSurfaceView = 0; + } +} + +bool PluginSurface::lock(SkIRect* dirty, SkBitmap* bitmap) { + if (!bitmap || !Surface::isValid(m_surface)) { + return false; + } + + Region dirtyRegion; + if (dirty) { + Rect rect(dirty->fLeft, dirty->fTop, dirty->fRight, dirty->fBottom); + if (!rect.isEmpty()) { + dirtyRegion.set(rect); + } + } else { + dirtyRegion.set(Rect(0x3FFF, 0x3FFF)); + } + + Surface::SurfaceInfo info; + status_t err = m_surface->lock(&info, &dirtyRegion); + if (err < 0) { + return false; + } + + ssize_t bpr = info.s * bytesPerPixel(info.format); + bitmap->setConfig(convertPixelFormat(info.format), info.w, info.h, bpr); + if (info.w > 0 && info.h > 0) { + bitmap->setPixels(info.bits); + } else { + bitmap->setPixels(NULL); + } + + return true; +} + +void PluginSurface::unlock() { + if (!Surface::isValid(m_surface)) { + return; + } + + m_surface->unlockAndPost(); +} + +static void sendSurfaceEvent(PluginWidgetAndroid* widget, + ANPSurfaceAction action, int format = 0, int width = 0, + int height = 0) { + // format is currently not reported to the plugin. The plumbing from Java + // to C is still provided in case we add the format back to the event. + ANPEvent event; + SkANP::InitEvent(&event, kSurface_ANPEventType); + + event.data.surface.action = action; + if (action == kChanged_ANPSurfaceAction) { + event.data.surface.data.changed.width = width; + event.data.surface.data.changed.height = height; + } + + widget->sendEvent(event); +} + +// SurfaceCallback methods +void PluginSurface::surfaceCreated() { + m_surface = getSurface(m_jSurfaceView); + // Not sure what values for format, width, and height should be here. + sendSurfaceEvent(m_widget, kCreated_ANPSurfaceAction); +} + +void PluginSurface::surfaceChanged(int format, int width, int height) { + m_surface = getSurface(m_jSurfaceView); + sendSurfaceEvent(m_widget, kChanged_ANPSurfaceAction, format, width, + height); +} + +void PluginSurface::surfaceDestroyed() { + m_surface = getSurface(m_jSurfaceView); + // Not sure what values for format, width, and height should be here. + sendSurfaceEvent(m_widget, kDestroyed_ANPSurfaceAction); +} + +} // namespace android diff --git a/WebKit/android/plugins/PluginSurface.h b/WebKit/android/plugins/PluginSurface.h new file mode 100644 index 0000000..b8cbac9 --- /dev/null +++ b/WebKit/android/plugins/PluginSurface.h @@ -0,0 +1,75 @@ +/* + * Copyright 2009, The Android Open Source Project + * Copyright (C) 2008 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PluginSurface_H +#define PluginSurface_H + +#include "android_npapi.h" +#include "SkANP.h" +#include "SurfaceCallback.h" + +#include <jni.h> +#include <ui/Surface.h> +#include <utils/RefBase.h> + +struct PluginWidgetAndroid; +class SkBitmap; +struct SkIRect; + +struct ANPSurface { + void* data; + ANPSurfaceType type; +}; + +namespace android { + +class Surface; + +class PluginSurface : public SurfaceCallback { +public: + PluginSurface(PluginWidgetAndroid* widget); + virtual ~PluginSurface() { + destroy(); + } + + void attach(int x, int y, int width, int height); + void destroy(); + bool lock(SkIRect* dirty, SkBitmap* bitmap); + void unlock(); + + virtual void surfaceCreated(); + virtual void surfaceChanged(int format, int width, int height); + virtual void surfaceDestroyed(); + +private: + jobject m_jSurfaceView; + sp<Surface> m_surface; + PluginWidgetAndroid* m_widget; +}; + +} // namespace android + +#endif diff --git a/WebKit/android/plugins/PluginWidgetAndroid.cpp b/WebKit/android/plugins/PluginWidgetAndroid.cpp index ea13a0c..30a55cb 100644 --- a/WebKit/android/plugins/PluginWidgetAndroid.cpp +++ b/WebKit/android/plugins/PluginWidgetAndroid.cpp @@ -25,9 +25,14 @@ #include "config.h" #include "android_graphics.h" +#include "Document.h" +#include "Element.h" +#include "Frame.h" #include "PluginPackage.h" +#include "PluginSurface.h" #include "PluginView.h" #include "PluginWidgetAndroid.h" +#include "ScrollView.h" #include "SkANP.h" #include "SkFlipPixelRef.h" #include "WebViewCore.h" @@ -37,7 +42,11 @@ PluginWidgetAndroid::PluginWidgetAndroid(WebCore::PluginView* view) m_flipPixelRef = NULL; m_core = NULL; m_drawingModel = kBitmap_ANPDrawingModel; - m_x = m_y = 0; + m_eventFlags = 0; + m_pluginWindow = NULL; + m_requestedVisibleRectCount = 0; + m_requestedFrameRect.setEmpty(); + m_visibleDocRect.setEmpty(); } PluginWidgetAndroid::~PluginWidgetAndroid() { @@ -57,21 +66,28 @@ static SkBitmap::Config computeConfig(bool isTransparent) { : SkBitmap::kRGB_565_Config; } -void PluginWidgetAndroid::setWindow(int x, int y, int width, int height, - bool isTransparent) { - m_x = x; - m_y = y; - m_flipPixelRef->safeUnref(); - m_flipPixelRef = new SkFlipPixelRef(computeConfig(isTransparent), - width, height); +void PluginWidgetAndroid::setWindow(NPWindow* window, bool isTransparent) { + m_pluginWindow = window; + + if (m_drawingModel == kSurface_ANPDrawingModel) { + if (m_surface) { + m_surface->attach(window->x, window->y, window->width, window->height); + } + } else { + m_flipPixelRef->safeUnref(); + m_flipPixelRef = new SkFlipPixelRef(computeConfig(isTransparent), + window->width, window->height); + } } -void PluginWidgetAndroid::setDrawingModel(ANPDrawingModel model) { +bool PluginWidgetAndroid::setDrawingModel(ANPDrawingModel model) { m_drawingModel = model; + return true; } void PluginWidgetAndroid::localToPageCoords(SkIRect* rect) const { - rect->offset(m_x, m_y); + if (m_pluginWindow) + rect->offset(m_pluginWindow->x, m_pluginWindow->y); } bool PluginWidgetAndroid::isDirty(SkIRect* rect) const { @@ -93,14 +109,14 @@ bool PluginWidgetAndroid::isDirty(SkIRect* rect) const { void PluginWidgetAndroid::inval(const WebCore::IntRect& rect, bool signalRedraw) { - // nothing to do if we haven't had setWindow() called yet + // nothing to do if we haven't had setWindow() called yet. m_flipPixelRef + // will also be null if this is a Surface model. if (NULL == m_flipPixelRef) { return; } - SkIRect r; - m_flipPixelRef->inval(*android_setrect(&r, rect)); - + m_flipPixelRef->inval(rect); + if (signalRedraw && m_flipPixelRef->isDirty()) { m_core->invalPlugin(this); } @@ -110,7 +126,7 @@ void PluginWidgetAndroid::draw(SkCanvas* canvas) { if (NULL == m_flipPixelRef || !m_flipPixelRef->isDirty()) { return; } - + SkAutoFlipUpdate update(m_flipPixelRef); const SkBitmap& bitmap = update.bitmap(); const SkRegion& dirty = update.dirty(); @@ -118,23 +134,23 @@ void PluginWidgetAndroid::draw(SkCanvas* canvas) { ANPEvent event; SkANP::InitEvent(&event, kDraw_ANPEventType); - event.data.drawContext.model = m_drawingModel; - SkANP::SetRect(&event.data.drawContext.clip, dirty.getBounds()); - + event.data.draw.model = m_drawingModel; + SkANP::SetRect(&event.data.draw.clip, dirty.getBounds()); + switch (m_drawingModel) { case kBitmap_ANPDrawingModel: { WebCore::PluginPackage* pkg = m_pluginView->plugin(); NPP instance = m_pluginView->instance(); - - if (SkANP::SetBitmap(&event.data.drawContext.data.bitmap, + + if (SkANP::SetBitmap(&event.data.draw.data.bitmap, bitmap) && pkg->pluginFuncs()->event(instance, &event)) { - - if (canvas) { + + if (canvas && m_pluginWindow) { SkBitmap bm(bitmap); bm.setPixelRef(m_flipPixelRef); - canvas->drawBitmap(bm, SkIntToScalar(m_x), - SkIntToScalar(m_y), NULL); + canvas->drawBitmap(bm, SkIntToScalar(m_pluginWindow->x), + SkIntToScalar(m_pluginWindow->y), NULL); } } break; @@ -144,3 +160,152 @@ void PluginWidgetAndroid::draw(SkCanvas* canvas) { } } +bool PluginWidgetAndroid::sendEvent(const ANPEvent& evt) { + WebCore::PluginPackage* pkg = m_pluginView->plugin(); + NPP instance = m_pluginView->instance(); + // "missing" plugins won't have these + if (pkg && instance) { + // make a localCopy since the actual plugin may not respect its constness, + // and so we don't want our caller to have its param modified + ANPEvent localCopy = evt; + return pkg->pluginFuncs()->event(instance, &localCopy); + } + return false; +} + +void PluginWidgetAndroid::updateEventFlags(ANPEventFlags flags) { + + // if there are no differences then immediately return + if (m_eventFlags == flags) { + return; + } + + Document* doc = m_pluginView->getParentFrame()->document(); + if((m_eventFlags ^ flags) & kTouch_ANPEventFlag) { + if(flags & kTouch_ANPEventFlag) + doc->addTouchEventListener(m_pluginView->getElement()); + else + doc->removeTouchEventListener(m_pluginView->getElement()); + } + + m_eventFlags = flags; +} + +bool PluginWidgetAndroid::isAcceptingEvent(ANPEventFlag flag) { + return m_eventFlags & flag; +} + +ANPSurface* PluginWidgetAndroid::createSurface(ANPSurfaceType ignored) { + if (m_drawingModel != kSurface_ANPDrawingModel) { + return NULL; + } + m_surface.set(new android::PluginSurface(this)); + ANPSurface* surface = new ANPSurface; + surface->data = m_surface.get(); + surface->type = ignored; + return surface; +} + +void PluginWidgetAndroid::setVisibleScreen(const ANPRectI& visibleDocRect, float zoom) { + + //TODO send an event to the plugin that communicates the zoom + + int oldScreenW = m_visibleDocRect.width(); + int oldScreenH = m_visibleDocRect.height(); + + m_visibleDocRect.set(visibleDocRect.left, visibleDocRect.top, + visibleDocRect.right, visibleDocRect.bottom); + + int newScreenW = m_visibleDocRect.width(); + int newScreenH = m_visibleDocRect.height(); + + if (oldScreenW != newScreenW || oldScreenH != newScreenH) + computeVisibleFrameRect(); +} + +void PluginWidgetAndroid::setVisibleRects(const ANPRectI rects[], int32_t count) { + + // ensure the count does not exceed our allocated space + if (count > MAX_REQUESTED_RECTS) + count = MAX_REQUESTED_RECTS; + + // store the values in member variables + m_requestedVisibleRectCount = count; + memcpy(m_requestedVisibleRect, rects, count * sizeof(rects[0])); + + computeVisibleFrameRect(); +} + +void PluginWidgetAndroid::computeVisibleFrameRect() { + + // ensure the visibleDocRect has been set (i.e. not equal to zero) + if (m_visibleDocRect.isEmpty() || !m_pluginWindow) + return; + + // create a rect that represents the plugin's bounds + SkIRect pluginBounds; + pluginBounds.set(m_pluginWindow->x, m_pluginWindow->y, + m_pluginWindow->x + m_pluginWindow->width, + m_pluginWindow->y + m_pluginWindow->height); + + // create a rect that will contain as many of the rects that will fit on screen + SkIRect visibleRect; + visibleRect.setEmpty(); + + for (int counter = 0; counter < m_requestedVisibleRectCount; counter++) { + + ANPRectI* rect = &m_requestedVisibleRect[counter]; + + // create skia rect for easier manipulation and convert it to frame coordinates + SkIRect pluginRect; + pluginRect.set(rect->left, rect->top, rect->right, rect->bottom); + pluginRect.offset(m_pluginWindow->x, m_pluginWindow->y); + + // ensure the rect falls within the plugin's bounds + if (!pluginBounds.contains(pluginRect)) + continue; + + // combine this new rect with the higher priority rects + pluginRect.join(visibleRect); + + // check to see if the new rect fits within the screen bounds. If this + // is the highest priority rect then attempt to center even if it doesn't + // fit on the screen. + if (counter > 0 && (m_visibleDocRect.width() < pluginRect.width() || + m_visibleDocRect.height() < pluginRect.height())) + break; + + // set the new visible rect + visibleRect = pluginRect; + } + + m_requestedFrameRect = visibleRect; + scrollToVisibleFrameRect(); +} + +void PluginWidgetAndroid::scrollToVisibleFrameRect() { + + if (m_requestedFrameRect.isEmpty() || m_visibleDocRect.isEmpty()) + return; + + // TODO if the entire rect is already visible then we don't need to scroll, + // this requires converting the m_requestedFrameRect from frame to doc coordinates + + // find the center of the visibleRect in document coordinates + ScrollView* scrollView = m_pluginView->parent(); + IntPoint pluginFramePoint = IntPoint(m_requestedFrameRect.fLeft, m_requestedFrameRect.fTop); + IntPoint pluginDocPoint = scrollView->convertToContainingWindow(pluginFramePoint); + int rectCenterX = pluginDocPoint.x() + m_requestedFrameRect.width()/2; + int rectCenterY = pluginDocPoint.y() + m_requestedFrameRect.height()/2; + + // find document coordinates for center of the visible screen + int screenCenterX = m_visibleDocRect.fLeft + m_visibleDocRect.width()/2; + int screenCenterY = m_visibleDocRect.fTop + m_visibleDocRect.height()/2; + + //compute the delta of the two points + int deltaX = rectCenterX - screenCenterX; + int deltaY = rectCenterY - screenCenterY; + + android::WebViewCore* core = android::WebViewCore::getWebViewCore(scrollView); + core->scrollBy(deltaX, deltaY, true); +} diff --git a/WebKit/android/plugins/PluginWidgetAndroid.h b/WebKit/android/plugins/PluginWidgetAndroid.h index f5e9363..1da618f 100644 --- a/WebKit/android/plugins/PluginWidgetAndroid.h +++ b/WebKit/android/plugins/PluginWidgetAndroid.h @@ -27,12 +27,16 @@ #define PluginWidgetAndroid_H #include "android_npapi.h" +#include "SkRect.h" + +#include <wtf/OwnPtr.h> namespace WebCore { class PluginView; } namespace android { + class PluginSurface; class WebViewCore; } @@ -49,18 +53,26 @@ struct PluginWidgetAndroid { // destroyed. PluginWidgetAndroid(WebCore::PluginView* view); ~PluginWidgetAndroid(); - + + WebCore::PluginView* pluginView() const { return m_pluginView; } + + // Needed by PluginSurface to manage the java SurfaceView. + android::WebViewCore* webViewCore() const { return m_core; } + /* Can't determine our core at construction time, so PluginView calls this as soon as it has a parent. */ void init(android::WebViewCore*); /* Called each time the PluginView gets a new size or position. */ - void setWindow(int x, int y, int width, int height, bool isTransparent); - /* Called whenever the plugin itself requests a new drawing model + void setWindow(NPWindow* window, bool isTransparent); + + /* Called whenever the plugin itself requests a new drawing model. If the + hardware does not support the requested model then false is returned, + otherwise true is returned. */ - void setDrawingModel(ANPDrawingModel); - + bool setDrawingModel(ANPDrawingModel); + /* Utility method to convert from local (plugin) coordinates to docuemnt coordinates. Needed (for instance) to convert the dirty rectangle into document coordinates to inturn inval the screen. @@ -76,19 +88,72 @@ struct PluginWidgetAndroid { a subsequent call to draw(NULL). */ void inval(const WebCore::IntRect&, bool signalRedraw); - + /* Called to draw into the plugin's bitmap. If canvas is non-null, the bitmap itself is then drawn into the canvas. */ void draw(SkCanvas* canvas = NULL); - + + /* Send this event to the plugin instance, and return true if the plugin + handled it. + */ + bool sendEvent(const ANPEvent&); + + /* Update the plugins event flags. If a flag is set to true then the plugin + wants to be notified of events of this type. + */ + void updateEventFlags(ANPEventFlags); + + /* Called to check if a plugin wants to accept a given event type. It + returns true if the plugin wants the events and false otherwise. + */ + bool isAcceptingEvent(ANPEventFlag); + + /* Create an ANPSurface that the plugin may draw in to. The drawing model + must be kSurface_ANPDrawingModel for this call to succeed. The type + specifies what kind of pixel access will be available. + */ + ANPSurface* createSurface(ANPSurfaceType type); + + /* Notify the plugin of the currently visible screen coordinates (document + space) and the current zoom level. + */ + void setVisibleScreen(const ANPRectI& visibleScreenRect, float zoom); + + /** Registers a set of rectangles that the plugin would like to keep on + screen. The rectangles are listed in order of priority with the highest + priority rectangle in location rects[0]. The browser will attempt to keep + as many of the rectangles on screen as possible and will scroll them into + view in response to the invocation of this method and other various events. + The count specifies how many rectangles are in the array. If the count is + zero it signals the plugin that any existing rectangles should be cleared + and no rectangles will be tracked. + */ + void setVisibleRects(const ANPRectI rects[], int32_t count); + private: + void computeVisibleFrameRect(); + void scrollToVisibleFrameRect(); + WebCore::PluginView* m_pluginView; android::WebViewCore* m_core; SkFlipPixelRef* m_flipPixelRef; ANPDrawingModel m_drawingModel; - int m_x; - int m_y; + ANPEventFlags m_eventFlags; + NPWindow* m_pluginWindow; + SkIRect m_visibleDocRect; + SkIRect m_requestedFrameRect; + OwnPtr<android::PluginSurface> m_surface; + + /* We limit the number of rectangles to minimize storage and ensure adequate + speed. + */ + enum { + MAX_REQUESTED_RECTS = 5, + }; + + ANPRectI m_requestedVisibleRect[MAX_REQUESTED_RECTS]; + int32_t m_requestedVisibleRectCount; }; #endif diff --git a/WebKit/android/plugins/sample/pluginGraphics.h b/WebKit/android/plugins/SurfaceCallback.h index 4dceb26..fb2e015 100644 --- a/WebKit/android/plugins/sample/pluginGraphics.h +++ b/WebKit/android/plugins/SurfaceCallback.h @@ -1,16 +1,17 @@ /* - * Copyright 2008, The Android Open Source Project + * Copyright 2009, The Android Open Source Project + * Copyright (C) 2008 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: - * * Redistributions of source code must retain the above copyright + * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright + * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR @@ -22,19 +23,20 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - -#include "main.h" // for NPAPI definitions -#include "PluginObject.h" -#ifndef pluginGraphics__DEFINED -#define pluginGraphics__DEFINED +#ifndef SurfaceCallback_H +#define SurfaceCallback_H -struct ANPBitmap; -struct ANPCanvas; -struct ANPRectI; +namespace android { -void drawPlugin(NPP instance, const ANPBitmap& bitmap, const ANPRectI& clip); -void drawPlugin(NPP instance, ANPCanvas*); -uint32_t getMSecs(); + class SurfaceCallback { + public: + virtual ~SurfaceCallback() {} + virtual void surfaceCreated() = 0; + virtual void surfaceChanged(int format, int width, int height) = 0; + virtual void surfaceDestroyed() = 0; + }; -#endif // pluginGraphics__DEFINED +} // namespace android + +#endif diff --git a/WebKit/android/plugins/android_npapi.h b/WebKit/android/plugins/android_npapi.h index f64c8ce..e50f031 100644 --- a/WebKit/android/plugins/android_npapi.h +++ b/WebKit/android/plugins/android_npapi.h @@ -24,10 +24,10 @@ */ /* Defines the android-specific types and functions as part of npapi - + In particular, defines the window and event types that are passed to NPN_GetValue, NPP_SetWindow and NPP_HandleEvent. - + To minimize what native libraries the plugin links against, some functionality is provided via function-ptrs (e.g. time, sound) */ @@ -49,6 +49,17 @@ enum ANPBitmapFormats { }; typedef int32_t ANPBitmapFormat; +struct ANPPixelPacking { + uint8_t AShift; + uint8_t ABits; + uint8_t RShift; + uint8_t RBits; + uint8_t GShift; + uint8_t GBits; + uint8_t BShift; + uint8_t BBits; +}; + struct ANPBitmap { void* baseAddr; ANPBitmapFormat format; @@ -91,9 +102,9 @@ typedef uint32_t ANPMatrixFlag; // NPN_GetValue /* queries for a specific ANPInterface. - + Maybe called with NULL for the NPP instance - + NPN_GetValue(inst, interface_enum, ANPInterface*) */ #define kLogInterfaceV0_ANPGetValue ((NPNVariable)1000) @@ -101,22 +112,25 @@ typedef uint32_t ANPMatrixFlag; #define kCanvasInterfaceV0_ANPGetValue ((NPNVariable)1002) #define kMatrixInterfaceV0_ANPGetValue ((NPNVariable)1003) #define kPaintInterfaceV0_ANPGetValue ((NPNVariable)1004) -#define kTypefaceInterfaceV0_ANPGetValue ((NPNVariable)1005) -#define kWindowInterfaceV0_ANPGetValue ((NPNVariable)1006) +#define kPathInterfaceV0_ANPGetValue ((NPNVariable)1005) +#define kTypefaceInterfaceV0_ANPGetValue ((NPNVariable)1006) +#define kWindowInterfaceV0_ANPGetValue ((NPNVariable)1007) +#define kBitmapInterfaceV0_ANPGetValue ((NPNVariable)1008) +#define kSurfaceInterfaceV0_ANPGetValue ((NPNVariable)1009) /* queries for which drawing model is desired (for the draw event) - + Should be called inside NPP_New(...) - + NPN_GetValue(inst, ANPSupportedDrawingModel_EnumValue, uint32_t* bits) */ #define kSupportedDrawingModel_ANPGetValue ((NPNVariable)2000) /////////////////////////////////////////////////////////////////////////////// -// NPN_GetValue +// NPN_SetValue + +/** Request to set the drawing model. -/** Reqeust to set the drawing model. - NPN_SetValue(inst, ANPRequestDrawingModel_EnumValue, (void*)foo_DrawingModel) */ #define kRequestDrawingModel_ANPSetValue ((NPPVariable)1000) @@ -130,14 +144,33 @@ enum ANPDrawingModels { /** Draw into a bitmap from the browser thread in response to a Draw event. NPWindow->window is reserved (ignore) */ - kBitmap_ANPDrawingModel = 0, + kBitmap_ANPDrawingModel = 0, + kSurface_ANPDrawingModel = 1, }; typedef int32_t ANPDrawingModel; +/** Request to receive/disable events. If the pointer is NULL then all input will + be disabled. Otherwise, the input type will be enabled iff its corresponding + bit in the EventFlags bit field is set. + + NPN_SetValue(inst, ANPAcceptEvents, (void*)EventFlags) + */ +#define kAcceptEvents_ANPSetValue ((NPPVariable)1001) + +/* The EventFlags are a set of bits used to determine which types of input the + plugin wishes to receive. For example, if the value is 0x03 then both key + and touch events will be provided to the plugin. + */ +enum ANPEventFlag { + kKey_ANPEventFlag = 0x01, + kTouch_ANPEventFlag = 0x02, +}; +typedef uint32_t ANPEventFlags; + /* Interfaces provide additional functionality to the plugin via function ptrs. Once an interface is retrived, it is valid for the lifetime of the plugin (just like browserfuncs). - + All ANPInterfaces begin with an inSize field, which must be set by the caller (plugin) with the number of bytes allocated for the interface. e.g. SomeInterface si; si.inSize = sizeof(si); browser->getvalue(..., &si); @@ -159,6 +192,50 @@ struct ANPLogInterfaceV0 : ANPInterface { void (*log)(NPP instance, ANPLogType, const char format[], ...); }; +struct ANPBitmapInterfaceV0 : ANPInterface { + /** Returns true if the specified bitmap format is supported, and if packing + is non-null, sets it to the packing info for that format. + */ + bool (*getPixelPacking)(ANPBitmapFormat, ANPPixelPacking* packing); +}; + +/** The surfaceType is the mechanism by which the plugin informs the native + libraries which type of surface view it wishes to use. + */ +enum ANPSurfaceTypes { + kRGBA_ANPSurfaceType = 0 +}; +typedef int32_t ANPSurfaceType; + +/** The ANPSurface acts as a handle between the plugin and the native libraries + that render the surface to the screen. + */ +struct ANPSurface; + +struct ANPSurfaceInterfaceV0 : ANPInterface { + /** Creates a new surface handle based on the given surface type. If the + given surface type is not supported then NULL is returned. + */ + ANPSurface* (*newSurface)(NPP instance, ANPSurfaceType); + /** Given a valid surface handle (i.e. one created by calling newSurface) + the underlying surface is removed and the pointer is set to NULL. + */ + void (*deleteSurface)(ANPSurface* surface); + /** Locks the surface from manipulation by other threads and provides a bitmap + to be written to. The dirtyRect param specifies which portion of the + bitmap will be written to. If the dirtyRect is NULL then the entire + surface will be considered dirty. If the lock was successful the function + will return true and the bitmap will be set to point to a valid bitmap. + If not the function will return false and the bitmap will be set to NULL. + */ + bool (*lock)(ANPSurface* surface, ANPBitmap* bitmap, ANPRectI* dirtyRect); + /** Given a locked surface handle (i.e. result of a successful call to lock) + the surface is unlocked and the contents of the bitmap, specifically + those inside the dirtyRect are written to the screen. + */ + void (*unlock)(ANPSurface* surface); +}; + struct ANPMatrixInterfaceV0 : ANPInterface { /* Return a new identity matrix */ @@ -212,9 +289,70 @@ struct ANPMatrixInterfaceV0 : ANPInterface { int32_t count); }; +struct ANPPathInterfaceV0 : ANPInterface { + /* Return a new path */ + ANPPath* (*newPath)(); + + /* Delete a path previously allocated by ANPPath() */ + void (*deletePath)(ANPPath*); + + /* Make a deep copy of the src path, into the dst path (already allocated + by the caller). + */ + void (*copy)(ANPPath* dst, const ANPPath* src); + + /* Returns true if the two paths are the same (i.e. have the same points) + */ + bool (*equal)(const ANPPath* path0, const ANPPath* path1); + + /* Remove any previous points, initializing the path back to empty. */ + void (*reset)(ANPPath*); + + /* Return true if the path is empty (has no lines, quads or cubics). */ + bool (*isEmpty)(const ANPPath*); + + /* Return the path's bounds in bounds. */ + void (*getBounds)(const ANPPath*, ANPRectF* bounds); + + void (*moveTo)(ANPPath*, float x, float y); + void (*lineTo)(ANPPath*, float x, float y); + void (*quadTo)(ANPPath*, float x0, float y0, float x1, float y1); + void (*cubicTo)(ANPPath*, float x0, float y0, float x1, float y1, + float x2, float y2); + void (*close)(ANPPath*); + + /* Offset the src path by [dx, dy]. If dst is null, apply the + change directly to the src path. If dst is not null, write the + changed path into dst, and leave the src path unchanged. In that case + dst must have been previously allocated by the caller. + */ + void (*offset)(ANPPath* src, float dx, float dy, ANPPath* dst); + + /* Transform the path by the matrix. If dst is null, apply the + change directly to the src path. If dst is not null, write the + changed path into dst, and leave the src path unchanged. In that case + dst must have been previously allocated by the caller. + */ + void (*transform)(ANPPath* src, const ANPMatrix*, ANPPath* dst); +}; + +/** ANPColor is always defined to have the same packing on all platforms, and + it is always unpremultiplied. + + This is in contrast to 32bit format(s) in bitmaps, which are premultiplied, + and their packing may vary depending on the platform, hence the need for + ANPBitmapInterface::getPixelPacking() + */ typedef uint32_t ANPColor; +#define ANPColor_ASHIFT 24 +#define ANPColor_RSHIFT 16 +#define ANPColor_GSHIFT 8 +#define ANPColor_BSHIFT 0 #define ANP_MAKE_COLOR(a, r, g, b) \ - (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)) + (((a) << ANPColor_ASHIFT) | \ + ((r) << ANPColor_RSHIFT) | \ + ((g) << ANPColor_GSHIFT) | \ + ((b) << ANPColor_BSHIFT)) enum ANPPaintFlag { kAntiAlias_ANPPaintFlag = 1 << 0, @@ -266,6 +404,8 @@ enum ANPTypefaceStyles { }; typedef uint32_t ANPTypefaceStyle; +typedef uint32_t ANPFontTableTag; + struct ANPFontMetrics { //! The greatest distance above the baseline for any glyph (will be <= 0) float fTop; @@ -303,7 +443,7 @@ struct ANPTypefaceInterfaceV0 : ANPInterface { */ ANPTypeface* (*createFromTypeface)(const ANPTypeface* family, ANPTypefaceStyle); - + /** Return the owner count of the typeface. A newly created typeface has an owner count of 1. When the owner count is reaches 0, the typeface is deleted. @@ -318,29 +458,33 @@ struct ANPTypefaceInterfaceV0 : ANPInterface { the typeface is deleted. */ void (*unref)(ANPTypeface*); - + /** Return the style bits for the specified typeface */ ANPTypefaceStyle (*getStyle)(const ANPTypeface*); + + /** Return the path name for the font directory, or NULL if not supported + */ + const char* (*getFontDirectoryPath)(); }; struct ANPPaintInterfaceV0 : ANPInterface { /* Return a new paint object, which holds all of the color and style attributes that affect how things (geometry, text, bitmaps) are drawn in a ANPCanvas. - + The paint that is returned is not tied to any particular plugin instance, but it must only be accessed from one thread at a time. */ ANPPaint* (*newPaint)(); void (*deletePaint)(ANPPaint*); - + ANPPaintFlags (*getFlags)(const ANPPaint*); void (*setFlags)(ANPPaint*, ANPPaintFlags); - + ANPColor (*getColor)(const ANPPaint*); void (*setColor)(ANPPaint*, ANPColor); - + ANPPaintStyle (*getStyle)(const ANPPaint*); void (*setStyle)(ANPPaint*, ANPPaintStyle); @@ -352,7 +496,7 @@ struct ANPPaintInterfaceV0 : ANPInterface { void (*setStrokeMiter)(ANPPaint*, float); void (*setStrokeCap)(ANPPaint*, ANPPaintCap); void (*setStrokeJoin)(ANPPaint*, ANPPaintJoin); - + ANPTextEncoding (*getTextEncoding)(const ANPPaint*); ANPPaintAlign (*getTextAlign)(const ANPPaint*); float (*getTextSize)(const ANPPaint*); @@ -380,7 +524,7 @@ struct ANPPaintInterfaceV0 : ANPInterface { */ float (*measureText)(ANPPaint*, const void* text, uint32_t byteLength, ANPRectF* bounds); - + /** Return the number of unichars specifed by the text. If widths is not null, returns the array of advance widths for each unichar. @@ -388,7 +532,7 @@ struct ANPPaintInterfaceV0 : ANPInterface { */ int (*getTextWidths)(ANPPaint*, const void* text, uint32_t byteLength, float widths[], ANPRectF bounds[]); - + /** Return in metrics the spacing values for text, respecting the paint's typeface and pointsize, and return the spacing between lines (descent - ascent + leading). If metrics is NULL, it will be ignored. @@ -404,7 +548,7 @@ struct ANPCanvasInterfaceV0 : ANPInterface { goes out of scope. In the case of creating a canvas to draw into the pixels provided by kDraw_ANPEventType, those pixels are only while handling that event. - + The canvas that is returned is not tied to any particular plugin instance, but it must only be accessed from one thread at a time. */ @@ -433,9 +577,11 @@ struct ANPCanvasInterfaceV0 : ANPInterface { current clip is empty, return false and ignore the bounds argument. */ bool (*getDeviceClipBounds)(ANPCanvas*, ANPRectI* bounds); - + void (*drawColor)(ANPCanvas*, ANPColor); void (*drawPaint)(ANPCanvas*, const ANPPaint*); + void (*drawLine)(ANPCanvas*, float x0, float y0, float x1, float y1, + const ANPPaint*); void (*drawRect)(ANPCanvas*, const ANPRectF*, const ANPPaint*); void (*drawOval)(ANPCanvas*, const ANPRectF*, const ANPPaint*); void (*drawPath)(ANPCanvas*, const ANPPath*, const ANPPaint*); @@ -455,7 +601,7 @@ struct ANPWindowInterfaceV0 : ANPInterface { describing the subset of the window that will be drawn to (may be null) return true if the bitmap for that window can be accessed, and if so, fill out the specified ANPBitmap to point to the window's pixels. - + When drawing is complete, call unlock(window) */ bool (*lockRect)(void* window, const ANPRectI* inval, ANPBitmap*); @@ -468,6 +614,26 @@ struct ANPWindowInterfaceV0 : ANPInterface { results. If lock returned false, unlock should not be called. */ void (*unlock)(void* window); + /** Registers a set of rectangles that the plugin would like to keep on + screen. The rectangles are listed in order of priority with the highest + priority rectangle in location rects[0]. The browser will attempt to keep + as many of the rectangles on screen as possible and will scroll them into + view in response to the invocation of this method and other various events. + The count specifies how many rectangles are in the array. If the count is + zero it signals the browser that any existing rectangles should be cleared + and no rectangles will be tracked. + */ + void (*setVisibleRects)(NPP instance, const ANPRectI rects[], int32_t count); + /** Clears any rectangles that are being tracked as a result of a call to + setVisibleRects. This call is equivalent to setVisibleRect(inst, NULL, 0). + */ + void (*clearVisibleRects)(NPP instance); + /** Given a boolean value of true the device will be requested to provide + a keyboard. A value of false will result in a request to hide the + keyboard. Further, the on-screen keyboard will not be displayed if a + physical keyboard is active. + */ + void (*showKeyboard)(NPP instance, bool value); }; /////////////////////////////////////////////////////////////////////////////// @@ -517,11 +683,11 @@ typedef int32_t ANPAudioEvent; /** Called to feed sample data to the track. This will be called in a separate thread. However, you may call trackStop() from the callback (but you cannot delete the track). - + For example, when you have written the last chunk of sample data, you can immediately call trackStop(). This will take effect after the current buffer has been played. - + The "user" parameter is the same value that was passed to newTrack() */ typedef void (*ANPAudioCallbackProc)(ANPAudioEvent event, void* user, @@ -552,10 +718,13 @@ struct ANPAudioTrackInterfaceV0 : ANPInterface { // HandleEvent enum ANPEventTypes { - kNull_ANPEventType = 0, - kKey_ANPEventType = 1, - kTouch_ANPEventType = 2, - kDraw_ANPEventType = 3, + kNull_ANPEventType = 0, + kKey_ANPEventType = 1, + kMouse_ANPEventType = 2, + kTouch_ANPEventType = 3, + kDraw_ANPEventType = 4, + kLifecycle_ANPEventType = 5, + kSurface_ANPEventType = 6, }; typedef int32_t ANPEventType; @@ -575,21 +744,45 @@ enum ANPKeyModifiers { // bit-field containing some number of ANPKeyModifier bits typedef uint32_t ANPKeyModifier; +enum ANPMouseActions { + kDown_ANPMouseAction = 0, + kUp_ANPMouseAction = 1, +}; +typedef int32_t ANPMouseAction; + enum ANPTouchActions { - kDown_ANPTouchAction = 0, - kUp_ANPTouchAction = 1, + kDown_ANPTouchAction = 0, + kUp_ANPTouchAction = 1, + kMove_ANPTouchAction = 2, + kCancel_ANPTouchAction = 3, }; typedef int32_t ANPTouchAction; -struct ANPDrawContext { - ANPDrawingModel model; - // relative to (0,0) in top-left of your plugin - ANPRectI clip; - // use based on the value in model - union { - ANPBitmap bitmap; - } data; +enum ANPLifecycleActions { + kPause_ANPLifecycleAction = 0, + kResume_ANPLifecycleAction = 1, + kGainFocus_ANPLifecycleAction = 2, + kLoseFocus_ANPLifecycleAction = 3, + kFreeMemory_ANPLifecycleAction = 4, +}; +typedef uint32_t ANPLifecycleAction; + +enum ANPSurfaceActions { + /** The surface has been created and is ready to be used. Any calls to + lock/unlock before this action will fail. + */ + kCreated_ANPSurfaceAction = 0, + /** The surface's dimension has changed. + */ + kChanged_ANPSurfaceAction = 1, + /** The surface has been destroyed. This happens when the view system has + remove the surface (possibly due to the plugin being offscreen). Calls + to lock/unlock will fail after this action and before + kCreate_ANPSurfaceAction. + */ + kDestroyed_ANPSurfaceAction = 2, }; +typedef uint32_t ANPSurfaceAction; /* This is what is passed to NPP_HandleEvent() */ struct ANPEvent { @@ -606,12 +799,44 @@ struct ANPEvent { int32_t unichar; // 0 if there is no value } key; struct { + ANPMouseAction action; + int32_t x; // relative to your "window" (0...width) + int32_t y; // relative to your "window" (0...height) + } mouse; + struct { ANPTouchAction action; ANPKeyModifier modifiers; int32_t x; // relative to your "window" (0...width) int32_t y; // relative to your "window" (0...height) } touch; - ANPDrawContext drawContext; + struct { + ANPLifecycleAction action; + } lifecycle; + struct { + ANPDrawingModel model; + // relative to (0,0) in top-left of your plugin + ANPRectI clip; + // use based on the value in model + union { + ANPBitmap bitmap; + } data; + } draw; + struct { + ANPSurfaceAction action; + /** This union is based on the value of action and contains data + specific to the given action. + */ + union { + /** This struct is filled in only during the + kChanged_ANPSurfaceAction action. For all other actions, + this struct is undefined. + */ + struct { + int32_t width; + int32_t height; + } changed; + } data; + } surface; int32_t other[8]; } data; }; diff --git a/WebKit/android/plugins/sample/Android.mk b/WebKit/android/plugins/sample/Android.mk deleted file mode 100644 index 328ddc5..0000000 --- a/WebKit/android/plugins/sample/Android.mk +++ /dev/null @@ -1,50 +0,0 @@ -## -## -## Copyright 2008, The Android Open Source Project -## -## Redistribution and use in source and binary forms, with or without -## modification, are permitted provided that the following conditions -## are met: -## * Redistributions of source code must retain the above copyright -## notice, this list of conditions and the following disclaimer. -## * Redistributions in binary form must reproduce the above copyright -## notice, this list of conditions and the following disclaimer in the -## documentation and/or other materials provided with the distribution. -## -## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY -## EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR -## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -## EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -## PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -## PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -## OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -## - -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - main.cpp \ - PluginObject.cpp \ - pluginGraphics.cpp - -LOCAL_C_INCLUDES += \ - $(LOCAL_PATH) \ - external/webkit/WebCore/bridge \ - external/webkit/WebCore/plugins \ - external/webkit/WebCore/platform/android/JavaVM \ - external/webkit/WebKit/android/plugins - -LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) -LOCAL_CFLAGS += -fvisibility=hidden -LOCAL_PRELINK_MODULE:=false -LOCAL_MODULE_CLASS := SHARED_LIBRARIES - -LOCAL_MODULE:= browsertestplugin - -include $(BUILD_SHARED_LIBRARY) - diff --git a/WebKit/android/plugins/sample/PluginObject.cpp b/WebKit/android/plugins/sample/PluginObject.cpp deleted file mode 100644 index 5499072..0000000 --- a/WebKit/android/plugins/sample/PluginObject.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/* - IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. ("Apple") in - consideration of your agreement to the following terms, and your use, installation, - modification or redistribution of this Apple software constitutes acceptance of these - terms. If you do not agree with these terms, please do not use, install, modify or - redistribute this Apple software. - - In consideration of your agreement to abide by the following terms, and subject to these - terms, Apple grants you a personal, non-exclusive license, under AppleÕs copyrights in - this original Apple software (the "Apple Software"), to use, reproduce, modify and - redistribute the Apple Software, with or without modifications, in source and/or binary - forms; provided that if you redistribute the Apple Software in its entirety and without - modifications, you must retain this notice and the following text and disclaimers in all - such redistributions of the Apple Software. Neither the name, trademarks, service marks - or logos of Apple Computer, Inc. may be used to endorse or promote products derived from - the Apple Software without specific prior written permission from Apple. Except as expressly - stated in this notice, no other rights or licenses, express or implied, are granted by Apple - herein, including but not limited to any patent rights that may be infringed by your - derivative works or by other works in which the Apple Software may be incorporated. - - The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, - EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS - USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. - - IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, - REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND - WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR - OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <stdlib.h> -#include "main.h" -#include "PluginObject.h" - -static void pluginInvalidate(NPObject *obj); -static bool pluginHasProperty(NPObject *obj, NPIdentifier name); -static bool pluginHasMethod(NPObject *obj, NPIdentifier name); -static bool pluginGetProperty(NPObject *obj, NPIdentifier name, NPVariant *variant); -static bool pluginSetProperty(NPObject *obj, NPIdentifier name, const NPVariant *variant); -static bool pluginInvoke(NPObject *obj, NPIdentifier name, const NPVariant *args, uint32_t argCount, NPVariant *result); -static bool pluginInvokeDefault(NPObject *obj, const NPVariant *args, uint32_t argCount, NPVariant *result); -static NPObject *pluginAllocate(NPP npp, NPClass *theClass); -static void pluginDeallocate(NPObject *obj); -static bool pluginRemoveProperty(NPObject *npobj, NPIdentifier name); -static bool pluginEnumerate(NPObject *npobj, NPIdentifier **value, uint32_t *count); - - - -static NPClass pluginClass = { - NP_CLASS_STRUCT_VERSION, - pluginAllocate, - pluginDeallocate, - pluginInvalidate, - pluginHasMethod, - pluginInvoke, - pluginInvokeDefault, - pluginHasProperty, - pluginGetProperty, - pluginSetProperty, - pluginRemoveProperty, - pluginEnumerate -}; - -NPClass *getPluginClass(void) -{ - return &pluginClass; -} - -static bool identifiersInitialized = false; - -#define ID_TESTFILE_PROPERTY 0 -#define NUM_PROPERTY_IDENTIFIERS 1 - -static NPIdentifier pluginPropertyIdentifiers[NUM_PROPERTY_IDENTIFIERS]; -static const NPUTF8 *pluginPropertyIdentifierNames[NUM_PROPERTY_IDENTIFIERS] = { - "testfile" -}; - -#define ID_GETTESTFILE_METHOD 0 -#define NUM_METHOD_IDENTIFIERS 1 - -static NPIdentifier pluginMethodIdentifiers[NUM_METHOD_IDENTIFIERS]; -static const NPUTF8 *pluginMethodIdentifierNames[NUM_METHOD_IDENTIFIERS] = { - "getTestFile" -}; - -static void initializeIdentifiers(void) -{ - browser->getstringidentifiers(pluginPropertyIdentifierNames, NUM_PROPERTY_IDENTIFIERS, pluginPropertyIdentifiers); - browser->getstringidentifiers(pluginMethodIdentifierNames, NUM_METHOD_IDENTIFIERS, pluginMethodIdentifiers); -} - -static bool pluginHasProperty(NPObject *obj, NPIdentifier name) -{ - int i; - for (i = 0; i < NUM_PROPERTY_IDENTIFIERS; i++) - if (name == pluginPropertyIdentifiers[i]) - return true; - return false; -} - -static bool pluginHasMethod(NPObject *obj, NPIdentifier name) -{ - int i; - for (i = 0; i < NUM_METHOD_IDENTIFIERS; i++) - if (name == pluginMethodIdentifiers[i]) - return true; - return false; -} - -static bool pluginGetProperty(NPObject *obj, NPIdentifier name, NPVariant *variant) -{ - PluginObject *plugin = (PluginObject *)obj; - if (name == pluginPropertyIdentifiers[ID_TESTFILE_PROPERTY]) { - BOOLEAN_TO_NPVARIANT(true, *variant); - return true; - } - return false; -} - -static bool pluginSetProperty(NPObject *obj, NPIdentifier name, const NPVariant *variant) -{ - return false; -} - -static bool pluginInvoke(NPObject *obj, NPIdentifier name, const NPVariant *args, uint32_t argCount, NPVariant *result) -{ - PluginObject *plugin = (PluginObject *)obj; - if (name == pluginMethodIdentifiers[ID_GETTESTFILE_METHOD]) { - return true; - } - return false; -} - -static bool pluginInvokeDefault(NPObject *obj, const NPVariant *args, uint32_t argCount, NPVariant *result) -{ - return false; -} - -static void pluginInvalidate(NPObject *obj) -{ - // Release any remaining references to JavaScript objects. -} - -static NPObject *pluginAllocate(NPP npp, NPClass *theClass) -{ - PluginObject *newInstance = (PluginObject*) malloc(sizeof(PluginObject)); - newInstance->header._class = theClass; - newInstance->header.referenceCount = 1; - - if (!identifiersInitialized) { - identifiersInitialized = true; - initializeIdentifiers(); - } - - newInstance->npp = npp; - - return &newInstance->header; -} - -static void pluginDeallocate(NPObject *obj) -{ - free(obj); -} - -static bool pluginRemoveProperty(NPObject *npobj, NPIdentifier name) -{ - return false; -} - -static bool pluginEnumerate(NPObject *npobj, NPIdentifier **value, uint32_t *count) -{ - return false; -} - diff --git a/WebKit/android/plugins/sample/PluginObject.h b/WebKit/android/plugins/sample/PluginObject.h deleted file mode 100644 index ae8963d..0000000 --- a/WebKit/android/plugins/sample/PluginObject.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. ("Apple") in - consideration of your agreement to the following terms, and your use, installation, - modification or redistribution of this Apple software constitutes acceptance of these - terms. If you do not agree with these terms, please do not use, install, modify or - redistribute this Apple software. - - In consideration of your agreement to abide by the following terms, and subject to these - terms, Apple grants you a personal, non-exclusive license, under AppleÕs copyrights in - this original Apple software (the "Apple Software"), to use, reproduce, modify and - redistribute the Apple Software, with or without modifications, in source and/or binary - forms; provided that if you redistribute the Apple Software in its entirety and without - modifications, you must retain this notice and the following text and disclaimers in all - such redistributions of the Apple Software. Neither the name, trademarks, service marks - or logos of Apple Computer, Inc. may be used to endorse or promote products derived from - the Apple Software without specific prior written permission from Apple. Except as expressly - stated in this notice, no other rights or licenses, express or implied, are granted by Apple - herein, including but not limited to any patent rights that may be infringed by your - derivative works or by other works in which the Apple Software may be incorporated. - - The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, - EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS - USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. - - IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, - REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND - WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR - OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef PluginObject__DEFINED -#define PluginObject__DEFINED - -#include "npapi.h" - -struct ANPCanvas; -struct ANPAudioTrack; - -class Animation { -public: - Animation(NPP inst) : m_inst(inst) {} - virtual ~Animation() {} - virtual void draw(ANPCanvas*) = 0; - - NPP inst() const { return m_inst; } - -private: - NPP m_inst; -}; - -typedef struct PluginObject { - NPObject header; - NPP npp; - NPWindow* window; - Animation* anim; - ANPAudioTrack* track; - int32_t mUnichar; - - bool mTestTimers; - uint32_t mStartTime; - uint32_t mPrevTime; - int mTimerCount; -} PluginObject; - -NPClass *getPluginClass(void); - -#endif // PluginObject__DEFINED diff --git a/WebKit/android/plugins/sample/main.cpp b/WebKit/android/plugins/sample/main.cpp deleted file mode 100644 index e34cee6..0000000 --- a/WebKit/android/plugins/sample/main.cpp +++ /dev/null @@ -1,435 +0,0 @@ -/* - * Copyright 2008, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <stdlib.h> -#include <string.h> -#include <stdio.h> -#include "main.h" -#include "PluginObject.h" -#include "pluginGraphics.h" -#include "android_npapi.h" - -NPNetscapeFuncs* browser; -#define EXPORT __attribute__((visibility("default"))) - -NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, - char* argn[], char* argv[], NPSavedData* saved); -NPError NPP_Destroy(NPP instance, NPSavedData** save); -NPError NPP_SetWindow(NPP instance, NPWindow* window); -NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, - NPBool seekable, uint16* stype); -NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason); -int32 NPP_WriteReady(NPP instance, NPStream* stream); -int32 NPP_Write(NPP instance, NPStream* stream, int32 offset, int32 len, - void* buffer); -void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname); -void NPP_Print(NPP instance, NPPrint* platformPrint); -int16 NPP_HandleEvent(NPP instance, void* event); -void NPP_URLNotify(NPP instance, const char* URL, NPReason reason, - void* notifyData); -NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value); -NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value); - -extern "C" { -EXPORT NPError NP_Initialize(NPNetscapeFuncs* browserFuncs, NPPluginFuncs* pluginFuncs, void *java_env, void *application_context); -EXPORT NPError NP_GetValue(NPP instance, NPPVariable variable, void *value); -EXPORT const char* NP_GetMIMEDescription(void); -EXPORT void NP_Shutdown(void); -}; - -ANPAudioTrackInterfaceV0 gSoundI; -ANPCanvasInterfaceV0 gCanvasI; -ANPLogInterfaceV0 gLogI; -ANPPaintInterfaceV0 gPaintI; -ANPTypefaceInterfaceV0 gTypefaceI; - -#define ARRAY_COUNT(array) (sizeof(array) / sizeof(array[0])) - -NPError NP_Initialize(NPNetscapeFuncs* browserFuncs, NPPluginFuncs* pluginFuncs, void *java_env, void *application_context) -{ - // Make sure we have a function table equal or larger than we are built against. - if (browserFuncs->size < sizeof(NPNetscapeFuncs)) { - return NPERR_GENERIC_ERROR; - } - - // Copy the function table (structure) - browser = (NPNetscapeFuncs*) malloc(sizeof(NPNetscapeFuncs)); - memcpy(browser, browserFuncs, sizeof(NPNetscapeFuncs)); - - // Build the plugin function table - pluginFuncs->version = 11; - pluginFuncs->size = sizeof(pluginFuncs); - pluginFuncs->newp = NPP_New; - pluginFuncs->destroy = NPP_Destroy; - pluginFuncs->setwindow = NPP_SetWindow; - pluginFuncs->newstream = NPP_NewStream; - pluginFuncs->destroystream = NPP_DestroyStream; - pluginFuncs->asfile = NPP_StreamAsFile; - pluginFuncs->writeready = NPP_WriteReady; - pluginFuncs->write = (NPP_WriteProcPtr)NPP_Write; - pluginFuncs->print = NPP_Print; - pluginFuncs->event = NPP_HandleEvent; - pluginFuncs->urlnotify = NPP_URLNotify; - pluginFuncs->getvalue = NPP_GetValue; - pluginFuncs->setvalue = NPP_SetValue; - - static const struct { - NPNVariable v; - uint32_t size; - ANPInterface* i; - } gPairs[] = { - { kLogInterfaceV0_ANPGetValue, sizeof(gLogI), &gLogI }, - { kCanvasInterfaceV0_ANPGetValue, sizeof(gCanvasI), &gCanvasI }, - { kPaintInterfaceV0_ANPGetValue, sizeof(gPaintI), &gPaintI }, - { kTypefaceInterfaceV0_ANPGetValue, sizeof(gPaintI), &gTypefaceI }, - { kAudioTrackInterfaceV0_ANPGetValue, sizeof(gSoundI), &gSoundI }, - }; - for (size_t i = 0; i < ARRAY_COUNT(gPairs); i++) { - gPairs[i].i->inSize = gPairs[i].size; - NPError err = browser->getvalue(NULL, gPairs[i].v, gPairs[i].i); - if (err) { - return err; - } - } - - return NPERR_NO_ERROR; -} - -void NP_Shutdown(void) -{ - -} - -const char *NP_GetMIMEDescription(void) -{ - return "application/x-testplugin:tst:Test plugin mimetype is application/x-testplugin"; -} - -NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, - char* argn[], char* argv[], NPSavedData* saved) -{ - PluginObject *obj = NULL; - - // Scripting functions appeared in NPAPI version 14 - if (browser->version >= 14) { - instance->pdata = browser->createobject (instance, getPluginClass()); - obj = static_cast<PluginObject*>(instance->pdata); - bzero(obj, sizeof(*obj)); - } - - uint32_t bits; - NPError err = browser->getvalue(instance, kSupportedDrawingModel_ANPGetValue, &bits); - if (err) { - gLogI.log(instance, kError_ANPLogType, "supported model err %d", err); - return err; - } - - ANPDrawingModel model = kBitmap_ANPDrawingModel; - - int count = argc; - for (int i = 0; i < count; i++) { - if (!strcmp(argn[i], "DrawingModel")) { - if (!strcmp(argv[i], "Bitmap")) { - model = kBitmap_ANPDrawingModel; - } - if (!strcmp(argv[i], "Canvas")) { - // obj->mTestTimers = true; - } - gLogI.log(instance, kDebug_ANPLogType, "------ %p DrawingModel is %d", instance, model); - break; - } - } - - // comment this out to draw via bitmaps (the default) - err = browser->setvalue(instance, kRequestDrawingModel_ANPSetValue, - reinterpret_cast<void*>(model)); - if (err) { - gLogI.log(instance, kError_ANPLogType, "request model %d err %d", model, err); - } - return err; -} - -NPError NPP_Destroy(NPP instance, NPSavedData** save) -{ - PluginObject *obj = (PluginObject*) instance->pdata; - delete obj->anim; - gSoundI.deleteTrack(obj->track); - - return NPERR_NO_ERROR; -} - -static void timer_oneshot(NPP instance, uint32 timerID) { - gLogI.log(instance, kDebug_ANPLogType, "-------- oneshot timer\n"); -} - -static int gTimerRepeatCount; -static void timer_repeat(NPP instance, uint32 timerID) { - - gLogI.log(instance, kDebug_ANPLogType, "-------- repeat timer %d\n", - gTimerRepeatCount); - if (--gTimerRepeatCount == 0) { - browser->unscheduletimer(instance, timerID); - } -} - -static void timer_neverfires(NPP instance, uint32 timerID) { - gLogI.log(instance, kError_ANPLogType, "-------- timer_neverfires!!!\n"); -} - -#define TIMER_INTERVAL 50 - -static void timer_latency(NPP instance, uint32 timerID) { - PluginObject *obj = (PluginObject*) instance->pdata; - - obj->mTimerCount += 1; - - uint32_t now = getMSecs(); - uint32_t interval = now - obj->mPrevTime; - - uint32_t dur = now - obj->mStartTime; - uint32_t expectedDur = obj->mTimerCount * TIMER_INTERVAL; - int32_t drift = dur - expectedDur; - int32_t aveDrift = drift / obj->mTimerCount; - - obj->mPrevTime = now; - - gLogI.log(instance, kDebug_ANPLogType, - "-------- latency test: [%3d] interval %d expected %d, total %d expected %d, drift %d ave %d\n", - obj->mTimerCount, interval, TIMER_INTERVAL, dur, expectedDur, - drift, aveDrift); -} - -NPError NPP_SetWindow(NPP instance, NPWindow* window) -{ - PluginObject *obj = (PluginObject*) instance->pdata; - - // Do nothing if browser didn't support NPN_CreateObject which would have created the PluginObject. - if (obj != NULL) { - obj->window = window; - } - - static bool gTestTimers; - if (!gTestTimers) { - gTestTimers = true; - // test for bogus timerID - browser->unscheduletimer(instance, 999999); - // test oneshot - browser->scheduletimer(instance, 100, false, timer_oneshot); - // test repeat - gTimerRepeatCount = 10; - browser->scheduletimer(instance, 50, true, timer_repeat); - // test unschedule immediately - uint32 id = browser->scheduletimer(instance, 100, false, timer_neverfires); - browser->unscheduletimer(instance, id); - // test double unschedlue (should be no-op) - browser->unscheduletimer(instance, id); - } - - if (obj->mTestTimers) { - browser->scheduletimer(instance, TIMER_INTERVAL, true, timer_latency); - obj->mStartTime = obj->mPrevTime = getMSecs(); - obj->mTestTimers = false; - } - - browser->invalidaterect(instance, NULL); - - return NPERR_NO_ERROR; -} - - -NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16* stype) -{ - *stype = NP_ASFILEONLY; - return NPERR_NO_ERROR; -} - -NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason) -{ - return NPERR_NO_ERROR; -} - -int32 NPP_WriteReady(NPP instance, NPStream* stream) -{ - return 0; -} - -int32 NPP_Write(NPP instance, NPStream* stream, int32 offset, int32 len, void* buffer) -{ - return 0; -} - -void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname) -{ -} - -void NPP_Print(NPP instance, NPPrint* platformPrint) -{ - -} - -struct SoundPlay { - NPP instance; - ANPAudioTrack* track; - FILE* file; -}; - -static void audioCallback(ANPAudioEvent evt, void* user, ANPAudioBuffer* buffer) { - switch (evt) { - case kMoreData_ANPAudioEvent: { - SoundPlay* play = reinterpret_cast<SoundPlay*>(user); - size_t amount = fread(buffer->bufferData, 1, buffer->size, play->file); - buffer->size = amount; - if (amount == 0) { - gSoundI.stop(play->track); - fclose(play->file); - play->file = NULL; - // need to notify our main thread to delete the track now - } - break; - } - default: - break; - } -} - -static ANPAudioTrack* createTrack(NPP instance, const char path[]) { - FILE* f = fopen(path, "r"); - gLogI.log(instance, kWarning_ANPLogType, "--- path %s FILE %p", path, f); - if (NULL == f) { - return NULL; - } - SoundPlay* play = new SoundPlay; - play->file = f; - play->track = gSoundI.newTrack(44100, kPCM16Bit_ANPSampleFormat, 2, audioCallback, play); - if (NULL == play->track) { - fclose(f); - delete play; - return NULL; - } - return play->track; -} - -int16 NPP_HandleEvent(NPP instance, void* event) -{ - PluginObject *obj = reinterpret_cast<PluginObject*>(instance->pdata); - const ANPEvent* evt = reinterpret_cast<const ANPEvent*>(event); - - switch (evt->eventType) { - case kDraw_ANPEventType: - switch (evt->data.drawContext.model) { - case kBitmap_ANPDrawingModel: - drawPlugin(instance, evt->data.drawContext.data.bitmap, - evt->data.drawContext.clip); - return 1; - default: - break; // unknown drawing model - } - - case kKey_ANPEventType: - gLogI.log(instance, kDebug_ANPLogType, "---- %p Key action=%d" - " code=%d vcode=%d unichar=%d repeat=%d mods=%x", instance, - evt->data.key.action, - evt->data.key.nativeCode, - evt->data.key.virtualCode, - evt->data.key.unichar, - evt->data.key.repeatCount, - evt->data.key.modifiers); - if (evt->data.key.action == kDown_ANPKeyAction) { - obj->mUnichar = evt->data.key.unichar; - browser->invalidaterect(instance, NULL); - } - return 1; - - case kTouch_ANPEventType: - gLogI.log(instance, kDebug_ANPLogType, "---- %p Touch action=%d [%d %d]", - instance, evt->data.touch.action, evt->data.touch.x, - evt->data.touch.y); - if (kUp_ANPTouchAction == evt->data.touch.action) { - if (obj->track) { - if (gSoundI.isStopped(obj->track)) { - gSoundI.start(obj->track); - } else { - gSoundI.pause(obj->track); - } - } else { - obj->track = createTrack(instance, "/sdcard/sample.snd"); - gLogI.log(instance, kDebug_ANPLogType, "track %p %d", - obj->track, gSoundI.isStopped(obj->track)); - gSoundI.start(obj->track); - gLogI.log(instance, kDebug_ANPLogType, "track %p %d", - obj->track, gSoundI.isStopped(obj->track)); - } - } - return 1; - - default: - break; - } - return 0; // unknown or unhandled event -} - -void NPP_URLNotify(NPP instance, const char* url, NPReason reason, void* notifyData) -{ - -} - -EXPORT NPError NP_GetValue(NPP instance, NPPVariable variable, void *value) { - - if (variable == NPPVpluginNameString) { - const char **str = (const char **)value; - *str = "Test Plugin"; - return NPERR_NO_ERROR; - } - - if (variable == NPPVpluginDescriptionString) { - const char **str = (const char **)value; - *str = "Description of Test Plugin"; - return NPERR_NO_ERROR; - } - - return NPERR_GENERIC_ERROR; -} - -NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value) -{ - if (variable == NPPVpluginScriptableNPObject) { - void **v = (void **)value; - PluginObject *obj = (PluginObject*) instance->pdata; - - if (obj) - browser->retainobject((NPObject*)obj); - - *v = obj; - return NPERR_NO_ERROR; - } - - return NPERR_GENERIC_ERROR; -} - -NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value) -{ - return NPERR_GENERIC_ERROR; -} - diff --git a/WebKit/android/plugins/sample/main.h b/WebKit/android/plugins/sample/main.h deleted file mode 100644 index 8bf520e..0000000 --- a/WebKit/android/plugins/sample/main.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2008, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <npapi.h> -#include <npfunctions.h> -#include <npruntime.h> - -extern NPNetscapeFuncs* browser; diff --git a/WebKit/android/plugins/sample/pluginGraphics.cpp b/WebKit/android/plugins/sample/pluginGraphics.cpp deleted file mode 100644 index ffa43e5..0000000 --- a/WebKit/android/plugins/sample/pluginGraphics.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright 2008, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "pluginGraphics.h" - -#include "android_npapi.h" -#include <stdio.h> -#include <sys/time.h> -#include <time.h> -#include <math.h> -#include <string.h> - -extern NPNetscapeFuncs* browser; -extern ANPLogInterfaceV0 gLogI; -extern ANPCanvasInterfaceV0 gCanvasI; -extern ANPPaintInterfaceV0 gPaintI; -extern ANPTypefaceInterfaceV0 gTypefaceI; - -static void inval(NPP instance) { - browser->invalidaterect(instance, NULL); -} - -static uint16 rnd16(float x, int inset) { - int ix = (int)roundf(x) + inset; - if (ix < 0) { - ix = 0; - } - return static_cast<uint16>(ix); -} - -static void inval(NPP instance, const ANPRectF& r, bool doAA) { - const int inset = doAA ? -1 : 0; - - PluginObject *obj = reinterpret_cast<PluginObject*>(instance->pdata); - NPRect inval; - inval.left = rnd16(r.left, inset); - inval.top = rnd16(r.top, inset); - inval.right = rnd16(r.right, -inset); - inval.bottom = rnd16(r.bottom, -inset); - browser->invalidaterect(instance, &inval); -} - -uint32_t getMSecs() { - struct timeval tv; - gettimeofday(&tv, NULL); - return (uint32_t) (tv.tv_sec * 1000 + tv.tv_usec / 1000 ); // microseconds to milliseconds -} - -/////////////////////////////////////////////////////////////////////////////// - -class BallAnimation : public Animation { -public: - BallAnimation(NPP inst); - virtual ~BallAnimation(); - virtual void draw(ANPCanvas*); -private: - float m_x; - float m_y; - float m_dx; - float m_dy; - - ANPRectF m_oval; - ANPPaint* m_paint; - - static const float SCALE = 0.1; -}; - -BallAnimation::BallAnimation(NPP inst) : Animation(inst) { - m_x = m_y = 0; - m_dx = 7 * SCALE; - m_dy = 5 * SCALE; - - memset(&m_oval, 0, sizeof(m_oval)); - - m_paint = gPaintI.newPaint(); - gPaintI.setFlags(m_paint, gPaintI.getFlags(m_paint) | kAntiAlias_ANPPaintFlag); - gPaintI.setColor(m_paint, 0xFFFF0000); - gPaintI.setTextSize(m_paint, 24); - - ANPTypeface* tf = gTypefaceI.createFromName("serif", kItalic_ANPTypefaceStyle); - gPaintI.setTypeface(m_paint, tf); - gTypefaceI.unref(tf); -} - -BallAnimation::~BallAnimation() { - gPaintI.deletePaint(m_paint); -} - -static void bounce(float* x, float* dx, const float max) { - *x += *dx; - if (*x < 0) { - *x = 0; - if (*dx < 0) { - *dx = -*dx; - } - } else if (*x > max) { - *x = max; - if (*dx > 0) { - *dx = -*dx; - } - } -} - -void BallAnimation::draw(ANPCanvas* canvas) { - NPP instance = this->inst(); - PluginObject *obj = (PluginObject*) instance->pdata; - const float OW = 20; - const float OH = 20; - - inval(instance, m_oval, true); // inval the old - m_oval.left = m_x; - m_oval.top = m_y; - m_oval.right = m_x + OW; - m_oval.bottom = m_y + OH; - inval(instance, m_oval, true); // inval the new - - gCanvasI.drawColor(canvas, 0xFFFFFFFF); - - gPaintI.setColor(m_paint, 0xFFFF0000); - gCanvasI.drawOval(canvas, &m_oval, m_paint); - - bounce(&m_x, &m_dx, obj->window->width - OW); - bounce(&m_y, &m_dy, obj->window->height - OH); - - if (obj->mUnichar) { - ANPFontMetrics fm; - gPaintI.getFontMetrics(m_paint, &fm); - - gPaintI.setColor(m_paint, 0xFF0000FF); - char c = static_cast<char>(obj->mUnichar); - gCanvasI.drawText(canvas, &c, 1, 10, -fm.fTop, m_paint); - } -} - -/////////////////////////////////////////////////////////////////////////////// - -void drawPlugin(NPP instance, const ANPBitmap& bitmap, const ANPRectI& clip) { - ANPCanvas* canvas = gCanvasI.newCanvas(&bitmap); - - ANPRectF clipR; - clipR.left = clip.left; - clipR.top = clip.top; - clipR.right = clip.right; - clipR.bottom = clip.bottom; - gCanvasI.clipRect(canvas, &clipR); - - drawPlugin(instance, canvas); - - gCanvasI.deleteCanvas(canvas); -} - -void drawPlugin(NPP instance, ANPCanvas* canvas) { - PluginObject *obj = (PluginObject*) instance->pdata; - if (obj->anim == NULL) { - obj->anim = new BallAnimation(instance); - } - obj->anim->draw(canvas); -} - diff --git a/WebKit/android/stl/algorithm b/WebKit/android/stl/algorithm index 33968ab..131fe0d 100644 --- a/WebKit/android/stl/algorithm +++ b/WebKit/android/stl/algorithm @@ -49,10 +49,6 @@ #include <SkScalar.h> // for SK_ScalarNaN #ifdef PREFIX_FOR_WEBCORE #include <SkTSearch.h> -namespace WebCore { - class InlineTextBox; - class RenderLayer; -} #endif #include <float.h> @@ -64,14 +60,6 @@ namespace WebCore { #define WCHAR_MAX 0xFFFF #endif -namespace JSC { - class ProfileNode; -} - -namespace WTF { - template <typename T> class RefPtr; -} - namespace std { template<typename _Tp> @@ -83,6 +71,24 @@ namespace std __b = __tmp; } + template<typename _Tp> + inline void + reverse(_Tp* __first, _Tp* __last) + { + while(true) + { + if (__first == __last || __first == --__last) + return; + else + { + _Tp __tmp = *__first; + *__first = *__last; + *__last = __tmp; + } + ++__first; + } + } + #undef min #undef max @@ -199,12 +205,17 @@ extern void sort(const void** start, const void** end, Comparator comp); } - inline void sort (WebCore::InlineTextBox** start, WebCore::InlineTextBox**end, - bool (* comp)(const WebCore::InlineTextBox*, const WebCore::InlineTextBox*)) + template<typename P> inline void sort (P** start, P**end, + bool (* comp)(const P*, const P*)) { sort((const void**) start, (const void**) end, (Comparator) comp); } + template<typename P> void sort(P* start, P* end, + bool (* comp)(const P&, const P&)) { + stable_sort(start, end, *comp); + } + template<typename P> inline void stable_sort(P** start, P** end, bool (* comp)(P*, P*)) { @@ -258,15 +269,6 @@ extern void sort(const void** start, const void** end, Comparator comp); }; #endif -typedef bool (* ProfileComparator)(const WTF::RefPtr<JSC::ProfileNode>&, - const WTF::RefPtr<JSC::ProfileNode>&); - -inline void sort(WTF::RefPtr<JSC::ProfileNode>* start, - WTF::RefPtr<JSC::ProfileNode>* end, ProfileComparator comp) -{ - sort((const void**) start, (const void**) end, (Comparator) comp); -} - } #endif diff --git a/WebKit/android/wds/DebugServer.h b/WebKit/android/wds/DebugServer.h index a0a2aa8..3ec158b 100644 --- a/WebKit/android/wds/DebugServer.h +++ b/WebKit/android/wds/DebugServer.h @@ -63,7 +63,7 @@ public: } private: DebugServer(); - Vector<Frame*> m_frames; + WTF::Vector<Frame*> m_frames; ThreadIdentifier m_threadId; friend DebugServer* server(); }; diff --git a/WebKit/android/wds/client/ClientUtils.h b/WebKit/android/wds/client/ClientUtils.h index 0aa068e..261af27 100644 --- a/WebKit/android/wds/client/ClientUtils.h +++ b/WebKit/android/wds/client/ClientUtils.h @@ -28,6 +28,14 @@ #include <arpa/inet.h> +/* + * included for sockaddr_in structure, AF_INET definiton and etc. + */ +#ifdef __FreeBSD__ +#include <netinet/in.h> +#include <sys/socket.h> +#endif + // Callers need to include Log.h and errno.h to use this macro #define log_errno(str) LOGE("%s: %s", str, strerror(errno)) |
