/* * 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 "DeviceOrientationManager.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 Color; class FrameView; class HTMLAnchorElement; class HTMLSelectElement; class RenderPart; class RenderText; class Node; class PlatformKeyboardEvent; class RenderTextControl; class ScrollView; class TimerBase; class PageGroup; } #if USE(ACCELERATED_COMPOSITING) namespace WebCore { class GraphicsLayerAndroid; } #endif namespace WebCore { class BaseLayerAndroid; } struct PluginWidgetAndroid; class SkPicture; class SkIRect; namespace android { class CachedFrame; class CachedNode; 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(); #if USE(ACCELERATED_COMPOSITING) GraphicsLayerAndroid* graphicsRootLayer() const; #endif /** 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. Also restore the scale for the text wrap. */ void restoreScale(int scale, int textWrapScale); /** * 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 WTF::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 WTF::String& url, const WTF::String& text); bool jsConfirm(const WTF::String& url, const WTF::String& text); bool jsPrompt(const WTF::String& url, const WTF::String& message, const WTF::String& defaultValue, WTF::String& result); bool jsUnload(const WTF::String& url, const WTF::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 WTF::String& url, const WTF::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 WTF::String& origin); /** * Instruct the browser to hide the Geolocation permission prompt. */ void geolocationPermissionsHidePrompt(); jobject getDeviceOrientationService(); void addMessageToConsole(const String& message, unsigned int lineNumber, const String& sourceID, int msgLevel); /** * Tell the Java side of the scrollbar mode */ void setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode); // // Followings support calls from Java to native WebCore // WTF::String retrieveHref(WebCore::Frame* frame, WebCore::Node* node); WTF::String retrieveAnchorText(WebCore::Frame* frame, WebCore::Node* node); WTF::String requestLabel(WebCore::Frame* , WebCore::Node* ); // 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 moveFocus(WebCore::Frame* frame, WebCore::Node* node); 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, int anchorX, int anchorY, 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, int metaState); /** * 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); /** * Modifies the current selection. * * alter - Specifies how to alter the selection. * direction - The direction in which to alter the selection. * granularity - The granularity of the selection modification. * * returns - The selection as string. */ String modifySelection(const String& alter, const String& direction, const String& granularity); /** * 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 WTF::String& replace, int start, int end, int textGeneration); void passToJs(int generation, const WTF::String& , const WebCore::PlatformKeyboardEvent& ); /** * Scroll the focused textfield to (x, y) in document space */ void scrollFocusedTextInput(float x, int y); /** * Set the FocusController's active and focused states, so that * the caret will draw (true) or not. */ 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*); // returns true if the pluginwidgit is in our active list bool isPlugin(PluginWidgetAndroid*) const; 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&); // lookup the plugin widget struct given an NPP PluginWidgetAndroid* getPluginWidget(NPP npp); // 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); void requestKeyboardWithSelection(const WebCore::Node*, int selStart, int selEnd); // Notify the Java side that webkit is requesting a keyboard void requestKeyboard(bool showKeyboard); // Generates a class loader that contains classes from the plugin's apk jclass getPluginClass(const WTF::String& libName, const char* className); // Creates a full screen surface for a plugin void showFullScreenPlugin(jobject webkitPlugin, NPP npp); // Instructs the UI thread to discard the plugin's full-screen surface void hideFullScreenPlugin(); // Adds the plugin's view (aka surface) to the view hierarchy jobject addSurface(jobject view, 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); // Returns the context (android.content.Context) of the WebView jobject getContext(); bool validNodeAndBounds(Frame* , Node* , const IntRect& ); // Make the rect (left, top, width, height) visible. If it can be fully // fit, center it on the screen. Otherwise make sure the point specified // by (left + xPercentInDoc * width, top + yPercentInDoc * height) // pinned at the screen position (xPercentInView, yPercentInView). void showRect(int left, int top, int width, int height, int contentWidth, int contentHeight, float xPercentInDoc, float xPercentInView, float yPercentInDoc, float yPercentInView); // Scale the rect (x, y, width, height) to make it just fit and centered // in the current view. void centerFitRect(int x, int y, int width, int height); // return a list of rects matching the touch point (x, y) with the slop Vector getTouchHighlightRects(int x, int y, int slop); // 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(); bool focusBoundsChanged(); // record the inval area, and the picture size BaseLayerAndroid* recordContent(SkRegion* , SkIPoint* ); int textWrapWidth() const { return m_textWrapWidth; } float scale() const { return m_scale; } float textWrapScale() const { return m_screenWidth * m_scale / m_textWrapWidth; } WebCore::Frame* mainFrame() const { return m_mainFrame; } void updateCursorBounds(const CachedRoot* root, const CachedFrame* cachedFrame, const CachedNode* cachedNode); void updateFrameCacheIfLoading(); // utility to split slow parts of the picture set void splitContent(PictureSet*); void notifyWebAppCanBeInstalled(); DeviceOrientationManager* deviceOrientationManager() { return &m_deviceOrientationManager; } // 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; bool isPaused() const { return m_isPaused; } void setIsPaused(bool isPaused) { m_isPaused = isPaused; } // 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; PictureSet m_content; // the set of pictures to draw 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 int m_textWrapWidth; float m_scale; unsigned m_domtree_version; bool m_check_domtree_version; PageGroup* m_groupForVisitedLinks; bool m_isPaused; 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); WebCore::HTMLAnchorElement* retrieveAnchorElement(WebCore::Frame* frame, WebCore::Node* node); #if ENABLE(TOUCH_EVENTS) bool m_forwardingTouchEvents; #endif #if DEBUG_NAV_UI uint32_t m_now; #endif DeviceOrientationManager m_deviceOrientationManager; private: // called from constructor, to add this to a global list static void addInstance(WebViewCore*); // called from destructor, to remove this from a global list static void removeInstance(WebViewCore*); public: // call only from webkit thread (like add/remove), return true if inst // is still alive static bool isInstance(WebViewCore*); // if there exists at least on WebViewCore instance then we return the // application context, otherwise NULL is returned. static jobject getApplicationContext(); }; } // namespace android #endif // WEBVIEWCORE_H