/* * Copyright 2006, The Android Open Source Project * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef WEBVIEWCORE_H #define WEBVIEWCORE_H #include "android_npapi.h" #include "FileChooser.h" #include "CacheBuilder.h" #include "CachedHistory.h" #include "PictureSet.h" #include "PlatformGraphicsContext.h" #include "SkColor.h" #include "SkTDArray.h" #include "SkRegion.h" #include "Timer.h" #include "WebCoreRefObject.h" #include "WebCoreJni.h" #include #include #include namespace WebCore { class AtomicString; class Color; class FrameView; class HTMLSelectElement; class RenderPart; class RenderText; class Node; class PlatformKeyboardEvent; class RenderTextControl; class ScrollView; class TimerBase; class PageGroup; } struct PluginWidgetAndroid; class SkPicture; class SkIRect; namespace android { class CachedRoot; class ListBoxReply; class WebCoreReply : public WebCoreRefObject { public: virtual ~WebCoreReply() {} virtual void replyInt(int value) { SkDEBUGF(("WebCoreReply::replyInt(%d) not handled\n", value)); } virtual void replyIntArray(const int* array, int count) { SkDEBUGF(("WebCoreReply::replyIntArray() not handled\n")); } // add more replyFoo signatures as needed }; // one instance of WebViewCore per page for calling into Java's WebViewCore class WebViewCore : public WebCoreRefObject { public: /** * Initialize the native WebViewCore with a JNI environment, a Java * WebViewCore object and the main frame. */ WebViewCore(JNIEnv* env, jobject javaView, WebCore::Frame* mainframe); ~WebViewCore(); // helper function static WebViewCore* getWebViewCore(const WebCore::FrameView* view); static WebViewCore* getWebViewCore(const WebCore::ScrollView* view); // Followings are called from native WebCore to Java /** * Scroll to an absolute position. * @param x The x coordinate. * @param y The y coordinate. * @param animate If it is true, animate to the new scroll position * * This method calls Java to trigger a gradual scroll event. */ void scrollTo(int x, int y, bool animate = false); /** * Scroll to the point x,y relative to the current position. * @param x The relative x position. * @param y The relative y position. * @param animate If it is true, animate to the new scroll position */ void scrollBy(int x, int y, bool animate); /** * Record the invalid rectangle */ void contentInvalidate(const WebCore::IntRect &rect); /** * Satisfy any outstanding invalidates, so that the current state * of the DOM is drawn. */ void contentDraw(); /** Invalidate the view/screen, NOT the content/DOM, but expressed in * content/DOM coordinates (i.e. they need to eventually be scaled, * by webview into view.java coordinates */ void viewInvalidate(const WebCore::IntRect& rect); /** * Invalidate part of the content that may be offscreen at the moment */ void offInvalidate(const WebCore::IntRect &rect); /** * Called by webcore when the progress indicator is done * used to rebuild and display any changes in focus */ void notifyProgressFinished(); /** * Notify the view that WebCore did its first layout. */ void didFirstLayout(); /** * Notify the view to update the viewport. */ void updateViewport(); /** * Notify the view to restore the screen width, which in turn restores * the scale. */ void restoreScale(int); /** * Notify the view to restore the scale used to calculate the screen * width for wrapping the text */ void restoreScreenWidthScale(int); /** * Tell the java side to update the focused textfield * @param pointer Pointer to the node for the input field. * @param changeToPassword If true, we are changing the textfield to * a password field, and ignore the String * @param text If changeToPassword is false, this is the new text that * should go into the textfield. */ void updateTextfield(WebCore::Node* pointer, bool changeToPassword, const WebCore::String& text); /** * Tell the java side to update the current selection in the focused * textfield to the WebTextView. This function finds the currently * focused textinput, and passes its selection to java. * If there is no focus, or it is not a text input, this does nothing. */ void updateTextSelection(); void clearTextEntry(); // JavaScript support void jsAlert(const WebCore::String& url, const WebCore::String& text); bool jsConfirm(const WebCore::String& url, const WebCore::String& text); bool jsPrompt(const WebCore::String& url, const WebCore::String& message, const WebCore::String& defaultValue, WebCore::String& result); bool jsUnload(const WebCore::String& url, const WebCore::String& message); bool jsInterrupt(); /** * Tell the Java side that the origin has exceeded its 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 * @param estimatedSize The estimated size of the database */ void exceededDatabaseQuota(const WebCore::String& url, const WebCore::String& databaseIdentifier, const unsigned long long currentQuota, const unsigned long long estimatedSize); /** * Tell the Java side that the appcache has exceeded its max size. * @param spaceNeeded is the amount of disk space that would be needed * in order for the last appcache operation to succeed. */ void reachedMaxAppCacheSize(const unsigned long long spaceNeeded); /** * Set up the PageGroup's idea of which links have been visited, * with the browser history. * @param group the object to deliver the links to. */ void populateVisitedLinks(WebCore::PageGroup*); /** * Instruct the browser to show a Geolocation permission prompt for the * specified origin. * @param origin The origin of the frame requesting Geolocation * permissions. */ void geolocationPermissionsShowPrompt(const WebCore::String& origin); /** * Instruct the browser to hide the Geolocation permission prompt. */ void geolocationPermissionsHidePrompt(); void addMessageToConsole(const String& message, unsigned int lineNumber, const String& sourceID); // // Followings support calls from Java to native WebCore // 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 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 moveGeneration, int dx, int dy); void setGlobalBounds(int x, int y, int h, int v); void setSizeScreenWidthAndScale(int width, int height, int screenWidth, float scale, int realScreenWidth, int screenHeight, bool ignoreHeight); /** * Handle key events from Java. * @return Whether keyCode was handled by this class. */ bool key(const WebCore::PlatformKeyboardEvent& event); /** * Handle (trackball) click event from Java */ void click(WebCore::Frame* frame, WebCore::Node* node); /** * Handle touch event */ bool handleTouchEvent(int action, int x, int y); /** * Handle motionUp event from the UI thread (called touchUp in the * WebCore thread). */ void touchUp(int touchGeneration, WebCore::Frame* frame, WebCore::Node* node, int x, int y); /** * Sets the index of the label from a popup */ void popupReply(int index); void popupReply(const int* array, int count); /** * 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. */ 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. */ void setSelection(int start, int end); /** * 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(int oldStart, int oldEnd, const WebCore::String& replace, int start, int end, int textGeneration); void passToJs(int generation, const WebCore::String& , const WebCore::PlatformKeyboardEvent& ); /** * Scroll the focused textfield to (x, y) in document space */ void scrollFocusedTextInput(float x, int y); void setFocusControllerActive(bool active); void saveDocumentState(WebCore::Frame* frame); void addVisitedLink(const UChar*, int); // TODO: I don't like this hack but I need to access the java object in // order to send it as a parameter to java AutoJObject getJavaObject(); // Return the parent WebView Java object associated with this // WebViewCore. jobject getWebViewJavaObject(); void setBackgroundColor(SkColor c); void updateFrameCache(); void updateCacheOnNodeChange(); void dumpDomTree(bool); void dumpRenderTree(bool); void dumpNavTree(); /* We maintain a list of active plugins. The list is edited by the pluginview itself. The list is used to service invals to the plugin pageflipping bitmap. */ void addPlugin(PluginWidgetAndroid*); void removePlugin(PluginWidgetAndroid*); void invalPlugin(PluginWidgetAndroid*); void drawPlugins(); // send the current screen size/zoom to all of the plugins in our list void sendPluginVisibleScreen(); // send onLoad event to plugins who are descendents of the given frame void notifyPluginsOnFrameLoad(const Frame*); // 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 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); // Generates a class loader that contains classes from the plugin's apk jclass getPluginClass(const char* libName, const char* className); // Creates a full screen surface (i.e. View on an Activity) for a plugin void startFullScreenPluginActivity(const char* libName, const char* className, NPP npp); // Creates a Surface (i.e. View) for a plugin jobject createSurface(const char* libName, const char* className, NPP npp, int x, int y, int width, int height); // Updates a Surface coordinates and dimensions for a plugin void updateSurface(jobject childView, int x, int y, int width, int height); // Destroys a SurfaceView for a plugin void destroySurface(jobject childView); // other public functions public: // Open a file chooser for selecting a file to upload void openFileChooser(PassRefPtr ); // 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 focusBoundsChanged(); bool pictureReady(); // record the inval area, and the picture size bool recordContent(SkRegion* , SkIPoint* ); int screenWidth() const { return m_screenWidth; } float scale() const { return m_scale; } float screenWidthScale() const { return m_screenWidthScale; } WebCore::Frame* mainFrame() const { return m_mainFrame; } void updateFrameCacheIfLoading(); // utility to split slow parts of the picture set void splitContent(); // these members are shared with webview.cpp static Mutex gFrameCacheMutex; CachedRoot* m_frameCacheKit; // nav data being built by webcore SkPicture* m_navPictureKit; int m_moveGeneration; // copy of state in WebViewNative triggered by move 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_findIsUp; 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 static Mutex gButtonMutex; WTF::Vector m_buttons; // end of shared members // 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. void updateButtonList(WTF::Vector* buttons); void reset(bool fromConstructor); void listBoxRequest(WebCoreReply* reply, const uint16_t** labels, size_t count, const int enabled[], size_t enabledCount, bool multiple, const int selected[], size_t selectedCountOrSelection); friend class ListBoxReply; struct JavaGlue; struct JavaGlue* m_javaGlue; WebCore::Frame* m_mainFrame; WebCoreReply* m_popupReply; WebCore::Node* m_lastFocused; WebCore::IntRect m_lastFocusedBounds; int m_lastFocusedSelStart; int m_lastFocusedSelEnd; 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) SkRegion m_rebuildInval; // the accumulated region for rebuilt pictures // Used in passToJS to avoid updating the UI text field until after the // key event has been processed. bool m_blockTextfieldUpdates; bool m_focusBoundsChanged; bool m_skipContentDraw; // Passed in with key events to know when they were generated. Store it // with the cache so that we can ignore stale text changes. int m_textGeneration; CachedRoot* m_temp; SkPicture* m_tempPict; 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_progressDone; int m_lastPassed; int m_lastVelocity; CachedHistory m_history; int m_screenWidth; // width of the visible rect in document coordinates int m_screenHeight;// height of the visible rect in document coordinates float m_scale; float m_screenWidthScale; unsigned m_domtree_version; bool m_check_domtree_version; PageGroup* m_groupForVisitedLinks; SkTDArray m_plugins; WebCore::Timer m_pluginInvalTimer; void pluginInvalTimerFired(WebCore::Timer*) { this->drawPlugins(); } void doMaxScroll(CacheBuilder::Direction dir); SkPicture* rebuildPicture(const SkIRect& inval); void rebuildPictureSet(PictureSet* ); void sendNotifyProgressFinished(); bool handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* nodePtr); #if DEBUG_NAV_UI uint32_t m_now; #endif }; } // namespace android #endif // WEBVIEWCORE_H