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