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