• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2006, The Android Open Source Project
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *  * Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  *  * Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #define LOG_TAG "webcoreglue"
27 
28 #include "config.h"
29 #include "WebViewCore.h"
30 
31 #include "AccessibilityObject.h"
32 #include "AndroidHitTestResult.h"
33 #include "ApplicationCacheStorage.h"
34 #include "Attribute.h"
35 #include "content/address_detector.h"
36 #include "Chrome.h"
37 #include "ChromeClientAndroid.h"
38 #include "ChromiumIncludes.h"
39 #include "ClientRect.h"
40 #include "ClientRectList.h"
41 #include "Color.h"
42 #include "CSSPropertyNames.h"
43 #include "CSSValueKeywords.h"
44 #include "DatabaseTracker.h"
45 #include "Document.h"
46 #include "DocumentMarkerController.h"
47 #include "DOMWindow.h"
48 #include "DOMSelection.h"
49 #include "Element.h"
50 #include "Editor.h"
51 #include "EditorClientAndroid.h"
52 #include "EventHandler.h"
53 #include "EventNames.h"
54 #include "ExceptionCode.h"
55 #include "FocusController.h"
56 #include "Font.h"
57 #include "FontCache.h"
58 #include "Frame.h"
59 #include "FrameLoader.h"
60 #include "FrameLoaderClientAndroid.h"
61 #include "FrameTree.h"
62 #include "FrameView.h"
63 #include "Geolocation.h"
64 #include "GraphicsContext.h"
65 #include "GraphicsJNI.h"
66 #include "HTMLAnchorElement.h"
67 #include "HTMLAreaElement.h"
68 #include "HTMLElement.h"
69 #include "HTMLFormControlElement.h"
70 #include "HTMLImageElement.h"
71 #include "HTMLInputElement.h"
72 #include "HTMLLabelElement.h"
73 #include "HTMLMapElement.h"
74 #include "HTMLNames.h"
75 #include "HTMLOptGroupElement.h"
76 #include "HTMLOptionElement.h"
77 #include "HTMLSelectElement.h"
78 #include "HTMLTextAreaElement.h"
79 #include "HistoryItem.h"
80 #include "HitTestRequest.h"
81 #include "HitTestResult.h"
82 #include "InlineTextBox.h"
83 #include "KeyboardEvent.h"
84 #include "MemoryUsage.h"
85 #include "NamedNodeMap.h"
86 #include "Navigator.h"
87 #include "Node.h"
88 #include "NodeList.h"
89 #include "Page.h"
90 #include "PageGroup.h"
91 #include "PictureLayerContent.h"
92 #include "PicturePileLayerContent.h"
93 #include "PlatformKeyboardEvent.h"
94 #include "PlatformString.h"
95 #include "PluginWidgetAndroid.h"
96 #include "PluginView.h"
97 #include "Position.h"
98 #include "ProgressTracker.h"
99 #include "Range.h"
100 #include "RenderBox.h"
101 #include "RenderImage.h"
102 #include "RenderInline.h"
103 #include "RenderLayer.h"
104 #include "RenderPart.h"
105 #include "RenderText.h"
106 #include "RenderTextControl.h"
107 #include "RenderThemeAndroid.h"
108 #include "RenderView.h"
109 #include "ResourceRequest.h"
110 #include "RuntimeEnabledFeatures.h"
111 #include "SchemeRegistry.h"
112 #include "ScopedLocalRef.h"
113 #include "ScriptController.h"
114 #include "SelectionController.h"
115 #include "SelectText.h"
116 #include "Settings.h"
117 #include "SkANP.h"
118 #include "SkTemplates.h"
119 #include "SkTDArray.h"
120 #include "SkTypes.h"
121 #include "SkCanvas.h"
122 #include "SkGraphics.h"
123 #include "SkPicture.h"
124 #include "SkUtils.h"
125 #include "Text.h"
126 #include "TextIterator.h"
127 #include "TilesManager.h"
128 #include "TypingCommand.h"
129 #include "WebCache.h"
130 #include "WebCoreFrameBridge.h"
131 #include "WebCoreJni.h"
132 #include "WebFrameView.h"
133 #include "WindowsKeyboardCodes.h"
134 #include "autofill/WebAutofill.h"
135 #include "htmlediting.h"
136 #include "markup.h"
137 #include "unicode/uloc.h"
138 #include "visible_units.h"
139 
140 #include <JNIHelp.h>
141 #include <JNIUtility.h>
142 #include <androidfw/KeycodeLabels.h>
143 #include <cutils/properties.h>
144 #include <v8.h>
145 #include <wtf/CurrentTime.h>
146 #include <wtf/text/AtomicString.h>
147 #include <wtf/text/CString.h>
148 #include <wtf/text/StringImpl.h>
149 
150 #if DEBUG_NAV_UI
151 #include "SkTime.h"
152 #endif
153 
154 #if ENABLE(TOUCH_EVENTS) // Android
155 #include "PlatformTouchEvent.h"
156 #endif
157 
158 #ifdef ANDROID_DOM_LOGGING
159 #include "AndroidLog.h"
160 #include "RenderTreeAsText.h"
161 #include <wtf/text/CString.h>
162 
163 FILE* gDomTreeFile = 0;
164 FILE* gRenderTreeFile = 0;
165 #endif
166 
167 #include "BaseLayerAndroid.h"
168 
169 #if USE(ACCELERATED_COMPOSITING)
170 #include "GraphicsLayerAndroid.h"
171 #include "RenderLayerCompositor.h"
172 #endif
173 
174 #define FOREGROUND_TIMER_INTERVAL 0.004 // 4ms
175 #define BACKGROUND_TIMER_INTERVAL 1.0 // 1s
176 
177 // How many ms to wait for the scroll to "settle" before we will consider doing
178 // prerenders
179 #define PRERENDER_AFTER_SCROLL_DELAY 750
180 
181 #define TOUCH_FLAG_HIT_HANDLER 0x1
182 #define TOUCH_FLAG_PREVENT_DEFAULT 0x2
183 
184 ////////////////////////////////////////////////////////////////////////////////////////////////
185 
186 namespace android {
187 
188 // Copied from CacheBuilder, not sure if this is needed/correct
getAreaRect(const HTMLAreaElement * area)189 IntRect getAreaRect(const HTMLAreaElement* area)
190 {
191     Node* node = area->document();
192     while ((node = node->traverseNextNode()) != NULL) {
193         RenderObject* renderer = node->renderer();
194         if (renderer && renderer->isRenderImage()) {
195             RenderImage* image = static_cast<RenderImage*>(renderer);
196             HTMLMapElement* map = image->imageMap();
197             if (map) {
198                 Node* n;
199                 for (n = map->firstChild(); n;
200                         n = n->traverseNextNode(map)) {
201                     if (n == area) {
202                         if (area->isDefault())
203                             return image->absoluteBoundingBoxRect();
204                         return area->computeRect(image);
205                     }
206                 }
207             }
208         }
209     }
210     return IntRect();
211 }
212 
213 // Copied from CacheBuilder, not sure if this is needed/correct
214 // TODO: See if this is even needed (I suspect not), and if not remove it
validNode(Frame * startFrame,void * matchFrame,void * matchNode)215 bool validNode(Frame* startFrame, void* matchFrame,
216         void* matchNode)
217 {
218     if (matchFrame == startFrame) {
219         if (matchNode == NULL)
220             return true;
221         Node* node = startFrame->document();
222         while (node != NULL) {
223             if (node == matchNode) {
224                 const IntRect& rect = node->hasTagName(HTMLNames::areaTag) ?
225                     getAreaRect(static_cast<HTMLAreaElement*>(node)) : node->getRect();
226                 // Consider nodes with empty rects that are not at the origin
227                 // to be valid, since news.google.com has valid nodes like this
228                 if (rect.x() == 0 && rect.y() == 0 && rect.isEmpty())
229                     return false;
230                 return true;
231             }
232             node = node->traverseNextNode();
233         }
234         return false;
235     }
236     Frame* child = startFrame->tree()->firstChild();
237     while (child) {
238         bool result = validNode(child, matchFrame, matchNode);
239         if (result)
240             return result;
241         child = child->tree()->nextSibling();
242     }
243     return false;
244 }
245 
246 static SkTDArray<WebViewCore*> gInstanceList;
247 
addInstance(WebViewCore * inst)248 void WebViewCore::addInstance(WebViewCore* inst) {
249     *gInstanceList.append() = inst;
250 }
251 
removeInstance(WebViewCore * inst)252 void WebViewCore::removeInstance(WebViewCore* inst) {
253     int index = gInstanceList.find(inst);
254     ALOG_ASSERT(index >= 0, "RemoveInstance inst not found");
255     if (index >= 0) {
256         gInstanceList.removeShuffle(index);
257     }
258 }
259 
isInstance(WebViewCore * inst)260 bool WebViewCore::isInstance(WebViewCore* inst) {
261     return gInstanceList.find(inst) >= 0;
262 }
263 
getApplicationContext()264 jobject WebViewCore::getApplicationContext() {
265 
266     // check to see if there is a valid webviewcore object
267     if (gInstanceList.isEmpty())
268         return 0;
269 
270     // get the context from the webview
271     jobject context = gInstanceList[0]->getContext();
272 
273     if (!context)
274         return 0;
275 
276     // get the application context using JNI
277     JNIEnv* env = JSC::Bindings::getJNIEnv();
278     jclass contextClass = env->GetObjectClass(context);
279     jmethodID appContextMethod = env->GetMethodID(contextClass, "getApplicationContext", "()Landroid/content/Context;");
280     env->DeleteLocalRef(contextClass);
281     jobject result = env->CallObjectMethod(context, appContextMethod);
282     checkException(env);
283     return result;
284 }
285 
286 
287 struct WebViewCoreStaticMethods {
288     jmethodID    m_isSupportedMediaMimeType;
289 } gWebViewCoreStaticMethods;
290 
291 // Check whether a media mimeType is supported in Android media framework.
isSupportedMediaMimeType(const WTF::String & mimeType)292 bool WebViewCore::isSupportedMediaMimeType(const WTF::String& mimeType) {
293     JNIEnv* env = JSC::Bindings::getJNIEnv();
294     jstring jMimeType = wtfStringToJstring(env, mimeType);
295     jclass webViewCore = env->FindClass("android/webkit/WebViewCore");
296     bool val = env->CallStaticBooleanMethod(webViewCore,
297           gWebViewCoreStaticMethods.m_isSupportedMediaMimeType, jMimeType);
298     checkException(env);
299     env->DeleteLocalRef(webViewCore);
300     env->DeleteLocalRef(jMimeType);
301 
302     return val;
303 }
304 
305 // ----------------------------------------------------------------------------
306 
307 // Field ids for WebViewCore
308 struct WebViewCoreFields {
309     jfieldID    m_nativeClass;
310     jfieldID    m_viewportWidth;
311     jfieldID    m_viewportHeight;
312     jfieldID    m_viewportInitialScale;
313     jfieldID    m_viewportMinimumScale;
314     jfieldID    m_viewportMaximumScale;
315     jfieldID    m_viewportUserScalable;
316     jfieldID    m_viewportDensityDpi;
317     jfieldID    m_drawIsPaused;
318     jfieldID    m_lowMemoryUsageMb;
319     jfieldID    m_highMemoryUsageMb;
320     jfieldID    m_highUsageDeltaMb;
321 } gWebViewCoreFields;
322 
323 // ----------------------------------------------------------------------------
324 
325 struct WebViewCore::JavaGlue {
326     jweak       m_obj;
327     jmethodID   m_scrollTo;
328     jmethodID   m_contentDraw;
329     jmethodID   m_requestListBox;
330     jmethodID   m_openFileChooser;
331     jmethodID   m_requestSingleListBox;
332     jmethodID   m_jsAlert;
333     jmethodID   m_jsConfirm;
334     jmethodID   m_jsPrompt;
335     jmethodID   m_jsUnload;
336     jmethodID   m_jsInterrupt;
337     jmethodID   m_getWebView;
338     jmethodID   m_didFirstLayout;
339     jmethodID   m_updateViewport;
340     jmethodID   m_sendNotifyProgressFinished;
341     jmethodID   m_sendViewInvalidate;
342     jmethodID   m_updateTextfield;
343     jmethodID   m_updateTextSelection;
344     jmethodID   m_updateTextSizeAndScroll;
345     jmethodID   m_clearTextEntry;
346     jmethodID   m_restoreScale;
347     jmethodID   m_needTouchEvents;
348     jmethodID   m_requestKeyboard;
349     jmethodID   m_exceededDatabaseQuota;
350     jmethodID   m_reachedMaxAppCacheSize;
351     jmethodID   m_populateVisitedLinks;
352     jmethodID   m_geolocationPermissionsShowPrompt;
353     jmethodID   m_geolocationPermissionsHidePrompt;
354     jmethodID   m_getDeviceMotionService;
355     jmethodID   m_getDeviceOrientationService;
356     jmethodID   m_addMessageToConsole;
357     jmethodID   m_focusNodeChanged;
358     jmethodID   m_getPluginClass;
359     jmethodID   m_showFullScreenPlugin;
360     jmethodID   m_hideFullScreenPlugin;
361     jmethodID   m_createSurface;
362     jmethodID   m_addSurface;
363     jmethodID   m_updateSurface;
364     jmethodID   m_destroySurface;
365     jmethodID   m_getContext;
366     jmethodID   m_keepScreenOn;
367     jmethodID   m_showRect;
368     jmethodID   m_centerFitRect;
369     jmethodID   m_setScrollbarModes;
370     jmethodID   m_exitFullscreenVideo;
371     jmethodID   m_setWebTextViewAutoFillable;
372     jmethodID   m_selectAt;
373     jmethodID   m_initEditField;
374     jmethodID   m_chromeCanTakeFocus;
375     jmethodID   m_chromeTakeFocus;
objectandroid::WebViewCore::JavaGlue376     AutoJObject object(JNIEnv* env) {
377         // We hold a weak reference to the Java WebViewCore to avoid memeory
378         // leaks due to circular references when WebView.destroy() is not
379         // called manually. The WebView and hence the WebViewCore could become
380         // weakly reachable at any time, after which the GC could null our weak
381         // reference, so we have to check the return value of this method at
382         // every use. Note that our weak reference will be nulled before the
383         // WebViewCore is finalized.
384         return getRealObject(env, m_obj);
385     }
386 };
387 
388 struct WebViewCore::TextFieldInitDataGlue {
389     jmethodID  m_constructor;
390     jfieldID   m_fieldPointer;
391     jfieldID   m_text;
392     jfieldID   m_type;
393     jfieldID   m_isSpellCheckEnabled;
394     jfieldID   m_isTextFieldNext;
395     jfieldID   m_isTextFieldPrev;
396     jfieldID   m_isAutoCompleteEnabled;
397     jfieldID   m_name;
398     jfieldID   m_label;
399     jfieldID   m_maxLength;
400     jfieldID   m_contentBounds;
401     jfieldID   m_nodeLayerId;
402     jfieldID   m_clientRect;
403 };
404 
405 /*
406  * WebViewCore Implementation
407  */
408 
GetJMethod(JNIEnv * env,jclass clazz,const char name[],const char signature[])409 static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[])
410 {
411     jmethodID m = env->GetMethodID(clazz, name, signature);
412     ALOG_ASSERT(m, "Could not find method %s", name);
413     return m;
414 }
415 
WebViewCore(JNIEnv * env,jobject javaWebViewCore,WebCore::Frame * mainframe)416 WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* mainframe)
417     : m_touchGeneration(0)
418     , m_lastGeneration(0)
419     , m_javaGlue(new JavaGlue)
420     , m_textFieldInitDataGlue(new TextFieldInitDataGlue)
421     , m_mainFrame(mainframe)
422     , m_popupReply(0)
423     , m_blockTextfieldUpdates(false)
424     , m_skipContentDraw(false)
425     , m_textGeneration(0)
426     , m_maxXScroll(320/4)
427     , m_maxYScroll(240/4)
428     , m_scrollOffsetX(0)
429     , m_scrollOffsetY(0)
430     , m_scrollSetTime(0)
431     , m_mousePos(WebCore::IntPoint(0,0))
432     , m_screenWidth(320)
433     , m_screenHeight(240)
434     , m_textWrapWidth(320)
435     , m_scale(1.0f)
436     , m_groupForVisitedLinks(0)
437     , m_cacheMode(0)
438     , m_fullscreenVideoMode(false)
439     , m_matchCount(0)
440     , m_activeMatchIndex(0)
441     , m_activeMatch(0)
442     , m_pluginInvalTimer(this, &WebViewCore::pluginInvalTimerFired)
443     , m_screenOnCounter(0)
444     , m_currentNodeDomNavigationAxis(0)
445     , m_deviceMotionAndOrientationManager(this)
446     , m_geolocationManager(this)
447 #if ENABLE(TOUCH_EVENTS)
448     , m_forwardingTouchEvents(false)
449 #endif
450     , m_webRequestContext(0)
451     , m_prerenderEnabled(false)
452 {
453     ALOG_ASSERT(m_mainFrame, "Uh oh, somehow a frameview was made without an initial frame!");
454 
455     jclass clazz = env->GetObjectClass(javaWebViewCore);
456     m_javaGlue->m_obj = env->NewWeakGlobalRef(javaWebViewCore);
457     m_javaGlue->m_scrollTo = GetJMethod(env, clazz, "contentScrollTo", "(IIZZ)V");
458     m_javaGlue->m_contentDraw = GetJMethod(env, clazz, "contentDraw", "()V");
459     m_javaGlue->m_requestListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[I[I)V");
460     m_javaGlue->m_openFileChooser = GetJMethod(env, clazz, "openFileChooser", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
461     m_javaGlue->m_requestSingleListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[II)V");
462     m_javaGlue->m_jsAlert = GetJMethod(env, clazz, "jsAlert", "(Ljava/lang/String;Ljava/lang/String;)V");
463     m_javaGlue->m_jsConfirm = GetJMethod(env, clazz, "jsConfirm", "(Ljava/lang/String;Ljava/lang/String;)Z");
464     m_javaGlue->m_jsPrompt = GetJMethod(env, clazz, "jsPrompt", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
465     m_javaGlue->m_jsUnload = GetJMethod(env, clazz, "jsUnload", "(Ljava/lang/String;Ljava/lang/String;)Z");
466     m_javaGlue->m_jsInterrupt = GetJMethod(env, clazz, "jsInterrupt", "()Z");
467     m_javaGlue->m_getWebView = GetJMethod(env, clazz, "getWebView", "()Landroid/webkit/WebView;");
468     m_javaGlue->m_didFirstLayout = GetJMethod(env, clazz, "didFirstLayout", "(Z)V");
469     m_javaGlue->m_updateViewport = GetJMethod(env, clazz, "updateViewport", "()V");
470     m_javaGlue->m_sendNotifyProgressFinished = GetJMethod(env, clazz, "sendNotifyProgressFinished", "()V");
471     m_javaGlue->m_sendViewInvalidate = GetJMethod(env, clazz, "sendViewInvalidate", "(IIII)V");
472     m_javaGlue->m_updateTextfield = GetJMethod(env, clazz, "updateTextfield", "(ILjava/lang/String;I)V");
473     m_javaGlue->m_updateTextSelection = GetJMethod(env, clazz, "updateTextSelection", "(IIIII)V");
474     m_javaGlue->m_updateTextSizeAndScroll = GetJMethod(env, clazz, "updateTextSizeAndScroll", "(IIIII)V");
475     m_javaGlue->m_clearTextEntry = GetJMethod(env, clazz, "clearTextEntry", "()V");
476     m_javaGlue->m_restoreScale = GetJMethod(env, clazz, "restoreScale", "(FF)V");
477     m_javaGlue->m_needTouchEvents = GetJMethod(env, clazz, "needTouchEvents", "(Z)V");
478     m_javaGlue->m_requestKeyboard = GetJMethod(env, clazz, "requestKeyboard", "(Z)V");
479     m_javaGlue->m_exceededDatabaseQuota = GetJMethod(env, clazz, "exceededDatabaseQuota", "(Ljava/lang/String;Ljava/lang/String;JJ)V");
480     m_javaGlue->m_reachedMaxAppCacheSize = GetJMethod(env, clazz, "reachedMaxAppCacheSize", "(JJ)V");
481     m_javaGlue->m_populateVisitedLinks = GetJMethod(env, clazz, "populateVisitedLinks", "()V");
482     m_javaGlue->m_geolocationPermissionsShowPrompt = GetJMethod(env, clazz, "geolocationPermissionsShowPrompt", "(Ljava/lang/String;)V");
483     m_javaGlue->m_geolocationPermissionsHidePrompt = GetJMethod(env, clazz, "geolocationPermissionsHidePrompt", "()V");
484     m_javaGlue->m_getDeviceMotionService = GetJMethod(env, clazz, "getDeviceMotionService", "()Landroid/webkit/DeviceMotionService;");
485     m_javaGlue->m_getDeviceOrientationService = GetJMethod(env, clazz, "getDeviceOrientationService", "()Landroid/webkit/DeviceOrientationService;");
486     m_javaGlue->m_addMessageToConsole = GetJMethod(env, clazz, "addMessageToConsole", "(Ljava/lang/String;ILjava/lang/String;I)V");
487     m_javaGlue->m_focusNodeChanged = GetJMethod(env, clazz, "focusNodeChanged", "(ILandroid/webkit/WebViewCore$WebKitHitTest;)V");
488     m_javaGlue->m_getPluginClass = GetJMethod(env, clazz, "getPluginClass", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Class;");
489     m_javaGlue->m_showFullScreenPlugin = GetJMethod(env, clazz, "showFullScreenPlugin", "(Landroid/webkit/ViewManager$ChildView;II)V");
490     m_javaGlue->m_hideFullScreenPlugin = GetJMethod(env, clazz, "hideFullScreenPlugin", "()V");
491     m_javaGlue->m_createSurface = GetJMethod(env, clazz, "createSurface", "(Landroid/view/View;)Landroid/webkit/ViewManager$ChildView;");
492     m_javaGlue->m_addSurface = GetJMethod(env, clazz, "addSurface", "(Landroid/view/View;IIII)Landroid/webkit/ViewManager$ChildView;");
493     m_javaGlue->m_updateSurface = GetJMethod(env, clazz, "updateSurface", "(Landroid/webkit/ViewManager$ChildView;IIII)V");
494     m_javaGlue->m_destroySurface = GetJMethod(env, clazz, "destroySurface", "(Landroid/webkit/ViewManager$ChildView;)V");
495     m_javaGlue->m_getContext = GetJMethod(env, clazz, "getContext", "()Landroid/content/Context;");
496     m_javaGlue->m_keepScreenOn = GetJMethod(env, clazz, "keepScreenOn", "(Z)V");
497     m_javaGlue->m_showRect = GetJMethod(env, clazz, "showRect", "(IIIIIIFFFF)V");
498     m_javaGlue->m_centerFitRect = GetJMethod(env, clazz, "centerFitRect", "(IIII)V");
499     m_javaGlue->m_setScrollbarModes = GetJMethod(env, clazz, "setScrollbarModes", "(II)V");
500 #if ENABLE(VIDEO)
501     m_javaGlue->m_exitFullscreenVideo = GetJMethod(env, clazz, "exitFullscreenVideo", "()V");
502 #endif
503     m_javaGlue->m_setWebTextViewAutoFillable = GetJMethod(env, clazz, "setWebTextViewAutoFillable", "(ILjava/lang/String;)V");
504     m_javaGlue->m_selectAt = GetJMethod(env, clazz, "selectAt", "(II)V");
505     m_javaGlue->m_initEditField = GetJMethod(env, clazz, "initEditField", "(IIILandroid/webkit/WebViewCore$TextFieldInitData;)V");
506     m_javaGlue->m_chromeCanTakeFocus = GetJMethod(env, clazz, "chromeCanTakeFocus", "(I)Z");
507     m_javaGlue->m_chromeTakeFocus = GetJMethod(env, clazz, "chromeTakeFocus", "(I)V");
508     env->DeleteLocalRef(clazz);
509 
510     env->SetIntField(javaWebViewCore, gWebViewCoreFields.m_nativeClass, (jint)this);
511 
512     jclass tfidClazz = env->FindClass("android/webkit/WebViewCore$TextFieldInitData");
513     m_textFieldInitDataGlue->m_fieldPointer = env->GetFieldID(tfidClazz, "mFieldPointer", "I");
514     m_textFieldInitDataGlue->m_text = env->GetFieldID(tfidClazz, "mText", "Ljava/lang/String;");
515     m_textFieldInitDataGlue->m_type = env->GetFieldID(tfidClazz, "mType", "I");
516     m_textFieldInitDataGlue->m_isSpellCheckEnabled = env->GetFieldID(tfidClazz, "mIsSpellCheckEnabled", "Z");
517     m_textFieldInitDataGlue->m_isTextFieldNext = env->GetFieldID(tfidClazz, "mIsTextFieldNext", "Z");
518     m_textFieldInitDataGlue->m_isTextFieldPrev = env->GetFieldID(tfidClazz, "mIsTextFieldPrev", "Z");
519     m_textFieldInitDataGlue->m_isAutoCompleteEnabled = env->GetFieldID(tfidClazz, "mIsAutoCompleteEnabled", "Z");
520     m_textFieldInitDataGlue->m_name = env->GetFieldID(tfidClazz, "mName", "Ljava/lang/String;");
521     m_textFieldInitDataGlue->m_label = env->GetFieldID(tfidClazz, "mLabel", "Ljava/lang/String;");
522     m_textFieldInitDataGlue->m_maxLength = env->GetFieldID(tfidClazz, "mMaxLength", "I");
523     m_textFieldInitDataGlue->m_contentBounds = env->GetFieldID(tfidClazz, "mContentBounds", "Landroid/graphics/Rect;");
524     m_textFieldInitDataGlue->m_nodeLayerId = env->GetFieldID(tfidClazz, "mNodeLayerId", "I");
525     m_textFieldInitDataGlue->m_clientRect = env->GetFieldID(tfidClazz, "mClientRect", "Landroid/graphics/Rect;");
526     m_textFieldInitDataGlue->m_constructor = GetJMethod(env, tfidClazz, "<init>", "()V");
527     env->DeleteLocalRef(tfidClazz);
528 
529     PageGroup::setShouldTrackVisitedLinks(true);
530 
531     clearContent();
532 
533     MemoryUsage::setLowMemoryUsageMb(env->GetIntField(javaWebViewCore, gWebViewCoreFields.m_lowMemoryUsageMb));
534     MemoryUsage::setHighMemoryUsageMb(env->GetIntField(javaWebViewCore, gWebViewCoreFields.m_highMemoryUsageMb));
535     MemoryUsage::setHighUsageDeltaMb(env->GetIntField(javaWebViewCore, gWebViewCoreFields.m_highUsageDeltaMb));
536 
537     WebViewCore::addInstance(this);
538 
539     AndroidNetworkLibraryImpl::InitWithApplicationContext(env, 0);
540 
541     // increase the font cache size beyond the standard system setting
542     SkGraphics::SetFontCacheLimit(1572864); // 1572864 bytes == 1.5 MB
543 
544     // Static initialisation of certain important V8 static data gets performed at system startup when
545     // libwebcore gets loaded. We now need to associate the WebCore thread with V8 to complete
546     // initialisation.
547     v8::V8::Initialize();
548 
549     // Configure any RuntimeEnabled features that we need to change from their default now.
550     // See WebCore/bindings/generic/RuntimeEnabledFeatures.h
551 
552     // HTML5 History API
553     RuntimeEnabledFeatures::setPushStateEnabled(true);
554     if (m_mainFrame)
555         m_mainFrame->settings()->setMinDOMTimerInterval(FOREGROUND_TIMER_INTERVAL);
556 }
557 
~WebViewCore()558 WebViewCore::~WebViewCore()
559 {
560     WebViewCore::removeInstance(this);
561 
562     // Release the focused view
563     ::Release(m_popupReply);
564 
565     if (m_javaGlue->m_obj) {
566         JNIEnv* env = JSC::Bindings::getJNIEnv();
567         env->DeleteWeakGlobalRef(m_javaGlue->m_obj);
568         m_javaGlue->m_obj = 0;
569     }
570     delete m_javaGlue;
571     delete m_textFieldInitDataGlue;
572 }
573 
getWebViewCore(const WebCore::FrameView * view)574 WebViewCore* WebViewCore::getWebViewCore(const WebCore::FrameView* view)
575 {
576     if (!view)
577         return 0;
578     if (view->platformWidget())
579         return static_cast<WebFrameView*>(view->platformWidget())->webViewCore();
580     Frame* frame = view->frame();
581     while (Frame* parent = frame->tree()->parent())
582         frame = parent;
583     WebFrameView* webFrameView = 0;
584     if (frame && frame->view())
585         webFrameView = static_cast<WebFrameView*>(frame->view()->platformWidget());
586     if (!webFrameView)
587         return 0;
588     return webFrameView->webViewCore();
589 }
590 
getWebViewCore(const WebCore::ScrollView * view)591 WebViewCore* WebViewCore::getWebViewCore(const WebCore::ScrollView* view)
592 {
593     if (!view)
594         return 0;
595     if (view->platformWidget())
596         return static_cast<WebFrameView*>(view->platformWidget())->webViewCore();
597     const FrameView* frameView = 0;
598     if (view->isFrameView())
599         frameView = static_cast<const FrameView*>(view);
600     else {
601         frameView = static_cast<const FrameView*>(view->root());
602         if (!frameView)
603             return 0;
604     }
605     return getWebViewCore(frameView);
606 }
607 
layoutIfNeededRecursive(WebCore::Frame * f)608 static bool layoutIfNeededRecursive(WebCore::Frame* f)
609 {
610     if (!f)
611         return true;
612 
613     WebCore::FrameView* v = f->view();
614     if (!v)
615         return true;
616     v->updateLayoutAndStyleIfNeededRecursive();
617     return !v->needsLayout();
618 }
619 
currentFocus()620 WebCore::Node* WebViewCore::currentFocus()
621 {
622     return focusedFrame()->document()->focusedNode();
623 }
624 
layout()625 void WebViewCore::layout()
626 {
627     TRACE_METHOD();
628 
629     // if there is no document yet, just return
630     if (!m_mainFrame->document()) {
631         ALOGV("!m_mainFrame->document()");
632         return;
633     }
634 
635     // Call layout to ensure that the contentWidth and contentHeight are correct
636     // it's fine for layout to gather invalidates, but defeat sending a message
637     // back to java to call webkitDraw, since we're already in the middle of
638     // doing that
639     bool success = layoutIfNeededRecursive(m_mainFrame);
640 
641     // We may be mid-layout and thus cannot draw.
642     if (!success)
643         return;
644 
645     // if the webkit page dimensions changed, discard the pictureset and redraw.
646     WebCore::FrameView* view = m_mainFrame->view();
647     int width = view->contentsWidth();
648     int height = view->contentsHeight();
649 
650     // Use the contents width and height as a starting point.
651     SkIRect contentRect;
652     contentRect.set(0, 0, width, height);
653     SkIRect total(contentRect);
654 
655     // Traverse all the frames and add their sizes if they are in the visible
656     // rectangle.
657     for (WebCore::Frame* frame = m_mainFrame->tree()->traverseNext(); frame;
658             frame = frame->tree()->traverseNext()) {
659         // If the frame doesn't have an owner then it is the top frame and the
660         // view size is the frame size.
661         WebCore::RenderPart* owner = frame->ownerRenderer();
662         if (owner && owner->style()->visibility() == VISIBLE) {
663             int x = owner->x();
664             int y = owner->y();
665 
666             // Traverse the tree up to the parent to find the absolute position
667             // of this frame.
668             WebCore::Frame* parent = frame->tree()->parent();
669             while (parent) {
670                 WebCore::RenderPart* parentOwner = parent->ownerRenderer();
671                 if (parentOwner) {
672                     x += parentOwner->x();
673                     y += parentOwner->y();
674                 }
675                 parent = parent->tree()->parent();
676             }
677             // Use the owner dimensions so that padding and border are
678             // included.
679             int right = x + owner->width();
680             int bottom = y + owner->height();
681             SkIRect frameRect = {x, y, right, bottom};
682             // Ignore a width or height that is smaller than 1. Some iframes
683             // have small dimensions in order to be hidden. The iframe
684             // expansion code does not expand in that case so we should ignore
685             // them here.
686             if (frameRect.width() > 1 && frameRect.height() > 1
687                     && SkIRect::Intersects(total, frameRect))
688                 total.join(x, y, right, bottom);
689         }
690     }
691 
692     // If the new total is larger than the content, resize the view to include
693     // all the content.
694     if (!contentRect.contains(total)) {
695         // TODO: Does this ever happen? Is this needed now that we don't flatten
696         // frames?
697         // Resize the view to change the overflow clip.
698         view->resize(total.fRight, total.fBottom);
699 
700         // We have to force a layout in order for the clip to change.
701         m_mainFrame->contentRenderer()->setNeedsLayoutAndPrefWidthsRecalc();
702         view->forceLayout();
703 
704         // Relayout similar to above
705         layoutIfNeededRecursive(m_mainFrame);
706     }
707 }
708 
recordPicturePile()709 void WebViewCore::recordPicturePile()
710 {
711     // if the webkit page dimensions changed, discard the pictureset and redraw.
712     WebCore::FrameView* view = m_mainFrame->view();
713     int width = view ? view->contentsWidth() : 0;
714     int height = view ? view->contentsHeight() : 0;
715 
716     m_content.setSize(IntSize(width, height));
717 
718     // Rebuild the pictureset (webkit repaint)
719     m_content.updatePicturesIfNeeded(this);
720 }
721 
clearContent()722 void WebViewCore::clearContent()
723 {
724     m_content.reset();
725     updateLocale();
726 }
727 
paintContents(WebCore::GraphicsContext * gc,WebCore::IntRect & dirty)728 void WebViewCore::paintContents(WebCore::GraphicsContext* gc, WebCore::IntRect& dirty)
729 {
730     WebCore::FrameView* view = m_mainFrame->view();
731     if (!view) {
732         gc->setFillColor(WebCore::Color::white, WebCore::ColorSpaceDeviceRGB);
733         gc->fillColor();
734         return;
735     }
736 
737     IntPoint origin = view->minimumScrollPosition();
738     IntRect drawArea = dirty;
739     gc->translate(-origin.x(), -origin.y());
740     drawArea.move(origin.x(), origin.y());
741     view->platformWidget()->draw(gc, drawArea);
742 }
743 
setPrerenderingEnabled(bool enable)744 void WebViewCore::setPrerenderingEnabled(bool enable)
745 {
746     MutexLocker locker(m_prerenderLock);
747     m_prerenderEnabled = enable;
748 }
749 
prerenderingEnabled()750 bool WebViewCore::prerenderingEnabled()
751 {
752     MutexLocker locker(m_prerenderLock);
753     return m_prerenderEnabled;
754 }
755 
createPrerenderCanvas(PrerenderedInval * prerendered)756 SkCanvas* WebViewCore::createPrerenderCanvas(PrerenderedInval* prerendered)
757 {
758     // Has WebView disabled prerenders (not attached, etc...)?
759     if (!prerenderingEnabled())
760         return 0;
761     // Does this WebView have focus?
762     if (!m_mainFrame->page()->focusController()->isActive())
763         return 0;
764     // Are we scrolling?
765     if (currentTimeMS() - m_scrollSetTime < PRERENDER_AFTER_SCROLL_DELAY)
766         return 0;
767     // Do we have anything to render?
768     if (prerendered->area.isEmpty())
769         return 0;
770     FloatRect scaleTemp(m_scrollOffsetX, m_scrollOffsetY, m_screenWidth, m_screenHeight);
771     scaleTemp.scale(m_scale);
772     IntRect visibleTileClip = enclosingIntRect(scaleTemp);
773     FloatRect scaledArea = prerendered->area;
774     scaledArea.scale(m_scale);
775     IntRect enclosingScaledArea = enclosingIntRect(scaledArea);
776     if (enclosingScaledArea.isEmpty())
777         return 0;
778     // "round out" the screen to tile boundaries so that we can clip yet still
779     // cover any visible tiles with the prerender
780     int tw = TilesManager::tileWidth();
781     int th = TilesManager::tileHeight();
782     float left = tw * (int) (visibleTileClip.x() / tw);
783     float top = th * (int) (visibleTileClip.y() / th);
784     float right = tw * (int) ceilf(visibleTileClip.maxX() / (float) tw);
785     float bottom = th * (int) ceilf(visibleTileClip.maxY() / (float) th);
786     visibleTileClip = IntRect(left, top, right - left, bottom - top);
787     enclosingScaledArea.intersect(visibleTileClip);
788     if (enclosingScaledArea.isEmpty())
789         return 0;
790     prerendered->screenArea = enclosingScaledArea;
791     FloatRect enclosingDocArea(enclosingScaledArea);
792     enclosingDocArea.scale(1 / m_scale);
793     prerendered->area = enclosingIntRect(enclosingDocArea);
794     if (prerendered->area.isEmpty())
795         return 0;
796     prerendered->bitmap.setConfig(SkBitmap::kARGB_8888_Config,
797                                   enclosingScaledArea.width(),
798                                   enclosingScaledArea.height());
799     prerendered->bitmap.allocPixels();
800     SkCanvas* bitmapCanvas = new SkCanvas(prerendered->bitmap);
801     bitmapCanvas->scale(m_scale, m_scale);
802     bitmapCanvas->translate(-enclosingDocArea.x(), -enclosingDocArea.y());
803     return bitmapCanvas;
804 }
805 
notifyAnimationStarted()806 void WebViewCore::notifyAnimationStarted()
807 {
808     // We notify webkit that the animations have begun
809     // TODO: handle case where not all have begun
810     ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client());
811     GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync());
812     if (root)
813         root->notifyClientAnimationStarted();
814 
815 }
816 
createBaseLayer(GraphicsLayerAndroid * root)817 BaseLayerAndroid* WebViewCore::createBaseLayer(GraphicsLayerAndroid* root)
818 {
819     // We set the background color
820     Color background = Color::white;
821 
822     bool bodyHasFixedBackgroundImage = false;
823     bool bodyHasCSSBackground = false;
824 
825     if (m_mainFrame && m_mainFrame->document()
826         && m_mainFrame->document()->body()) {
827 
828         Document* document = m_mainFrame->document();
829         RefPtr<RenderStyle> style = document->styleForElementIgnoringPendingStylesheets(document->body());
830         if (style->hasBackground()) {
831             background = style->visitedDependentColor(CSSPropertyBackgroundColor);
832             bodyHasCSSBackground = true;
833         }
834         WebCore::FrameView* view = m_mainFrame->view();
835         if (view) {
836             Color viewBackground = view->baseBackgroundColor();
837             background = bodyHasCSSBackground ? viewBackground.blend(background) : viewBackground;
838         }
839         if (style->hasFixedBackgroundImage()) {
840             Image* backgroundImage = FixedBackgroundImageLayerAndroid::GetCachedImage(style);
841             if (backgroundImage && backgroundImage->width() > 1 && backgroundImage->height() > 1)
842                 bodyHasFixedBackgroundImage = true;
843         }
844     }
845 
846     PicturePileLayerContent* content = new PicturePileLayerContent(m_content);
847     m_content.clearPrerenders();
848 
849     BaseLayerAndroid* realBase = 0;
850     LayerAndroid* base = 0;
851 
852     //If we have a fixed background image on the body element, the fixed image
853     // will be contained in the PictureSet (the content object), and the foreground
854     //of the body element will be moved to a layer.
855     //In that case, let's change the hierarchy to obtain:
856     //
857     //BaseLayerAndroid
858     // \- FixedBackgroundBaseLayerAndroid (fixed positioning)
859     // \- ForegroundBaseLayerAndroid
860     //   \- root layer (webkit composited tree)
861 
862     if (bodyHasFixedBackgroundImage) {
863         base = new ForegroundBaseLayerAndroid(0);
864         base->setSize(content->width(), content->height());
865 
866         Document* document = m_mainFrame->document();
867         RefPtr<RenderStyle> style = document->styleForElementIgnoringPendingStylesheets(document->body());
868 
869         FixedBackgroundImageLayerAndroid* baseBackground =
870              new FixedBackgroundImageLayerAndroid(style, content->width(), content->height());
871 
872         realBase = new BaseLayerAndroid(0);
873         realBase->setSize(content->width(), content->height());
874         realBase->addChild(baseBackground);
875         realBase->addChild(base);
876         baseBackground->unref();
877         base->unref();
878     } else {
879         realBase = new BaseLayerAndroid(content);
880         base = realBase;
881     }
882 
883     realBase->setBackgroundColor(background);
884 
885     SkSafeUnref(content);
886 
887     // We update the layers
888     if (root) {
889         LayerAndroid* copyLayer = new LayerAndroid(*root->contentLayer());
890         base->addChild(copyLayer);
891         copyLayer->unref();
892         root->contentLayer()->clearDirtyRegion();
893     }
894 
895     return realBase;
896 }
897 
recordContent(SkIPoint * point)898 BaseLayerAndroid* WebViewCore::recordContent(SkIPoint* point)
899 {
900     m_skipContentDraw = true;
901     layout();
902     ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client());
903     GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync());
904     m_skipContentDraw = false;
905     recordPicturePile();
906 
907     BaseLayerAndroid* baseLayer = createBaseLayer(root);
908 
909     baseLayer->markAsDirty(m_content.dirtyRegion());
910     m_content.dirtyRegion().setEmpty();
911 #if USE(ACCELERATED_COMPOSITING)
912 #else
913     baseLayer->markAsDirty(m_rebuildInval);
914 #endif
915     point->fX = m_content.size().width();
916     point->fY = m_content.size().height();
917 
918     return baseLayer;
919 }
920 
scrollTo(int x,int y,bool animate)921 void WebViewCore::scrollTo(int x, int y, bool animate)
922 {
923     ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
924 
925     JNIEnv* env = JSC::Bindings::getJNIEnv();
926     AutoJObject javaObject = m_javaGlue->object(env);
927     if (!javaObject.get())
928         return;
929     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_scrollTo,
930             x, y, animate, false);
931     checkException(env);
932 }
933 
sendNotifyProgressFinished()934 void WebViewCore::sendNotifyProgressFinished()
935 {
936     ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
937     JNIEnv* env = JSC::Bindings::getJNIEnv();
938     AutoJObject javaObject = m_javaGlue->object(env);
939     if (!javaObject.get())
940         return;
941     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_sendNotifyProgressFinished);
942     checkException(env);
943 }
944 
viewInvalidate(const WebCore::IntRect & rect)945 void WebViewCore::viewInvalidate(const WebCore::IntRect& rect)
946 {
947     ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
948     JNIEnv* env = JSC::Bindings::getJNIEnv();
949     AutoJObject javaObject = m_javaGlue->object(env);
950     if (!javaObject.get())
951         return;
952     env->CallVoidMethod(javaObject.get(),
953                         m_javaGlue->m_sendViewInvalidate,
954                         rect.x(), rect.y(), rect.maxX(), rect.maxY());
955     checkException(env);
956 }
957 
contentDraw()958 void WebViewCore::contentDraw()
959 {
960     JNIEnv* env = JSC::Bindings::getJNIEnv();
961     AutoJObject javaObject = m_javaGlue->object(env);
962     if (!javaObject.get())
963         return;
964     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_contentDraw);
965     checkException(env);
966 }
967 
contentInvalidate(const WebCore::IntRect & r)968 void WebViewCore::contentInvalidate(const WebCore::IntRect &r)
969 {
970     IntPoint origin = m_mainFrame->view()->minimumScrollPosition();
971     IntRect dirty = r;
972     dirty.move(-origin.x(), -origin.y());
973     m_content.invalidate(dirty);
974     if (!m_skipContentDraw)
975         contentDraw();
976 }
977 
contentInvalidateAll()978 void WebViewCore::contentInvalidateAll()
979 {
980     WebCore::FrameView* view = m_mainFrame->view();
981     contentInvalidate(WebCore::IntRect(0, 0,
982         view->contentsWidth(), view->contentsHeight()));
983 }
984 
offInvalidate(const WebCore::IntRect & r)985 void WebViewCore::offInvalidate(const WebCore::IntRect &r)
986 {
987     // FIXME: these invalidates are offscreen, and can be throttled or
988     // deferred until the area is visible. For now, treat them as
989     // regular invals so that drawing happens (inefficiently) for now.
990     contentInvalidate(r);
991 }
992 
didFirstLayout()993 void WebViewCore::didFirstLayout()
994 {
995     ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
996 
997     JNIEnv* env = JSC::Bindings::getJNIEnv();
998     AutoJObject javaObject = m_javaGlue->object(env);
999     if (!javaObject.get())
1000         return;
1001 
1002     const WebCore::KURL& url = m_mainFrame->document()->url();
1003     if (url.isEmpty())
1004         return;
1005     ALOGV("::WebCore:: didFirstLayout %s", url.string().ascii().data());
1006 
1007     WebCore::FrameLoadType loadType = m_mainFrame->loader()->loadType();
1008 
1009     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_didFirstLayout,
1010             loadType == WebCore::FrameLoadTypeStandard
1011             // When redirect with locked history, we would like to reset the
1012             // scale factor. This is important for www.yahoo.com as it is
1013             // redirected to www.yahoo.com/?rs=1 on load.
1014             || loadType == WebCore::FrameLoadTypeRedirectWithLockedBackForwardList
1015             // When "request desktop page" is used, we want to treat it as
1016             // a newly-loaded page.
1017             || loadType == WebCore::FrameLoadTypeSame);
1018     checkException(env);
1019 }
1020 
updateViewport()1021 void WebViewCore::updateViewport()
1022 {
1023     ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1024 
1025     JNIEnv* env = JSC::Bindings::getJNIEnv();
1026     AutoJObject javaObject = m_javaGlue->object(env);
1027     if (!javaObject.get())
1028         return;
1029     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateViewport);
1030     checkException(env);
1031 }
1032 
restoreScale(float scale,float textWrapScale)1033 void WebViewCore::restoreScale(float scale, float textWrapScale)
1034 {
1035     ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1036 
1037     JNIEnv* env = JSC::Bindings::getJNIEnv();
1038     AutoJObject javaObject = m_javaGlue->object(env);
1039     if (!javaObject.get())
1040         return;
1041     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_restoreScale, scale, textWrapScale);
1042     checkException(env);
1043 }
1044 
needTouchEvents(bool need)1045 void WebViewCore::needTouchEvents(bool need)
1046 {
1047     ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1048 
1049 #if ENABLE(TOUCH_EVENTS)
1050     JNIEnv* env = JSC::Bindings::getJNIEnv();
1051     AutoJObject javaObject = m_javaGlue->object(env);
1052     if (!javaObject.get())
1053         return;
1054 
1055     if (m_forwardingTouchEvents == need)
1056         return;
1057 
1058     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_needTouchEvents, need);
1059     checkException(env);
1060 
1061     m_forwardingTouchEvents = need;
1062 #endif
1063 }
1064 
requestKeyboard(bool showKeyboard)1065 void WebViewCore::requestKeyboard(bool showKeyboard)
1066 {
1067     ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1068 
1069     JNIEnv* env = JSC::Bindings::getJNIEnv();
1070     AutoJObject javaObject = m_javaGlue->object(env);
1071     if (!javaObject.get())
1072         return;
1073     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_requestKeyboard, showKeyboard);
1074     checkException(env);
1075 }
1076 
notifyProgressFinished()1077 void WebViewCore::notifyProgressFinished()
1078 {
1079     sendNotifyProgressFinished();
1080 }
1081 
setScrollOffset(bool sendScrollEvent,int dx,int dy)1082 void WebViewCore::setScrollOffset(bool sendScrollEvent, int dx, int dy)
1083 {
1084     if (m_scrollOffsetX != dx || m_scrollOffsetY != dy) {
1085         m_scrollOffsetX = dx;
1086         m_scrollOffsetY = dy;
1087         m_scrollSetTime = currentTimeMS();
1088         // The visible rect is located within our coordinate space so it
1089         // contains the actual scroll position. Setting the location makes hit
1090         // testing work correctly.
1091         m_mainFrame->view()->platformWidget()->setLocation(m_scrollOffsetX,
1092                 m_scrollOffsetY);
1093         if (sendScrollEvent) {
1094             m_mainFrame->eventHandler()->sendScrollEvent();
1095 
1096             // Only update history position if it's user scrolled.
1097             // Update history item to reflect the new scroll position.
1098             // This also helps save the history information when the browser goes to
1099             // background, so scroll position will be restored if browser gets
1100             // killed while in background.
1101             WebCore::HistoryController* history = m_mainFrame->loader()->history();
1102             // Because the history item saving could be heavy for large sites and
1103             // scrolling can generate lots of small scroll offset, the following code
1104             // reduces the saving frequency.
1105             static const int MIN_SCROLL_DIFF = 32;
1106             if (history->currentItem()) {
1107                 WebCore::IntPoint currentPoint = history->currentItem()->scrollPoint();
1108                 if (std::abs(currentPoint.x() - dx) >= MIN_SCROLL_DIFF ||
1109                     std::abs(currentPoint.y() - dy) >= MIN_SCROLL_DIFF) {
1110                     history->saveScrollPositionAndViewStateToItem(history->currentItem());
1111                 }
1112             }
1113         }
1114 
1115         // update the currently visible screen
1116         sendPluginVisibleScreen();
1117     }
1118 }
1119 
setGlobalBounds(int x,int y,int h,int v)1120 void WebViewCore::setGlobalBounds(int x, int y, int h, int v)
1121 {
1122     m_mainFrame->view()->platformWidget()->setWindowBounds(x, y, h, v);
1123 }
1124 
setSizeScreenWidthAndScale(int width,int height,int textWrapWidth,float scale,int screenWidth,int screenHeight,int anchorX,int anchorY,bool ignoreHeight)1125 void WebViewCore::setSizeScreenWidthAndScale(int width, int height,
1126     int textWrapWidth, float scale, int screenWidth, int screenHeight,
1127     int anchorX, int anchorY, bool ignoreHeight)
1128 {
1129     // Ignore the initial empty document.
1130     const WebCore::KURL& url = m_mainFrame->document()->url();
1131     if (url.isEmpty())
1132         return;
1133 
1134     WebCoreViewBridge* window = m_mainFrame->view()->platformWidget();
1135     int ow = window->width();
1136     int oh = window->height();
1137     int osw = m_screenWidth;
1138     int osh = m_screenHeight;
1139     int otw = m_textWrapWidth;
1140     m_screenWidth = screenWidth;
1141     m_screenHeight = screenHeight;
1142     m_textWrapWidth = textWrapWidth;
1143     if (scale >= 0) // negative means keep the current scale
1144         m_scale = scale;
1145     m_maxXScroll = screenWidth >> 2;
1146     m_maxYScroll = m_maxXScroll * height / width;
1147     // Don't reflow if the diff is small.
1148     const bool reflow = otw && textWrapWidth &&
1149         ((float) abs(otw - textWrapWidth) / textWrapWidth) >= 0.01f;
1150 
1151     // When the screen size change, fixed positioned element should be updated.
1152     // This is supposed to be light weighted operation without a full layout.
1153     if (osh != screenHeight || osw != screenWidth)
1154         m_mainFrame->view()->updatePositionedObjects();
1155 
1156     if (ow != width || (!ignoreHeight && oh != height) || reflow) {
1157         WebCore::RenderObject *r = m_mainFrame->contentRenderer();
1158         if (r) {
1159             WebCore::IntPoint anchorPoint = WebCore::IntPoint(anchorX, anchorY);
1160             RefPtr<WebCore::Node> node;
1161             WebCore::IntRect bounds;
1162             WebCore::IntPoint offset;
1163             // If the text wrap changed, it is probably zoom change or
1164             // orientation change. Try to keep the anchor at the same place.
1165             if (otw && textWrapWidth && otw != textWrapWidth &&
1166                 (anchorX != 0 || anchorY != 0)) {
1167                 WebCore::HitTestResult hitTestResult =
1168                         m_mainFrame->eventHandler()->hitTestResultAtPoint(
1169                                 anchorPoint, false);
1170                 node = hitTestResult.innerNode();
1171                 if (node && !node->isTextNode()) {
1172                     // If the hitTestResultAtPoint didn't find a suitable node
1173                     // for anchoring, try again with some slop.
1174                     static const int HIT_SLOP = 30;
1175                     anchorPoint.move(HIT_SLOP, HIT_SLOP);
1176                     hitTestResult =
1177                         m_mainFrame->eventHandler()->hitTestResultAtPoint(
1178                                 anchorPoint, false);
1179                     node = hitTestResult.innerNode();
1180                 }
1181             }
1182             if (node) {
1183                 bounds = node->getRect();
1184                 // sites like nytimes.com insert a non-standard tag <nyt_text>
1185                 // in the html. If it is the HitTestResult, it may have zero
1186                 // width and height. In this case, use its parent node.
1187                 if (bounds.width() == 0) {
1188                     node = node->parentOrHostNode();
1189                     if (node) {
1190                         bounds = node->getRect();
1191                     }
1192                 }
1193             }
1194 
1195             // Set the size after finding the old anchor point as
1196             // hitTestResultAtPoint causes a layout.
1197             window->setSize(width, height);
1198             window->setVisibleSize(screenWidth, screenHeight);
1199             if (width != screenWidth) {
1200                 m_mainFrame->view()->setUseFixedLayout(true);
1201                 m_mainFrame->view()->setFixedLayoutSize(IntSize(width, height));
1202             } else
1203                 m_mainFrame->view()->setUseFixedLayout(false);
1204             r->setNeedsLayoutAndPrefWidthsRecalc();
1205             if (m_mainFrame->view()->didFirstLayout())
1206                 m_mainFrame->view()->forceLayout();
1207 
1208             // scroll to restore current screen center
1209             if (node && node->inDocument()) {
1210                 const WebCore::IntRect& newBounds = node->getRect();
1211                 if ((osw && osh && bounds.width() && bounds.height())
1212                     && (bounds != newBounds)) {
1213                     WebCore::FrameView* view = m_mainFrame->view();
1214                     // force left align if width is not changed while height changed.
1215                     // the anchorPoint is probably at some white space in the node
1216                     // which is affected by text wrap around the screen width.
1217                     const bool leftAlign = (otw != textWrapWidth)
1218                         && (bounds.width() == newBounds.width())
1219                         && (bounds.height() != newBounds.height());
1220                     const float xPercentInDoc =
1221                         leftAlign ? 0.0 : (float) (anchorX - bounds.x()) / bounds.width();
1222                     const float xPercentInView =
1223                         leftAlign ? 0.0 : (float) (anchorX - m_scrollOffsetX) / osw;
1224                     const float yPercentInDoc = (float) (anchorY - bounds.y()) / bounds.height();
1225                     const float yPercentInView = (float) (anchorY - m_scrollOffsetY) / osh;
1226                     showRect(newBounds.x(), newBounds.y(), newBounds.width(),
1227                              newBounds.height(), view->contentsWidth(),
1228                              view->contentsHeight(),
1229                              xPercentInDoc, xPercentInView,
1230                              yPercentInDoc, yPercentInView);
1231                 }
1232             }
1233         }
1234     } else {
1235         window->setSize(width, height);
1236         window->setVisibleSize(screenWidth, screenHeight);
1237         m_mainFrame->view()->resize(width, height);
1238         if (width != screenWidth) {
1239             m_mainFrame->view()->setUseFixedLayout(true);
1240             m_mainFrame->view()->setFixedLayoutSize(IntSize(width, height));
1241         } else
1242             m_mainFrame->view()->setUseFixedLayout(false);
1243     }
1244 
1245     // update the currently visible screen as perceived by the plugin
1246     sendPluginVisibleScreen();
1247 }
1248 
dumpDomTree(bool useFile)1249 void WebViewCore::dumpDomTree(bool useFile)
1250 {
1251 #ifdef ANDROID_DOM_LOGGING
1252     if (useFile)
1253         gDomTreeFile = fopen(DOM_TREE_LOG_FILE, "w");
1254     m_mainFrame->document()->showTreeForThis();
1255     if (gDomTreeFile) {
1256         fclose(gDomTreeFile);
1257         gDomTreeFile = 0;
1258     }
1259 #endif
1260 }
1261 
dumpRenderTree(bool useFile)1262 void WebViewCore::dumpRenderTree(bool useFile)
1263 {
1264 #ifdef ANDROID_DOM_LOGGING
1265     WTF::CString renderDump = WebCore::externalRepresentation(m_mainFrame).utf8();
1266     const char* data = renderDump.data();
1267     if (useFile) {
1268         gRenderTreeFile = fopen(RENDER_TREE_LOG_FILE, "w");
1269         DUMP_RENDER_LOGD("%s", data);
1270         fclose(gRenderTreeFile);
1271         gRenderTreeFile = 0;
1272     } else {
1273         // adb log can only output 1024 characters, so write out line by line.
1274         // exclude '\n' as adb log adds it for each output.
1275         int length = renderDump.length();
1276         for (int i = 0, last = 0; i < length; i++) {
1277             if (data[i] == '\n') {
1278                 if (i != last)
1279                     DUMP_RENDER_LOGD("%.*s", (i - last), &(data[last]));
1280                 last = i + 1;
1281             }
1282         }
1283     }
1284 #endif
1285 }
1286 
retrieveElement(int x,int y,const QualifiedName & tagName)1287 HTMLElement* WebViewCore::retrieveElement(int x, int y,
1288     const QualifiedName& tagName)
1289 {
1290     HitTestResult hitTestResult = m_mainFrame->eventHandler()
1291         ->hitTestResultAtPoint(IntPoint(x, y), false, false,
1292         DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly,
1293         IntSize(1, 1));
1294     if (!hitTestResult.innerNode() || !hitTestResult.innerNode()->inDocument()) {
1295         ALOGE("Should not happen: no in document Node found");
1296         return 0;
1297     }
1298     const ListHashSet<RefPtr<Node> >& list = hitTestResult.rectBasedTestResult();
1299     if (list.isEmpty()) {
1300         ALOGE("Should not happen: no rect-based-test nodes found");
1301         return 0;
1302     }
1303     Node* node = hitTestResult.innerNode();
1304     Node* element = node;
1305     while (element && (!element->isElementNode()
1306         || !element->hasTagName(tagName))) {
1307         element = element->parentNode();
1308     }
1309     return static_cast<WebCore::HTMLElement*>(element);
1310 }
1311 
retrieveAnchorElement(int x,int y)1312 HTMLAnchorElement* WebViewCore::retrieveAnchorElement(int x, int y)
1313 {
1314     return static_cast<HTMLAnchorElement*>
1315         (retrieveElement(x, y, HTMLNames::aTag));
1316 }
1317 
retrieveImageElement(int x,int y)1318 HTMLImageElement* WebViewCore::retrieveImageElement(int x, int y)
1319 {
1320     return static_cast<HTMLImageElement*>
1321         (retrieveElement(x, y, HTMLNames::imgTag));
1322 }
1323 
retrieveHref(int x,int y)1324 WTF::String WebViewCore::retrieveHref(int x, int y)
1325 {
1326     // TODO: This is expensive, cache
1327     HitTestResult result = m_mainFrame->eventHandler()->hitTestResultAtPoint(IntPoint(x, y),
1328                 false, false, DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly, IntSize(1, 1));
1329     return result.absoluteLinkURL();
1330 }
1331 
retrieveAnchorText(int x,int y)1332 WTF::String WebViewCore::retrieveAnchorText(int x, int y)
1333 {
1334     WebCore::HTMLAnchorElement* anchor = retrieveAnchorElement(x, y);
1335     return anchor ? anchor->text() : WTF::String();
1336 }
1337 
retrieveImageSource(int x,int y)1338 WTF::String WebViewCore::retrieveImageSource(int x, int y)
1339 {
1340     // TODO: This is expensive, cache
1341     HitTestResult result = m_mainFrame->eventHandler()->hitTestResultAtPoint(IntPoint(x, y),
1342                 false, false, DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly, IntSize(1, 1));
1343     return result.absoluteImageURL();
1344 }
1345 
requestLabel(WebCore::Frame * frame,WebCore::Node * node)1346 WTF::String WebViewCore::requestLabel(WebCore::Frame* frame,
1347         WebCore::Node* node)
1348 {
1349     if (node && validNode(m_mainFrame, frame, node)) {
1350         RefPtr<WebCore::NodeList> list = node->document()->getElementsByTagName("label");
1351         unsigned length = list->length();
1352         for (unsigned i = 0; i < length; i++) {
1353             WebCore::HTMLLabelElement* label = static_cast<WebCore::HTMLLabelElement*>(
1354                     list->item(i));
1355             if (label->control() == node) {
1356                 Node* node = label;
1357                 String result;
1358                 while ((node = node->traverseNextNode(label))) {
1359                     if (node->isTextNode()) {
1360                         Text* textNode = static_cast<Text*>(node);
1361                         result += textNode->dataImpl();
1362                     }
1363                 }
1364                 return result;
1365             }
1366         }
1367     }
1368     return WTF::String();
1369 }
1370 
isContentEditable(const WebCore::Node * node)1371 static bool isContentEditable(const WebCore::Node* node)
1372 {
1373     if (!node)
1374         return false;
1375     return node->isContentEditable();
1376 }
1377 
1378 // Returns true if the node is a textfield, textarea, or contentEditable
isTextInput(const WebCore::Node * node)1379 static bool isTextInput(const WebCore::Node* node)
1380 {
1381     if (!node)
1382         return false;
1383     if (isContentEditable(node))
1384         return true;
1385     WebCore::RenderObject* renderer = node->renderer();
1386     return renderer && (renderer->isTextField() || renderer->isTextArea());
1387 }
1388 
revealSelection()1389 void WebViewCore::revealSelection()
1390 {
1391     WebCore::Node* focus = currentFocus();
1392     if (!focus)
1393         return;
1394     if (!isTextInput(focus))
1395         return;
1396     WebCore::Frame* focusedFrame = focus->document()->frame();
1397     if (!focusedFrame->page()->focusController()->isActive())
1398         return;
1399     focusedFrame->selection()->revealSelection(ScrollAlignment::alignToEdgeIfNeeded);
1400 }
1401 
1402 struct TouchNodeData {
1403     Node* mUrlNode;
1404     Node* mInnerNode;
1405     IntRect mBounds;
1406 };
1407 
1408 // get the bounding box of the Node
getAbsoluteBoundingBox(Node * node)1409 static IntRect getAbsoluteBoundingBox(Node* node) {
1410     IntRect rect;
1411     RenderObject* render = node->renderer();
1412     if (!render)
1413         return rect;
1414     if (render->isRenderInline())
1415         rect = toRenderInline(render)->linesVisualOverflowBoundingBox();
1416     else if (render->isBox())
1417         rect = toRenderBox(render)->visualOverflowRect();
1418     else if (render->isText())
1419         rect = toRenderText(render)->linesBoundingBox();
1420     else
1421         ALOGE("getAbsoluteBoundingBox failed for node %p, name %s", node, render->renderName());
1422     FloatPoint absPos = render->localToAbsolute(FloatPoint(), false, true);
1423     rect.move(absPos.x(), absPos.y());
1424     return rect;
1425 }
1426 
focusedFrame() const1427 WebCore::Frame* WebViewCore::focusedFrame() const
1428 {
1429     return m_mainFrame->page()->focusController()->focusedOrMainFrame();
1430 }
1431 
visiblePositionForContentPoint(int x,int y)1432 VisiblePosition WebViewCore::visiblePositionForContentPoint(int x, int y)
1433 {
1434     return visiblePositionForContentPoint(IntPoint(x, y));
1435 }
1436 
visiblePositionForContentPoint(const IntPoint & point)1437 VisiblePosition WebViewCore::visiblePositionForContentPoint(const IntPoint& point)
1438 {
1439     // Hit test of this kind required for this to work inside input fields
1440     HitTestRequest request(HitTestRequest::Active
1441                            | HitTestRequest::MouseMove
1442                            | HitTestRequest::ReadOnly
1443                            | HitTestRequest::IgnoreClipping);
1444     HitTestResult result(point);
1445     focusedFrame()->document()->renderView()->layer()->hitTest(request, result);
1446 
1447     // Matching the logic in MouseEventWithHitTestResults::targetNode()
1448     Node* node = result.innerNode();
1449     if (!node)
1450         return VisiblePosition();
1451     Element* element = node->parentElement();
1452     if (!node->inDocument() && element && element->inDocument())
1453         node = element;
1454 
1455     return node->renderer()->positionForPoint(result.localPoint());
1456 }
1457 
selectWordAt(int x,int y)1458 bool WebViewCore::selectWordAt(int x, int y)
1459 {
1460     HitTestResult hoverResult;
1461     moveMouse(x, y, &hoverResult);
1462     if (hoverResult.innerNode()) {
1463         Node* node = hoverResult.innerNode();
1464         Frame* frame = node->document()->frame();
1465         Page* page = m_mainFrame->document()->page();
1466         page->focusController()->setFocusedFrame(frame);
1467     }
1468 
1469     IntPoint point = convertGlobalContentToFrameContent(IntPoint(x, y));
1470 
1471     // Hit test of this kind required for this to work inside input fields
1472     HitTestRequest request(HitTestRequest::Active);
1473     HitTestResult result(point);
1474 
1475     focusedFrame()->document()->renderView()->layer()->hitTest(request, result);
1476 
1477     // Matching the logic in MouseEventWithHitTestResults::targetNode()
1478     Node* node = result.innerNode();
1479     if (!node)
1480         return false;
1481     Element* element = node->parentElement();
1482     if (!node->inDocument() && element && element->inDocument())
1483         node = element;
1484 
1485     SelectionController* sc = focusedFrame()->selection();
1486     bool wordSelected = false;
1487     if (!sc->contains(point) && (node->isContentEditable() || node->isTextNode()) && !result.isLiveLink()
1488             && node->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true))) {
1489         VisiblePosition pos(node->renderer()->positionForPoint(result.localPoint()));
1490         wordSelected = selectWordAroundPosition(node->document()->frame(), pos);
1491     }
1492     return wordSelected;
1493 }
1494 
selectWordAroundPosition(Frame * frame,VisiblePosition pos)1495 bool WebViewCore::selectWordAroundPosition(Frame* frame, VisiblePosition pos)
1496 {
1497     VisibleSelection selection(pos);
1498     selection.expandUsingGranularity(WordGranularity);
1499     SelectionController* selectionController = frame->selection();
1500     selection = VisibleSelection(selection.start(), selection.end());
1501 
1502     bool wordSelected = false;
1503     if (selectionController->shouldChangeSelection(selection)) {
1504         bool allWhitespaces = true;
1505         RefPtr<Range> firstRange = selection.firstRange();
1506         String text = firstRange.get() ? firstRange->text() : "";
1507         for (size_t i = 0; i < text.length(); ++i) {
1508             if (!isSpaceOrNewline(text[i])) {
1509                 allWhitespaces = false;
1510                 break;
1511             }
1512         }
1513         if (allWhitespaces) {
1514             VisibleSelection emptySelection(pos);
1515             selectionController->setSelection(emptySelection);
1516         } else {
1517             selectionController->setSelection(selection);
1518             wordSelected = true;
1519         }
1520     }
1521     return wordSelected;
1522 }
1523 
platformLayerIdFromNode(Node * node,LayerAndroid ** outLayer)1524 int WebViewCore::platformLayerIdFromNode(Node* node, LayerAndroid** outLayer)
1525 {
1526     if (!node || !node->renderer())
1527         return -1;
1528     RenderLayer* renderLayer = node->renderer()->enclosingLayer();
1529     while (renderLayer && !renderLayer->isComposited())
1530         renderLayer = renderLayer->parent();
1531     if (!renderLayer || !renderLayer->isComposited())
1532         return -1;
1533     GraphicsLayer* graphicsLayer = renderLayer->backing()->graphicsLayer();
1534     if (!graphicsLayer)
1535         return -1;
1536     GraphicsLayerAndroid* agl = static_cast<GraphicsLayerAndroid*>(graphicsLayer);
1537     LayerAndroid* layer = agl->foregroundLayer();
1538     if (!layer)
1539         layer = agl->contentLayer();
1540     if (!layer)
1541         return -1;
1542     if (outLayer)
1543         *outLayer = layer;
1544     return layer->uniqueId();
1545 }
1546 
layerToAbsoluteOffset(const LayerAndroid * layer,IntPoint & offset)1547 void WebViewCore::layerToAbsoluteOffset(const LayerAndroid* layer, IntPoint& offset)
1548 {
1549     while (layer) {
1550         const SkPoint& pos = layer->getPosition();
1551         offset.move(pos.fX, pos.fY);
1552         const IntPoint& scroll = layer->getScrollOffset();
1553         offset.move(-scroll.x(), -scroll.y());
1554         layer = static_cast<LayerAndroid*>(layer->getParent());
1555     }
1556 }
1557 
setSelectionCaretInfo(SelectText * selectTextContainer,const WebCore::Position & pos,const IntPoint & frameOffset,SelectText::HandleId handleId,SelectText::HandleType handleType,int caretRectOffset,EAffinity affinity)1558 void WebViewCore::setSelectionCaretInfo(SelectText* selectTextContainer,
1559         const WebCore::Position& pos, const IntPoint& frameOffset,
1560         SelectText::HandleId handleId, SelectText::HandleType handleType,
1561         int caretRectOffset, EAffinity affinity)
1562 {
1563     Node* node = pos.anchorNode();
1564     LayerAndroid* layer = 0;
1565     int layerId = platformLayerIdFromNode(node, &layer);
1566     selectTextContainer->setCaretLayerId(handleId, layerId);
1567     IntPoint offset = frameOffset;
1568     layerToAbsoluteOffset(layer, offset);
1569     RenderObject* r = node->renderer();
1570     RenderText* renderText = toRenderText(r);
1571     int caretOffset;
1572     InlineBox* inlineBox;
1573     pos.getInlineBoxAndOffset(affinity, inlineBox, caretOffset);
1574     IntRect caretRect = renderText->localCaretRect(inlineBox, caretOffset);
1575     FloatPoint absoluteOffset = renderText->localToAbsolute(caretRect.location());
1576     caretRect.setX(absoluteOffset.x() - offset.x() + caretRectOffset);
1577     caretRect.setY(absoluteOffset.y() - offset.y());
1578     selectTextContainer->setCaretRect(handleId, caretRect);
1579     selectTextContainer->setHandleType(handleId, handleType);
1580     selectTextContainer->setTextRect(handleId,
1581             positionToTextRect(pos, affinity, offset, caretRect));
1582 }
1583 
isLtr(const Position & position)1584 bool WebViewCore::isLtr(const Position& position)
1585 {
1586     InlineBox* inlineBox = 0;
1587     int caretOffset = 0;
1588     position.getInlineBoxAndOffset(DOWNSTREAM, inlineBox, caretOffset);
1589     bool isLtr;
1590     if (inlineBox)
1591         isLtr = inlineBox->isLeftToRightDirection();
1592     else
1593         isLtr = position.primaryDirection() == LTR;
1594     return isLtr;
1595 }
1596 
findInputParent(Node * node)1597 static Node* findInputParent(Node* node)
1598 {
1599     Node* testNode = node;
1600     while (testNode) {
1601         RenderObject* renderer = testNode->renderer();
1602         if (renderer
1603                 && (renderer->isTextArea() || renderer->isTextControl())) {
1604             return testNode;
1605         }
1606         testNode = testNode->parentOrHostNode();
1607     }
1608     return node;
1609 }
1610 
createSelectText(const VisibleSelection & selection)1611 SelectText* WebViewCore::createSelectText(const VisibleSelection& selection)
1612 {
1613     bool isCaret = selection.isCaret();
1614     Position base = selection.base();
1615     Position extent = selection.extent();
1616     if (selection.isNone() || (!selection.isContentEditable() && isCaret)
1617             || !base.anchorNode() || !base.anchorNode()->renderer()
1618             || !extent.anchorNode() || !extent.anchorNode()->renderer())
1619         return 0;
1620 
1621     RefPtr<Range> range = selection.firstRange();
1622     Node* startContainer = range->startContainer();
1623     Node* endContainer = range->endContainer();
1624 
1625     if (!startContainer || !endContainer)
1626         return 0;
1627     if (!isCaret && startContainer == endContainer
1628             && range->startOffset() == range->endOffset())
1629         return 0;
1630 
1631     IntPoint frameOffset = convertGlobalContentToFrameContent(IntPoint());
1632     SelectText* selectTextContainer = new SelectText();
1633     if (isCaret) {
1634         setSelectionCaretInfo(selectTextContainer, base, frameOffset,
1635                 SelectText::BaseHandle, SelectText::CenterHandle, 0,
1636                 selection.affinity());
1637         setSelectionCaretInfo(selectTextContainer, base, frameOffset,
1638                 SelectText::ExtentHandle, SelectText::CenterHandle, 0,
1639                 selection.affinity());
1640     } else {
1641         bool isBaseLtr = isLtr(base);
1642         bool isBaseStart = comparePositions(base, extent) <= 0;
1643         int baseOffset = isBaseLtr ? 0 : -1;
1644         SelectText::HandleType baseHandleType = (isBaseLtr == isBaseStart)
1645                 ? SelectText::LeftHandle : SelectText::RightHandle;
1646         EAffinity affinity = selection.affinity();
1647         setSelectionCaretInfo(selectTextContainer, base, frameOffset,
1648                 SelectText::BaseHandle, baseHandleType, baseOffset, affinity);
1649         bool isExtentLtr = isLtr(extent);
1650         int extentOffset = isExtentLtr ? 0 : -1;
1651         SelectText::HandleType extentHandleType = (isExtentLtr == isBaseStart)
1652                 ? SelectText::RightHandle : SelectText::LeftHandle;
1653         setSelectionCaretInfo(selectTextContainer, extent, frameOffset,
1654                 SelectText::ExtentHandle, extentHandleType, extentOffset, affinity);
1655         IntRect clipRect;
1656         if (selection.isContentEditable()) {
1657             Node* editable = findInputParent(base.anchorNode());
1658             RenderObject* render = editable->renderer();
1659             if (render && render->isBox() && !render->isBody()) {
1660                 RenderBox* renderBox = toRenderBox(render);
1661                 clipRect = renderBox->clientBoxRect();
1662                 FloatPoint pos = renderBox->localToAbsolute(clipRect.location());
1663                 clipRect.setX(pos.x());
1664                 clipRect.setY(pos.y());
1665             }
1666         }
1667 
1668         Node* stopNode = range->pastLastNode();
1669         for (Node* node = range->firstNode(); node != stopNode; node = node->traverseNextNode()) {
1670             RenderObject* r = node->renderer();
1671             if (!r || !r->isText() || r->style()->visibility() != VISIBLE)
1672                 continue;
1673             RenderText* renderText = toRenderText(r);
1674             int startOffset = node == startContainer ? range->startOffset() : 0;
1675             int endOffset = node == endContainer ? range->endOffset() : numeric_limits<int>::max();
1676             LayerAndroid* layer = 0;
1677             int layerId = platformLayerIdFromNode(node, &layer);
1678             Vector<IntRect> rects;
1679             renderText->absoluteRectsForRange(rects, startOffset, endOffset, true);
1680             selectTextContainer->addHighlightRegion(layer, rects, frameOffset,
1681                     clipRect);
1682         }
1683     }
1684     selectTextContainer->setText(range->text());
1685     return selectTextContainer;
1686 }
1687 
positionToTextRect(const Position & position,EAffinity affinity,const WebCore::IntPoint & offset,const IntRect & caretRect)1688 IntRect WebViewCore::positionToTextRect(const Position& position,
1689         EAffinity affinity, const WebCore::IntPoint& offset, const IntRect& caretRect)
1690 {
1691     IntRect textRect = caretRect;
1692     InlineBox* inlineBox;
1693     int offsetIndex;
1694     position.getInlineBoxAndOffset(affinity, inlineBox, offsetIndex);
1695     if (inlineBox && inlineBox->isInlineTextBox()) {
1696         InlineTextBox* box = static_cast<InlineTextBox*>(inlineBox);
1697         RootInlineBox* root = box->root();
1698         RenderText* renderText = box->textRenderer();
1699         int left = root->logicalLeft();
1700         int width = root->logicalWidth();
1701         int top = root->selectionTop();
1702         int height = root->selectionHeight();
1703 
1704         if (!renderText->style()->isHorizontalWritingMode()) {
1705             swap(left, top);
1706             swap(width, height);
1707         }
1708         FloatPoint origin(left, top);
1709         FloatPoint absoluteOrigin = renderText->localToAbsolute(origin);
1710 
1711         textRect.setX(absoluteOrigin.x() - offset.x());
1712         textRect.setWidth(width);
1713         textRect.setY(absoluteOrigin.y() - offset.y());
1714         textRect.setHeight(height);
1715     }
1716     return textRect;
1717 }
1718 
convertGlobalContentToFrameContent(const IntPoint & point,WebCore::Frame * frame)1719 IntPoint WebViewCore::convertGlobalContentToFrameContent(const IntPoint& point, WebCore::Frame* frame)
1720 {
1721     if (!frame) frame = focusedFrame();
1722     IntPoint frameOffset(-m_scrollOffsetX, -m_scrollOffsetY);
1723     frameOffset = frame->view()->windowToContents(frameOffset);
1724     return IntPoint(point.x() + frameOffset.x(), point.y() + frameOffset.y());
1725 }
1726 
trimSelectionPosition(const VisiblePosition & start,const VisiblePosition & stop)1727 VisiblePosition WebViewCore::trimSelectionPosition(const VisiblePosition &start,
1728         const VisiblePosition& stop)
1729 {
1730     int direction = comparePositions(start, stop);
1731     if (direction == 0)
1732         return start;
1733     bool forward = direction < 0;
1734     bool move;
1735     VisiblePosition pos = start;
1736     bool movedTooFar = false;
1737     do {
1738         move = true;
1739         Node* node = pos.deepEquivalent().anchorNode();
1740         if (node && node->isTextNode() && node->renderer()) {
1741             RenderText *textRenderer = toRenderText(node->renderer());
1742             move = !textRenderer->textLength();
1743         }
1744         if (move) {
1745             VisiblePosition nextPos = forward ? pos.next() : pos.previous();
1746             movedTooFar = nextPos.isNull() || pos == nextPos
1747                     || ((comparePositions(nextPos, stop) < 0) != forward);
1748             pos = nextPos;
1749         }
1750     } while (move && !movedTooFar);
1751     if (movedTooFar)
1752         pos = stop;
1753     return pos;
1754 }
1755 
selectText(SelectText::HandleId handleId,int x,int y)1756 void WebViewCore::selectText(SelectText::HandleId handleId, int x, int y)
1757 {
1758     SelectionController* sc = focusedFrame()->selection();
1759     VisibleSelection selection = sc->selection();
1760     Position base = selection.base();
1761     Position extent = selection.extent();
1762     IntPoint dragPoint = convertGlobalContentToFrameContent(IntPoint(x, y));
1763     VisiblePosition dragPosition(visiblePositionForContentPoint(dragPoint));
1764 
1765     if (base.isNull() || extent.isNull() || dragPosition.isNull())
1766         return;
1767     bool draggingBase = (handleId == SelectText::BaseHandle);
1768     if (draggingBase)
1769         base = dragPosition.deepEquivalent();
1770     else
1771         extent = dragPosition.deepEquivalent();
1772 
1773     bool baseIsStart = (comparePositions(base, extent) <= 0);
1774     Position& start = baseIsStart ? base : extent;
1775     Position& end = baseIsStart ? extent : base;
1776     VisiblePosition startPosition(start, selection.affinity());
1777     VisiblePosition endPosition(end, selection.affinity());
1778     bool draggingStart = (baseIsStart == draggingBase);
1779 
1780     if (draggingStart) {
1781         if (selection.isRange()) {
1782             startPosition = trimSelectionPosition(startPosition, endPosition);
1783             if ((startPosition != endPosition) && isEndOfBlock(startPosition)) {
1784                 // Ensure startPosition is not at end of block
1785                 VisiblePosition nextStartPosition(startPosition.next());
1786                 if (nextStartPosition.isNotNull())
1787                     startPosition = nextStartPosition;
1788             }
1789         }
1790         startPosition = endPosition.honorEditableBoundaryAtOrAfter(startPosition);
1791         if (startPosition.isNull())
1792             return;
1793         start = startPosition.deepEquivalent();
1794         if (selection.isCaret())
1795             end = start;
1796     } else {
1797         if (selection.isRange()) {
1798             endPosition = trimSelectionPosition(endPosition, startPosition);
1799             if ((start != end) && isStartOfBlock(endPosition)) {
1800                 // Ensure endPosition is not at start of block
1801                 VisiblePosition prevEndPosition(endPosition.previous());
1802                 if (!prevEndPosition.isNull())
1803                     endPosition = prevEndPosition;
1804             }
1805         }
1806         endPosition = startPosition.honorEditableBoundaryAtOrAfter(endPosition);
1807         if (endPosition.isNull())
1808             return;
1809         end = endPosition.deepEquivalent();
1810         if (selection.isCaret())
1811             start = end;
1812     }
1813 
1814     selection = VisibleSelection(base, extent);
1815     // Only allow changes between caret positions or to text selection.
1816     bool selectChangeAllowed = (!selection.isCaret() || sc->isCaret());
1817     if (selectChangeAllowed && sc->shouldChangeSelection(selection))
1818         sc->setSelection(selection);
1819 }
1820 
nodeIsClickableOrFocusable(Node * node)1821 bool WebViewCore::nodeIsClickableOrFocusable(Node* node)
1822 {
1823     if (!node)
1824         return false;
1825     if (node->disabled())
1826         return false;
1827     if (!node->inDocument())
1828         return false;
1829     if (!node->renderer() || node->renderer()->style()->visibility() != VISIBLE)
1830         return false;
1831     return node->supportsFocus()
1832             || node->hasEventListeners(eventNames().clickEvent)
1833             || node->hasEventListeners(eventNames().mousedownEvent)
1834             || node->hasEventListeners(eventNames().mouseupEvent)
1835             || node->hasEventListeners(eventNames().mouseoverEvent);
1836 }
1837 
1838 // get the highlight rectangles for the touch point (x, y) with the slop
hitTestAtPoint(int x,int y,int slop,bool doMoveMouse)1839 AndroidHitTestResult WebViewCore::hitTestAtPoint(int x, int y, int slop, bool doMoveMouse)
1840 {
1841     if (doMoveMouse)
1842         moveMouse(x, y, 0, true);
1843     HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(IntPoint(x, y),
1844             false, false, DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly, IntSize(slop, slop));
1845     AndroidHitTestResult androidHitResult(this, hitTestResult);
1846     if (!hitTestResult.innerNode() || !hitTestResult.innerNode()->inDocument()) {
1847         ALOGE("Should not happen: no in document Node found");
1848         return androidHitResult;
1849     }
1850     const ListHashSet<RefPtr<Node> >& list = hitTestResult.rectBasedTestResult();
1851     if (list.isEmpty()) {
1852         ALOGE("Should not happen: no rect-based-test nodes found");
1853         return androidHitResult;
1854     }
1855     Frame* frame = hitTestResult.innerNode()->document()->frame();
1856     Vector<TouchNodeData> nodeDataList;
1857     if (hitTestResult.innerNode() != hitTestResult.innerNonSharedNode()
1858             && hitTestResult.innerNode()->hasTagName(WebCore::HTMLNames::areaTag)) {
1859         HTMLAreaElement* area = static_cast<HTMLAreaElement*>(hitTestResult.innerNode());
1860         androidHitResult.hitTestResult().setURLElement(area);
1861         androidHitResult.highlightRects().append(area->computeRect(
1862                 hitTestResult.innerNonSharedNode()->renderer()));
1863         return androidHitResult;
1864     }
1865     ListHashSet<RefPtr<Node> >::const_iterator last = list.end();
1866     for (ListHashSet<RefPtr<Node> >::const_iterator it = list.begin(); it != last; ++it) {
1867         // TODO: it seems reasonable to not search across the frame. Isn't it?
1868         // if the node is not in the same frame as the innerNode, skip it
1869         if (it->get()->document()->frame() != frame)
1870             continue;
1871         // traverse up the tree to find the first node that needs highlight
1872         bool found = false;
1873         Node* eventNode = it->get();
1874         Node* innerNode = eventNode;
1875         while (eventNode) {
1876             RenderObject* render = eventNode->renderer();
1877             if (render && (render->isBody() || render->isRenderView()))
1878                 break;
1879             if (nodeIsClickableOrFocusable(eventNode)) {
1880                 found = true;
1881                 break;
1882             }
1883             // the nodes in the rectBasedTestResult() are ordered based on z-index during hit testing.
1884             // so do not search for the eventNode across explicit z-index border.
1885             // TODO: this is a hard one to call. z-index is quite complicated as its value only
1886             // matters when you compare two RenderLayer in the same hierarchy level. e.g. in
1887             // the following example, "b" is on the top as its z level is the highest. even "c"
1888             // has 100 as z-index, it is still below "d" as its parent has the same z-index as
1889             // "d" and logically before "d". Of course "a" is the lowest in the z level.
1890             //
1891             // z-index:auto "a"
1892             //   z-index:2 "b"
1893             //   z-index:1
1894             //     z-index:100 "c"
1895             //   z-index:1 "d"
1896             //
1897             // If the fat point touches everyone, the order in the list should be "b", "d", "c"
1898             // and "a". When we search for the event node for "b", we really don't want "a" as
1899             // in the z-order it is behind everything else.
1900             if (render && !render->style()->hasAutoZIndex())
1901                 break;
1902             eventNode = eventNode->parentNode();
1903         }
1904         // didn't find any eventNode, skip it
1905         if (!found)
1906             continue;
1907         // first quick check whether it is a duplicated node before computing bounding box
1908         Vector<TouchNodeData>::const_iterator nlast = nodeDataList.end();
1909         for (Vector<TouchNodeData>::const_iterator n = nodeDataList.begin(); n != nlast; ++n) {
1910             // found the same node, skip it
1911             if (eventNode == n->mUrlNode) {
1912                 found = false;
1913                 break;
1914             }
1915         }
1916         if (!found)
1917             continue;
1918         // next check whether the node is fully covered by or fully covering another node.
1919         found = false;
1920         IntRect rect = getAbsoluteBoundingBox(eventNode);
1921         if (rect.isEmpty()) {
1922             // if the node's bounds is empty and it is not a ContainerNode, skip it.
1923             if (!eventNode->isContainerNode())
1924                 continue;
1925             // if the node's children are all positioned objects, its bounds can be empty.
1926             // Walk through the children to find the bounding box.
1927             Node* child = static_cast<const ContainerNode*>(eventNode)->firstChild();
1928             while (child) {
1929                 IntRect childrect;
1930                 if (child->renderer())
1931                     childrect = getAbsoluteBoundingBox(child);
1932                 if (!childrect.isEmpty()) {
1933                     rect.unite(childrect);
1934                     child = child->traverseNextSibling(eventNode);
1935                 } else
1936                     child = child->traverseNextNode(eventNode);
1937             }
1938         }
1939         for (int i = nodeDataList.size() - 1; i >= 0; i--) {
1940             TouchNodeData n = nodeDataList.at(i);
1941             // the new node is enclosing an existing node, skip it
1942             if (rect.contains(n.mBounds)) {
1943                 found = true;
1944                 break;
1945             }
1946             // the new node is fully inside an existing node, remove the existing node
1947             if (n.mBounds.contains(rect))
1948                 nodeDataList.remove(i);
1949         }
1950         if (!found) {
1951             TouchNodeData newNode;
1952             newNode.mUrlNode = eventNode;
1953             newNode.mBounds = rect;
1954             newNode.mInnerNode = innerNode;
1955             nodeDataList.append(newNode);
1956         }
1957     }
1958     if (!nodeDataList.size()) {
1959         androidHitResult.searchContentDetectors();
1960         return androidHitResult;
1961     }
1962     // finally select the node with the largest overlap with the fat point
1963     TouchNodeData final;
1964     final.mUrlNode = 0;
1965     IntPoint docPos = frame->view()->windowToContents(m_mousePos);
1966     IntRect testRect(docPos.x() - slop, docPos.y() - slop, 2 * slop + 1, 2 * slop + 1);
1967     int area = 0;
1968     Vector<TouchNodeData>::const_iterator nlast = nodeDataList.end();
1969     for (Vector<TouchNodeData>::const_iterator n = nodeDataList.begin(); n != nlast; ++n) {
1970         IntRect rect = n->mBounds;
1971         rect.intersect(testRect);
1972         int a = rect.width() * rect.height();
1973         if (a > area || !final.mUrlNode) {
1974             final = *n;
1975             area = a;
1976         }
1977     }
1978     // now get the node's highlight rectangles in the page coordinate system
1979     if (final.mUrlNode) {
1980         // Update innerNode and innerNonSharedNode
1981         androidHitResult.hitTestResult().setInnerNode(final.mInnerNode);
1982         androidHitResult.hitTestResult().setInnerNonSharedNode(final.mInnerNode);
1983         if (final.mUrlNode->isElementNode()) {
1984             // We found a URL element. Update the hitTestResult
1985             androidHitResult.setURLElement(static_cast<Element*>(final.mUrlNode));
1986         } else {
1987             androidHitResult.setURLElement(0);
1988         }
1989         Vector<IntRect>& highlightRects = androidHitResult.highlightRects();
1990         if (doMoveMouse && highlightRects.size() > 0) {
1991             // adjust m_mousePos if it is not inside the returned highlight
1992             // rectangles
1993             IntRect foundIntersection;
1994             IntRect inputRect = IntRect(x - slop, y - slop,
1995                                         slop * 2 + 1, slop * 2 + 1);
1996             for (size_t i = 0; i < highlightRects.size(); i++) {
1997                 IntRect& hr = highlightRects[i];
1998                 IntRect test = inputRect;
1999                 test.intersect(hr);
2000                 if (!test.isEmpty()) {
2001                     foundIntersection = test;
2002                     break;
2003                 }
2004             }
2005             if (!foundIntersection.isEmpty() && !foundIntersection.contains(x, y)) {
2006                 IntPoint pt = foundIntersection.center();
2007                 moveMouse(pt.x(), pt.y(), 0, true);
2008             }
2009         }
2010     } else {
2011         androidHitResult.searchContentDetectors();
2012     }
2013     return androidHitResult;
2014 }
2015 
2016 ///////////////////////////////////////////////////////////////////////////////
2017 
addPlugin(PluginWidgetAndroid * w)2018 void WebViewCore::addPlugin(PluginWidgetAndroid* w)
2019 {
2020 //    SkDebugf("----------- addPlugin %p", w);
2021     /* The plugin must be appended to the end of the array. This ensures that if
2022        the plugin is added while iterating through the array (e.g. sendEvent(...))
2023        that the iteration process is not corrupted.
2024      */
2025     *m_plugins.append() = w;
2026 }
2027 
removePlugin(PluginWidgetAndroid * w)2028 void WebViewCore::removePlugin(PluginWidgetAndroid* w)
2029 {
2030 //    SkDebugf("----------- removePlugin %p", w);
2031     int index = m_plugins.find(w);
2032     if (index < 0) {
2033         SkDebugf("--------------- pluginwindow not found! %p\n", w);
2034     } else {
2035         m_plugins.removeShuffle(index);
2036     }
2037 }
2038 
isPlugin(PluginWidgetAndroid * w) const2039 bool WebViewCore::isPlugin(PluginWidgetAndroid* w) const
2040 {
2041     return m_plugins.find(w) >= 0;
2042 }
2043 
invalPlugin(PluginWidgetAndroid * w)2044 void WebViewCore::invalPlugin(PluginWidgetAndroid* w)
2045 {
2046     const double PLUGIN_INVAL_DELAY = 1.0 / 60;
2047 
2048     if (!m_pluginInvalTimer.isActive()) {
2049         m_pluginInvalTimer.startOneShot(PLUGIN_INVAL_DELAY);
2050     }
2051 }
2052 
drawPlugins()2053 void WebViewCore::drawPlugins()
2054 {
2055     SkRegion inval; // accumualte what needs to be redrawn
2056     PluginWidgetAndroid** iter = m_plugins.begin();
2057     PluginWidgetAndroid** stop = m_plugins.end();
2058 
2059     for (; iter < stop; ++iter) {
2060         PluginWidgetAndroid* w = *iter;
2061         SkIRect dirty;
2062         if (w->isDirty(&dirty)) {
2063             w->draw();
2064             inval.op(dirty, SkRegion::kUnion_Op);
2065         }
2066     }
2067 
2068     if (!inval.isEmpty()) {
2069         // inval.getBounds() is our rectangle
2070         const SkIRect& bounds = inval.getBounds();
2071         WebCore::IntRect r(bounds.fLeft, bounds.fTop,
2072                            bounds.width(), bounds.height());
2073         this->viewInvalidate(r);
2074     }
2075 }
2076 
notifyPluginsOnFrameLoad(const Frame * frame)2077 void WebViewCore::notifyPluginsOnFrameLoad(const Frame* frame) {
2078     // if frame is the parent then notify all plugins
2079     if (!frame->tree()->parent()) {
2080         // trigger an event notifying the plugins that the page has loaded
2081         ANPEvent event;
2082         SkANP::InitEvent(&event, kLifecycle_ANPEventType);
2083         event.data.lifecycle.action = kOnLoad_ANPLifecycleAction;
2084         sendPluginEvent(event);
2085         // trigger the on/off screen notification if the page was reloaded
2086         sendPluginVisibleScreen();
2087     }
2088     // else if frame's parent has completed
2089     else if (!frame->tree()->parent()->loader()->isLoading()) {
2090         // send to all plugins who have this frame in their heirarchy
2091         PluginWidgetAndroid** iter = m_plugins.begin();
2092         PluginWidgetAndroid** stop = m_plugins.end();
2093         for (; iter < stop; ++iter) {
2094             Frame* currentFrame = (*iter)->pluginView()->parentFrame();
2095             while (currentFrame) {
2096                 if (frame == currentFrame) {
2097                     ANPEvent event;
2098                     SkANP::InitEvent(&event, kLifecycle_ANPEventType);
2099                     event.data.lifecycle.action = kOnLoad_ANPLifecycleAction;
2100                     (*iter)->sendEvent(event);
2101 
2102                     // trigger the on/off screen notification if the page was reloaded
2103                     ANPRectI visibleRect;
2104                     getVisibleScreen(visibleRect);
2105                     (*iter)->setVisibleScreen(visibleRect, m_scale);
2106 
2107                     break;
2108                 }
2109                 currentFrame = currentFrame->tree()->parent();
2110             }
2111         }
2112     }
2113 }
2114 
getVisibleScreen(ANPRectI & visibleRect)2115 void WebViewCore::getVisibleScreen(ANPRectI& visibleRect)
2116 {
2117     visibleRect.left = m_scrollOffsetX;
2118     visibleRect.top = m_scrollOffsetY;
2119     visibleRect.right = m_scrollOffsetX + m_screenWidth;
2120     visibleRect.bottom = m_scrollOffsetY + m_screenHeight;
2121 }
2122 
sendPluginVisibleScreen()2123 void WebViewCore::sendPluginVisibleScreen()
2124 {
2125     /* We may want to cache the previous values and only send the notification
2126        to the plugin in the event that one of the values has changed.
2127      */
2128 
2129     ANPRectI visibleRect;
2130     getVisibleScreen(visibleRect);
2131 
2132     PluginWidgetAndroid** iter = m_plugins.begin();
2133     PluginWidgetAndroid** stop = m_plugins.end();
2134     for (; iter < stop; ++iter) {
2135         (*iter)->setVisibleScreen(visibleRect, m_scale);
2136     }
2137 }
2138 
sendPluginSurfaceReady()2139 void WebViewCore::sendPluginSurfaceReady()
2140 {
2141     PluginWidgetAndroid** iter = m_plugins.begin();
2142     PluginWidgetAndroid** stop = m_plugins.end();
2143     for (; iter < stop; ++iter) {
2144         (*iter)->checkSurfaceReady();
2145     }
2146 }
2147 
sendPluginEvent(const ANPEvent & evt)2148 void WebViewCore::sendPluginEvent(const ANPEvent& evt)
2149 {
2150     /* The list of plugins may be manipulated as we iterate through the list.
2151        This implementation allows for the addition of new plugins during an
2152        iteration, but may fail if a plugin is removed. Currently, there are not
2153        any use cases where a plugin is deleted while processing this loop, but
2154        if it does occur we will have to use an alternate data structure and/or
2155        iteration mechanism.
2156      */
2157     for (int x = 0; x < m_plugins.count(); x++) {
2158         m_plugins[x]->sendEvent(evt);
2159     }
2160 }
2161 
getPluginWidget(NPP npp)2162 PluginWidgetAndroid* WebViewCore::getPluginWidget(NPP npp)
2163 {
2164     PluginWidgetAndroid** iter = m_plugins.begin();
2165     PluginWidgetAndroid** stop = m_plugins.end();
2166     for (; iter < stop; ++iter) {
2167         if ((*iter)->pluginView()->instance() == npp) {
2168             return (*iter);
2169         }
2170     }
2171     return 0;
2172 }
2173 
nodeIsPlugin(Node * node)2174 static PluginView* nodeIsPlugin(Node* node) {
2175     RenderObject* renderer = node->renderer();
2176     if (renderer && renderer->isWidget()) {
2177         Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
2178         if (widget && widget->isPluginView())
2179             return static_cast<PluginView*>(widget);
2180     }
2181     return 0;
2182 }
2183 
2184 ///////////////////////////////////////////////////////////////////////////////
2185 
2186 // Update mouse position
moveMouse(int x,int y,HitTestResult * hoveredNode,bool isClickCandidate)2187 void WebViewCore::moveMouse(int x, int y, HitTestResult* hoveredNode, bool isClickCandidate)
2188 {
2189     // mouse event expects the position in the window coordinate
2190     m_mousePos = WebCore::IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY);
2191     if (isClickCandidate)
2192         m_mouseClickPos = m_mousePos;
2193     // validNode will still return true if the node is null, as long as we have
2194     // a valid frame.  Do not want to make a call on frame unless it is valid.
2195     WebCore::PlatformMouseEvent mouseEvent(m_mousePos, m_mousePos,
2196         WebCore::NoButton, WebCore::MouseEventMoved, 1, false, false, false,
2197         false, WTF::currentTime());
2198     m_mainFrame->eventHandler()->handleMouseMoveEvent(mouseEvent, hoveredNode);
2199 }
2200 
getPositionForOffset(Node * node,int offset)2201 Position WebViewCore::getPositionForOffset(Node* node, int offset)
2202 {
2203     Position start = firstPositionInNode(node);
2204     Position end = lastPositionInNode(node);
2205     Document* document = node->document();
2206     PassRefPtr<Range> range = Range::create(document, start, end);
2207     WebCore::CharacterIterator iterator(range.get());
2208     iterator.advance(offset);
2209     return iterator.range()->startPosition();
2210 }
2211 
setSelection(Node * node,int start,int end)2212 void WebViewCore::setSelection(Node* node, int start, int end)
2213 {
2214     RenderTextControl* control = toRenderTextControl(node);
2215     if (control)
2216         setSelectionRange(node, start, end);
2217     else {
2218         Position startPosition = getPositionForOffset(node, start);
2219         Position endPosition = getPositionForOffset(node, end);
2220         VisibleSelection selection(startPosition, endPosition);
2221         SelectionController* selector = node->document()->frame()->selection();
2222         selector->setSelection(selection);
2223     }
2224 }
2225 
setSelection(int start,int end)2226 void WebViewCore::setSelection(int start, int end)
2227 {
2228     WebCore::Node* focus = currentFocus();
2229     if (!focus)
2230         return;
2231     if (start > end)
2232         swap(start, end);
2233 
2234     // Tell our EditorClient that this change was generated from the UI, so it
2235     // does not need to echo it to the UI.
2236     EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
2237             m_mainFrame->editor()->client());
2238     client->setUiGeneratedSelectionChange(true);
2239     setSelection(focus, start, end);
2240     RenderTextControl* control = toRenderTextControl(focus);
2241     if (start != end && control) {
2242         // Fire a select event. No event is sent when the selection reduces to
2243         // an insertion point
2244         control->selectionChanged(true);
2245     }
2246     client->setUiGeneratedSelectionChange(false);
2247     bool isPasswordField = false;
2248     if (focus->isElementNode()) {
2249         WebCore::Element* element = static_cast<WebCore::Element*>(focus);
2250         if (WebCore::InputElement* inputElement = element->toInputElement())
2251             isPasswordField = static_cast<WebCore::HTMLInputElement*>(inputElement)->isPasswordField();
2252     }
2253     // For password fields, this is done in the UI side via
2254     // bringPointIntoView, since the UI does the drawing.
2255     if ((control && control->isTextArea()) || !isPasswordField)
2256         revealSelection();
2257 }
2258 
modifySelection(const int direction,const int axis)2259 String WebViewCore::modifySelection(const int direction, const int axis)
2260 {
2261     DOMSelection* selection = m_mainFrame->domWindow()->getSelection();
2262     ASSERT(selection);
2263     // We've seen crashes where selection is null, but we don't know why
2264     // See http://b/5244036
2265     if (!selection)
2266         return String();
2267     if (selection->rangeCount() > 1)
2268         selection->removeAllRanges();
2269     switch (axis) {
2270         case AXIS_CHARACTER:
2271         case AXIS_WORD:
2272         case AXIS_SENTENCE:
2273             return modifySelectionTextNavigationAxis(selection, direction, axis);
2274         case AXIS_HEADING:
2275         case AXIS_SIBLING:
2276         case AXIS_PARENT_FIRST_CHILD:
2277         case AXIS_DOCUMENT:
2278             return modifySelectionDomNavigationAxis(selection, direction, axis);
2279         default:
2280             ALOGE("Invalid navigation axis: %d", axis);
2281             return String();
2282     }
2283 }
2284 
scrollNodeIntoView(Frame * frame,Node * node)2285 void WebViewCore::scrollNodeIntoView(Frame* frame, Node* node)
2286 {
2287     if (!frame || !node)
2288         return;
2289 
2290     Element* elementNode = 0;
2291 
2292     // If not an Element, find a visible predecessor
2293     // Element to scroll into view.
2294     if (!node->isElementNode()) {
2295         HTMLElement* body = frame->document()->body();
2296         do {
2297             if (node == body)
2298                 return;
2299             node = node->parentNode();
2300         } while (node && !node->isElementNode() && !isVisible(node));
2301     }
2302 
2303     // Couldn't find a visible predecessor.
2304     if (!node)
2305         return;
2306 
2307     elementNode = static_cast<Element*>(node);
2308     elementNode->scrollIntoViewIfNeeded(true);
2309 }
2310 
modifySelectionTextNavigationAxis(DOMSelection * selection,int direction,int axis)2311 String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, int direction, int axis)
2312 {
2313     Node* body = m_mainFrame->document()->body();
2314 
2315     ExceptionCode ec = 0;
2316     String markup;
2317 
2318     // initialize the selection if necessary
2319     if (selection->rangeCount() == 0) {
2320         if (m_currentNodeDomNavigationAxis
2321                 && validNode(m_mainFrame,
2322                 m_mainFrame, m_currentNodeDomNavigationAxis)) {
2323             RefPtr<Range> rangeRef =
2324                 selection->frame()->document()->createRange();
2325             rangeRef->selectNode(m_currentNodeDomNavigationAxis, ec);
2326             m_currentNodeDomNavigationAxis = 0;
2327             if (ec)
2328                 return String();
2329             selection->addRange(rangeRef.get());
2330         } else if (currentFocus()) {
2331             selection->setPosition(currentFocus(), 0, ec);
2332         } else {
2333             selection->setPosition(body, 0, ec);
2334         }
2335         if (ec)
2336             return String();
2337     }
2338 
2339     // collapse the selection
2340     if (direction == DIRECTION_FORWARD)
2341         selection->collapseToEnd(ec);
2342     else
2343         selection->collapseToStart(ec);
2344     if (ec)
2345         return String();
2346 
2347     // Make sure the anchor node is a text node since we are generating
2348     // the markup of the selection which includes the anchor, the focus,
2349     // and any crossed nodes. Forcing the condition that the selection
2350     // starts and ends on text nodes guarantees symmetric selection markup.
2351     // Also this way the text content, rather its container, is highlighted.
2352     Node* anchorNode = selection->anchorNode();
2353     if (anchorNode->isElementNode()) {
2354         // Collapsed selection while moving forward points to the
2355         // next unvisited node and while moving backward to the
2356         // last visited node.
2357         if (direction == DIRECTION_FORWARD)
2358             advanceAnchorNode(selection, direction, markup, false, ec);
2359         else
2360             advanceAnchorNode(selection, direction, markup, true, ec);
2361         if (ec)
2362             return String();
2363         if (!markup.isEmpty())
2364             return markup;
2365     }
2366 
2367     // If the selection is at the end of a non white space text move
2368     // it to the next visible text node with non white space content.
2369     // This is a workaround for the selection getting stuck.
2370     anchorNode = selection->anchorNode();
2371     if (anchorNode->isTextNode()) {
2372         if (direction == DIRECTION_FORWARD) {
2373             String suffix = anchorNode->textContent().substring(
2374                     selection->anchorOffset(), caretMaxOffset(anchorNode));
2375             // If at the end of non white space text we advance the
2376             // anchor node to either an input element or non empty text.
2377             if (suffix.stripWhiteSpace().isEmpty()) {
2378                 advanceAnchorNode(selection, direction, markup, true, ec);
2379             }
2380         } else {
2381             String prefix = anchorNode->textContent().substring(0,
2382                     selection->anchorOffset());
2383             // If at the end of non white space text we advance the
2384             // anchor node to either an input element or non empty text.
2385             if (prefix.stripWhiteSpace().isEmpty()) {
2386                 advanceAnchorNode(selection, direction, markup, true, ec);
2387             }
2388         }
2389         if (ec)
2390             return String();
2391         if (!markup.isEmpty())
2392             return markup;
2393     }
2394 
2395     // extend the selection
2396     String directionStr;
2397     if (direction == DIRECTION_FORWARD)
2398         directionStr = "forward";
2399     else
2400         directionStr = "backward";
2401 
2402     String axisStr;
2403     if (axis == AXIS_CHARACTER)
2404         axisStr = "character";
2405     else if (axis == AXIS_WORD)
2406         axisStr = "word";
2407     else
2408         axisStr = "sentence";
2409 
2410     selection->modify("extend", directionStr, axisStr);
2411 
2412     // Make sure the focus node is a text node in order to have the
2413     // selection generate symmetric markup because the latter
2414     // includes all nodes crossed by the selection.  Also this way
2415     // the text content, rather its container, is highlighted.
2416     Node* focusNode = selection->focusNode();
2417     if (focusNode->isElementNode()) {
2418         focusNode = getImplicitBoundaryNode(selection->focusNode(),
2419                 selection->focusOffset(), direction);
2420         if (!focusNode)
2421             return String();
2422         if (direction == DIRECTION_FORWARD) {
2423             focusNode = focusNode->traversePreviousSiblingPostOrder(body);
2424             if (focusNode && !isContentTextNode(focusNode)) {
2425                 Node* textNode = traverseNextContentTextNode(focusNode,
2426                         anchorNode, DIRECTION_BACKWARD);
2427                 if (textNode)
2428                     anchorNode = textNode;
2429             }
2430             if (focusNode && isContentTextNode(focusNode)) {
2431                 selection->extend(focusNode, caretMaxOffset(focusNode), ec);
2432                 if (ec)
2433                     return String();
2434             }
2435         } else {
2436             focusNode = focusNode->traverseNextSibling();
2437             if (focusNode && !isContentTextNode(focusNode)) {
2438                 Node* textNode = traverseNextContentTextNode(focusNode,
2439                         anchorNode, DIRECTION_FORWARD);
2440                 if (textNode)
2441                     anchorNode = textNode;
2442             }
2443             if (anchorNode && isContentTextNode(anchorNode)) {
2444                 selection->extend(focusNode, 0, ec);
2445                 if (ec)
2446                     return String();
2447             }
2448         }
2449     }
2450 
2451     // Enforce that the selection does not cross anchor boundaries. This is
2452     // a workaround for the asymmetric behavior of WebKit while crossing
2453     // anchors.
2454     anchorNode = getImplicitBoundaryNode(selection->anchorNode(),
2455             selection->anchorOffset(), direction);
2456     focusNode = getImplicitBoundaryNode(selection->focusNode(),
2457             selection->focusOffset(), direction);
2458     if (anchorNode && focusNode && anchorNode != focusNode) {
2459         Node* inputControl = getIntermediaryInputElement(anchorNode, focusNode,
2460                 direction);
2461         if (inputControl) {
2462             if (direction == DIRECTION_FORWARD) {
2463                 if (isDescendantOf(inputControl, anchorNode)) {
2464                     focusNode = inputControl;
2465                 } else {
2466                     focusNode = inputControl->traversePreviousSiblingPostOrder(
2467                             body);
2468                     if (!focusNode)
2469                         focusNode = inputControl;
2470                 }
2471                 // We prefer a text node contained in the input element.
2472                 if (!isContentTextNode(focusNode)) {
2473                     Node* textNode = traverseNextContentTextNode(focusNode,
2474                         anchorNode, DIRECTION_BACKWARD);
2475                     if (textNode)
2476                         focusNode = textNode;
2477                 }
2478                 // If we found text in the input select it.
2479                 // Otherwise, select the input element itself.
2480                 if (isContentTextNode(focusNode)) {
2481                     selection->extend(focusNode, caretMaxOffset(focusNode), ec);
2482                 } else if (anchorNode != focusNode) {
2483                     // Note that the focusNode always has parent and that
2484                     // the offset can be one more that the index of the last
2485                     // element - this is how WebKit selects such elements.
2486                     selection->extend(focusNode->parentNode(),
2487                             focusNode->nodeIndex() + 1, ec);
2488                 }
2489                 if (ec)
2490                     return String();
2491             } else {
2492                 if (isDescendantOf(inputControl, anchorNode)) {
2493                     focusNode = inputControl;
2494                 } else {
2495                     focusNode = inputControl->traverseNextSibling();
2496                     if (!focusNode)
2497                         focusNode = inputControl;
2498                 }
2499                 // We prefer a text node contained in the input element.
2500                 if (!isContentTextNode(focusNode)) {
2501                     Node* textNode = traverseNextContentTextNode(focusNode,
2502                             anchorNode, DIRECTION_FORWARD);
2503                     if (textNode)
2504                         focusNode = textNode;
2505                 }
2506                 // If we found text in the input select it.
2507                 // Otherwise, select the input element itself.
2508                 if (isContentTextNode(focusNode)) {
2509                     selection->extend(focusNode, caretMinOffset(focusNode), ec);
2510                 } else if (anchorNode != focusNode) {
2511                     // Note that the focusNode always has parent and that
2512                     // the offset can be one more that the index of the last
2513                     // element - this is how WebKit selects such elements.
2514                     selection->extend(focusNode->parentNode(),
2515                             focusNode->nodeIndex() + 1, ec);
2516                 }
2517                 if (ec)
2518                    return String();
2519             }
2520         }
2521     }
2522 
2523     // make sure the selection is visible
2524     if (direction == DIRECTION_FORWARD)
2525         scrollNodeIntoView(m_mainFrame, selection->focusNode());
2526     else
2527         scrollNodeIntoView(m_mainFrame, selection->anchorNode());
2528 
2529     // format markup for the visible content
2530     RefPtr<Range> range = selection->getRangeAt(0, ec);
2531     if (ec)
2532         return String();
2533     IntRect bounds = range->boundingBox();
2534     selectAt(bounds.center().x(), bounds.center().y());
2535     markup = formatMarkup(selection);
2536     ALOGV("Selection markup: %s", markup.utf8().data());
2537 
2538     return markup;
2539 }
2540 
getImplicitBoundaryNode(Node * node,unsigned offset,int direction)2541 Node* WebViewCore::getImplicitBoundaryNode(Node* node, unsigned offset, int direction)
2542 {
2543     if (node->offsetInCharacters())
2544         return node;
2545     if (!node->hasChildNodes())
2546         return node;
2547     if (offset < node->childNodeCount())
2548         return node->childNode(offset);
2549     else
2550         if (direction == DIRECTION_FORWARD)
2551             return node->traverseNextSibling();
2552         else
2553             return node->traversePreviousNodePostOrder(
2554                     node->document()->body());
2555 }
2556 
getNextAnchorNode(Node * anchorNode,bool ignoreFirstNode,int direction)2557 Node* WebViewCore::getNextAnchorNode(Node* anchorNode, bool ignoreFirstNode, int direction)
2558 {
2559     Node* body = 0;
2560     Node* currentNode = 0;
2561     if (direction == DIRECTION_FORWARD) {
2562         if (ignoreFirstNode)
2563             currentNode = anchorNode->traverseNextNode(body);
2564         else
2565             currentNode = anchorNode;
2566     } else {
2567         body = anchorNode->document()->body();
2568         if (ignoreFirstNode)
2569             currentNode = anchorNode->traversePreviousSiblingPostOrder(body);
2570         else
2571             currentNode = anchorNode;
2572     }
2573     while (currentNode) {
2574         if (isContentTextNode(currentNode)
2575                 || isContentInputElement(currentNode))
2576             return currentNode;
2577         if (direction == DIRECTION_FORWARD)
2578             currentNode = currentNode->traverseNextNode();
2579         else
2580             currentNode = currentNode->traversePreviousNodePostOrder(body);
2581     }
2582     return 0;
2583 }
2584 
advanceAnchorNode(DOMSelection * selection,int direction,String & markup,bool ignoreFirstNode,ExceptionCode & ec)2585 void WebViewCore::advanceAnchorNode(DOMSelection* selection, int direction,
2586         String& markup, bool ignoreFirstNode, ExceptionCode& ec)
2587 {
2588     Node* anchorNode = getImplicitBoundaryNode(selection->anchorNode(),
2589             selection->anchorOffset(), direction);
2590     if (!anchorNode) {
2591         ec = NOT_FOUND_ERR;
2592         return;
2593     }
2594     // If the anchor offset is invalid i.e. the anchor node has no
2595     // child with that index getImplicitAnchorNode returns the next
2596     // logical node in the current direction. In such a case our
2597     // position in the DOM tree was has already been advanced,
2598     // therefore we there is no need to do that again.
2599     if (selection->anchorNode()->isElementNode()) {
2600         unsigned anchorOffset = selection->anchorOffset();
2601         unsigned childNodeCount = selection->anchorNode()->childNodeCount();
2602         if (anchorOffset >= childNodeCount)
2603             ignoreFirstNode = false;
2604     }
2605     // Find the next anchor node given our position in the DOM and
2606     // whether we want the current node to be considered as well.
2607     Node* nextAnchorNode = getNextAnchorNode(anchorNode, ignoreFirstNode,
2608             direction);
2609     if (!nextAnchorNode) {
2610         ec = NOT_FOUND_ERR;
2611         return;
2612     }
2613     if (nextAnchorNode->isElementNode()) {
2614         // If this is an input element tell the WebView thread
2615         // to set the cursor to that control.
2616         if (isContentInputElement(nextAnchorNode)) {
2617             IntRect bounds = nextAnchorNode->getRect();
2618             selectAt(bounds.center().x(), bounds.center().y());
2619         }
2620         Node* textNode = 0;
2621         // Treat the text content of links as any other text but
2622         // for the rest input elements select the control itself.
2623         if (nextAnchorNode->hasTagName(WebCore::HTMLNames::aTag))
2624             textNode = traverseNextContentTextNode(nextAnchorNode,
2625                     nextAnchorNode, direction);
2626         // We prefer to select the text content of the link if such,
2627         // otherwise just select the element itself.
2628         if (textNode) {
2629             nextAnchorNode = textNode;
2630         } else {
2631             if (direction == DIRECTION_FORWARD) {
2632                 selection->setBaseAndExtent(nextAnchorNode,
2633                         caretMinOffset(nextAnchorNode), nextAnchorNode,
2634                         caretMaxOffset(nextAnchorNode), ec);
2635             } else {
2636                 selection->setBaseAndExtent(nextAnchorNode,
2637                         caretMaxOffset(nextAnchorNode), nextAnchorNode,
2638                         caretMinOffset(nextAnchorNode), ec);
2639             }
2640             if (!ec)
2641                 markup = formatMarkup(selection);
2642             // make sure the selection is visible
2643             scrollNodeIntoView(selection->frame(), nextAnchorNode);
2644             return;
2645         }
2646     }
2647     if (direction == DIRECTION_FORWARD)
2648         selection->setPosition(nextAnchorNode,
2649                 caretMinOffset(nextAnchorNode), ec);
2650     else
2651         selection->setPosition(nextAnchorNode,
2652                 caretMaxOffset(nextAnchorNode), ec);
2653 }
2654 
isContentInputElement(Node * node)2655 bool WebViewCore::isContentInputElement(Node* node)
2656 {
2657   return (isVisible(node)
2658           && (node->hasTagName(WebCore::HTMLNames::selectTag)
2659           || node->hasTagName(WebCore::HTMLNames::aTag)
2660           || node->hasTagName(WebCore::HTMLNames::inputTag)
2661           || node->hasTagName(WebCore::HTMLNames::buttonTag)));
2662 }
2663 
isContentTextNode(Node * node)2664 bool WebViewCore::isContentTextNode(Node* node)
2665 {
2666    if (!node || !node->isTextNode())
2667        return false;
2668    Text* textNode = static_cast<Text*>(node);
2669    return (isVisible(textNode) && textNode->length() > 0
2670        && !textNode->containsOnlyWhitespace());
2671 }
2672 
traverseNextContentTextNode(Node * fromNode,Node * toNode,int direction)2673 Text* WebViewCore::traverseNextContentTextNode(Node* fromNode, Node* toNode, int direction)
2674 {
2675     Node* currentNode = fromNode;
2676     do {
2677         if (direction == DIRECTION_FORWARD)
2678             currentNode = currentNode->traverseNextNode(toNode);
2679         else
2680             currentNode = currentNode->traversePreviousNodePostOrder(toNode);
2681     } while (currentNode && !isContentTextNode(currentNode));
2682     return static_cast<Text*>(currentNode);
2683 }
2684 
getIntermediaryInputElement(Node * fromNode,Node * toNode,int direction)2685 Node* WebViewCore::getIntermediaryInputElement(Node* fromNode, Node* toNode, int direction)
2686 {
2687     if (fromNode == toNode)
2688         return 0;
2689     if (direction == DIRECTION_FORWARD) {
2690         Node* currentNode = fromNode;
2691         while (currentNode && currentNode != toNode) {
2692             if (isContentInputElement(currentNode))
2693                 return currentNode;
2694             currentNode = currentNode->traverseNextNodePostOrder();
2695         }
2696         currentNode = fromNode;
2697         while (currentNode && currentNode != toNode) {
2698             if (isContentInputElement(currentNode))
2699                 return currentNode;
2700             currentNode = currentNode->traverseNextNode();
2701         }
2702     } else {
2703         Node* currentNode = fromNode->traversePreviousNode();
2704         while (currentNode && currentNode != toNode) {
2705             if (isContentInputElement(currentNode))
2706                 return currentNode;
2707             currentNode = currentNode->traversePreviousNode();
2708         }
2709         currentNode = fromNode->traversePreviousNodePostOrder();
2710         while (currentNode && currentNode != toNode) {
2711             if (isContentInputElement(currentNode))
2712                 return currentNode;
2713             currentNode = currentNode->traversePreviousNodePostOrder();
2714         }
2715     }
2716     return 0;
2717 }
2718 
isDescendantOf(Node * parent,Node * node)2719 bool WebViewCore::isDescendantOf(Node* parent, Node* node)
2720 {
2721     Node* currentNode = node;
2722     while (currentNode) {
2723         if (currentNode == parent) {
2724             return true;
2725         }
2726         currentNode = currentNode->parentNode();
2727     }
2728     return false;
2729 }
2730 
modifySelectionDomNavigationAxis(DOMSelection * selection,int direction,int axis)2731 String WebViewCore::modifySelectionDomNavigationAxis(DOMSelection* selection, int direction, int axis)
2732 {
2733     HTMLElement* body = m_mainFrame->document()->body();
2734     if (!m_currentNodeDomNavigationAxis && selection->focusNode()) {
2735         m_currentNodeDomNavigationAxis = selection->focusNode();
2736         selection->empty();
2737         if (m_currentNodeDomNavigationAxis->isTextNode())
2738             m_currentNodeDomNavigationAxis =
2739                 m_currentNodeDomNavigationAxis->parentNode();
2740     }
2741     if (!m_currentNodeDomNavigationAxis)
2742         m_currentNodeDomNavigationAxis = currentFocus();
2743     if (!m_currentNodeDomNavigationAxis
2744             || !validNode(m_mainFrame, m_mainFrame,
2745                                         m_currentNodeDomNavigationAxis))
2746         m_currentNodeDomNavigationAxis = body;
2747     Node* currentNode = m_currentNodeDomNavigationAxis;
2748     if (axis == AXIS_HEADING) {
2749         if (currentNode == body && direction == DIRECTION_BACKWARD)
2750             currentNode = currentNode->lastDescendant();
2751         do {
2752             if (direction == DIRECTION_FORWARD)
2753                 currentNode = currentNode->traverseNextNode(body);
2754             else
2755                 currentNode = currentNode->traversePreviousNode(body);
2756         } while (currentNode && (currentNode->isTextNode()
2757             || !isVisible(currentNode) || !isHeading(currentNode)));
2758     } else if (axis == AXIS_PARENT_FIRST_CHILD) {
2759         if (direction == DIRECTION_FORWARD) {
2760             currentNode = currentNode->firstChild();
2761             while (currentNode && (currentNode->isTextNode()
2762                     || !isVisible(currentNode)))
2763                 currentNode = currentNode->nextSibling();
2764         } else {
2765             do {
2766                 if (currentNode == body)
2767                     return String();
2768                 currentNode = currentNode->parentNode();
2769             } while (currentNode && (currentNode->isTextNode()
2770                     || !isVisible(currentNode)));
2771         }
2772     } else if (axis == AXIS_SIBLING) {
2773         do {
2774             if (direction == DIRECTION_FORWARD)
2775                 currentNode = currentNode->nextSibling();
2776             else {
2777                 if (currentNode == body)
2778                     return String();
2779                 currentNode = currentNode->previousSibling();
2780             }
2781         } while (currentNode && (currentNode->isTextNode()
2782                 || !isVisible(currentNode)));
2783     } else if (axis == AXIS_DOCUMENT) {
2784         currentNode = body;
2785         if (direction == DIRECTION_FORWARD)
2786             currentNode = currentNode->lastDescendant();
2787     } else {
2788         ALOGE("Invalid axis: %d", axis);
2789         return String();
2790     }
2791     if (currentNode) {
2792         m_currentNodeDomNavigationAxis = currentNode;
2793         scrollNodeIntoView(m_mainFrame, currentNode);
2794         String selectionString = createMarkup(currentNode);
2795         ALOGV("Selection markup: %s", selectionString.utf8().data());
2796         return selectionString;
2797     }
2798     return String();
2799 }
2800 
isHeading(Node * node)2801 bool WebViewCore::isHeading(Node* node)
2802 {
2803     if (node->hasTagName(WebCore::HTMLNames::h1Tag)
2804             || node->hasTagName(WebCore::HTMLNames::h2Tag)
2805             || node->hasTagName(WebCore::HTMLNames::h3Tag)
2806             || node->hasTagName(WebCore::HTMLNames::h4Tag)
2807             || node->hasTagName(WebCore::HTMLNames::h5Tag)
2808             || node->hasTagName(WebCore::HTMLNames::h6Tag)) {
2809         return true;
2810     }
2811 
2812     if (node->isElementNode()) {
2813         Element* element = static_cast<Element*>(node);
2814         String roleAttribute =
2815             element->getAttribute(WebCore::HTMLNames::roleAttr).string();
2816         if (equalIgnoringCase(roleAttribute, "heading"))
2817             return true;
2818     }
2819 
2820     return false;
2821 }
2822 
isVisible(Node * node)2823 bool WebViewCore::isVisible(Node* node)
2824 {
2825     // start off an element
2826     Element* element = 0;
2827     if (node->isElementNode())
2828         element = static_cast<Element*>(node);
2829     else
2830         element = node->parentElement();
2831     // check renderer
2832     if (!element->renderer()) {
2833         return false;
2834     }
2835     // check size
2836     if (element->offsetHeight() == 0 || element->offsetWidth() == 0) {
2837         return false;
2838     }
2839     // check style
2840     Node* body = m_mainFrame->document()->body();
2841     Node* currentNode = element;
2842     while (currentNode && currentNode != body) {
2843         RenderStyle* style = currentNode->computedStyle();
2844         if (style &&
2845                 (style->display() == WebCore::NONE || style->visibility() == WebCore::HIDDEN)) {
2846             return false;
2847         }
2848         currentNode = currentNode->parentNode();
2849     }
2850     return true;
2851 }
2852 
formatMarkup(DOMSelection * selection)2853 String WebViewCore::formatMarkup(DOMSelection* selection)
2854 {
2855     ExceptionCode ec = 0;
2856     String markup = String();
2857     RefPtr<Range> wholeRange = selection->getRangeAt(0, ec);
2858     if (ec)
2859         return String();
2860     if (!wholeRange->startContainer() || !wholeRange->startContainer())
2861         return String();
2862     // Since formatted markup contains invisible nodes it
2863     // is created from the concatenation of the visible fragments.
2864     Node* firstNode = wholeRange->firstNode();
2865     Node* pastLastNode = wholeRange->pastLastNode();
2866     Node* currentNode = firstNode;
2867     RefPtr<Range> currentRange;
2868 
2869     while (currentNode != pastLastNode) {
2870         Node* nextNode = currentNode->traverseNextNode();
2871         if (!isVisible(currentNode)) {
2872             if (currentRange) {
2873                 markup = markup + currentRange->toHTML().utf8().data();
2874                 currentRange = 0;
2875             }
2876         } else {
2877             if (!currentRange) {
2878                 currentRange = selection->frame()->document()->createRange();
2879                 if (ec)
2880                     break;
2881                 if (currentNode == firstNode) {
2882                     currentRange->setStart(wholeRange->startContainer(),
2883                         wholeRange->startOffset(), ec);
2884                     if (ec)
2885                         break;
2886                 } else {
2887                     currentRange->setStart(currentNode->parentNode(),
2888                         currentNode->nodeIndex(), ec);
2889                     if (ec)
2890                        break;
2891                 }
2892             }
2893             if (nextNode == pastLastNode) {
2894                 currentRange->setEnd(wholeRange->endContainer(),
2895                     wholeRange->endOffset(), ec);
2896                 if (ec)
2897                     break;
2898                 markup = markup + currentRange->toHTML().utf8().data();
2899             } else {
2900                 if (currentNode->offsetInCharacters())
2901                     currentRange->setEnd(currentNode,
2902                         currentNode->maxCharacterOffset(), ec);
2903                 else
2904                     currentRange->setEnd(currentNode->parentNode(),
2905                             currentNode->nodeIndex() + 1, ec);
2906                 if (ec)
2907                     break;
2908             }
2909         }
2910         currentNode = nextNode;
2911     }
2912     return markup.stripWhiteSpace();
2913 }
2914 
selectAt(int x,int y)2915 void WebViewCore::selectAt(int x, int y)
2916 {
2917     JNIEnv* env = JSC::Bindings::getJNIEnv();
2918     AutoJObject javaObject = m_javaGlue->object(env);
2919     if (!javaObject.get())
2920         return;
2921     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_selectAt, x, y);
2922     checkException(env);
2923 }
2924 
deleteSelection(int start,int end,int textGeneration)2925 void WebViewCore::deleteSelection(int start, int end, int textGeneration)
2926 {
2927     setSelection(start, end);
2928     if (start == end)
2929         return;
2930     WebCore::Node* focus = currentFocus();
2931     if (!focus)
2932         return;
2933     // Prevent our editor client from passing a message to change the
2934     // selection.
2935     EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
2936             m_mainFrame->editor()->client());
2937     client->setUiGeneratedSelectionChange(true);
2938     PlatformKeyboardEvent down(AKEYCODE_DEL, 0, 0, true, false, false, false);
2939     PlatformKeyboardEvent up(AKEYCODE_DEL, 0, 0, false, false, false, false);
2940     key(down);
2941     key(up);
2942     client->setUiGeneratedSelectionChange(false);
2943     m_textGeneration = textGeneration;
2944 }
2945 
replaceTextfieldText(int oldStart,int oldEnd,const WTF::String & replace,int start,int end,int textGeneration)2946 void WebViewCore::replaceTextfieldText(int oldStart,
2947         int oldEnd, const WTF::String& replace, int start, int end,
2948         int textGeneration)
2949 {
2950     WebCore::Node* focus = currentFocus();
2951     if (!focus)
2952         return;
2953     setSelection(oldStart, oldEnd);
2954     // Prevent our editor client from passing a message to change the
2955     // selection.
2956     EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
2957             m_mainFrame->editor()->client());
2958     client->setUiGeneratedSelectionChange(true);
2959     if (replace.length())
2960         WebCore::TypingCommand::insertText(focus->document(), replace,
2961                 false);
2962     else
2963         WebCore::TypingCommand::deleteSelection(focus->document());
2964     client->setUiGeneratedSelectionChange(false);
2965     // setSelection calls revealSelection, so there is no need to do it here.
2966     setSelection(start, end);
2967     m_textGeneration = textGeneration;
2968 }
2969 
passToJs(int generation,const WTF::String & current,const PlatformKeyboardEvent & event)2970 void WebViewCore::passToJs(int generation, const WTF::String& current,
2971     const PlatformKeyboardEvent& event)
2972 {
2973     WebCore::Node* focus = currentFocus();
2974     if (!focus) {
2975         clearTextEntry();
2976         return;
2977     }
2978     // Block text field updates during a key press.
2979     m_blockTextfieldUpdates = true;
2980     // Also prevent our editor client from passing a message to change the
2981     // selection.
2982     EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
2983             m_mainFrame->editor()->client());
2984     client->setUiGeneratedSelectionChange(true);
2985     key(event);
2986     client->setUiGeneratedSelectionChange(false);
2987     m_blockTextfieldUpdates = false;
2988     m_textGeneration = generation;
2989     WTF::String test = getInputText(focus);
2990     if (test != current) {
2991         // If the text changed during the key event, update the UI text field.
2992         updateTextfield(focus, test);
2993     }
2994     // Now that the selection has settled down, send it.
2995     updateTextSelection();
2996 }
2997 
scrollFocusedTextInput(float xPercent,int y)2998 void WebViewCore::scrollFocusedTextInput(float xPercent, int y)
2999 {
3000     WebCore::Node* focus = currentFocus();
3001     if (!focus) {
3002         clearTextEntry();
3003         return;
3004     }
3005     WebCore::RenderTextControl* renderText = toRenderTextControl(focus);
3006     if (!renderText) {
3007         clearTextEntry();
3008         return;
3009     }
3010 
3011     int x = (int)round(xPercent * (renderText->scrollWidth() -
3012         renderText->contentWidth()));
3013     renderText->setScrollLeft(x);
3014     renderText->setScrollTop(y);
3015     focus->document()->frame()->selection()->recomputeCaretRect();
3016     updateTextSelection();
3017 }
3018 
setFocusControllerActive(bool active)3019 void WebViewCore::setFocusControllerActive(bool active)
3020 {
3021     m_mainFrame->page()->focusController()->setActive(active);
3022 }
3023 
saveDocumentState(WebCore::Frame * frame)3024 void WebViewCore::saveDocumentState(WebCore::Frame* frame)
3025 {
3026     if (!validNode(m_mainFrame, frame, 0))
3027         frame = m_mainFrame;
3028     WebCore::HistoryItem *item = frame->loader()->history()->currentItem();
3029 
3030     // item can be null when there is no offical URL for the current page. This happens
3031     // when the content is loaded using with WebCoreFrameBridge::LoadData() and there
3032     // is no failing URL (common case is when content is loaded using data: scheme)
3033     if (item) {
3034         item->setDocumentState(frame->document()->formElementsState());
3035     }
3036 }
3037 
3038 // Create an array of java Strings.
makeLabelArray(JNIEnv * env,const uint16_t ** labels,size_t count)3039 static jobjectArray makeLabelArray(JNIEnv* env, const uint16_t** labels, size_t count)
3040 {
3041     jclass stringClass = env->FindClass("java/lang/String");
3042     ALOG_ASSERT(stringClass, "Could not find java/lang/String");
3043     jobjectArray array = env->NewObjectArray(count, stringClass, 0);
3044     ALOG_ASSERT(array, "Could not create new string array");
3045 
3046     for (size_t i = 0; i < count; i++) {
3047         jobject newString = env->NewString(&labels[i][1], labels[i][0]);
3048         env->SetObjectArrayElement(array, i, newString);
3049         env->DeleteLocalRef(newString);
3050         checkException(env);
3051     }
3052     env->DeleteLocalRef(stringClass);
3053     return array;
3054 }
3055 
openFileChooser(PassRefPtr<WebCore::FileChooser> chooser)3056 void WebViewCore::openFileChooser(PassRefPtr<WebCore::FileChooser> chooser)
3057 {
3058     JNIEnv* env = JSC::Bindings::getJNIEnv();
3059     AutoJObject javaObject = m_javaGlue->object(env);
3060     if (!javaObject.get())
3061         return;
3062 
3063     if (!chooser)
3064         return;
3065 
3066     WTF::String acceptType = chooser->acceptTypes();
3067     WTF::String capture;
3068 
3069 #if ENABLE(MEDIA_CAPTURE)
3070     capture = chooser->capture();
3071 #endif
3072 
3073     jstring jAcceptType = wtfStringToJstring(env, acceptType, true);
3074     jstring jCapture = wtfStringToJstring(env, capture, true);
3075     jstring jName = (jstring) env->CallObjectMethod(
3076             javaObject.get(), m_javaGlue->m_openFileChooser, jAcceptType, jCapture);
3077     checkException(env);
3078     env->DeleteLocalRef(jAcceptType);
3079     env->DeleteLocalRef(jCapture);
3080 
3081     WTF::String wtfString = jstringToWtfString(env, jName);
3082     env->DeleteLocalRef(jName);
3083 
3084     if (!wtfString.isEmpty())
3085         chooser->chooseFile(wtfString);
3086 }
3087 
listBoxRequest(WebCoreReply * reply,const uint16_t ** labels,size_t count,const int enabled[],size_t enabledCount,bool multiple,const int selected[],size_t selectedCountOrSelection)3088 void WebViewCore::listBoxRequest(WebCoreReply* reply, const uint16_t** labels, size_t count, const int enabled[], size_t enabledCount,
3089         bool multiple, const int selected[], size_t selectedCountOrSelection)
3090 {
3091     ALOG_ASSERT(m_javaGlue->m_obj, "No java widget associated with this view!");
3092 
3093     JNIEnv* env = JSC::Bindings::getJNIEnv();
3094     AutoJObject javaObject = m_javaGlue->object(env);
3095     if (!javaObject.get())
3096         return;
3097 
3098     // If m_popupReply is not null, then we already have a list showing.
3099     if (m_popupReply != 0)
3100         return;
3101 
3102     // Create an array of java Strings for the drop down.
3103     jobjectArray labelArray = makeLabelArray(env, labels, count);
3104 
3105     // Create an array determining whether each item is enabled.
3106     jintArray enabledArray = env->NewIntArray(enabledCount);
3107     checkException(env);
3108     jint* ptrArray = env->GetIntArrayElements(enabledArray, 0);
3109     checkException(env);
3110     for (size_t i = 0; i < enabledCount; i++) {
3111         ptrArray[i] = enabled[i];
3112     }
3113     env->ReleaseIntArrayElements(enabledArray, ptrArray, 0);
3114     checkException(env);
3115 
3116     if (multiple) {
3117         // Pass up an array representing which items are selected.
3118         jintArray selectedArray = env->NewIntArray(selectedCountOrSelection);
3119         checkException(env);
3120         jint* selArray = env->GetIntArrayElements(selectedArray, 0);
3121         checkException(env);
3122         for (size_t i = 0; i < selectedCountOrSelection; i++) {
3123             selArray[i] = selected[i];
3124         }
3125         env->ReleaseIntArrayElements(selectedArray, selArray, 0);
3126 
3127         env->CallVoidMethod(javaObject.get(),
3128                 m_javaGlue->m_requestListBox, labelArray, enabledArray,
3129                 selectedArray);
3130         env->DeleteLocalRef(selectedArray);
3131     } else {
3132         // Pass up the single selection.
3133         env->CallVoidMethod(javaObject.get(),
3134                 m_javaGlue->m_requestSingleListBox, labelArray, enabledArray,
3135                 selectedCountOrSelection);
3136     }
3137 
3138     env->DeleteLocalRef(labelArray);
3139     env->DeleteLocalRef(enabledArray);
3140     checkException(env);
3141 
3142     Retain(reply);
3143     m_popupReply = reply;
3144 }
3145 
key(const PlatformKeyboardEvent & event)3146 bool WebViewCore::key(const PlatformKeyboardEvent& event)
3147 {
3148     WebCore::EventHandler* eventHandler;
3149     WebCore::Node* focusNode = currentFocus();
3150     if (focusNode) {
3151         WebCore::Frame* frame = focusNode->document()->frame();
3152         eventHandler = frame->eventHandler();
3153         VisibleSelection old = frame->selection()->selection();
3154         EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
3155                 m_mainFrame->editor()->client());
3156         client->setUiGeneratedSelectionChange(true);
3157         bool handled = eventHandler->keyEvent(event);
3158         client->setUiGeneratedSelectionChange(false);
3159         if (isContentEditable(focusNode)) {
3160             // keyEvent will return true even if the contentEditable did not
3161             // change its selection.  In the case that it does not, we want to
3162             // return false so that the key will be sent back to our navigation
3163             // system.
3164             handled |= frame->selection()->selection() != old;
3165         }
3166         return handled;
3167     } else {
3168         eventHandler = focusedFrame()->eventHandler();
3169     }
3170     return eventHandler->keyEvent(event);
3171 }
3172 
chromeCanTakeFocus(FocusDirection direction)3173 bool WebViewCore::chromeCanTakeFocus(FocusDirection direction)
3174 {
3175     JNIEnv* env = JSC::Bindings::getJNIEnv();
3176     AutoJObject javaObject = m_javaGlue->object(env);
3177     if (!javaObject.get())
3178         return false;
3179     return env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_chromeCanTakeFocus, direction);
3180 }
3181 
chromeTakeFocus(FocusDirection direction)3182 void WebViewCore::chromeTakeFocus(FocusDirection direction)
3183 {
3184     JNIEnv* env = JSC::Bindings::getJNIEnv();
3185     AutoJObject javaObject = m_javaGlue->object(env);
3186     if (!javaObject.get())
3187         return;
3188     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_chromeTakeFocus, direction);
3189 }
3190 
setInitialFocus(const WebCore::PlatformKeyboardEvent & platformEvent)3191 void WebViewCore::setInitialFocus(const WebCore::PlatformKeyboardEvent& platformEvent)
3192 {
3193     Frame* frame = focusedFrame();
3194     Document* document = frame->document();
3195     if (document)
3196         document->setFocusedNode(0);
3197     FocusDirection direction;
3198     switch (platformEvent.nativeVirtualKeyCode()) {
3199     case AKEYCODE_DPAD_LEFT:
3200         direction = FocusDirectionLeft;
3201         break;
3202     case AKEYCODE_DPAD_RIGHT:
3203         direction = FocusDirectionRight;
3204         break;
3205     case AKEYCODE_DPAD_UP:
3206         direction = FocusDirectionUp;
3207         break;
3208     default:
3209         direction = FocusDirectionDown;
3210         break;
3211     }
3212     RefPtr<KeyboardEvent> webkitEvent = KeyboardEvent::create(platformEvent, 0);
3213     m_mainFrame->page()->focusController()->setInitialFocus(direction,
3214             webkitEvent.get());
3215 }
3216 
3217 #if USE(ACCELERATED_COMPOSITING)
graphicsRootLayer() const3218 GraphicsLayerAndroid* WebViewCore::graphicsRootLayer() const
3219 {
3220     RenderView* contentRenderer = m_mainFrame->contentRenderer();
3221     if (!contentRenderer)
3222         return 0;
3223     return static_cast<GraphicsLayerAndroid*>(
3224           contentRenderer->compositor()->rootPlatformLayer());
3225 }
3226 #endif
3227 
handleTouchEvent(int action,Vector<int> & ids,Vector<IntPoint> & points,int actionIndex,int metaState)3228 int WebViewCore::handleTouchEvent(int action, Vector<int>& ids, Vector<IntPoint>& points, int actionIndex, int metaState)
3229 {
3230     int flags = 0;
3231 
3232 #if USE(ACCELERATED_COMPOSITING)
3233     GraphicsLayerAndroid* rootLayer = graphicsRootLayer();
3234     if (rootLayer)
3235       rootLayer->pauseDisplay(true);
3236 #endif
3237 
3238 #if ENABLE(TOUCH_EVENTS) // Android
3239     #define MOTION_EVENT_ACTION_POINTER_DOWN 5
3240     #define MOTION_EVENT_ACTION_POINTER_UP 6
3241 
3242     WebCore::TouchEventType type = WebCore::TouchStart;
3243     WebCore::PlatformTouchPoint::State defaultTouchState;
3244     Vector<WebCore::PlatformTouchPoint::State> touchStates(points.size());
3245 
3246     switch (action) {
3247     case 0: // MotionEvent.ACTION_DOWN
3248         type = WebCore::TouchStart;
3249         defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed;
3250         break;
3251     case 1: // MotionEvent.ACTION_UP
3252         type = WebCore::TouchEnd;
3253         defaultTouchState = WebCore::PlatformTouchPoint::TouchReleased;
3254         break;
3255     case 2: // MotionEvent.ACTION_MOVE
3256         type = WebCore::TouchMove;
3257         defaultTouchState = WebCore::PlatformTouchPoint::TouchMoved;
3258         break;
3259     case 3: // MotionEvent.ACTION_CANCEL
3260         type = WebCore::TouchCancel;
3261         defaultTouchState = WebCore::PlatformTouchPoint::TouchCancelled;
3262         break;
3263     case 5: // MotionEvent.ACTION_POINTER_DOWN
3264         type = WebCore::TouchStart;
3265         defaultTouchState = WebCore::PlatformTouchPoint::TouchStationary;
3266         break;
3267     case 6: // MotionEvent.ACTION_POINTER_UP
3268         type = WebCore::TouchEnd;
3269         defaultTouchState = WebCore::PlatformTouchPoint::TouchStationary;
3270         break;
3271     default:
3272         // We do not support other kinds of touch event inside WebCore
3273         // at the moment.
3274         ALOGW("Java passed a touch event type that we do not support in WebCore: %d", action);
3275         return 0;
3276     }
3277 
3278     for (int c = 0; c < static_cast<int>(points.size()); c++) {
3279         points[c].setX(points[c].x() - m_scrollOffsetX);
3280         points[c].setY(points[c].y() - m_scrollOffsetY);
3281 
3282         // Setting the touch state for each point.
3283         // Note: actionIndex will be 0 for all actions that are not ACTION_POINTER_DOWN/UP.
3284         if (action == MOTION_EVENT_ACTION_POINTER_DOWN && c == actionIndex) {
3285             touchStates[c] = WebCore::PlatformTouchPoint::TouchPressed;
3286         } else if (action == MOTION_EVENT_ACTION_POINTER_UP && c == actionIndex) {
3287             touchStates[c] = WebCore::PlatformTouchPoint::TouchReleased;
3288         } else {
3289             touchStates[c] = defaultTouchState;
3290         };
3291     }
3292 
3293     WebCore::PlatformTouchEvent te(ids, points, type, touchStates, metaState);
3294     if (m_mainFrame->eventHandler()->handleTouchEvent(te))
3295         flags |= TOUCH_FLAG_PREVENT_DEFAULT;
3296     if (te.hitTouchHandler())
3297         flags |= TOUCH_FLAG_HIT_HANDLER;
3298 #endif
3299 
3300 #if USE(ACCELERATED_COMPOSITING)
3301     if (rootLayer)
3302       rootLayer->pauseDisplay(false);
3303 #endif
3304     return flags;
3305 }
3306 
performMouseClick()3307 bool WebViewCore::performMouseClick()
3308 {
3309     WebCore::PlatformMouseEvent mouseDown(m_mouseClickPos, m_mouseClickPos, WebCore::LeftButton,
3310             WebCore::MouseEventPressed, 1, false, false, false, false,
3311             WTF::currentTime());
3312     // ignore the return from as it will return true if the hit point can trigger selection change
3313     m_mainFrame->eventHandler()->handleMousePressEvent(mouseDown);
3314     WebCore::PlatformMouseEvent mouseUp(m_mouseClickPos, m_mouseClickPos, WebCore::LeftButton,
3315             WebCore::MouseEventReleased, 1, false, false, false, false,
3316             WTF::currentTime());
3317     bool handled = m_mainFrame->eventHandler()->handleMouseReleaseEvent(mouseUp);
3318 
3319     WebCore::Node* focusNode = currentFocus();
3320     initializeTextInput(focusNode, false);
3321     return handled;
3322 }
3323 
3324 // Check for the "x-webkit-soft-keyboard" attribute.  If it is there and
3325 // set to hidden, do not show the soft keyboard.  Node passed as a parameter
3326 // must not be null.
shouldSuppressKeyboard(const WebCore::Node * node)3327 static bool shouldSuppressKeyboard(const WebCore::Node* node) {
3328     ALOG_ASSERT(node, "node passed to shouldSuppressKeyboard cannot be null");
3329     const NamedNodeMap* attributes = node->attributes();
3330     if (!attributes) return false;
3331     size_t length = attributes->length();
3332     for (size_t i = 0; i < length; i++) {
3333         const Attribute* a = attributes->attributeItem(i);
3334         if (a->localName() == "x-webkit-soft-keyboard" && a->value() == "hidden")
3335             return true;
3336     }
3337     return false;
3338 }
3339 
getInputType(Node * node)3340 WebViewCore::InputType WebViewCore::getInputType(Node* node)
3341 {
3342     WebCore::RenderObject* renderer = node->renderer();
3343     if (!renderer)
3344         return WebViewCore::NONE;
3345     if (renderer->isTextArea())
3346         return WebViewCore::TEXT_AREA;
3347 
3348     if (node->hasTagName(WebCore::HTMLNames::inputTag)) {
3349         HTMLInputElement* htmlInput = static_cast<HTMLInputElement*>(node);
3350         if (htmlInput->isPasswordField())
3351             return WebViewCore::PASSWORD;
3352         if (htmlInput->isSearchField())
3353             return WebViewCore::SEARCH;
3354         if (htmlInput->isEmailField())
3355             return WebViewCore::EMAIL;
3356         if (htmlInput->isNumberField())
3357             return WebViewCore::NUMBER;
3358         if (htmlInput->isTelephoneField())
3359             return WebViewCore::TELEPHONE;
3360         if (htmlInput->isTextField())
3361             return WebViewCore::NORMAL_TEXT_FIELD;
3362     }
3363 
3364     if (node->isContentEditable())
3365         return WebViewCore::TEXT_AREA;
3366 
3367     return WebViewCore::NONE;
3368 }
3369 
getMaxLength(Node * node)3370 int WebViewCore::getMaxLength(Node* node)
3371 {
3372     int maxLength = -1;
3373     if (node->hasTagName(WebCore::HTMLNames::inputTag)) {
3374         HTMLInputElement* htmlInput = static_cast<HTMLInputElement*>(node);
3375         maxLength = htmlInput->maxLength();
3376     }
3377     return maxLength;
3378 }
3379 
getFieldName(Node * node)3380 String WebViewCore::getFieldName(Node* node)
3381 {
3382     String name;
3383     if (node->hasTagName(WebCore::HTMLNames::inputTag)) {
3384         HTMLInputElement* htmlInput = static_cast<HTMLInputElement*>(node);
3385         name = htmlInput->name();
3386     }
3387     return name;
3388 }
3389 
isSpellCheckEnabled(Node * node)3390 bool WebViewCore::isSpellCheckEnabled(Node* node)
3391 {
3392     bool isEnabled = true;
3393     if (node->isElementNode()) {
3394         WebCore::Element* element = static_cast<WebCore::Element*>(node);
3395         isEnabled = element->isSpellCheckingEnabled();
3396     }
3397     return isEnabled;
3398 }
3399 
isAutoCompleteEnabled(Node * node)3400 bool WebViewCore::isAutoCompleteEnabled(Node* node)
3401 {
3402     bool isEnabled = false;
3403     if (node->hasTagName(WebCore::HTMLNames::inputTag)) {
3404         HTMLInputElement* htmlInput = static_cast<HTMLInputElement*>(node);
3405         isEnabled = htmlInput->autoComplete();
3406     }
3407     return isEnabled;
3408 }
3409 
absoluteClientRect(WebCore::Node * node,LayerAndroid * layer)3410 WebCore::IntRect WebViewCore::absoluteClientRect(WebCore::Node* node,
3411         LayerAndroid* layer)
3412 {
3413     IntRect clientRect;
3414     if (node) {
3415         RenderObject* render = node->renderer();
3416         if (render && render->isBox() && !render->isBody()) {
3417             IntPoint offset = convertGlobalContentToFrameContent(IntPoint(),
3418                     node->document()->frame());
3419             WebViewCore::layerToAbsoluteOffset(layer, offset);
3420 
3421             RenderBox* renderBox = toRenderBox(render);
3422             clientRect = renderBox->clientBoxRect();
3423             IntRect contentBox = renderBox->contentBoxRect();
3424             clientRect.setX(contentBox.x());
3425             clientRect.setWidth(contentBox.width());
3426             FloatPoint absPos = renderBox->localToAbsolute(FloatPoint());
3427             clientRect.move(absPos.x() - offset.x(), absPos.y() - offset.y());
3428         }
3429     }
3430     return clientRect;
3431 }
3432 
createTextFieldInitData(Node * node)3433 jobject WebViewCore::createTextFieldInitData(Node* node)
3434 {
3435     JNIEnv* env = JSC::Bindings::getJNIEnv();
3436     TextFieldInitDataGlue* classDef = m_textFieldInitDataGlue;
3437     ScopedLocalRef<jclass> clazz(env,
3438             env->FindClass("android/webkit/WebViewCore$TextFieldInitData"));
3439     jobject initData = env->NewObject(clazz.get(), classDef->m_constructor);
3440     env->SetIntField(initData, classDef->m_fieldPointer,
3441             reinterpret_cast<int>(node));
3442     ScopedLocalRef<jstring> inputText(env,
3443             wtfStringToJstring(env, getInputText(node), true));
3444     env->SetObjectField(initData, classDef->m_text, inputText.get());
3445     env->SetIntField(initData, classDef->m_type, getInputType(node));
3446     env->SetBooleanField(initData, classDef->m_isSpellCheckEnabled,
3447             isSpellCheckEnabled(node));
3448     Document* document = node->document();
3449     PlatformKeyboardEvent tab(AKEYCODE_TAB, 0, 0, false, false, false, false);
3450     PassRefPtr<KeyboardEvent> tabEvent =
3451             KeyboardEvent::create(tab, document->defaultView());
3452     env->SetBooleanField(initData, classDef->m_isTextFieldNext,
3453             isTextInput(document->nextFocusableNode(node, tabEvent.get())));
3454     env->SetBooleanField(initData, classDef->m_isTextFieldPrev,
3455             isTextInput(document->previousFocusableNode(node, tabEvent.get())));
3456     env->SetBooleanField(initData, classDef->m_isAutoCompleteEnabled,
3457             isAutoCompleteEnabled(node));
3458     ScopedLocalRef<jstring> fieldName(env,
3459             wtfStringToJstring(env, getFieldName(node), false));
3460     env->SetObjectField(initData, classDef->m_name, fieldName.get());
3461     ScopedLocalRef<jstring> label(env,
3462             wtfStringToJstring(env, requestLabel(document->frame(), node), false));
3463     env->SetObjectField(initData, classDef->m_label, label.get());
3464     env->SetIntField(initData, classDef->m_maxLength, getMaxLength(node));
3465     LayerAndroid* layer = 0;
3466     int layerId = platformLayerIdFromNode(node, &layer);
3467     IntRect bounds = absoluteClientRect(node, layer);
3468     ScopedLocalRef<jobject> jbounds(env, intRectToRect(env, bounds));
3469     env->SetObjectField(initData, classDef->m_contentBounds, jbounds.get());
3470     env->SetIntField(initData, classDef->m_nodeLayerId, layerId);
3471     IntRect contentRect;
3472     RenderTextControl* rtc = toRenderTextControl(node);
3473     if (rtc) {
3474         contentRect.setWidth(rtc->scrollWidth());
3475         contentRect.setHeight(rtc->scrollHeight());
3476         contentRect.move(-rtc->scrollLeft(), -rtc->scrollTop());
3477     }
3478     ScopedLocalRef<jobject> jcontentRect(env, intRectToRect(env, contentRect));
3479     env->SetObjectField(initData, classDef->m_clientRect, jcontentRect.get());
3480     return initData;
3481 }
3482 
initEditField(Node * node)3483 void WebViewCore::initEditField(Node* node)
3484 {
3485     JNIEnv* env = JSC::Bindings::getJNIEnv();
3486     AutoJObject javaObject = m_javaGlue->object(env);
3487     if (!javaObject.get())
3488         return;
3489     m_textGeneration = 0;
3490     int start = 0;
3491     int end = 0;
3492     getSelectionOffsets(node, start, end);
3493     SelectText* selectText = createSelectText(focusedFrame()->selection()->selection());
3494     ScopedLocalRef<jobject> initData(env, createTextFieldInitData(node));
3495     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_initEditField,
3496             start, end, reinterpret_cast<int>(selectText), initData.get());
3497     checkException(env);
3498 }
3499 
popupReply(int index)3500 void WebViewCore::popupReply(int index)
3501 {
3502     if (m_popupReply) {
3503         m_popupReply->replyInt(index);
3504         ::Release(m_popupReply);
3505         m_popupReply = 0;
3506     }
3507 }
3508 
popupReply(const int * array,int count)3509 void WebViewCore::popupReply(const int* array, int count)
3510 {
3511     if (m_popupReply) {
3512         m_popupReply->replyIntArray(array, count);
3513         ::Release(m_popupReply);
3514         m_popupReply = 0;
3515     }
3516 }
3517 
3518 // This is a slightly modified Node::nextNodeConsideringAtomicNodes() with the
3519 // extra constraint of limiting the search to inside a containing parent
nextNodeWithinParent(WebCore::Node * parent,WebCore::Node * start)3520 WebCore::Node* nextNodeWithinParent(WebCore::Node* parent, WebCore::Node* start)
3521 {
3522     if (!isAtomicNode(start) && start->firstChild())
3523         return start->firstChild();
3524     if (start->nextSibling())
3525         return start->nextSibling();
3526     const Node *n = start;
3527     while (n && !n->nextSibling()) {
3528         n = n->parentNode();
3529         if (n == parent)
3530             return 0;
3531     }
3532     if (n)
3533         return n->nextSibling();
3534     return 0;
3535 }
3536 
initializeTextInput(WebCore::Node * node,bool fake)3537 void WebViewCore::initializeTextInput(WebCore::Node* node, bool fake)
3538 {
3539     if (node) {
3540         if (isTextInput(node)) {
3541             bool showKeyboard = true;
3542             initEditField(node);
3543             WebCore::RenderTextControl* rtc = toRenderTextControl(node);
3544             if (rtc && node->hasTagName(HTMLNames::inputTag)) {
3545                 HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(node);
3546                 bool ime = !shouldSuppressKeyboard(node) && !inputElement->readOnly();
3547                 if (ime) {
3548 #if ENABLE(WEB_AUTOFILL)
3549                     if (rtc->isTextField()) {
3550                         Page* page = node->document()->page();
3551                         EditorClient* editorClient = page->editorClient();
3552                         EditorClientAndroid* androidEditor =
3553                                 static_cast<EditorClientAndroid*>(editorClient);
3554                         WebAutofill* autoFill = androidEditor->getAutofill();
3555                         autoFill->formFieldFocused(inputElement);
3556                     }
3557 #endif
3558                 } else
3559                     showKeyboard = false;
3560             }
3561             if (!fake)
3562                 requestKeyboard(showKeyboard);
3563         } else if (!fake && !nodeIsPlugin(node)) {
3564             // not a text entry field, put away the keyboard.
3565             clearTextEntry();
3566         }
3567     } else if (!fake) {
3568         // There is no focusNode, so the keyboard is not needed.
3569         clearTextEntry();
3570     }
3571 }
3572 
focusNodeChanged(WebCore::Node * newFocus)3573 void WebViewCore::focusNodeChanged(WebCore::Node* newFocus)
3574 {
3575     JNIEnv* env = JSC::Bindings::getJNIEnv();
3576     AutoJObject javaObject = m_javaGlue->object(env);
3577     if (!javaObject.get())
3578         return;
3579     if (isTextInput(newFocus))
3580         initializeTextInput(newFocus, true);
3581     HitTestResult focusHitResult;
3582     focusHitResult.setInnerNode(newFocus);
3583     focusHitResult.setInnerNonSharedNode(newFocus);
3584     if (newFocus && newFocus->isLink() && newFocus->isElementNode()) {
3585         focusHitResult.setURLElement(static_cast<Element*>(newFocus));
3586         if (newFocus->hasChildNodes() && !newFocus->hasTagName(HTMLNames::imgTag)) {
3587             // Check to see if any of the children are images, and if so
3588             // set them as the innerNode and innerNonSharedNode
3589             // This will stop when it hits the first image. I'm not sure what
3590             // should be done in the case of multiple images inside one anchor...
3591             Node* nextNode = newFocus->firstChild();
3592             bool found = false;
3593             while (nextNode) {
3594                 if (nextNode->hasTagName(HTMLNames::imgTag)) {
3595                     found = true;
3596                     break;
3597                 }
3598                 nextNode = nextNodeWithinParent(newFocus, nextNode);
3599             }
3600             if (found) {
3601                 focusHitResult.setInnerNode(nextNode);
3602                 focusHitResult.setInnerNonSharedNode(nextNode);
3603             }
3604         }
3605     }
3606     AndroidHitTestResult androidHitTest(this, focusHitResult);
3607     jobject jHitTestObj = androidHitTest.createJavaObject(env);
3608     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_focusNodeChanged,
3609             reinterpret_cast<int>(newFocus), jHitTestObj);
3610     env->DeleteLocalRef(jHitTestObj);
3611 }
3612 
addMessageToConsole(const WTF::String & message,unsigned int lineNumber,const WTF::String & sourceID,int msgLevel)3613 void WebViewCore::addMessageToConsole(const WTF::String& message, unsigned int lineNumber, const WTF::String& sourceID, int msgLevel) {
3614     JNIEnv* env = JSC::Bindings::getJNIEnv();
3615     AutoJObject javaObject = m_javaGlue->object(env);
3616     if (!javaObject.get())
3617         return;
3618     jstring jMessageStr = wtfStringToJstring(env, message);
3619     jstring jSourceIDStr = wtfStringToJstring(env, sourceID);
3620     env->CallVoidMethod(javaObject.get(),
3621             m_javaGlue->m_addMessageToConsole, jMessageStr, lineNumber,
3622             jSourceIDStr, msgLevel);
3623     env->DeleteLocalRef(jMessageStr);
3624     env->DeleteLocalRef(jSourceIDStr);
3625     checkException(env);
3626 }
3627 
jsAlert(const WTF::String & url,const WTF::String & text)3628 void WebViewCore::jsAlert(const WTF::String& url, const WTF::String& text)
3629 {
3630     JNIEnv* env = JSC::Bindings::getJNIEnv();
3631     AutoJObject javaObject = m_javaGlue->object(env);
3632     if (!javaObject.get())
3633         return;
3634     jstring jInputStr = wtfStringToJstring(env, text);
3635     jstring jUrlStr = wtfStringToJstring(env, url);
3636     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_jsAlert, jUrlStr, jInputStr);
3637     env->DeleteLocalRef(jInputStr);
3638     env->DeleteLocalRef(jUrlStr);
3639     checkException(env);
3640 }
3641 
exceededDatabaseQuota(const WTF::String & url,const WTF::String & databaseIdentifier,const unsigned long long currentQuota,unsigned long long estimatedSize)3642 bool WebViewCore::exceededDatabaseQuota(const WTF::String& url, const WTF::String& databaseIdentifier, const unsigned long long currentQuota, unsigned long long estimatedSize)
3643 {
3644 #if ENABLE(DATABASE)
3645     JNIEnv* env = JSC::Bindings::getJNIEnv();
3646     AutoJObject javaObject = m_javaGlue->object(env);
3647     if (!javaObject.get())
3648         return false;
3649     jstring jDatabaseIdentifierStr = wtfStringToJstring(env, databaseIdentifier);
3650     jstring jUrlStr = wtfStringToJstring(env, url);
3651     env->CallVoidMethod(javaObject.get(),
3652             m_javaGlue->m_exceededDatabaseQuota, jUrlStr,
3653             jDatabaseIdentifierStr, currentQuota, estimatedSize);
3654     env->DeleteLocalRef(jDatabaseIdentifierStr);
3655     env->DeleteLocalRef(jUrlStr);
3656     checkException(env);
3657     return true;
3658 #endif
3659 }
3660 
3661 /*
3662  * TODO Note that this logic still needs to be cleaned up. Normally the
3663  * information provided in this callback is used to resize the appcache.
3664  * so we need to provide the current database size. However, webkit provides no
3665  * way to reach this information. It can be calculated by fetching all the
3666  * origins and their usage, however this is too expensize (requires one inner
3667  * join operation for each origin). Rather, we simply return the maximum cache size,
3668  * which should be equivalent to the current cache size. This is generally safe.
3669  * However, setting the maximum database size to less than the current database size
3670  * may cause a problem. In this case, ApplicationCacheStorage ("the owner of database")
3671  * uses the updated value, while database internally ignores it and uses the current size
3672  * as quota. This means the value we returned here won't reflect the actual database size.
3673  */
reachedMaxAppCacheSize(const unsigned long long spaceNeeded)3674 bool WebViewCore::reachedMaxAppCacheSize(const unsigned long long spaceNeeded)
3675 {
3676 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
3677     JNIEnv* env = JSC::Bindings::getJNIEnv();
3678     AutoJObject javaObject = m_javaGlue->object(env);
3679     if (!javaObject.get())
3680         return false;
3681     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_reachedMaxAppCacheSize, spaceNeeded, WebCore::cacheStorage().maximumSize());
3682     checkException(env);
3683     return true;
3684 #endif
3685 }
3686 
populateVisitedLinks(WebCore::PageGroup * group)3687 void WebViewCore::populateVisitedLinks(WebCore::PageGroup* group)
3688 {
3689     JNIEnv* env = JSC::Bindings::getJNIEnv();
3690     AutoJObject javaObject = m_javaGlue->object(env);
3691     if (!javaObject.get())
3692         return;
3693     m_groupForVisitedLinks = group;
3694     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_populateVisitedLinks);
3695     checkException(env);
3696 }
3697 
geolocationPermissionsShowPrompt(const WTF::String & origin)3698 void WebViewCore::geolocationPermissionsShowPrompt(const WTF::String& origin)
3699 {
3700     JNIEnv* env = JSC::Bindings::getJNIEnv();
3701     AutoJObject javaObject = m_javaGlue->object(env);
3702     if (!javaObject.get())
3703         return;
3704     jstring originString = wtfStringToJstring(env, origin);
3705     env->CallVoidMethod(javaObject.get(),
3706                         m_javaGlue->m_geolocationPermissionsShowPrompt,
3707                         originString);
3708     env->DeleteLocalRef(originString);
3709     checkException(env);
3710 }
3711 
geolocationPermissionsHidePrompt()3712 void WebViewCore::geolocationPermissionsHidePrompt()
3713 {
3714     JNIEnv* env = JSC::Bindings::getJNIEnv();
3715     AutoJObject javaObject = m_javaGlue->object(env);
3716     if (!javaObject.get())
3717         return;
3718     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_geolocationPermissionsHidePrompt);
3719     checkException(env);
3720 }
3721 
getDeviceMotionService()3722 jobject WebViewCore::getDeviceMotionService()
3723 {
3724     JNIEnv* env = JSC::Bindings::getJNIEnv();
3725     AutoJObject javaObject = m_javaGlue->object(env);
3726     if (!javaObject.get())
3727         return 0;
3728     jobject object = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getDeviceMotionService);
3729     checkException(env);
3730     return object;
3731 }
3732 
getDeviceOrientationService()3733 jobject WebViewCore::getDeviceOrientationService()
3734 {
3735     JNIEnv* env = JSC::Bindings::getJNIEnv();
3736     AutoJObject javaObject = m_javaGlue->object(env);
3737     if (!javaObject.get())
3738         return 0;
3739     jobject object = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getDeviceOrientationService);
3740     checkException(env);
3741     return object;
3742 }
3743 
jsConfirm(const WTF::String & url,const WTF::String & text)3744 bool WebViewCore::jsConfirm(const WTF::String& url, const WTF::String& text)
3745 {
3746     JNIEnv* env = JSC::Bindings::getJNIEnv();
3747     AutoJObject javaObject = m_javaGlue->object(env);
3748     if (!javaObject.get())
3749         return false;
3750     jstring jInputStr = wtfStringToJstring(env, text);
3751     jstring jUrlStr = wtfStringToJstring(env, url);
3752     jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsConfirm, jUrlStr, jInputStr);
3753     env->DeleteLocalRef(jInputStr);
3754     env->DeleteLocalRef(jUrlStr);
3755     checkException(env);
3756     return result;
3757 }
3758 
jsPrompt(const WTF::String & url,const WTF::String & text,const WTF::String & defaultValue,WTF::String & result)3759 bool WebViewCore::jsPrompt(const WTF::String& url, const WTF::String& text, const WTF::String& defaultValue, WTF::String& result)
3760 {
3761     JNIEnv* env = JSC::Bindings::getJNIEnv();
3762     AutoJObject javaObject = m_javaGlue->object(env);
3763     if (!javaObject.get())
3764         return false;
3765     jstring jUrlStr = wtfStringToJstring(env, url);
3766     jstring jInputStr = wtfStringToJstring(env, text);
3767     jstring jDefaultStr = wtfStringToJstring(env, defaultValue);
3768     jstring returnVal = static_cast<jstring>(env->CallObjectMethod(javaObject.get(), m_javaGlue->m_jsPrompt, jUrlStr, jInputStr, jDefaultStr));
3769     env->DeleteLocalRef(jUrlStr);
3770     env->DeleteLocalRef(jInputStr);
3771     env->DeleteLocalRef(jDefaultStr);
3772     checkException(env);
3773 
3774     // If returnVal is null, it means that the user cancelled the dialog.
3775     if (!returnVal)
3776         return false;
3777 
3778     result = jstringToWtfString(env, returnVal);
3779     env->DeleteLocalRef(returnVal);
3780     return true;
3781 }
3782 
jsUnload(const WTF::String & url,const WTF::String & message)3783 bool WebViewCore::jsUnload(const WTF::String& url, const WTF::String& message)
3784 {
3785     JNIEnv* env = JSC::Bindings::getJNIEnv();
3786     AutoJObject javaObject = m_javaGlue->object(env);
3787     if (!javaObject.get())
3788         return false;
3789     jstring jInputStr = wtfStringToJstring(env, message);
3790     jstring jUrlStr = wtfStringToJstring(env, url);
3791     jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsUnload, jUrlStr, jInputStr);
3792     env->DeleteLocalRef(jInputStr);
3793     env->DeleteLocalRef(jUrlStr);
3794     checkException(env);
3795     return result;
3796 }
3797 
jsInterrupt()3798 bool WebViewCore::jsInterrupt()
3799 {
3800     JNIEnv* env = JSC::Bindings::getJNIEnv();
3801     AutoJObject javaObject = m_javaGlue->object(env);
3802     if (!javaObject.get())
3803         return false;
3804     jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsInterrupt);
3805     checkException(env);
3806     return result;
3807 }
3808 
3809 AutoJObject
getJavaObject()3810 WebViewCore::getJavaObject()
3811 {
3812     return m_javaGlue->object(JSC::Bindings::getJNIEnv());
3813 }
3814 
3815 jobject
getWebViewJavaObject()3816 WebViewCore::getWebViewJavaObject()
3817 {
3818     JNIEnv* env = JSC::Bindings::getJNIEnv();
3819     AutoJObject javaObject = m_javaGlue->object(env);
3820     if (!javaObject.get())
3821         return 0;
3822     return env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getWebView);
3823 }
3824 
toRenderTextControl(Node * node)3825 RenderTextControl* WebViewCore::toRenderTextControl(Node* node)
3826 {
3827     RenderTextControl* rtc = 0;
3828     RenderObject* renderer = node->renderer();
3829     if (renderer && renderer->isTextControl()) {
3830         rtc = WebCore::toRenderTextControl(renderer);
3831     }
3832     return rtc;
3833 }
3834 
getSelectionOffsets(Node * node,int & start,int & end)3835 void WebViewCore::getSelectionOffsets(Node* node, int& start, int& end)
3836 {
3837     RenderTextControl* rtc = toRenderTextControl(node);
3838     if (rtc) {
3839         start = rtc->selectionStart();
3840         end = rtc->selectionEnd();
3841     } else {
3842         // It must be content editable field.
3843         Document* document = node->document();
3844         Frame* frame = document->frame();
3845         SelectionController* selector = frame->selection();
3846         Position selectionStart = selector->start();
3847         Position selectionEnd = selector->end();
3848         Position startOfNode = firstPositionInNode(node);
3849         RefPtr<Range> startRange = Range::create(document, startOfNode,
3850                 selectionStart);
3851         start = TextIterator::rangeLength(startRange.get(), true);
3852         RefPtr<Range> endRange = Range::create(document, startOfNode,
3853                 selectionEnd);
3854         end = TextIterator::rangeLength(endRange.get(), true);
3855     }
3856 }
3857 
getInputText(Node * node)3858 String WebViewCore::getInputText(Node* node)
3859 {
3860     String text;
3861     WebCore::RenderTextControl* renderText = toRenderTextControl(node);
3862     if (renderText)
3863         text = renderText->text();
3864     else {
3865         // It must be content editable field.
3866         Position start = firstPositionInNode(node);
3867         Position end = lastPositionInNode(node);
3868         VisibleSelection allEditableText(start, end);
3869         if (allEditableText.isRange())
3870             text = allEditableText.firstRange()->text();
3871     }
3872     return text;
3873 }
3874 
updateTextSelection()3875 void WebViewCore::updateTextSelection()
3876 {
3877     JNIEnv* env = JSC::Bindings::getJNIEnv();
3878     AutoJObject javaObject = m_javaGlue->object(env);
3879     if (!javaObject.get())
3880         return;
3881     VisibleSelection selection = focusedFrame()->selection()->selection();
3882     int start = 0;
3883     int end = 0;
3884     if (selection.isCaretOrRange())
3885         getSelectionOffsets(selection.start().anchorNode(), start, end);
3886     SelectText* selectText = createSelectText(selection);
3887     env->CallVoidMethod(javaObject.get(),
3888             m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(currentFocus()),
3889             start, end, m_textGeneration, reinterpret_cast<int>(selectText));
3890     checkException(env);
3891 }
3892 
updateTextSizeAndScroll(WebCore::Node * node)3893 void WebViewCore::updateTextSizeAndScroll(WebCore::Node* node)
3894 {
3895     JNIEnv* env = JSC::Bindings::getJNIEnv();
3896     AutoJObject javaObject = m_javaGlue->object(env);
3897     if (!javaObject.get())
3898         return;
3899     RenderTextControl* rtc = toRenderTextControl(node);
3900     if (!rtc)
3901         return;
3902     int width = rtc->scrollWidth();
3903     int height = rtc->contentHeight();
3904     int scrollX = rtc->scrollLeft();
3905     int scrollY = rtc->scrollTop();
3906     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextSizeAndScroll,
3907             reinterpret_cast<int>(node), width, height, scrollX, scrollY);
3908     checkException(env);
3909 }
3910 
updateTextfield(WebCore::Node * ptr,const WTF::String & text)3911 void WebViewCore::updateTextfield(WebCore::Node* ptr, const WTF::String& text)
3912 {
3913     JNIEnv* env = JSC::Bindings::getJNIEnv();
3914     AutoJObject javaObject = m_javaGlue->object(env);
3915     if (!javaObject.get())
3916         return;
3917     if (m_blockTextfieldUpdates)
3918         return;
3919     jstring string = wtfStringToJstring(env, text);
3920     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextfield,
3921             (int) ptr, string, m_textGeneration);
3922     env->DeleteLocalRef(string);
3923     checkException(env);
3924 }
3925 
clearTextEntry()3926 void WebViewCore::clearTextEntry()
3927 {
3928     JNIEnv* env = JSC::Bindings::getJNIEnv();
3929     AutoJObject javaObject = m_javaGlue->object(env);
3930     if (!javaObject.get())
3931         return;
3932     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_clearTextEntry);
3933 }
3934 
setBackgroundColor(SkColor c)3935 void WebViewCore::setBackgroundColor(SkColor c)
3936 {
3937     WebCore::FrameView* view = m_mainFrame->view();
3938     if (!view)
3939         return;
3940 
3941     // need (int) cast to find the right constructor
3942     WebCore::Color bcolor((int)SkColorGetR(c), (int)SkColorGetG(c),
3943                           (int)SkColorGetB(c), (int)SkColorGetA(c));
3944 
3945     if (view->baseBackgroundColor() == bcolor)
3946         return;
3947 
3948     view->setBaseBackgroundColor(bcolor);
3949 
3950     // Background color of 0 indicates we want a transparent background
3951     if (c == 0)
3952         view->setTransparent(true);
3953 
3954     //invalidate so the new color is shown
3955     contentInvalidateAll();
3956 }
3957 
getPluginClass(const WTF::String & libName,const char * className)3958 jclass WebViewCore::getPluginClass(const WTF::String& libName, const char* className)
3959 {
3960     JNIEnv* env = JSC::Bindings::getJNIEnv();
3961     AutoJObject javaObject = m_javaGlue->object(env);
3962     if (!javaObject.get())
3963         return 0;
3964 
3965     jstring libString = wtfStringToJstring(env, libName);
3966     jstring classString = env->NewStringUTF(className);
3967     jobject pluginClass = env->CallObjectMethod(javaObject.get(),
3968                                            m_javaGlue->m_getPluginClass,
3969                                            libString, classString);
3970     checkException(env);
3971 
3972     // cleanup unneeded local JNI references
3973     env->DeleteLocalRef(libString);
3974     env->DeleteLocalRef(classString);
3975 
3976     if (pluginClass != 0) {
3977         return static_cast<jclass>(pluginClass);
3978     } else {
3979         return 0;
3980     }
3981 }
3982 
showFullScreenPlugin(jobject childView,int32_t orientation,NPP npp)3983 void WebViewCore::showFullScreenPlugin(jobject childView, int32_t orientation, NPP npp)
3984 {
3985     JNIEnv* env = JSC::Bindings::getJNIEnv();
3986     AutoJObject javaObject = m_javaGlue->object(env);
3987     if (!javaObject.get())
3988         return;
3989 
3990     env->CallVoidMethod(javaObject.get(),
3991                         m_javaGlue->m_showFullScreenPlugin,
3992                         childView, orientation, reinterpret_cast<int>(npp));
3993     checkException(env);
3994 }
3995 
hideFullScreenPlugin()3996 void WebViewCore::hideFullScreenPlugin()
3997 {
3998     JNIEnv* env = JSC::Bindings::getJNIEnv();
3999     AutoJObject javaObject = m_javaGlue->object(env);
4000     if (!javaObject.get())
4001         return;
4002     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_hideFullScreenPlugin);
4003     checkException(env);
4004 }
4005 
createSurface(jobject view)4006 jobject WebViewCore::createSurface(jobject view)
4007 {
4008     JNIEnv* env = JSC::Bindings::getJNIEnv();
4009     AutoJObject javaObject = m_javaGlue->object(env);
4010     if (!javaObject.get())
4011         return 0;
4012     jobject result = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_createSurface, view);
4013     checkException(env);
4014     return result;
4015 }
4016 
addSurface(jobject view,int x,int y,int width,int height)4017 jobject WebViewCore::addSurface(jobject view, int x, int y, int width, int height)
4018 {
4019     JNIEnv* env = JSC::Bindings::getJNIEnv();
4020     AutoJObject javaObject = m_javaGlue->object(env);
4021     if (!javaObject.get())
4022         return 0;
4023     jobject result = env->CallObjectMethod(javaObject.get(),
4024                                            m_javaGlue->m_addSurface,
4025                                            view, x, y, width, height);
4026     checkException(env);
4027     return result;
4028 }
4029 
updateSurface(jobject childView,int x,int y,int width,int height)4030 void WebViewCore::updateSurface(jobject childView, int x, int y, int width, int height)
4031 {
4032     JNIEnv* env = JSC::Bindings::getJNIEnv();
4033     AutoJObject javaObject = m_javaGlue->object(env);
4034     if (!javaObject.get())
4035         return;
4036     env->CallVoidMethod(javaObject.get(),
4037                         m_javaGlue->m_updateSurface, childView,
4038                         x, y, width, height);
4039     checkException(env);
4040 }
4041 
destroySurface(jobject childView)4042 void WebViewCore::destroySurface(jobject childView)
4043 {
4044     JNIEnv* env = JSC::Bindings::getJNIEnv();
4045     AutoJObject javaObject = m_javaGlue->object(env);
4046     if (!javaObject.get())
4047         return;
4048     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_destroySurface, childView);
4049     checkException(env);
4050 }
4051 
getContext()4052 jobject WebViewCore::getContext()
4053 {
4054     JNIEnv* env = JSC::Bindings::getJNIEnv();
4055     AutoJObject javaObject = m_javaGlue->object(env);
4056     if (!javaObject.get())
4057         return 0;
4058 
4059     jobject result = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getContext);
4060     checkException(env);
4061     return result;
4062 }
4063 
keepScreenOn(bool screenOn)4064 void WebViewCore::keepScreenOn(bool screenOn) {
4065     if ((screenOn && m_screenOnCounter == 0) || (!screenOn && m_screenOnCounter == 1)) {
4066         JNIEnv* env = JSC::Bindings::getJNIEnv();
4067         AutoJObject javaObject = m_javaGlue->object(env);
4068         if (!javaObject.get())
4069             return;
4070         env->CallVoidMethod(javaObject.get(), m_javaGlue->m_keepScreenOn, screenOn);
4071         checkException(env);
4072     }
4073 
4074     // update the counter
4075     if (screenOn)
4076         m_screenOnCounter++;
4077     else if (m_screenOnCounter > 0)
4078         m_screenOnCounter--;
4079 }
4080 
showRect(int left,int top,int width,int height,int contentWidth,int contentHeight,float xPercentInDoc,float xPercentInView,float yPercentInDoc,float yPercentInView)4081 void WebViewCore::showRect(int left, int top, int width, int height,
4082         int contentWidth, int contentHeight, float xPercentInDoc,
4083         float xPercentInView, float yPercentInDoc, float yPercentInView)
4084 {
4085     JNIEnv* env = JSC::Bindings::getJNIEnv();
4086     AutoJObject javaObject = m_javaGlue->object(env);
4087     if (!javaObject.get())
4088         return;
4089     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_showRect,
4090             left, top, width, height, contentWidth, contentHeight,
4091             xPercentInDoc, xPercentInView, yPercentInDoc, yPercentInView);
4092     checkException(env);
4093 }
4094 
centerFitRect(int x,int y,int width,int height)4095 void WebViewCore::centerFitRect(int x, int y, int width, int height)
4096 {
4097     JNIEnv* env = JSC::Bindings::getJNIEnv();
4098     AutoJObject javaObject = m_javaGlue->object(env);
4099     if (!javaObject.get())
4100         return;
4101     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_centerFitRect, x, y, width, height);
4102     checkException(env);
4103 }
4104 
setScrollbarModes(ScrollbarMode horizontalMode,ScrollbarMode verticalMode)4105 void WebViewCore::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode)
4106 {
4107     JNIEnv* env = JSC::Bindings::getJNIEnv();
4108     AutoJObject javaObject = m_javaGlue->object(env);
4109     if (!javaObject.get())
4110         return;
4111     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setScrollbarModes, horizontalMode, verticalMode);
4112     checkException(env);
4113 }
4114 
4115 #if ENABLE(VIDEO)
enterFullscreenForVideoLayer()4116 void WebViewCore::enterFullscreenForVideoLayer()
4117 {
4118     // Just need to update the video mode, to avoid multiple exit full screen.
4119     m_fullscreenVideoMode = true;
4120 }
4121 
exitFullscreenVideo()4122 void WebViewCore::exitFullscreenVideo()
4123 {
4124     JNIEnv* env = JSC::Bindings::getJNIEnv();
4125     AutoJObject javaObject = m_javaGlue->object(env);
4126     if (!javaObject.get())
4127         return;
4128     if (m_fullscreenVideoMode) {
4129         env->CallVoidMethod(javaObject.get(), m_javaGlue->m_exitFullscreenVideo);
4130         m_fullscreenVideoMode = false;
4131     }
4132     checkException(env);
4133 }
4134 #endif
4135 
setWebTextViewAutoFillable(int queryId,const string16 & previewSummary)4136 void WebViewCore::setWebTextViewAutoFillable(int queryId, const string16& previewSummary)
4137 {
4138 #if ENABLE(WEB_AUTOFILL)
4139     JNIEnv* env = JSC::Bindings::getJNIEnv();
4140     AutoJObject javaObject = m_javaGlue->object(env);
4141     if (!javaObject.get())
4142         return;
4143     jstring preview = env->NewString(previewSummary.data(), previewSummary.length());
4144     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setWebTextViewAutoFillable, queryId, preview);
4145     env->DeleteLocalRef(preview);
4146 #endif
4147 }
4148 
drawIsPaused() const4149 bool WebViewCore::drawIsPaused() const
4150 {
4151     // returning true says scrollview should be offscreen, which pauses
4152     // gifs. because this is not again queried when we stop scrolling, we don't
4153     // use the stopping currently.
4154     return false;
4155 }
4156 
setWebRequestContextUserAgent()4157 void WebViewCore::setWebRequestContextUserAgent()
4158 {
4159     // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet
4160     if (m_webRequestContext)
4161         m_webRequestContext->setUserAgent(WebFrame::getWebFrame(m_mainFrame)->userAgentForURL(0)); // URL not used
4162 }
4163 
setWebRequestContextCacheMode(int cacheMode)4164 void WebViewCore::setWebRequestContextCacheMode(int cacheMode)
4165 {
4166     m_cacheMode = cacheMode;
4167     // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet
4168     if (!m_webRequestContext)
4169         return;
4170 
4171     m_webRequestContext->setCacheMode(cacheMode);
4172 }
4173 
webRequestContext()4174 WebRequestContext* WebViewCore::webRequestContext()
4175 {
4176     if (!m_webRequestContext) {
4177         Settings* settings = mainFrame()->settings();
4178         m_webRequestContext = new WebRequestContext(settings && settings->privateBrowsingEnabled());
4179         setWebRequestContextUserAgent();
4180         setWebRequestContextCacheMode(m_cacheMode);
4181     }
4182     return m_webRequestContext.get();
4183 }
4184 
scrollRenderLayer(int layer,const SkRect & rect)4185 void WebViewCore::scrollRenderLayer(int layer, const SkRect& rect)
4186 {
4187 #if USE(ACCELERATED_COMPOSITING)
4188     GraphicsLayerAndroid* root = graphicsRootLayer();
4189     if (!root)
4190         return;
4191 
4192     LayerAndroid* layerAndroid = root->platformLayer();
4193     if (!layerAndroid)
4194         return;
4195 
4196     LayerAndroid* target = layerAndroid->findById(layer);
4197     if (!target)
4198         return;
4199 
4200     RenderLayer* owner = target->owningLayer();
4201     if (!owner)
4202         return;
4203 
4204     if (owner->isRootLayer()) {
4205         FrameView* view = owner->renderer()->frame()->view();
4206         IntPoint pt(rect.fLeft, rect.fTop);
4207         view->setScrollPosition(pt);
4208     } else
4209         owner->scrollToOffset(rect.fLeft, rect.fTop);
4210 #endif
4211 }
4212 
getTextRanges(int startX,int startY,int endX,int endY)4213 Vector<VisibleSelection> WebViewCore::getTextRanges(
4214         int startX, int startY, int endX, int endY)
4215 {
4216     // These are the positions of the selection handles,
4217     // which reside below the line that they are selecting.
4218     // Use the vertical position higher, which will include
4219     // the selected text.
4220     startY--;
4221     endY--;
4222     VisiblePosition startSelect = visiblePositionForContentPoint(startX, startY);
4223     VisiblePosition endSelect =  visiblePositionForContentPoint(endX, endY);
4224     Position start = startSelect.deepEquivalent();
4225     Position end = endSelect.deepEquivalent();
4226     if (isLtr(end)) {
4227         // The end caret could be just to the right of the text.
4228         endSelect =  visiblePositionForContentPoint(endX - 1, endY);
4229         Position newEnd = endSelect.deepEquivalent();
4230         if (!newEnd.isNull()) {
4231             end = newEnd;
4232         }
4233     }
4234     Vector<VisibleSelection> ranges;
4235     if (!start.isNull() && !end.isNull()) {
4236         if (comparePositions(start, end) > 0) {
4237             swap(start, end); // RTL start/end positions may be swapped
4238         }
4239         Position nextRangeStart = start;
4240         Position previousRangeEnd;
4241         do {
4242             VisibleSelection selection(nextRangeStart, end);
4243             ranges.append(selection);
4244             previousRangeEnd = selection.end();
4245             nextRangeStart = nextCandidate(previousRangeEnd);
4246         } while (comparePositions(previousRangeEnd, end) < 0);
4247     }
4248     return ranges;
4249 }
4250 
deleteText(int startX,int startY,int endX,int endY)4251 void WebViewCore::deleteText(int startX, int startY, int endX, int endY)
4252 {
4253     Vector<VisibleSelection> ranges =
4254             getTextRanges(startX, startY, endX, endY);
4255 
4256     EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
4257             m_mainFrame->editor()->client());
4258     client->setUiGeneratedSelectionChange(true);
4259 
4260     SelectionController* selector = m_mainFrame->selection();
4261     for (size_t i = 0; i < ranges.size(); i++) {
4262         const VisibleSelection& selection = ranges[i];
4263         if (selection.isContentEditable()) {
4264             selector->setSelection(selection, CharacterGranularity);
4265             Document* document = selection.start().anchorNode()->document();
4266             WebCore::TypingCommand::deleteSelection(document, 0);
4267         }
4268     }
4269     client->setUiGeneratedSelectionChange(false);
4270 }
4271 
insertText(const WTF::String & text)4272 void WebViewCore::insertText(const WTF::String &text)
4273 {
4274     WebCore::Node* focus = currentFocus();
4275     if (!focus || !isTextInput(focus))
4276         return;
4277 
4278     Document* document = focus->document();
4279 
4280     EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
4281             m_mainFrame->editor()->client());
4282     if (!client)
4283         return;
4284     client->setUiGeneratedSelectionChange(true);
4285     WebCore::TypingCommand::insertText(document, text,
4286             TypingCommand::PreventSpellChecking);
4287     client->setUiGeneratedSelectionChange(false);
4288 }
4289 
resetFindOnPage()4290 void WebViewCore::resetFindOnPage()
4291 {
4292     m_searchText.truncate(0);
4293     m_matchCount = 0;
4294     m_activeMatchIndex = 0;
4295     m_activeMatch = 0;
4296 }
4297 
findTextOnPage(const WTF::String & text)4298 int WebViewCore::findTextOnPage(const WTF::String &text)
4299 {
4300     resetFindOnPage(); // reset even if parameters are bad
4301 
4302     WebCore::Frame* frame = m_mainFrame;
4303     if (!frame)
4304         return 0;
4305 
4306     m_searchText = text;
4307     FindOptions findOptions = WebCore::CaseInsensitive;
4308 
4309     do {
4310         frame->document()->markers()->removeMarkers(DocumentMarker::TextMatch);
4311         m_matchCount += frame->editor()->countMatchesForText(text, findOptions,
4312             0, true);
4313         frame->editor()->setMarkedTextMatchesAreHighlighted(true);
4314         frame = frame->tree()->traverseNextWithWrap(false);
4315     } while (frame);
4316     m_activeMatchIndex = m_matchCount - 1; // prime first findNext
4317     return m_matchCount;
4318 }
4319 
findNextOnPage(bool forward)4320 int WebViewCore::findNextOnPage(bool forward)
4321 {
4322     if (!m_mainFrame)
4323         return -1;
4324     if (!m_matchCount)
4325         return -1;
4326 
4327     EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
4328         m_mainFrame->editor()->client());
4329     client->setUiGeneratedSelectionChange(true);
4330 
4331     // Clear previous active match.
4332     if (m_activeMatch) {
4333         m_mainFrame->document()->markers()->setMarkersActive(
4334             m_activeMatch.get(), false);
4335     }
4336 
4337     FindOptions findOptions = WebCore::CaseInsensitive
4338         | WebCore::StartInSelection | WebCore::WrapAround;
4339     if (!forward)
4340         findOptions |= WebCore::Backwards;
4341 
4342     // Start from the previous active match.
4343     if (m_activeMatch) {
4344         m_mainFrame->selection()->setSelection(m_activeMatch.get());
4345     }
4346 
4347     bool found = m_mainFrame->editor()->findString(m_searchText, findOptions);
4348     if (found) {
4349         VisibleSelection selection(m_mainFrame->selection()->selection());
4350         if (selection.isNone() || selection.start() == selection.end()) {
4351             // Temporary workaround for findString() refusing to select text
4352             // marked "-webkit-user-select: none".
4353             m_activeMatchIndex = 0;
4354             m_activeMatch = 0;
4355         } else {
4356             // Mark current match "active".
4357             if (forward) {
4358                 ++m_activeMatchIndex;
4359                 if (m_activeMatchIndex == m_matchCount)
4360                     m_activeMatchIndex = 0;
4361             } else {
4362                 if (m_activeMatchIndex == 0)
4363                     m_activeMatchIndex = m_matchCount;
4364                 --m_activeMatchIndex;
4365             }
4366             m_activeMatch = selection.firstRange();
4367             m_mainFrame->document()->markers()->setMarkersActive(
4368                 m_activeMatch.get(), true);
4369             m_mainFrame->selection()->revealSelection(
4370                 ScrollAlignment::alignCenterIfNeeded, true);
4371         }
4372     }
4373 
4374     // Clear selection so it doesn't display.
4375     m_mainFrame->selection()->clear();
4376     client->setUiGeneratedSelectionChange(false);
4377     return m_activeMatchIndex;
4378 }
4379 
getText(int startX,int startY,int endX,int endY)4380 String WebViewCore::getText(int startX, int startY, int endX, int endY)
4381 {
4382     String text;
4383 
4384     Vector<VisibleSelection> ranges =
4385             getTextRanges(startX, startY, endX, endY);
4386 
4387     for (size_t i = 0; i < ranges.size(); i++) {
4388         const VisibleSelection& selection = ranges[i];
4389         if (selection.isRange()) {
4390             PassRefPtr<Range> range = selection.firstRange();
4391             String textInRange = range->text();
4392             if (textInRange.length() > 0) {
4393                 if (text.length() > 0)
4394                     text.append('\n');
4395                 text.append(textInRange);
4396             }
4397         }
4398     }
4399 
4400     return text;
4401 }
4402 
4403 /**
4404  * Read the persistent locale.
4405  */
getLocale(String & language,String & region)4406 void WebViewCore::getLocale(String& language, String& region)
4407 {
4408     char propLang[PROPERTY_VALUE_MAX], propRegn[PROPERTY_VALUE_MAX];
4409 
4410     property_get("persist.sys.language", propLang, "");
4411     property_get("persist.sys.country", propRegn, "");
4412     if (*propLang == 0 && *propRegn == 0) {
4413         /* Set to ro properties, default is en_US */
4414         property_get("ro.product.locale.language", propLang, "en");
4415         property_get("ro.product.locale.region", propRegn, "US");
4416     }
4417     language = String(propLang, 2);
4418     region = String(propRegn, 2);
4419 }
4420 
4421 // generate bcp47 identifier for the supplied language/region
toLanguageTag(char * output,size_t outSize,const String & language,const String & region)4422 static void toLanguageTag(char* output, size_t outSize, const String& language,
4423     const String& region) {
4424     if (output == NULL || outSize <= 0)
4425         return;
4426     String locale = language;
4427     locale.append('_');
4428     locale.append(region);
4429     char canonicalChars[ULOC_FULLNAME_CAPACITY];
4430     UErrorCode uErr = U_ZERO_ERROR;
4431     uloc_canonicalize(locale.ascii().data(), canonicalChars,
4432         ULOC_FULLNAME_CAPACITY, &uErr);
4433     if (U_SUCCESS(uErr)) {
4434         char likelyChars[ULOC_FULLNAME_CAPACITY];
4435         uErr = U_ZERO_ERROR;
4436         uloc_addLikelySubtags(canonicalChars, likelyChars,
4437             ULOC_FULLNAME_CAPACITY, &uErr);
4438         if (U_SUCCESS(uErr)) {
4439             uErr = U_ZERO_ERROR;
4440             uloc_toLanguageTag(likelyChars, output, outSize, FALSE, &uErr);
4441             if (U_SUCCESS(uErr)) {
4442                 return;
4443             } else {
4444                 ALOGD("uloc_toLanguageTag(\"%s\") failed: %s", likelyChars,
4445                     u_errorName(uErr));
4446             }
4447         } else {
4448             ALOGD("uloc_addLikelySubtags(\"%s\") failed: %s", canonicalChars,
4449                 u_errorName(uErr));
4450         }
4451     } else {
4452         ALOGD("uloc_canonicalize(\"%s\") failed: %s", locale.ascii().data(),
4453             u_errorName(uErr));
4454     }
4455     // unable to build a proper language identifier
4456     output[0] = '\0';
4457 }
4458 
updateLocale()4459 void WebViewCore::updateLocale()
4460 {
4461     static String prevLang;
4462     static String prevRegn;
4463     String language;
4464     String region;
4465 
4466     getLocale(language, region);
4467 
4468     if ((language != prevLang) || (region != prevRegn)) {
4469         prevLang = language;
4470         prevRegn = region;
4471         GlyphPageTreeNode::resetRoots();
4472         fontCache()->invalidate();
4473         char langTag[ULOC_FULLNAME_CAPACITY];
4474         toLanguageTag(langTag, ULOC_FULLNAME_CAPACITY, language, region);
4475         FontPlatformData::setDefaultLanguage(langTag);
4476     }
4477 }
4478 
4479 //----------------------------------------------------------------------
4480 // Native JNI methods
4481 //----------------------------------------------------------------------
RevealSelection(JNIEnv * env,jobject obj,jint nativeClass)4482 static void RevealSelection(JNIEnv* env, jobject obj, jint nativeClass)
4483 {
4484     reinterpret_cast<WebViewCore*>(nativeClass)->revealSelection();
4485 }
4486 
RequestLabel(JNIEnv * env,jobject obj,jint nativeClass,int framePointer,int nodePointer)4487 static jstring RequestLabel(JNIEnv* env, jobject obj, jint nativeClass,
4488         int framePointer, int nodePointer)
4489 {
4490     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4491     return wtfStringToJstring(env, viewImpl->requestLabel(
4492             (WebCore::Frame*) framePointer, (WebCore::Node*) nodePointer));
4493 }
4494 
ClearContent(JNIEnv * env,jobject obj,jint nativeClass)4495 static void ClearContent(JNIEnv* env, jobject obj, jint nativeClass)
4496 {
4497     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4498     viewImpl->clearContent();
4499 }
4500 
SetSize(JNIEnv * env,jobject obj,jint nativeClass,jint width,jint height,jint textWrapWidth,jfloat scale,jint screenWidth,jint screenHeight,jint anchorX,jint anchorY,jboolean ignoreHeight)4501 static void SetSize(JNIEnv* env, jobject obj, jint nativeClass, jint width,
4502         jint height, jint textWrapWidth, jfloat scale, jint screenWidth,
4503         jint screenHeight, jint anchorX, jint anchorY, jboolean ignoreHeight)
4504 {
4505     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4506     ALOGV("webviewcore::nativeSetSize(%u %u)\n viewImpl: %p", (unsigned)width, (unsigned)height, viewImpl);
4507     ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSetSize");
4508     viewImpl->setSizeScreenWidthAndScale(width, height, textWrapWidth, scale,
4509             screenWidth, screenHeight, anchorX, anchorY, ignoreHeight);
4510 }
4511 
SetScrollOffset(JNIEnv * env,jobject obj,jint nativeClass,jboolean sendScrollEvent,jint x,jint y)4512 static void SetScrollOffset(JNIEnv* env, jobject obj, jint nativeClass,
4513         jboolean sendScrollEvent, jint x, jint y)
4514 {
4515     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4516     ALOG_ASSERT(viewImpl, "need viewImpl");
4517 
4518     viewImpl->setScrollOffset(sendScrollEvent, x, y);
4519 }
4520 
SetGlobalBounds(JNIEnv * env,jobject obj,jint nativeClass,jint x,jint y,jint h,jint v)4521 static void SetGlobalBounds(JNIEnv* env, jobject obj, jint nativeClass,
4522         jint x, jint y, jint h, jint v)
4523 {
4524     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4525     ALOG_ASSERT(viewImpl, "need viewImpl");
4526 
4527     viewImpl->setGlobalBounds(x, y, h, v);
4528 }
4529 
Key(JNIEnv * env,jobject obj,jint nativeClass,jint keyCode,jint unichar,jint repeatCount,jboolean isShift,jboolean isAlt,jboolean isSym,jboolean isDown)4530 static jboolean Key(JNIEnv* env, jobject obj, jint nativeClass, jint keyCode,
4531         jint unichar, jint repeatCount, jboolean isShift, jboolean isAlt,
4532         jboolean isSym, jboolean isDown)
4533 {
4534     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4535     return viewImpl->key(PlatformKeyboardEvent(keyCode,
4536         unichar, repeatCount, isDown, isShift, isAlt, isSym));
4537 }
4538 
SetInitialFocus(JNIEnv * env,jobject obj,jint nativeClass,jint keyDirection)4539 static void SetInitialFocus(JNIEnv* env, jobject obj, jint nativeClass,
4540                             jint keyDirection)
4541 {
4542     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4543     viewImpl->setInitialFocus(PlatformKeyboardEvent(keyDirection,
4544             0, 0, false, false, false, false));
4545 }
4546 
ContentInvalidateAll(JNIEnv * env,jobject obj,jint nativeClass)4547 static void ContentInvalidateAll(JNIEnv* env, jobject obj, jint nativeClass)
4548 {
4549     reinterpret_cast<WebViewCore*>(nativeClass)->contentInvalidateAll();
4550 }
4551 
DeleteSelection(JNIEnv * env,jobject obj,jint nativeClass,jint start,jint end,jint textGeneration)4552 static void DeleteSelection(JNIEnv* env, jobject obj, jint nativeClass,
4553         jint start, jint end, jint textGeneration)
4554 {
4555     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4556     viewImpl->deleteSelection(start, end, textGeneration);
4557 }
4558 
SetSelection(JNIEnv * env,jobject obj,jint nativeClass,jint start,jint end)4559 static void SetSelection(JNIEnv* env, jobject obj, jint nativeClass,
4560         jint start, jint end)
4561 {
4562     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4563     viewImpl->setSelection(start, end);
4564 }
4565 
ModifySelection(JNIEnv * env,jobject obj,jint nativeClass,jint direction,jint granularity)4566 static jstring ModifySelection(JNIEnv* env, jobject obj, jint nativeClass,
4567         jint direction, jint granularity)
4568 {
4569     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4570     String selectionString = viewImpl->modifySelection(direction, granularity);
4571     return wtfStringToJstring(env, selectionString);
4572 }
4573 
ReplaceTextfieldText(JNIEnv * env,jobject obj,jint nativeClass,jint oldStart,jint oldEnd,jstring replace,jint start,jint end,jint textGeneration)4574 static void ReplaceTextfieldText(JNIEnv* env, jobject obj, jint nativeClass,
4575     jint oldStart, jint oldEnd, jstring replace, jint start, jint end,
4576     jint textGeneration)
4577 {
4578     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4579     WTF::String webcoreString = jstringToWtfString(env, replace);
4580     viewImpl->replaceTextfieldText(oldStart,
4581             oldEnd, webcoreString, start, end, textGeneration);
4582 }
4583 
PassToJs(JNIEnv * env,jobject obj,jint nativeClass,jint generation,jstring currentText,jint keyCode,jint keyValue,jboolean down,jboolean cap,jboolean fn,jboolean sym)4584 static void PassToJs(JNIEnv* env, jobject obj, jint nativeClass,
4585     jint generation, jstring currentText, jint keyCode,
4586     jint keyValue, jboolean down, jboolean cap, jboolean fn, jboolean sym)
4587 {
4588     WTF::String current = jstringToWtfString(env, currentText);
4589     reinterpret_cast<WebViewCore*>(nativeClass)->passToJs(generation, current,
4590         PlatformKeyboardEvent(keyCode, keyValue, 0, down, cap, fn, sym));
4591 }
4592 
ScrollFocusedTextInput(JNIEnv * env,jobject obj,jint nativeClass,jfloat xPercent,jint y)4593 static void ScrollFocusedTextInput(JNIEnv* env, jobject obj, jint nativeClass,
4594         jfloat xPercent, jint y)
4595 {
4596     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4597     viewImpl->scrollFocusedTextInput(xPercent, y);
4598 }
4599 
SetFocusControllerActive(JNIEnv * env,jobject obj,jint nativeClass,jboolean active)4600 static void SetFocusControllerActive(JNIEnv* env, jobject obj, jint nativeClass,
4601         jboolean active)
4602 {
4603     ALOGV("webviewcore::nativeSetFocusControllerActive()\n");
4604     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4605     ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSetFocusControllerActive");
4606     viewImpl->setFocusControllerActive(active);
4607 }
4608 
SaveDocumentState(JNIEnv * env,jobject obj,jint nativeClass)4609 static void SaveDocumentState(JNIEnv* env, jobject obj, jint nativeClass)
4610 {
4611     ALOGV("webviewcore::nativeSaveDocumentState()\n");
4612     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4613     ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSaveDocumentState");
4614     viewImpl->saveDocumentState(viewImpl->focusedFrame());
4615 }
4616 
addVisitedLink(const UChar * string,int length)4617 void WebViewCore::addVisitedLink(const UChar* string, int length)
4618 {
4619     if (m_groupForVisitedLinks)
4620         m_groupForVisitedLinks->addVisitedLink(string, length);
4621 }
4622 
NotifyAnimationStarted(JNIEnv * env,jobject obj,jint nativeClass)4623 static void NotifyAnimationStarted(JNIEnv* env, jobject obj, jint nativeClass)
4624 {
4625     WebViewCore* viewImpl = (WebViewCore*) nativeClass;
4626     viewImpl->notifyAnimationStarted();
4627 }
4628 
RecordContent(JNIEnv * env,jobject obj,jint nativeClass,jobject pt)4629 static jint RecordContent(JNIEnv* env, jobject obj, jint nativeClass, jobject pt)
4630 {
4631     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4632     SkIPoint nativePt;
4633     BaseLayerAndroid* result = viewImpl->recordContent(&nativePt);
4634     GraphicsJNI::ipoint_to_jpoint(nativePt, env, pt);
4635     return reinterpret_cast<jint>(result);
4636 }
4637 
SendListBoxChoice(JNIEnv * env,jobject obj,jint nativeClass,jint choice)4638 static void SendListBoxChoice(JNIEnv* env, jobject obj, jint nativeClass,
4639         jint choice)
4640 {
4641     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4642     ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoice");
4643     viewImpl->popupReply(choice);
4644 }
4645 
4646 // Set aside a predetermined amount of space in which to place the listbox
4647 // choices, to avoid unnecessary allocations.
4648 // The size here is arbitrary.  We want the size to be at least as great as the
4649 // number of items in the average multiple-select listbox.
4650 #define PREPARED_LISTBOX_STORAGE 10
4651 
SendListBoxChoices(JNIEnv * env,jobject obj,jint nativeClass,jbooleanArray jArray,jint size)4652 static void SendListBoxChoices(JNIEnv* env, jobject obj, jint nativeClass,
4653         jbooleanArray jArray, jint size)
4654 {
4655     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4656     ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices");
4657     jboolean* ptrArray = env->GetBooleanArrayElements(jArray, 0);
4658     SkAutoSTMalloc<PREPARED_LISTBOX_STORAGE, int> storage(size);
4659     int* array = storage.get();
4660     int count = 0;
4661     for (int i = 0; i < size; i++) {
4662         if (ptrArray[i]) {
4663             array[count++] = i;
4664         }
4665     }
4666     env->ReleaseBooleanArrayElements(jArray, ptrArray, JNI_ABORT);
4667     viewImpl->popupReply(array, count);
4668 }
4669 
4670 // TODO: Move this to WebView.cpp since it is only needed there
FindAddress(JNIEnv * env,jobject obj,jstring addr,jboolean caseInsensitive)4671 static jstring FindAddress(JNIEnv* env, jobject obj, jstring addr,
4672         jboolean caseInsensitive)
4673 {
4674     if (!addr)
4675         return 0;
4676     int length = env->GetStringLength(addr);
4677     if (!length)
4678         return 0;
4679     const jchar* addrChars = env->GetStringChars(addr, 0);
4680     size_t start, end;
4681     AddressDetector detector;
4682     bool success = detector.FindContent(addrChars, addrChars + length, &start, &end);
4683     jstring ret = 0;
4684     if (success)
4685         ret = env->NewString(addrChars + start, end - start);
4686     env->ReleaseStringChars(addr, addrChars);
4687     return ret;
4688 }
4689 
HandleTouchEvent(JNIEnv * env,jobject obj,jint nativeClass,jint action,jintArray idArray,jintArray xArray,jintArray yArray,jint count,jint actionIndex,jint metaState)4690 static jint HandleTouchEvent(JNIEnv* env, jobject obj, jint nativeClass,
4691         jint action, jintArray idArray, jintArray xArray, jintArray yArray,
4692         jint count, jint actionIndex, jint metaState)
4693 {
4694     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4695     ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4696     jint* ptrIdArray = env->GetIntArrayElements(idArray, 0);
4697     jint* ptrXArray = env->GetIntArrayElements(xArray, 0);
4698     jint* ptrYArray = env->GetIntArrayElements(yArray, 0);
4699     Vector<int> ids(count);
4700     Vector<IntPoint> points(count);
4701     for (int c = 0; c < count; c++) {
4702         ids[c] = ptrIdArray[c];
4703         points[c].setX(ptrXArray[c]);
4704         points[c].setY(ptrYArray[c]);
4705     }
4706     env->ReleaseIntArrayElements(idArray, ptrIdArray, JNI_ABORT);
4707     env->ReleaseIntArrayElements(xArray, ptrXArray, JNI_ABORT);
4708     env->ReleaseIntArrayElements(yArray, ptrYArray, JNI_ABORT);
4709 
4710     return viewImpl->handleTouchEvent(action, ids, points, actionIndex, metaState);
4711 }
4712 
MouseClick(JNIEnv * env,jobject obj,jint nativeClass)4713 static bool MouseClick(JNIEnv* env, jobject obj, jint nativeClass)
4714 {
4715     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4716     return viewImpl->performMouseClick();
4717 }
4718 
RetrieveHref(JNIEnv * env,jobject obj,jint nativeClass,jint x,jint y)4719 static jstring RetrieveHref(JNIEnv* env, jobject obj, jint nativeClass,
4720         jint x, jint y)
4721 {
4722     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4723     ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4724     WTF::String result = viewImpl->retrieveHref(x, y);
4725     if (!result.isEmpty())
4726         return wtfStringToJstring(env, result);
4727     return 0;
4728 }
4729 
RetrieveAnchorText(JNIEnv * env,jobject obj,jint nativeClass,jint x,jint y)4730 static jstring RetrieveAnchorText(JNIEnv* env, jobject obj, jint nativeClass,
4731         jint x, jint y)
4732 {
4733     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4734     ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4735     WTF::String result = viewImpl->retrieveAnchorText(x, y);
4736     if (!result.isEmpty())
4737         return wtfStringToJstring(env, result);
4738     return 0;
4739 }
4740 
RetrieveImageSource(JNIEnv * env,jobject obj,jint nativeClass,jint x,jint y)4741 static jstring RetrieveImageSource(JNIEnv* env, jobject obj, jint nativeClass,
4742         jint x, jint y)
4743 {
4744     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4745     WTF::String result = viewImpl->retrieveImageSource(x, y);
4746     return !result.isEmpty() ? wtfStringToJstring(env, result) : 0;
4747 }
4748 
MoveMouse(JNIEnv * env,jobject obj,jint nativeClass,jint x,jint y)4749 static void MoveMouse(JNIEnv* env, jobject obj, jint nativeClass, jint x, jint y)
4750 {
4751     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4752     ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4753     viewImpl->moveMouse(x, y);
4754 }
4755 
GetContentMinPrefWidth(JNIEnv * env,jobject obj,jint nativeClass)4756 static jint GetContentMinPrefWidth(JNIEnv* env, jobject obj, jint nativeClass)
4757 {
4758     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4759     ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4760 
4761     WebCore::Frame* frame = viewImpl->mainFrame();
4762     if (frame) {
4763         WebCore::Document* document = frame->document();
4764         if (document) {
4765             WebCore::RenderObject* renderer = document->renderer();
4766             if (renderer && renderer->isRenderView()) {
4767                 return renderer->minPreferredLogicalWidth();
4768             }
4769         }
4770     }
4771     return 0;
4772 }
4773 
SetViewportSettingsFromNative(JNIEnv * env,jobject obj,jint nativeClass)4774 static void SetViewportSettingsFromNative(JNIEnv* env, jobject obj,
4775         jint nativeClass)
4776 {
4777     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4778     ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4779 
4780     WebCore::Settings* s = viewImpl->mainFrame()->page()->settings();
4781     if (!s)
4782         return;
4783 
4784 #ifdef ANDROID_META_SUPPORT
4785     env->SetIntField(obj, gWebViewCoreFields.m_viewportWidth, s->viewportWidth());
4786     env->SetIntField(obj, gWebViewCoreFields.m_viewportHeight, s->viewportHeight());
4787     env->SetIntField(obj, gWebViewCoreFields.m_viewportInitialScale, s->viewportInitialScale());
4788     env->SetIntField(obj, gWebViewCoreFields.m_viewportMinimumScale, s->viewportMinimumScale());
4789     env->SetIntField(obj, gWebViewCoreFields.m_viewportMaximumScale, s->viewportMaximumScale());
4790     env->SetBooleanField(obj, gWebViewCoreFields.m_viewportUserScalable, s->viewportUserScalable());
4791     env->SetIntField(obj, gWebViewCoreFields.m_viewportDensityDpi, s->viewportTargetDensityDpi());
4792 #endif
4793 }
4794 
SetBackgroundColor(JNIEnv * env,jobject obj,jint nativeClass,jint color)4795 static void SetBackgroundColor(JNIEnv* env, jobject obj, jint nativeClass,
4796         jint color)
4797 {
4798     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4799     ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4800 
4801     viewImpl->setBackgroundColor((SkColor) color);
4802 }
4803 
DumpDomTree(JNIEnv * env,jobject obj,jint nativeClass,jboolean useFile)4804 static void DumpDomTree(JNIEnv* env, jobject obj, jint nativeClass,
4805         jboolean useFile)
4806 {
4807     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4808     ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4809 
4810     viewImpl->dumpDomTree(useFile);
4811 }
4812 
DumpRenderTree(JNIEnv * env,jobject obj,jint nativeClass,jboolean useFile)4813 static void DumpRenderTree(JNIEnv* env, jobject obj, jint nativeClass,
4814         jboolean useFile)
4815 {
4816     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4817     ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4818 
4819     viewImpl->dumpRenderTree(useFile);
4820 }
4821 
SetJsFlags(JNIEnv * env,jobject obj,jint nativeClass,jstring flags)4822 static void SetJsFlags(JNIEnv* env, jobject obj, jint nativeClass, jstring flags)
4823 {
4824     WTF::String flagsString = jstringToWtfString(env, flags);
4825     WTF::CString utf8String = flagsString.utf8();
4826     WebCore::ScriptController::setFlags(utf8String.data(), utf8String.length());
4827 }
4828 
4829 
4830 // Called from the Java side to set a new quota for the origin or new appcache
4831 // max size in response to a notification that the original quota was exceeded or
4832 // that the appcache has reached its maximum size.
SetNewStorageLimit(JNIEnv * env,jobject obj,jint nativeClass,jlong quota)4833 static void SetNewStorageLimit(JNIEnv* env, jobject obj, jint nativeClass,
4834         jlong quota)
4835 {
4836 #if ENABLE(DATABASE) || ENABLE(OFFLINE_WEB_APPLICATIONS)
4837     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4838     Frame* frame = viewImpl->mainFrame();
4839 
4840     // The main thread is blocked awaiting this response, so now we can wake it
4841     // up.
4842     ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client());
4843     chromeC->wakeUpMainThreadWithNewQuota(quota);
4844 #endif
4845 }
4846 
4847 // Called from Java to provide a Geolocation permission state for the specified origin.
GeolocationPermissionsProvide(JNIEnv * env,jobject obj,jint nativeClass,jstring origin,jboolean allow,jboolean remember)4848 static void GeolocationPermissionsProvide(JNIEnv* env, jobject obj,
4849         jint nativeClass, jstring origin, jboolean allow, jboolean remember)
4850 {
4851     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4852     viewImpl->geolocationManager()->provideRealClientPermissionState(jstringToWtfString(env, origin), allow, remember);
4853 }
4854 
RegisterURLSchemeAsLocal(JNIEnv * env,jobject obj,jint nativeClass,jstring scheme)4855 static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jint nativeClass,
4856         jstring scheme)
4857 {
4858     WebCore::SchemeRegistry::registerURLSchemeAsLocal(jstringToWtfString(env, scheme));
4859 }
4860 
Pause(JNIEnv * env,jobject obj,jint nativeClass)4861 static void Pause(JNIEnv* env, jobject obj, jint nativeClass)
4862 {
4863     // This is called for the foreground tab when the browser is put to the
4864     // background (and also for any tab when it is put to the background of the
4865     // browser). The browser can only be killed by the system when it is in the
4866     // background, so saving the Geolocation permission state now ensures that
4867     // is maintained when the browser is killed.
4868     GeolocationPermissions::maybeStorePermanentPermissions();
4869 
4870     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4871     Frame* mainFrame = viewImpl->mainFrame();
4872     if (mainFrame)
4873         mainFrame->settings()->setMinDOMTimerInterval(BACKGROUND_TIMER_INTERVAL);
4874 
4875     viewImpl->deviceMotionAndOrientationManager()->maybeSuspendClients();
4876     viewImpl->geolocationManager()->suspendRealClient();
4877 
4878     ANPEvent event;
4879     SkANP::InitEvent(&event, kLifecycle_ANPEventType);
4880     event.data.lifecycle.action = kPause_ANPLifecycleAction;
4881     viewImpl->sendPluginEvent(event);
4882 }
4883 
Resume(JNIEnv * env,jobject obj,jint nativeClass)4884 static void Resume(JNIEnv* env, jobject obj, jint nativeClass)
4885 {
4886     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4887     Frame* mainFrame = viewImpl->mainFrame();
4888     if (mainFrame)
4889         mainFrame->settings()->setMinDOMTimerInterval(FOREGROUND_TIMER_INTERVAL);
4890 
4891     viewImpl->deviceMotionAndOrientationManager()->maybeResumeClients();
4892     viewImpl->geolocationManager()->resumeRealClient();
4893 
4894     ANPEvent event;
4895     SkANP::InitEvent(&event, kLifecycle_ANPEventType);
4896     event.data.lifecycle.action = kResume_ANPLifecycleAction;
4897     viewImpl->sendPluginEvent(event);
4898 }
4899 
FreeMemory(JNIEnv * env,jobject obj,jint nativeClass)4900 static void FreeMemory(JNIEnv* env, jobject obj, jint nativeClass)
4901 {
4902     ANPEvent event;
4903     SkANP::InitEvent(&event, kLifecycle_ANPEventType);
4904     event.data.lifecycle.action = kFreeMemory_ANPLifecycleAction;
4905     reinterpret_cast<WebViewCore*>(nativeClass)->sendPluginEvent(event);
4906 }
4907 
ProvideVisitedHistory(JNIEnv * env,jobject obj,jint nativeClass,jobject hist)4908 static void ProvideVisitedHistory(JNIEnv* env, jobject obj, jint nativeClass,
4909         jobject hist)
4910 {
4911     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4912     ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4913 
4914     jobjectArray array = static_cast<jobjectArray>(hist);
4915 
4916     jsize len = env->GetArrayLength(array);
4917     for (jsize i = 0; i < len; i++) {
4918         jstring item = static_cast<jstring>(env->GetObjectArrayElement(array, i));
4919         const UChar* str = static_cast<const UChar*>(env->GetStringChars(item, 0));
4920         jsize len = env->GetStringLength(item);
4921         viewImpl->addVisitedLink(str, len);
4922         env->ReleaseStringChars(item, str);
4923         env->DeleteLocalRef(item);
4924     }
4925 }
4926 
PluginSurfaceReady(JNIEnv * env,jobject obj,jint nativeClass)4927 static void PluginSurfaceReady(JNIEnv* env, jobject obj, jint nativeClass)
4928 {
4929     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4930     if (viewImpl)
4931         viewImpl->sendPluginSurfaceReady();
4932 }
4933 
4934 // Notification from the UI thread that the plugin's full-screen surface has been discarded
FullScreenPluginHidden(JNIEnv * env,jobject obj,jint nativeClass,jint npp)4935 static void FullScreenPluginHidden(JNIEnv* env, jobject obj, jint nativeClass,
4936         jint npp)
4937 {
4938     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4939     PluginWidgetAndroid* plugin = viewImpl->getPluginWidget((NPP)npp);
4940     if (plugin)
4941         plugin->exitFullScreen(false);
4942 }
4943 
HitTest(JNIEnv * env,jobject obj,jint nativeClass,jint x,jint y,jint slop,jboolean doMoveMouse)4944 static jobject HitTest(JNIEnv* env, jobject obj, jint nativeClass, jint x,
4945                        jint y, jint slop, jboolean doMoveMouse)
4946 {
4947     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4948     if (!viewImpl)
4949         return 0;
4950     AndroidHitTestResult result = viewImpl->hitTestAtPoint(x, y, slop, doMoveMouse);
4951     return result.createJavaObject(env);
4952 }
4953 
AutoFillForm(JNIEnv * env,jobject obj,jint nativeClass,jint queryId)4954 static void AutoFillForm(JNIEnv* env, jobject obj, jint nativeClass,
4955         jint queryId)
4956 {
4957 #if ENABLE(WEB_AUTOFILL)
4958     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4959     if (!viewImpl)
4960         return;
4961 
4962     WebCore::Frame* frame = viewImpl->mainFrame();
4963     if (frame) {
4964         EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(frame->page()->editorClient());
4965         WebAutofill* autoFill = editorC->getAutofill();
4966         autoFill->fillFormFields(queryId);
4967     }
4968 #endif
4969 }
4970 
CloseIdleConnections(JNIEnv * env,jobject obj,jint nativeClass)4971 static void CloseIdleConnections(JNIEnv* env, jobject obj, jint nativeClass)
4972 {
4973     WebCache::get(true)->closeIdleConnections();
4974     WebCache::get(false)->closeIdleConnections();
4975 }
4976 
nativeCertTrustChanged(JNIEnv * env,jobject obj)4977 static void nativeCertTrustChanged(JNIEnv *env, jobject obj)
4978 {
4979     WebCache::get(true)->certTrustChanged();
4980     WebCache::get(false)->certTrustChanged();
4981 }
4982 
ScrollRenderLayer(JNIEnv * env,jobject obj,jint nativeClass,jint layer,jobject jRect)4983 static void ScrollRenderLayer(JNIEnv* env, jobject obj, jint nativeClass,
4984         jint layer, jobject jRect)
4985 {
4986     SkRect rect;
4987     GraphicsJNI::jrect_to_rect(env, jRect, &rect);
4988     reinterpret_cast<WebViewCore*>(nativeClass)->scrollRenderLayer(layer, rect);
4989 }
4990 
DeleteText(JNIEnv * env,jobject obj,jint nativeClass,jint startX,jint startY,jint endX,jint endY)4991 static void DeleteText(JNIEnv* env, jobject obj, jint nativeClass,
4992         jint startX, jint startY, jint endX, jint endY)
4993 {
4994     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4995     viewImpl->deleteText(startX, startY, endX, endY);
4996 }
4997 
InsertText(JNIEnv * env,jobject obj,jint nativeClass,jstring text)4998 static void InsertText(JNIEnv* env, jobject obj, jint nativeClass,
4999         jstring text)
5000 {
5001     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5002     WTF::String wtfText = jstringToWtfString(env, text);
5003     viewImpl->insertText(wtfText);
5004 }
5005 
GetText(JNIEnv * env,jobject obj,jint nativeClass,jint startX,jint startY,jint endX,jint endY)5006 static jobject GetText(JNIEnv* env, jobject obj, jint nativeClass,
5007         jint startX, jint startY, jint endX, jint endY)
5008 {
5009     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5010     WTF::String text = viewImpl->getText(startX, startY, endX, endY);
5011     return text.isEmpty() ? 0 : wtfStringToJstring(env, text);
5012 }
5013 
SelectText(JNIEnv * env,jobject obj,jint nativeClass,jint handleId,jint x,jint y)5014 static void SelectText(JNIEnv* env, jobject obj, jint nativeClass,
5015         jint handleId, jint x, jint y)
5016 {
5017     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5018     viewImpl->selectText(static_cast<SelectText::HandleId>(handleId), x, y);
5019 }
5020 
ClearSelection(JNIEnv * env,jobject obj,jint nativeClass)5021 static void ClearSelection(JNIEnv* env, jobject obj, jint nativeClass)
5022 {
5023     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5024     viewImpl->focusedFrame()->selection()->clear();
5025 }
5026 
SelectWordAt(JNIEnv * env,jobject obj,jint nativeClass,jint x,jint y)5027 static bool SelectWordAt(JNIEnv* env, jobject obj, jint nativeClass, jint x, jint y)
5028 {
5029     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5030     return viewImpl->selectWordAt(x, y);
5031 }
5032 
SelectAll(JNIEnv * env,jobject obj,jint nativeClass)5033 static void SelectAll(JNIEnv* env, jobject obj, jint nativeClass)
5034 {
5035     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5036     viewImpl->focusedFrame()->selection()->selectAll();
5037 }
5038 
FindAll(JNIEnv * env,jobject obj,jint nativeClass,jstring text)5039 static int FindAll(JNIEnv* env, jobject obj, jint nativeClass,
5040         jstring text)
5041 {
5042     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5043     WTF::String wtfText = jstringToWtfString(env, text);
5044     return viewImpl->findTextOnPage(wtfText);
5045 }
5046 
FindNext(JNIEnv * env,jobject obj,jint nativeClass,jboolean forward)5047 static int FindNext(JNIEnv* env, jobject obj, jint nativeClass,
5048         jboolean forward)
5049 {
5050     WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5051     return viewImpl->findNextOnPage(forward);
5052 }
5053 
5054 // ----------------------------------------------------------------------------
5055 
5056 /*
5057  * JNI registration.
5058  */
5059 static JNINativeMethod gJavaWebViewCoreMethods[] = {
5060     { "nativeClearContent", "(I)V",
5061             (void*) ClearContent },
5062     { "nativeKey", "(IIIIZZZZ)Z",
5063         (void*) Key },
5064     { "nativeContentInvalidateAll", "(I)V",
5065         (void*) ContentInvalidateAll },
5066     { "nativeSendListBoxChoices", "(I[ZI)V",
5067         (void*) SendListBoxChoices },
5068     { "nativeSendListBoxChoice", "(II)V",
5069         (void*) SendListBoxChoice },
5070     { "nativeSetSize", "(IIIIFIIIIZ)V",
5071         (void*) SetSize },
5072     { "nativeSetScrollOffset", "(IZII)V",
5073         (void*) SetScrollOffset },
5074     { "nativeSetGlobalBounds", "(IIIII)V",
5075         (void*) SetGlobalBounds },
5076     { "nativeSetSelection", "(III)V",
5077         (void*) SetSelection } ,
5078     { "nativeModifySelection", "(III)Ljava/lang/String;",
5079         (void*) ModifySelection },
5080     { "nativeDeleteSelection", "(IIII)V",
5081         (void*) DeleteSelection } ,
5082     { "nativeReplaceTextfieldText", "(IIILjava/lang/String;III)V",
5083         (void*) ReplaceTextfieldText } ,
5084     { "nativeMoveMouse", "(III)V",
5085         (void*) MoveMouse },
5086     { "passToJs", "(IILjava/lang/String;IIZZZZ)V",
5087         (void*) PassToJs },
5088     { "nativeScrollFocusedTextInput", "(IFI)V",
5089         (void*) ScrollFocusedTextInput },
5090     { "nativeSetFocusControllerActive", "(IZ)V",
5091         (void*) SetFocusControllerActive },
5092     { "nativeSaveDocumentState", "(I)V",
5093         (void*) SaveDocumentState },
5094     { "nativeFindAddress", "(Ljava/lang/String;Z)Ljava/lang/String;",
5095         (void*) FindAddress },
5096     { "nativeHandleTouchEvent", "(II[I[I[IIII)I",
5097         (void*) HandleTouchEvent },
5098     { "nativeMouseClick", "(I)Z",
5099         (void*) MouseClick },
5100     { "nativeRetrieveHref", "(III)Ljava/lang/String;",
5101         (void*) RetrieveHref },
5102     { "nativeRetrieveAnchorText", "(III)Ljava/lang/String;",
5103         (void*) RetrieveAnchorText },
5104     { "nativeRetrieveImageSource", "(III)Ljava/lang/String;",
5105         (void*) RetrieveImageSource },
5106     { "nativeGetContentMinPrefWidth", "(I)I",
5107         (void*) GetContentMinPrefWidth },
5108     { "nativeNotifyAnimationStarted", "(I)V",
5109         (void*) NotifyAnimationStarted },
5110     { "nativeRecordContent", "(ILandroid/graphics/Point;)I",
5111         (void*) RecordContent },
5112     { "setViewportSettingsFromNative", "(I)V",
5113         (void*) SetViewportSettingsFromNative },
5114     { "nativeSetBackgroundColor", "(II)V",
5115         (void*) SetBackgroundColor },
5116     { "nativeRegisterURLSchemeAsLocal", "(ILjava/lang/String;)V",
5117         (void*) RegisterURLSchemeAsLocal },
5118     { "nativeDumpDomTree", "(IZ)V",
5119         (void*) DumpDomTree },
5120     { "nativeDumpRenderTree", "(IZ)V",
5121         (void*) DumpRenderTree },
5122     { "nativeSetNewStorageLimit", "(IJ)V",
5123         (void*) SetNewStorageLimit },
5124     { "nativeGeolocationPermissionsProvide", "(ILjava/lang/String;ZZ)V",
5125         (void*) GeolocationPermissionsProvide },
5126     { "nativePause", "(I)V", (void*) Pause },
5127     { "nativeResume", "(I)V", (void*) Resume },
5128     { "nativeFreeMemory", "(I)V", (void*) FreeMemory },
5129     { "nativeSetJsFlags", "(ILjava/lang/String;)V", (void*) SetJsFlags },
5130     { "nativeRequestLabel", "(III)Ljava/lang/String;",
5131         (void*) RequestLabel },
5132     { "nativeRevealSelection", "(I)V", (void*) RevealSelection },
5133     { "nativeProvideVisitedHistory", "(I[Ljava/lang/String;)V",
5134         (void*) ProvideVisitedHistory },
5135     { "nativeFullScreenPluginHidden", "(II)V",
5136         (void*) FullScreenPluginHidden },
5137     { "nativePluginSurfaceReady", "(I)V",
5138         (void*) PluginSurfaceReady },
5139     { "nativeHitTest", "(IIIIZ)Landroid/webkit/WebViewCore$WebKitHitTest;",
5140         (void*) HitTest },
5141     { "nativeAutoFillForm", "(II)V",
5142         (void*) AutoFillForm },
5143     { "nativeScrollLayer", "(IILandroid/graphics/Rect;)V",
5144         (void*) ScrollRenderLayer },
5145     { "nativeCloseIdleConnections", "(I)V",
5146         (void*) CloseIdleConnections },
5147     { "nativeDeleteText", "(IIIII)V",
5148         (void*) DeleteText },
5149     { "nativeInsertText", "(ILjava/lang/String;)V",
5150         (void*) InsertText },
5151     { "nativeGetText", "(IIIII)Ljava/lang/String;",
5152         (void*) GetText },
5153     { "nativeSelectText", "(IIII)V",
5154         (void*) SelectText },
5155     { "nativeClearTextSelection", "(I)V",
5156         (void*) ClearSelection },
5157     { "nativeSelectWordAt", "(III)Z",
5158         (void*) SelectWordAt },
5159     { "nativeSelectAll", "(I)V",
5160         (void*) SelectAll },
5161     { "nativeCertTrustChanged","()V",
5162         (void*) nativeCertTrustChanged },
5163     { "nativeFindAll", "(ILjava/lang/String;)I",
5164         (void*) FindAll },
5165     { "nativeFindNext", "(IZ)I",
5166         (void*) FindNext },
5167     { "nativeSetInitialFocus", "(II)V", (void*) SetInitialFocus },
5168 };
5169 
registerWebViewCore(JNIEnv * env)5170 int registerWebViewCore(JNIEnv* env)
5171 {
5172     jclass widget = env->FindClass("android/webkit/WebViewCore");
5173     ALOG_ASSERT(widget,
5174             "Unable to find class android/webkit/WebViewCore");
5175     gWebViewCoreFields.m_nativeClass = env->GetFieldID(widget, "mNativeClass",
5176             "I");
5177     ALOG_ASSERT(gWebViewCoreFields.m_nativeClass,
5178             "Unable to find android/webkit/WebViewCore.mNativeClass");
5179     gWebViewCoreFields.m_viewportWidth = env->GetFieldID(widget,
5180             "mViewportWidth", "I");
5181     ALOG_ASSERT(gWebViewCoreFields.m_viewportWidth,
5182             "Unable to find android/webkit/WebViewCore.mViewportWidth");
5183     gWebViewCoreFields.m_viewportHeight = env->GetFieldID(widget,
5184             "mViewportHeight", "I");
5185     ALOG_ASSERT(gWebViewCoreFields.m_viewportHeight,
5186             "Unable to find android/webkit/WebViewCore.mViewportHeight");
5187     gWebViewCoreFields.m_viewportInitialScale = env->GetFieldID(widget,
5188             "mViewportInitialScale", "I");
5189     ALOG_ASSERT(gWebViewCoreFields.m_viewportInitialScale,
5190             "Unable to find android/webkit/WebViewCore.mViewportInitialScale");
5191     gWebViewCoreFields.m_viewportMinimumScale = env->GetFieldID(widget,
5192             "mViewportMinimumScale", "I");
5193     ALOG_ASSERT(gWebViewCoreFields.m_viewportMinimumScale,
5194             "Unable to find android/webkit/WebViewCore.mViewportMinimumScale");
5195     gWebViewCoreFields.m_viewportMaximumScale = env->GetFieldID(widget,
5196             "mViewportMaximumScale", "I");
5197     ALOG_ASSERT(gWebViewCoreFields.m_viewportMaximumScale,
5198             "Unable to find android/webkit/WebViewCore.mViewportMaximumScale");
5199     gWebViewCoreFields.m_viewportUserScalable = env->GetFieldID(widget,
5200             "mViewportUserScalable", "Z");
5201     ALOG_ASSERT(gWebViewCoreFields.m_viewportUserScalable,
5202             "Unable to find android/webkit/WebViewCore.mViewportUserScalable");
5203     gWebViewCoreFields.m_viewportDensityDpi = env->GetFieldID(widget,
5204             "mViewportDensityDpi", "I");
5205     ALOG_ASSERT(gWebViewCoreFields.m_viewportDensityDpi,
5206             "Unable to find android/webkit/WebViewCore.mViewportDensityDpi");
5207     gWebViewCoreFields.m_drawIsPaused = env->GetFieldID(widget,
5208             "mDrawIsPaused", "Z");
5209     ALOG_ASSERT(gWebViewCoreFields.m_drawIsPaused,
5210             "Unable to find android/webkit/WebViewCore.mDrawIsPaused");
5211     gWebViewCoreFields.m_lowMemoryUsageMb = env->GetFieldID(widget, "mLowMemoryUsageThresholdMb", "I");
5212     gWebViewCoreFields.m_highMemoryUsageMb = env->GetFieldID(widget, "mHighMemoryUsageThresholdMb", "I");
5213     gWebViewCoreFields.m_highUsageDeltaMb = env->GetFieldID(widget, "mHighUsageDeltaMb", "I");
5214 
5215     gWebViewCoreStaticMethods.m_isSupportedMediaMimeType =
5216         env->GetStaticMethodID(widget, "isSupportedMediaMimeType", "(Ljava/lang/String;)Z");
5217     LOG_FATAL_IF(!gWebViewCoreStaticMethods.m_isSupportedMediaMimeType,
5218         "Could not find static method isSupportedMediaMimeType from WebViewCore");
5219 
5220     env->DeleteLocalRef(widget);
5221 
5222     return jniRegisterNativeMethods(env, "android/webkit/WebViewCore",
5223             gJavaWebViewCoreMethods, NELEM(gJavaWebViewCoreMethods));
5224 }
5225 
5226 } /* namespace android */
5227