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 "AtomicString.h"
32 #include "CachedNode.h"
33 #include "CachedRoot.h"
34 #include "Chrome.h"
35 #include "ChromeClientAndroid.h"
36 #include "Color.h"
37 #include "DatabaseTracker.h"
38 #include "Document.h"
39 #include "DOMWindow.h"
40 #include "Element.h"
41 #include "Editor.h"
42 #include "EditorClientAndroid.h"
43 #include "EventHandler.h"
44 #include "EventNames.h"
45 #include "FocusController.h"
46 #include "Font.h"
47 #include "Frame.h"
48 #include "FrameLoader.h"
49 #include "FrameLoaderClientAndroid.h"
50 #include "FrameTree.h"
51 #include "FrameView.h"
52 #include "Geolocation.h"
53 #include "GraphicsContext.h"
54 #include "GraphicsJNI.h"
55 #include "HTMLAnchorElement.h"
56 #include "HTMLAreaElement.h"
57 #include "HTMLElement.h"
58 #include "HTMLImageElement.h"
59 #include "HTMLInputElement.h"
60 #include "HTMLLabelElement.h"
61 #include "HTMLMapElement.h"
62 #include "HTMLNames.h"
63 #include "HTMLOptGroupElement.h"
64 #include "HTMLOptionElement.h"
65 #include "HTMLSelectElement.h"
66 #include "HTMLTextAreaElement.h"
67 #include "HistoryItem.h"
68 #include "HitTestResult.h"
69 #include "InlineTextBox.h"
70 #include "KeyboardCodes.h"
71 #include "Navigator.h"
72 #include "Node.h"
73 #include "NodeList.h"
74 #include "Page.h"
75 #include "PageGroup.h"
76 #include "PlatformKeyboardEvent.h"
77 #include "PlatformString.h"
78 #include "PluginWidgetAndroid.h"
79 #include "PluginView.h"
80 #include "Position.h"
81 #include "ProgressTracker.h"
82 #include "RenderBox.h"
83 #include "RenderLayer.h"
84 #include "RenderPart.h"
85 #include "RenderText.h"
86 #include "RenderTextControl.h"
87 #include "RenderThemeAndroid.h"
88 #include "RenderView.h"
89 #include "ResourceRequest.h"
90 #include "SelectionController.h"
91 #include "Settings.h"
92 #include "SkANP.h"
93 #include "SkTemplates.h"
94 #include "SkTDArray.h"
95 #include "SkTypes.h"
96 #include "SkCanvas.h"
97 #include "SkPicture.h"
98 #include "SkUtils.h"
99 #include "StringImpl.h"
100 #include "Text.h"
101 #include "TypingCommand.h"
102 #include "WebCoreFrameBridge.h"
103 #include "WebFrameView.h"
104 #include "android_graphics.h"
105
106 #include <JNIHelp.h>
107 #include <JNIUtility.h>
108 #include <ui/KeycodeLabels.h>
109 #include <wtf/CurrentTime.h>
110
111 #if USE(V8)
112 #include "CString.h"
113 #include "ScriptController.h"
114 #include "V8Counters.h"
115 #endif
116
117 #if DEBUG_NAV_UI
118 #include "SkTime.h"
119 #endif
120
121 #if ENABLE(TOUCH_EVENTS) // Android
122 #include "PlatformTouchEvent.h"
123 #endif
124
125 #ifdef ANDROID_DOM_LOGGING
126 #include "AndroidLog.h"
127 #include "RenderTreeAsText.h"
128 #include "CString.h"
129
130 FILE* gDomTreeFile = 0;
131 FILE* gRenderTreeFile = 0;
132 #endif
133
134 #ifdef ANDROID_INSTRUMENT
135 #include "TimeCounter.h"
136 #endif
137
138 #if USE(ACCELERATED_COMPOSITING)
139 #include "GraphicsLayerAndroid.h"
140 #include "RenderLayerCompositor.h"
141 #endif
142
143 /* We pass this flag when recording the actual content, so that we don't spend
144 time actually regionizing complex path clips, when all we really want to do
145 is record them.
146 */
147 #define PICT_RECORD_FLAGS SkPicture::kUsePathBoundsForClip_RecordingFlag
148
149 ////////////////////////////////////////////////////////////////////////////////////////////////
150
151 namespace android {
152
153 static SkTDArray<WebViewCore*> gInstanceList;
154
addInstance(WebViewCore * inst)155 void WebViewCore::addInstance(WebViewCore* inst) {
156 *gInstanceList.append() = inst;
157 }
158
removeInstance(WebViewCore * inst)159 void WebViewCore::removeInstance(WebViewCore* inst) {
160 int index = gInstanceList.find(inst);
161 LOG_ASSERT(index >= 0, "RemoveInstance inst not found");
162 if (index >= 0) {
163 gInstanceList.removeShuffle(index);
164 }
165 }
166
isInstance(WebViewCore * inst)167 bool WebViewCore::isInstance(WebViewCore* inst) {
168 return gInstanceList.find(inst) >= 0;
169 }
170
getApplicationContext()171 jobject WebViewCore::getApplicationContext() {
172
173 // check to see if there is a valid webviewcore object
174 if (gInstanceList.isEmpty())
175 return 0;
176
177 // get the context from the webview
178 jobject context = gInstanceList[0]->getContext();
179
180 if (!context)
181 return 0;
182
183 // get the application context using JNI
184 JNIEnv* env = JSC::Bindings::getJNIEnv();
185 jclass contextClass = env->GetObjectClass(context);
186 jmethodID appContextMethod = env->GetMethodID(contextClass, "getApplicationContext", "()Landroid/content/Context;");
187 jobject result = env->CallObjectMethod(context, appContextMethod);
188 checkException(env);
189 return result;
190 }
191
192
193 struct WebViewCoreStaticMethods {
194 jmethodID m_supportsMimeType;
195 } gWebViewCoreStaticMethods;
196
197 // Check whether a media mimeType is supported in Android media framework.
supportsMimeType(const WebCore::String & mimeType)198 bool WebViewCore::supportsMimeType(const WebCore::String& mimeType) {
199 JNIEnv* env = JSC::Bindings::getJNIEnv();
200 jstring jMimeType = env->NewString(mimeType.characters(), mimeType.length());
201 jclass webViewCore = env->FindClass("android/webkit/WebViewCore");
202 bool val = env->CallStaticBooleanMethod(webViewCore,
203 gWebViewCoreStaticMethods.m_supportsMimeType, jMimeType);
204 checkException(env);
205 env->DeleteLocalRef(jMimeType);
206
207 return val;
208 }
209
210 // ----------------------------------------------------------------------------
211
212 #define GET_NATIVE_VIEW(env, obj) ((WebViewCore*)env->GetIntField(obj, gWebViewCoreFields.m_nativeClass))
213
214 // Field ids for WebViewCore
215 struct WebViewCoreFields {
216 jfieldID m_nativeClass;
217 jfieldID m_viewportWidth;
218 jfieldID m_viewportHeight;
219 jfieldID m_viewportInitialScale;
220 jfieldID m_viewportMinimumScale;
221 jfieldID m_viewportMaximumScale;
222 jfieldID m_viewportUserScalable;
223 jfieldID m_viewportDensityDpi;
224 jfieldID m_webView;
225 } gWebViewCoreFields;
226
227 // ----------------------------------------------------------------------------
228
229 struct WebViewCore::JavaGlue {
230 jweak m_obj;
231 jmethodID m_spawnScrollTo;
232 jmethodID m_scrollTo;
233 jmethodID m_scrollBy;
234 jmethodID m_contentDraw;
235 jmethodID m_requestListBox;
236 jmethodID m_openFileChooser;
237 jmethodID m_requestSingleListBox;
238 jmethodID m_jsAlert;
239 jmethodID m_jsConfirm;
240 jmethodID m_jsPrompt;
241 jmethodID m_jsUnload;
242 jmethodID m_jsInterrupt;
243 jmethodID m_didFirstLayout;
244 jmethodID m_updateViewport;
245 jmethodID m_sendNotifyProgressFinished;
246 jmethodID m_sendViewInvalidate;
247 jmethodID m_sendImmediateRepaint;
248 jmethodID m_setRootLayer;
249 jmethodID m_updateTextfield;
250 jmethodID m_updateTextSelection;
251 jmethodID m_clearTextEntry;
252 jmethodID m_restoreScale;
253 jmethodID m_restoreScreenWidthScale;
254 jmethodID m_needTouchEvents;
255 jmethodID m_requestKeyboard;
256 jmethodID m_requestKeyboardWithSelection;
257 jmethodID m_exceededDatabaseQuota;
258 jmethodID m_reachedMaxAppCacheSize;
259 jmethodID m_populateVisitedLinks;
260 jmethodID m_geolocationPermissionsShowPrompt;
261 jmethodID m_geolocationPermissionsHidePrompt;
262 jmethodID m_addMessageToConsole;
263 jmethodID m_getPluginClass;
264 jmethodID m_showFullScreenPlugin;
265 jmethodID m_hideFullScreenPlugin;
266 jmethodID m_addSurface;
267 jmethodID m_updateSurface;
268 jmethodID m_destroySurface;
269 jmethodID m_getContext;
270 jmethodID m_sendFindAgain;
271 jmethodID m_showRect;
272 jmethodID m_centerFitRect;
273 jmethodID m_setScrollbarModes;
objectandroid::WebViewCore::JavaGlue274 AutoJObject object(JNIEnv* env) {
275 return getRealObject(env, m_obj);
276 }
277 };
278
279 /*
280 * WebViewCore Implementation
281 */
282
GetJMethod(JNIEnv * env,jclass clazz,const char name[],const char signature[])283 static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[])
284 {
285 jmethodID m = env->GetMethodID(clazz, name, signature);
286 LOG_ASSERT(m, "Could not find method %s", name);
287 return m;
288 }
289
290 Mutex WebViewCore::gFrameCacheMutex;
291 Mutex WebViewCore::gButtonMutex;
292 Mutex WebViewCore::gCursorBoundsMutex;
293 Mutex WebViewCore::m_contentMutex;
294
WebViewCore(JNIEnv * env,jobject javaWebViewCore,WebCore::Frame * mainframe)295 WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* mainframe)
296 : m_pluginInvalTimer(this, &WebViewCore::pluginInvalTimerFired)
297 {
298 m_mainFrame = mainframe;
299
300 m_popupReply = 0;
301 m_moveGeneration = 0;
302 m_lastGeneration = 0;
303 m_touchGeneration = 0;
304 m_blockTextfieldUpdates = false;
305 // just initial values. These should be set by client
306 m_maxXScroll = 320/4;
307 m_maxYScroll = 240/4;
308 m_textGeneration = 0;
309 m_screenWidth = 320;
310 m_scale = 1;
311 m_screenWidthScale = 1;
312 #if ENABLE(TOUCH_EVENTS)
313 m_forwardingTouchEvents = false;
314 #endif
315 m_isPaused = false;
316
317 LOG_ASSERT(m_mainFrame, "Uh oh, somehow a frameview was made without an initial frame!");
318
319 jclass clazz = env->GetObjectClass(javaWebViewCore);
320 m_javaGlue = new JavaGlue;
321 m_javaGlue->m_obj = env->NewWeakGlobalRef(javaWebViewCore);
322 m_javaGlue->m_spawnScrollTo = GetJMethod(env, clazz, "contentSpawnScrollTo", "(II)V");
323 m_javaGlue->m_scrollTo = GetJMethod(env, clazz, "contentScrollTo", "(II)V");
324 m_javaGlue->m_scrollBy = GetJMethod(env, clazz, "contentScrollBy", "(IIZ)V");
325 m_javaGlue->m_contentDraw = GetJMethod(env, clazz, "contentDraw", "()V");
326 m_javaGlue->m_requestListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[I[I)V");
327 m_javaGlue->m_openFileChooser = GetJMethod(env, clazz, "openFileChooser", "()Ljava/lang/String;");
328 m_javaGlue->m_requestSingleListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[II)V");
329 m_javaGlue->m_jsAlert = GetJMethod(env, clazz, "jsAlert", "(Ljava/lang/String;Ljava/lang/String;)V");
330 m_javaGlue->m_jsConfirm = GetJMethod(env, clazz, "jsConfirm", "(Ljava/lang/String;Ljava/lang/String;)Z");
331 m_javaGlue->m_jsPrompt = GetJMethod(env, clazz, "jsPrompt", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
332 m_javaGlue->m_jsUnload = GetJMethod(env, clazz, "jsUnload", "(Ljava/lang/String;Ljava/lang/String;)Z");
333 m_javaGlue->m_jsInterrupt = GetJMethod(env, clazz, "jsInterrupt", "()Z");
334 m_javaGlue->m_didFirstLayout = GetJMethod(env, clazz, "didFirstLayout", "(Z)V");
335 m_javaGlue->m_updateViewport = GetJMethod(env, clazz, "updateViewport", "()V");
336 m_javaGlue->m_sendNotifyProgressFinished = GetJMethod(env, clazz, "sendNotifyProgressFinished", "()V");
337 m_javaGlue->m_sendViewInvalidate = GetJMethod(env, clazz, "sendViewInvalidate", "(IIII)V");
338 m_javaGlue->m_sendImmediateRepaint = GetJMethod(env, clazz, "sendImmediateRepaint", "()V");
339 m_javaGlue->m_setRootLayer = GetJMethod(env, clazz, "setRootLayer", "(I)V");
340 m_javaGlue->m_updateTextfield = GetJMethod(env, clazz, "updateTextfield", "(IZLjava/lang/String;I)V");
341 m_javaGlue->m_updateTextSelection = GetJMethod(env, clazz, "updateTextSelection", "(IIII)V");
342 m_javaGlue->m_clearTextEntry = GetJMethod(env, clazz, "clearTextEntry", "()V");
343 m_javaGlue->m_restoreScale = GetJMethod(env, clazz, "restoreScale", "(I)V");
344 m_javaGlue->m_restoreScreenWidthScale = GetJMethod(env, clazz, "restoreScreenWidthScale", "(I)V");
345 m_javaGlue->m_needTouchEvents = GetJMethod(env, clazz, "needTouchEvents", "(Z)V");
346 m_javaGlue->m_requestKeyboard = GetJMethod(env, clazz, "requestKeyboard", "(Z)V");
347 m_javaGlue->m_requestKeyboardWithSelection = GetJMethod(env, clazz, "requestKeyboardWithSelection", "(IIII)V");
348 m_javaGlue->m_exceededDatabaseQuota = GetJMethod(env, clazz, "exceededDatabaseQuota", "(Ljava/lang/String;Ljava/lang/String;JJ)V");
349 m_javaGlue->m_reachedMaxAppCacheSize = GetJMethod(env, clazz, "reachedMaxAppCacheSize", "(J)V");
350 m_javaGlue->m_populateVisitedLinks = GetJMethod(env, clazz, "populateVisitedLinks", "()V");
351 m_javaGlue->m_geolocationPermissionsShowPrompt = GetJMethod(env, clazz, "geolocationPermissionsShowPrompt", "(Ljava/lang/String;)V");
352 m_javaGlue->m_geolocationPermissionsHidePrompt = GetJMethod(env, clazz, "geolocationPermissionsHidePrompt", "()V");
353 m_javaGlue->m_addMessageToConsole = GetJMethod(env, clazz, "addMessageToConsole", "(Ljava/lang/String;ILjava/lang/String;I)V");
354 m_javaGlue->m_getPluginClass = GetJMethod(env, clazz, "getPluginClass", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Class;");
355 m_javaGlue->m_showFullScreenPlugin = GetJMethod(env, clazz, "showFullScreenPlugin", "(Landroid/webkit/ViewManager$ChildView;I)V");
356 m_javaGlue->m_hideFullScreenPlugin = GetJMethod(env, clazz, "hideFullScreenPlugin", "()V");
357 m_javaGlue->m_addSurface = GetJMethod(env, clazz, "addSurface", "(Landroid/view/View;IIII)Landroid/webkit/ViewManager$ChildView;");
358 m_javaGlue->m_updateSurface = GetJMethod(env, clazz, "updateSurface", "(Landroid/webkit/ViewManager$ChildView;IIII)V");
359 m_javaGlue->m_destroySurface = GetJMethod(env, clazz, "destroySurface", "(Landroid/webkit/ViewManager$ChildView;)V");
360 m_javaGlue->m_getContext = GetJMethod(env, clazz, "getContext", "()Landroid/content/Context;");
361 m_javaGlue->m_sendFindAgain = GetJMethod(env, clazz, "sendFindAgain", "()V");
362 m_javaGlue->m_showRect = GetJMethod(env, clazz, "showRect", "(IIIIIIFFFF)V");
363 m_javaGlue->m_centerFitRect = GetJMethod(env, clazz, "centerFitRect", "(IIII)V");
364 m_javaGlue->m_setScrollbarModes = GetJMethod(env, clazz, "setScrollbarModes", "(II)V");
365
366 env->SetIntField(javaWebViewCore, gWebViewCoreFields.m_nativeClass, (jint)this);
367
368 m_scrollOffsetX = m_scrollOffsetY = 0;
369
370 PageGroup::setShouldTrackVisitedLinks(true);
371
372 reset(true);
373
374 WebViewCore::addInstance(this);
375 }
376
~WebViewCore()377 WebViewCore::~WebViewCore()
378 {
379 WebViewCore::removeInstance(this);
380
381 // Release the focused view
382 Release(m_popupReply);
383
384 if (m_javaGlue->m_obj) {
385 JNIEnv* env = JSC::Bindings::getJNIEnv();
386 env->DeleteWeakGlobalRef(m_javaGlue->m_obj);
387 m_javaGlue->m_obj = 0;
388 }
389 delete m_javaGlue;
390 delete m_frameCacheKit;
391 delete m_navPictureKit;
392 }
393
getWebViewCore(const WebCore::FrameView * view)394 WebViewCore* WebViewCore::getWebViewCore(const WebCore::FrameView* view)
395 {
396 return getWebViewCore(static_cast<const WebCore::ScrollView*>(view));
397 }
398
getWebViewCore(const WebCore::ScrollView * view)399 WebViewCore* WebViewCore::getWebViewCore(const WebCore::ScrollView* view)
400 {
401 if (!view)
402 return 0;
403
404 WebFrameView* webFrameView = static_cast<WebFrameView*>(view->platformWidget());
405 if (!webFrameView)
406 return 0;
407 return webFrameView->webViewCore();
408 }
409
reset(bool fromConstructor)410 void WebViewCore::reset(bool fromConstructor)
411 {
412 DBG_SET_LOG("");
413 if (fromConstructor) {
414 m_frameCacheKit = 0;
415 m_navPictureKit = 0;
416 } else {
417 gFrameCacheMutex.lock();
418 delete m_frameCacheKit;
419 delete m_navPictureKit;
420 m_frameCacheKit = 0;
421 m_navPictureKit = 0;
422 gFrameCacheMutex.unlock();
423 }
424
425 m_lastFocused = 0;
426 m_lastFocusedBounds = WebCore::IntRect(0,0,0,0);
427 m_focusBoundsChanged = false;
428 m_lastFocusedSelStart = 0;
429 m_lastFocusedSelEnd = 0;
430 clearContent();
431 m_updatedFrameCache = true;
432 m_frameCacheOutOfDate = true;
433 m_skipContentDraw = false;
434 m_findIsUp = false;
435 m_domtree_version = 0;
436 m_check_domtree_version = true;
437 m_progressDone = false;
438 m_hasCursorBounds = false;
439
440 m_scrollOffsetX = 0;
441 m_scrollOffsetY = 0;
442 m_screenWidth = 0;
443 m_screenHeight = 0;
444 m_groupForVisitedLinks = NULL;
445 }
446
layoutIfNeededRecursive(WebCore::Frame * f)447 static bool layoutIfNeededRecursive(WebCore::Frame* f)
448 {
449 if (!f)
450 return true;
451
452 WebCore::FrameView* v = f->view();
453 if (!v)
454 return true;
455
456 if (v->needsLayout())
457 v->layout(f->tree()->parent());
458
459 WebCore::Frame* child = f->tree()->firstChild();
460 bool success = true;
461 while (child) {
462 success &= layoutIfNeededRecursive(child);
463 child = child->tree()->nextSibling();
464 }
465
466 return success && !v->needsLayout();
467 }
468
cacheBuilder()469 CacheBuilder& WebViewCore::cacheBuilder()
470 {
471 return FrameLoaderClientAndroid::get(m_mainFrame)->getCacheBuilder();
472 }
473
currentFocus()474 WebCore::Node* WebViewCore::currentFocus()
475 {
476 return cacheBuilder().currentFocus();
477 }
478
recordPicture(SkPicture * picture)479 void WebViewCore::recordPicture(SkPicture* picture)
480 {
481 // if there is no document yet, just return
482 if (!m_mainFrame->document()) {
483 DBG_NAV_LOG("no document");
484 return;
485 }
486 // Call layout to ensure that the contentWidth and contentHeight are correct
487 if (!layoutIfNeededRecursive(m_mainFrame)) {
488 DBG_NAV_LOG("layout failed");
489 return;
490 }
491 // draw into the picture's recording canvas
492 WebCore::FrameView* view = m_mainFrame->view();
493 DBG_NAV_LOGD("view=(w=%d,h=%d)", view->contentsWidth(),
494 view->contentsHeight());
495 SkAutoPictureRecord arp(picture, view->contentsWidth(),
496 view->contentsHeight(), PICT_RECORD_FLAGS);
497 SkAutoMemoryUsageProbe mup(__FUNCTION__);
498
499 // Copy m_buttons so we can pass it to our graphics context.
500 gButtonMutex.lock();
501 WTF::Vector<Container> buttons(m_buttons);
502 gButtonMutex.unlock();
503
504 WebCore::PlatformGraphicsContext pgc(arp.getRecordingCanvas(), &buttons);
505 WebCore::GraphicsContext gc(&pgc);
506 view->platformWidget()->draw(&gc, WebCore::IntRect(0, 0, INT_MAX, INT_MAX));
507
508 gButtonMutex.lock();
509 updateButtonList(&buttons);
510 gButtonMutex.unlock();
511 }
512
recordPictureSet(PictureSet * content)513 void WebViewCore::recordPictureSet(PictureSet* content)
514 {
515 // if there is no document yet, just return
516 if (!m_mainFrame->document()) {
517 DBG_SET_LOG("!m_mainFrame->document()");
518 return;
519 }
520 if (m_addInval.isEmpty()) {
521 DBG_SET_LOG("m_addInval.isEmpty()");
522 return;
523 }
524 // Call layout to ensure that the contentWidth and contentHeight are correct
525 // it's fine for layout to gather invalidates, but defeat sending a message
526 // back to java to call webkitDraw, since we're already in the middle of
527 // doing that
528 m_skipContentDraw = true;
529 bool success = layoutIfNeededRecursive(m_mainFrame);
530 m_skipContentDraw = false;
531
532 // We may be mid-layout and thus cannot draw.
533 if (!success)
534 return;
535
536 { // collect WebViewCoreRecordTimeCounter after layoutIfNeededRecursive
537 #ifdef ANDROID_INSTRUMENT
538 TimeCounterAuto counter(TimeCounter::WebViewCoreRecordTimeCounter);
539 #endif
540
541 // if the webkit page dimensions changed, discard the pictureset and redraw.
542 WebCore::FrameView* view = m_mainFrame->view();
543 int width = view->contentsWidth();
544 int height = view->contentsHeight();
545
546 // Use the contents width and height as a starting point.
547 SkIRect contentRect;
548 contentRect.set(0, 0, width, height);
549 SkIRect total(contentRect);
550
551 // Traverse all the frames and add their sizes if they are in the visible
552 // rectangle.
553 for (WebCore::Frame* frame = m_mainFrame->tree()->traverseNext(); frame;
554 frame = frame->tree()->traverseNext()) {
555 // If the frame doesn't have an owner then it is the top frame and the
556 // view size is the frame size.
557 WebCore::RenderPart* owner = frame->ownerRenderer();
558 if (owner && owner->style()->visibility() == VISIBLE) {
559 int x = owner->x();
560 int y = owner->y();
561
562 // Traverse the tree up to the parent to find the absolute position
563 // of this frame.
564 WebCore::Frame* parent = frame->tree()->parent();
565 while (parent) {
566 WebCore::RenderPart* parentOwner = parent->ownerRenderer();
567 if (parentOwner) {
568 x += parentOwner->x();
569 y += parentOwner->y();
570 }
571 parent = parent->tree()->parent();
572 }
573 // Use the owner dimensions so that padding and border are
574 // included.
575 int right = x + owner->width();
576 int bottom = y + owner->height();
577 SkIRect frameRect = {x, y, right, bottom};
578 // Ignore a width or height that is smaller than 1. Some iframes
579 // have small dimensions in order to be hidden. The iframe
580 // expansion code does not expand in that case so we should ignore
581 // them here.
582 if (frameRect.width() > 1 && frameRect.height() > 1
583 && SkIRect::Intersects(total, frameRect))
584 total.join(x, y, right, bottom);
585 }
586 }
587
588 // If the new total is larger than the content, resize the view to include
589 // all the content.
590 if (!contentRect.contains(total)) {
591 // Resize the view to change the overflow clip.
592 view->resize(total.fRight, total.fBottom);
593
594 // We have to force a layout in order for the clip to change.
595 m_mainFrame->contentRenderer()->setNeedsLayoutAndPrefWidthsRecalc();
596 view->forceLayout();
597
598 // Relayout similar to above
599 m_skipContentDraw = true;
600 bool success = layoutIfNeededRecursive(m_mainFrame);
601 m_skipContentDraw = false;
602 if (!success)
603 return;
604
605 // Set the computed content width
606 width = view->contentsWidth();
607 height = view->contentsHeight();
608 }
609
610 content->checkDimensions(width, height, &m_addInval);
611
612 // The inval region may replace existing pictures. The existing pictures
613 // may have already been split into pieces. If reuseSubdivided() returns
614 // true, the split pieces are the last entries in the picture already. They
615 // are marked as invalid, and are rebuilt by rebuildPictureSet().
616
617 // If the new region doesn't match a set of split pieces, add it to the end.
618 if (!content->reuseSubdivided(m_addInval)) {
619 const SkIRect& inval = m_addInval.getBounds();
620 SkPicture* picture = rebuildPicture(inval);
621 DBG_SET_LOGD("{%d,%d,w=%d,h=%d}", inval.fLeft,
622 inval.fTop, inval.width(), inval.height());
623 content->add(m_addInval, picture, 0, false);
624 picture->safeUnref();
625 }
626 // Remove any pictures already in the set that are obscured by the new one,
627 // and check to see if any already split pieces need to be redrawn.
628 if (content->build())
629 rebuildPictureSet(content);
630 } // WebViewCoreRecordTimeCounter
631 WebCore::Node* oldFocusNode = currentFocus();
632 m_frameCacheOutOfDate = true;
633 WebCore::IntRect oldBounds;
634 int oldSelStart = 0;
635 int oldSelEnd = 0;
636 if (oldFocusNode) {
637 oldBounds = oldFocusNode->getRect();
638 RenderObject* renderer = oldFocusNode->renderer();
639 if (renderer && (renderer->isTextArea() || renderer->isTextField())) {
640 WebCore::RenderTextControl* rtc =
641 static_cast<WebCore::RenderTextControl*>(renderer);
642 oldSelStart = rtc->selectionStart();
643 oldSelEnd = rtc->selectionEnd();
644 }
645 } else
646 oldBounds = WebCore::IntRect(0,0,0,0);
647 unsigned latestVersion = 0;
648 if (m_check_domtree_version) {
649 // as domTreeVersion only increment, we can just check the sum to see
650 // whether we need to update the frame cache
651 for (Frame* frame = m_mainFrame; frame; frame = frame->tree()->traverseNext()) {
652 latestVersion += frame->document()->domTreeVersion();
653 }
654 }
655 DBG_NAV_LOGD("m_lastFocused=%p oldFocusNode=%p"
656 " m_lastFocusedBounds={%d,%d,%d,%d} oldBounds={%d,%d,%d,%d}"
657 " m_lastFocusedSelection={%d,%d} oldSelection={%d,%d}"
658 " m_check_domtree_version=%s latestVersion=%d m_domtree_version=%d",
659 m_lastFocused, oldFocusNode,
660 m_lastFocusedBounds.x(), m_lastFocusedBounds.y(),
661 m_lastFocusedBounds.width(), m_lastFocusedBounds.height(),
662 oldBounds.x(), oldBounds.y(), oldBounds.width(), oldBounds.height(),
663 m_lastFocusedSelStart, m_lastFocusedSelEnd, oldSelStart, oldSelEnd,
664 m_check_domtree_version ? "true" : "false",
665 latestVersion, m_domtree_version);
666 if (m_lastFocused == oldFocusNode && m_lastFocusedBounds == oldBounds
667 && m_lastFocusedSelStart == oldSelStart
668 && m_lastFocusedSelEnd == oldSelEnd
669 && !m_findIsUp
670 && (!m_check_domtree_version || latestVersion == m_domtree_version))
671 {
672 return;
673 }
674 m_focusBoundsChanged |= m_lastFocused == oldFocusNode
675 && m_lastFocusedBounds != oldBounds;
676 m_lastFocused = oldFocusNode;
677 m_lastFocusedBounds = oldBounds;
678 m_lastFocusedSelStart = oldSelStart;
679 m_lastFocusedSelEnd = oldSelEnd;
680 m_domtree_version = latestVersion;
681 DBG_NAV_LOG("call updateFrameCache");
682 updateFrameCache();
683 if (m_findIsUp) {
684 LOG_ASSERT(m_javaGlue->m_obj,
685 "A Java widget was not associated with this view bridge!");
686 JNIEnv* env = JSC::Bindings::getJNIEnv();
687 env->CallVoidMethod(m_javaGlue->object(env).get(),
688 m_javaGlue->m_sendFindAgain);
689 checkException(env);
690 }
691 }
692
updateButtonList(WTF::Vector<Container> * buttons)693 void WebViewCore::updateButtonList(WTF::Vector<Container>* buttons)
694 {
695 // All the entries in buttons are either updates of previous entries in
696 // m_buttons or they need to be added to it.
697 Container* end = buttons->end();
698 for (Container* updatedContainer = buttons->begin();
699 updatedContainer != end; updatedContainer++) {
700 bool updated = false;
701 // Search for a previous entry that references the same node as our new
702 // data
703 Container* lastPossibleMatch = m_buttons.end();
704 for (Container* possibleMatch = m_buttons.begin();
705 possibleMatch != lastPossibleMatch; possibleMatch++) {
706 if (updatedContainer->matches(possibleMatch->node())) {
707 // Update our record, and skip to the next one.
708 possibleMatch->setRect(updatedContainer->rect());
709 updated = true;
710 break;
711 }
712 }
713 if (!updated) {
714 // This is a brand new button, so append it to m_buttons
715 m_buttons.append(*updatedContainer);
716 }
717 }
718 size_t i = 0;
719 // count will decrease each time one is removed, so check count each time.
720 while (i < m_buttons.size()) {
721 if (m_buttons[i].canBeRemoved()) {
722 m_buttons[i] = m_buttons.last();
723 m_buttons.removeLast();
724 } else {
725 i++;
726 }
727 }
728 }
729
730 // note: updateCursorBounds is called directly by the WebView thread
731 // This needs to be called each time we call CachedRoot::setCursor() with
732 // non-null CachedNode/CachedFrame, since otherwise the WebViewCore's data
733 // about the cursor is incorrect. When we call setCursor(0,0), we need
734 // to set hasCursorBounds to false.
updateCursorBounds(const CachedRoot * root,const CachedFrame * cachedFrame,const CachedNode * cachedNode)735 void WebViewCore::updateCursorBounds(const CachedRoot* root,
736 const CachedFrame* cachedFrame, const CachedNode* cachedNode)
737 {
738 LOG_ASSERT(root, "updateCursorBounds: root cannot be null");
739 LOG_ASSERT(cachedNode, "updateCursorBounds: cachedNode cannot be null");
740 LOG_ASSERT(cachedFrame, "updateCursorBounds: cachedFrame cannot be null");
741 gCursorBoundsMutex.lock();
742 m_hasCursorBounds = !cachedNode->isHidden();
743 // If m_hasCursorBounds is false, we never look at the other
744 // values, so do not bother setting them.
745 if (m_hasCursorBounds) {
746 WebCore::IntRect bounds = cachedNode->bounds(cachedFrame);
747 if (m_cursorBounds != bounds)
748 DBG_NAV_LOGD("new cursor bounds=(%d,%d,w=%d,h=%d)",
749 bounds.x(), bounds.y(), bounds.width(), bounds.height());
750 m_cursorBounds = bounds;
751 m_cursorHitBounds = cachedNode->hitBounds(cachedFrame);
752 m_cursorFrame = cachedFrame->framePointer();
753 root->getSimulatedMousePosition(&m_cursorLocation);
754 m_cursorNode = cachedNode->nodePointer();
755 }
756 gCursorBoundsMutex.unlock();
757 }
758
clearContent()759 void WebViewCore::clearContent()
760 {
761 DBG_SET_LOG("");
762 m_contentMutex.lock();
763 m_content.clear();
764 m_contentMutex.unlock();
765 m_addInval.setEmpty();
766 m_rebuildInval.setEmpty();
767 }
768
copyContentToPicture(SkPicture * picture)769 void WebViewCore::copyContentToPicture(SkPicture* picture)
770 {
771 DBG_SET_LOG("start");
772 m_contentMutex.lock();
773 PictureSet copyContent = PictureSet(m_content);
774 m_contentMutex.unlock();
775
776 int w = copyContent.width();
777 int h = copyContent.height();
778 copyContent.draw(picture->beginRecording(w, h, PICT_RECORD_FLAGS));
779 picture->endRecording();
780 DBG_SET_LOG("end");
781 }
782
drawContent(SkCanvas * canvas,SkColor color)783 bool WebViewCore::drawContent(SkCanvas* canvas, SkColor color)
784 {
785 #ifdef ANDROID_INSTRUMENT
786 TimeCounterAuto counter(TimeCounter::WebViewUIDrawTimeCounter);
787 #endif
788 DBG_SET_LOG("start");
789 m_contentMutex.lock();
790 PictureSet copyContent = PictureSet(m_content);
791 m_contentMutex.unlock();
792 int sc = canvas->save(SkCanvas::kClip_SaveFlag);
793 SkRect clip;
794 clip.set(0, 0, copyContent.width(), copyContent.height());
795 canvas->clipRect(clip, SkRegion::kDifference_Op);
796 canvas->drawColor(color);
797 canvas->restoreToCount(sc);
798 bool tookTooLong = copyContent.draw(canvas);
799 m_contentMutex.lock();
800 m_content.setDrawTimes(copyContent);
801 m_contentMutex.unlock();
802 DBG_SET_LOG("end");
803 return tookTooLong;
804 }
805
focusBoundsChanged()806 bool WebViewCore::focusBoundsChanged()
807 {
808 bool result = m_focusBoundsChanged;
809 m_focusBoundsChanged = false;
810 return result;
811 }
812
pictureReady()813 bool WebViewCore::pictureReady()
814 {
815 bool done;
816 m_contentMutex.lock();
817 PictureSet copyContent = PictureSet(m_content);
818 done = m_progressDone;
819 m_contentMutex.unlock();
820 DBG_NAV_LOGD("done=%s empty=%s", done ? "true" : "false",
821 copyContent.isEmpty() ? "true" : "false");
822 return done || !copyContent.isEmpty();
823 }
824
rebuildPicture(const SkIRect & inval)825 SkPicture* WebViewCore::rebuildPicture(const SkIRect& inval)
826 {
827 WebCore::FrameView* view = m_mainFrame->view();
828 int width = view->contentsWidth();
829 int height = view->contentsHeight();
830 SkPicture* picture = new SkPicture();
831 SkAutoPictureRecord arp(picture, width, height, PICT_RECORD_FLAGS);
832 SkAutoMemoryUsageProbe mup(__FUNCTION__);
833 SkCanvas* recordingCanvas = arp.getRecordingCanvas();
834
835 gButtonMutex.lock();
836 WTF::Vector<Container> buttons(m_buttons);
837 gButtonMutex.unlock();
838
839 WebCore::PlatformGraphicsContext pgc(recordingCanvas, &buttons);
840 WebCore::GraphicsContext gc(&pgc);
841 recordingCanvas->translate(-inval.fLeft, -inval.fTop);
842 recordingCanvas->save();
843 view->platformWidget()->draw(&gc, WebCore::IntRect(inval.fLeft,
844 inval.fTop, inval.width(), inval.height()));
845 m_rebuildInval.op(inval, SkRegion::kUnion_Op);
846 DBG_SET_LOGD("m_rebuildInval={%d,%d,r=%d,b=%d}",
847 m_rebuildInval.getBounds().fLeft, m_rebuildInval.getBounds().fTop,
848 m_rebuildInval.getBounds().fRight, m_rebuildInval.getBounds().fBottom);
849
850 gButtonMutex.lock();
851 updateButtonList(&buttons);
852 gButtonMutex.unlock();
853
854 return picture;
855 }
856
rebuildPictureSet(PictureSet * pictureSet)857 void WebViewCore::rebuildPictureSet(PictureSet* pictureSet)
858 {
859 WebCore::FrameView* view = m_mainFrame->view();
860 size_t size = pictureSet->size();
861 for (size_t index = 0; index < size; index++) {
862 if (pictureSet->upToDate(index))
863 continue;
864 const SkIRect& inval = pictureSet->bounds(index);
865 DBG_SET_LOGD("pictSet=%p [%d] {%d,%d,w=%d,h=%d}", pictureSet, index,
866 inval.fLeft, inval.fTop, inval.width(), inval.height());
867 pictureSet->setPicture(index, rebuildPicture(inval));
868 }
869 pictureSet->validate(__FUNCTION__);
870 }
871
recordContent(SkRegion * region,SkIPoint * point)872 bool WebViewCore::recordContent(SkRegion* region, SkIPoint* point)
873 {
874 DBG_SET_LOG("start");
875 float progress = (float) m_mainFrame->page()->progress()->estimatedProgress();
876 m_contentMutex.lock();
877 PictureSet contentCopy(m_content);
878 m_progressDone = progress <= 0.0f || progress >= 1.0f;
879 m_contentMutex.unlock();
880 recordPictureSet(&contentCopy);
881 if (!m_progressDone && contentCopy.isEmpty()) {
882 DBG_SET_LOGD("empty (progress=%g)", progress);
883 return false;
884 }
885 region->set(m_addInval);
886 m_addInval.setEmpty();
887 region->op(m_rebuildInval, SkRegion::kUnion_Op);
888 m_rebuildInval.setEmpty();
889 m_contentMutex.lock();
890 contentCopy.setDrawTimes(m_content);
891 m_content.set(contentCopy);
892 point->fX = m_content.width();
893 point->fY = m_content.height();
894 m_contentMutex.unlock();
895 DBG_SET_LOGD("region={%d,%d,r=%d,b=%d}", region->getBounds().fLeft,
896 region->getBounds().fTop, region->getBounds().fRight,
897 region->getBounds().fBottom);
898 DBG_SET_LOG("end");
899 return true;
900 }
901
splitContent()902 void WebViewCore::splitContent()
903 {
904 bool layoutSuceeded = layoutIfNeededRecursive(m_mainFrame);
905 LOG_ASSERT(layoutSuceeded, "Can never be called recursively");
906 PictureSet tempPictureSet;
907 m_contentMutex.lock();
908 m_content.split(&tempPictureSet);
909 m_contentMutex.unlock();
910 rebuildPictureSet(&tempPictureSet);
911 m_contentMutex.lock();
912 m_content.set(tempPictureSet);
913 m_contentMutex.unlock();
914 }
915
scrollTo(int x,int y,bool animate)916 void WebViewCore::scrollTo(int x, int y, bool animate)
917 {
918 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
919
920 // LOGD("WebViewCore::scrollTo(%d %d)\n", x, y);
921
922 JNIEnv* env = JSC::Bindings::getJNIEnv();
923 env->CallVoidMethod(m_javaGlue->object(env).get(),
924 animate ? m_javaGlue->m_spawnScrollTo : m_javaGlue->m_scrollTo,
925 x, y);
926 checkException(env);
927 }
928
sendNotifyProgressFinished()929 void WebViewCore::sendNotifyProgressFinished()
930 {
931 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
932 JNIEnv* env = JSC::Bindings::getJNIEnv();
933 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_sendNotifyProgressFinished);
934 checkException(env);
935 }
936
viewInvalidate(const WebCore::IntRect & rect)937 void WebViewCore::viewInvalidate(const WebCore::IntRect& rect)
938 {
939 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
940 JNIEnv* env = JSC::Bindings::getJNIEnv();
941 env->CallVoidMethod(m_javaGlue->object(env).get(),
942 m_javaGlue->m_sendViewInvalidate,
943 rect.x(), rect.y(), rect.right(), rect.bottom());
944 checkException(env);
945 }
946
scrollBy(int dx,int dy,bool animate)947 void WebViewCore::scrollBy(int dx, int dy, bool animate)
948 {
949 if (!(dx | dy))
950 return;
951 JNIEnv* env = JSC::Bindings::getJNIEnv();
952 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_scrollBy,
953 dx, dy, animate);
954 checkException(env);
955 }
956
957 #if USE(ACCELERATED_COMPOSITING)
958
immediateRepaint()959 void WebViewCore::immediateRepaint()
960 {
961 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
962 JNIEnv* env = JSC::Bindings::getJNIEnv();
963 env->CallVoidMethod(m_javaGlue->object(env).get(),
964 m_javaGlue->m_sendImmediateRepaint);
965 checkException(env);
966 }
967
setUIRootLayer(const LayerAndroid * layer)968 void WebViewCore::setUIRootLayer(const LayerAndroid* layer)
969 {
970 JNIEnv* env = JSC::Bindings::getJNIEnv();
971 env->CallVoidMethod(m_javaGlue->object(env).get(),
972 m_javaGlue->m_setRootLayer,
973 reinterpret_cast<jint>(layer));
974 checkException(env);
975 }
976
977 #endif // USE(ACCELERATED_COMPOSITING)
978
contentDraw()979 void WebViewCore::contentDraw()
980 {
981 JNIEnv* env = JSC::Bindings::getJNIEnv();
982 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_contentDraw);
983 checkException(env);
984 }
985
contentInvalidate(const WebCore::IntRect & r)986 void WebViewCore::contentInvalidate(const WebCore::IntRect &r)
987 {
988 DBG_SET_LOGD("rect={%d,%d,w=%d,h=%d}", r.x(), r.y(), r.width(), r.height());
989 SkIRect rect(r);
990 if (!rect.intersect(0, 0, INT_MAX, INT_MAX))
991 return;
992 m_addInval.op(rect, SkRegion::kUnion_Op);
993 DBG_SET_LOGD("m_addInval={%d,%d,r=%d,b=%d}",
994 m_addInval.getBounds().fLeft, m_addInval.getBounds().fTop,
995 m_addInval.getBounds().fRight, m_addInval.getBounds().fBottom);
996 if (!m_skipContentDraw)
997 contentDraw();
998 }
999
offInvalidate(const WebCore::IntRect & r)1000 void WebViewCore::offInvalidate(const WebCore::IntRect &r)
1001 {
1002 // FIXME: these invalidates are offscreen, and can be throttled or
1003 // deferred until the area is visible. For now, treat them as
1004 // regular invals so that drawing happens (inefficiently) for now.
1005 contentInvalidate(r);
1006 }
1007
pin_pos(int x,int width,int targetWidth)1008 static int pin_pos(int x, int width, int targetWidth)
1009 {
1010 if (x + width > targetWidth)
1011 x = targetWidth - width;
1012 if (x < 0)
1013 x = 0;
1014 return x;
1015 }
1016
didFirstLayout()1017 void WebViewCore::didFirstLayout()
1018 {
1019 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
1020 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1021
1022 WebCore::FrameLoader* loader = m_mainFrame->loader();
1023 const WebCore::KURL& url = loader->url();
1024 if (url.isEmpty())
1025 return;
1026 LOGV("::WebCore:: didFirstLayout %s", url.string().ascii().data());
1027
1028 WebCore::FrameLoadType loadType = loader->loadType();
1029
1030 JNIEnv* env = JSC::Bindings::getJNIEnv();
1031 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_didFirstLayout,
1032 loadType == WebCore::FrameLoadTypeStandard
1033 // When redirect with locked history, we would like to reset the
1034 // scale factor. This is important for www.yahoo.com as it is
1035 // redirected to www.yahoo.com/?rs=1 on load.
1036 || loadType == WebCore::FrameLoadTypeRedirectWithLockedBackForwardList);
1037 checkException(env);
1038
1039 DBG_NAV_LOG("call updateFrameCache");
1040 m_check_domtree_version = false;
1041 updateFrameCache();
1042 m_history.setDidFirstLayout(true);
1043 }
1044
updateViewport()1045 void WebViewCore::updateViewport()
1046 {
1047 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
1048 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1049
1050 JNIEnv* env = JSC::Bindings::getJNIEnv();
1051 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateViewport);
1052 checkException(env);
1053 }
1054
restoreScale(int scale)1055 void WebViewCore::restoreScale(int scale)
1056 {
1057 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
1058 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1059
1060 JNIEnv* env = JSC::Bindings::getJNIEnv();
1061 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_restoreScale, scale);
1062 checkException(env);
1063 }
1064
restoreScreenWidthScale(int scale)1065 void WebViewCore::restoreScreenWidthScale(int scale)
1066 {
1067 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
1068 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1069
1070 JNIEnv* env = JSC::Bindings::getJNIEnv();
1071 env->CallVoidMethod(m_javaGlue->object(env).get(),
1072 m_javaGlue->m_restoreScreenWidthScale, scale);
1073 checkException(env);
1074 }
1075
needTouchEvents(bool need)1076 void WebViewCore::needTouchEvents(bool need)
1077 {
1078 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
1079 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1080
1081 #if ENABLE(TOUCH_EVENTS)
1082 if (m_forwardingTouchEvents == need)
1083 return;
1084
1085 JNIEnv* env = JSC::Bindings::getJNIEnv();
1086 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_needTouchEvents, need);
1087 checkException(env);
1088
1089 m_forwardingTouchEvents = need;
1090 #endif
1091 }
1092
requestKeyboardWithSelection(const WebCore::Node * node,int selStart,int selEnd)1093 void WebViewCore::requestKeyboardWithSelection(const WebCore::Node* node,
1094 int selStart, int selEnd)
1095 {
1096 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
1097 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1098
1099 JNIEnv* env = JSC::Bindings::getJNIEnv();
1100 env->CallVoidMethod(m_javaGlue->object(env).get(),
1101 m_javaGlue->m_requestKeyboardWithSelection,
1102 reinterpret_cast<int>(node), selStart, selEnd, m_textGeneration);
1103 checkException(env);
1104 }
1105
requestKeyboard(bool showKeyboard)1106 void WebViewCore::requestKeyboard(bool showKeyboard)
1107 {
1108 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
1109 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1110
1111 JNIEnv* env = JSC::Bindings::getJNIEnv();
1112 env->CallVoidMethod(m_javaGlue->object(env).get(),
1113 m_javaGlue->m_requestKeyboard, showKeyboard);
1114 checkException(env);
1115 }
1116
notifyProgressFinished()1117 void WebViewCore::notifyProgressFinished()
1118 {
1119 DBG_NAV_LOG("call updateFrameCache");
1120 m_check_domtree_version = true;
1121 updateFrameCache();
1122 sendNotifyProgressFinished();
1123 }
1124
doMaxScroll(CacheBuilder::Direction dir)1125 void WebViewCore::doMaxScroll(CacheBuilder::Direction dir)
1126 {
1127 int dx = 0, dy = 0;
1128
1129 switch (dir) {
1130 case CacheBuilder::LEFT:
1131 dx = -m_maxXScroll;
1132 break;
1133 case CacheBuilder::UP:
1134 dy = -m_maxYScroll;
1135 break;
1136 case CacheBuilder::RIGHT:
1137 dx = m_maxXScroll;
1138 break;
1139 case CacheBuilder::DOWN:
1140 dy = m_maxYScroll;
1141 break;
1142 case CacheBuilder::UNINITIALIZED:
1143 default:
1144 LOG_ASSERT(0, "unexpected focus selector");
1145 }
1146 this->scrollBy(dx, dy, true);
1147 }
1148
setScrollOffset(int moveGeneration,int dx,int dy)1149 void WebViewCore::setScrollOffset(int moveGeneration, int dx, int dy)
1150 {
1151 DBG_NAV_LOGD("{%d,%d} m_scrollOffset=(%d,%d)", dx, dy,
1152 m_scrollOffsetX, m_scrollOffsetY);
1153 if (m_scrollOffsetX != dx || m_scrollOffsetY != dy) {
1154 m_scrollOffsetX = dx;
1155 m_scrollOffsetY = dy;
1156 // The visible rect is located within our coordinate space so it
1157 // contains the actual scroll position. Setting the location makes hit
1158 // testing work correctly.
1159 m_mainFrame->view()->platformWidget()->setLocation(m_scrollOffsetX,
1160 m_scrollOffsetY);
1161 m_mainFrame->eventHandler()->sendScrollEvent();
1162
1163 // update the currently visible screen
1164 sendPluginVisibleScreen();
1165 }
1166 gCursorBoundsMutex.lock();
1167 bool hasCursorBounds = m_hasCursorBounds;
1168 Frame* frame = (Frame*) m_cursorFrame;
1169 IntPoint location = m_cursorLocation;
1170 gCursorBoundsMutex.unlock();
1171 if (!hasCursorBounds)
1172 return;
1173 moveMouseIfLatest(moveGeneration, frame, location.x(), location.y());
1174 }
1175
setGlobalBounds(int x,int y,int h,int v)1176 void WebViewCore::setGlobalBounds(int x, int y, int h, int v)
1177 {
1178 DBG_NAV_LOGD("{%d,%d}", x, y);
1179 m_mainFrame->view()->platformWidget()->setWindowBounds(x, y, h, v);
1180 }
1181
setSizeScreenWidthAndScale(int width,int height,int screenWidth,float scale,int realScreenWidth,int screenHeight,int anchorX,int anchorY,bool ignoreHeight)1182 void WebViewCore::setSizeScreenWidthAndScale(int width, int height,
1183 int screenWidth, float scale, int realScreenWidth, int screenHeight,
1184 int anchorX, int anchorY, bool ignoreHeight)
1185 {
1186 WebCoreViewBridge* window = m_mainFrame->view()->platformWidget();
1187 int ow = window->width();
1188 int oh = window->height();
1189 window->setSize(width, height);
1190 int osw = m_screenWidth;
1191 int orsw = m_screenWidth * m_screenWidthScale / m_scale;
1192 int osh = m_screenHeight;
1193 DBG_NAV_LOGD("old:(w=%d,h=%d,sw=%d,scale=%g) new:(w=%d,h=%d,sw=%d,scale=%g)",
1194 ow, oh, osw, m_scale, width, height, screenWidth, scale);
1195 m_screenWidth = screenWidth;
1196 m_screenHeight = screenHeight;
1197 if (scale >= 0) { // negative means ignore
1198 m_scale = scale;
1199 if (screenWidth != realScreenWidth)
1200 m_screenWidthScale = realScreenWidth * scale / screenWidth;
1201 else
1202 m_screenWidthScale = m_scale;
1203 }
1204 m_maxXScroll = screenWidth >> 2;
1205 m_maxYScroll = (screenWidth * height / width) >> 2;
1206 if (ow != width || (!ignoreHeight && oh != height) || osw != screenWidth) {
1207 WebCore::RenderObject *r = m_mainFrame->contentRenderer();
1208 DBG_NAV_LOGD("renderer=%p view=(w=%d,h=%d)", r,
1209 realScreenWidth, screenHeight);
1210 if (r) {
1211 WebCore::IntPoint anchorPoint = WebCore::IntPoint(anchorX, anchorY);
1212 DBG_NAV_LOGD("anchorX=%d anchorY=%d", anchorX, anchorY);
1213 WebCore::Node* node = 0;
1214 WebCore::IntRect bounds;
1215 WebCore::IntPoint offset;
1216 // If the screen width changed, it is probably zoom change or
1217 // orientation change. Try to keep the anchor at the same place.
1218 if (osw && screenWidth && osw != screenWidth) {
1219 WebCore::HitTestResult hitTestResult =
1220 m_mainFrame->eventHandler()-> hitTestResultAtPoint(
1221 anchorPoint, false);
1222 node = hitTestResult.innerNode();
1223 }
1224 if (node) {
1225 bounds = node->getRect();
1226 DBG_NAV_LOGD("ob:(x=%d,y=%d,w=%d,h=%d)",
1227 bounds.x(), bounds.y(), bounds.width(), bounds.height());
1228 // sites like nytimes.com insert a non-standard tag <nyt_text>
1229 // in the html. If it is the HitTestResult, it may have zero
1230 // width and height. In this case, use its parent node.
1231 if (bounds.width() == 0) {
1232 node = node->parent();
1233 if (node) {
1234 bounds = node->getRect();
1235 DBG_NAV_LOGD("found a zero width node and use its parent, whose ob:(x=%d,y=%d,w=%d,h=%d)",
1236 bounds.x(), bounds.y(), bounds.width(), bounds.height());
1237 }
1238 }
1239 }
1240 r->setNeedsLayoutAndPrefWidthsRecalc();
1241 m_mainFrame->view()->forceLayout();
1242 // scroll to restore current screen center
1243 if (node) {
1244 const WebCore::IntRect& newBounds = node->getRect();
1245 DBG_NAV_LOGD("nb:(x=%d,y=%d,w=%d,"
1246 "h=%d)", newBounds.x(), newBounds.y(),
1247 newBounds.width(), newBounds.height());
1248 if ((orsw && osh && bounds.width() && bounds.height())
1249 && (bounds != newBounds)) {
1250 WebCore::FrameView* view = m_mainFrame->view();
1251 // force left align if width is not changed while height changed.
1252 // the anchorPoint is probably at some white space in the node
1253 // which is affected by text wrap around the screen width.
1254 const bool leftAlign = (osw != m_screenWidth)
1255 && (bounds.width() == newBounds.width())
1256 && (bounds.height() != newBounds.height());
1257 const float xPercentInDoc =
1258 leftAlign ? 0.0 : (float) (anchorX - bounds.x()) / bounds.width();
1259 const float xPercentInView =
1260 leftAlign ? 0.0 : (float) (anchorX - m_scrollOffsetX) / orsw;
1261 const float yPercentInDoc = (float) (anchorY - bounds.y()) / bounds.height();
1262 const float yPercentInView = (float) (anchorY - m_scrollOffsetY) / osh;
1263 showRect(newBounds.x(), newBounds.y(), newBounds.width(),
1264 newBounds.height(), view->contentsWidth(),
1265 view->contentsHeight(),
1266 xPercentInDoc, xPercentInView,
1267 yPercentInDoc, yPercentInView);
1268 }
1269 }
1270 }
1271 }
1272
1273 // update the currently visible screen as perceived by the plugin
1274 sendPluginVisibleScreen();
1275 }
1276
dumpDomTree(bool useFile)1277 void WebViewCore::dumpDomTree(bool useFile)
1278 {
1279 #ifdef ANDROID_DOM_LOGGING
1280 if (useFile)
1281 gDomTreeFile = fopen(DOM_TREE_LOG_FILE, "w");
1282 m_mainFrame->document()->showTreeForThis();
1283 if (gDomTreeFile) {
1284 fclose(gDomTreeFile);
1285 gDomTreeFile = 0;
1286 }
1287 #endif
1288 }
1289
dumpRenderTree(bool useFile)1290 void WebViewCore::dumpRenderTree(bool useFile)
1291 {
1292 #ifdef ANDROID_DOM_LOGGING
1293 WebCore::CString renderDump = WebCore::externalRepresentation(m_mainFrame).utf8();
1294 const char* data = renderDump.data();
1295 if (useFile) {
1296 gRenderTreeFile = fopen(RENDER_TREE_LOG_FILE, "w");
1297 DUMP_RENDER_LOGD("%s", data);
1298 fclose(gRenderTreeFile);
1299 gRenderTreeFile = 0;
1300 } else {
1301 // adb log can only output 1024 characters, so write out line by line.
1302 // exclude '\n' as adb log adds it for each output.
1303 int length = renderDump.length();
1304 for (int i = 0, last = 0; i < length; i++) {
1305 if (data[i] == '\n') {
1306 if (i != last)
1307 DUMP_RENDER_LOGD("%.*s", (i - last), &(data[last]));
1308 last = i + 1;
1309 }
1310 }
1311 }
1312 #endif
1313 }
1314
dumpNavTree()1315 void WebViewCore::dumpNavTree()
1316 {
1317 #if DUMP_NAV_CACHE
1318 cacheBuilder().mDebug.print();
1319 #endif
1320 }
1321
retrieveAnchorElement(WebCore::Frame * frame,WebCore::Node * node)1322 WebCore::HTMLAnchorElement* WebViewCore::retrieveAnchorElement(WebCore::Frame* frame, WebCore::Node* node)
1323 {
1324 if (!CacheBuilder::validNode(m_mainFrame, frame, node))
1325 return 0;
1326 if (!node->hasTagName(WebCore::HTMLNames::aTag))
1327 return 0;
1328 return static_cast<WebCore::HTMLAnchorElement*>(node);
1329 }
1330
retrieveHref(WebCore::Frame * frame,WebCore::Node * node)1331 WebCore::String WebViewCore::retrieveHref(WebCore::Frame* frame, WebCore::Node* node)
1332 {
1333 WebCore::HTMLAnchorElement* anchor = retrieveAnchorElement(frame, node);
1334 return anchor ? anchor->href() : WebCore::String();
1335 }
1336
retrieveAnchorText(WebCore::Frame * frame,WebCore::Node * node)1337 WebCore::String WebViewCore::retrieveAnchorText(WebCore::Frame* frame, WebCore::Node* node)
1338 {
1339 WebCore::HTMLAnchorElement* anchor = retrieveAnchorElement(frame, node);
1340 return anchor ? anchor->text() : WebCore::String();
1341 }
1342
requestLabel(WebCore::Frame * frame,WebCore::Node * node)1343 WebCore::String WebViewCore::requestLabel(WebCore::Frame* frame,
1344 WebCore::Node* node)
1345 {
1346 if (node && CacheBuilder::validNode(m_mainFrame, frame, node)) {
1347 RefPtr<WebCore::NodeList> list = node->document()->getElementsByTagName("label");
1348 unsigned length = list->length();
1349 for (unsigned i = 0; i < length; i++) {
1350 WebCore::HTMLLabelElement* label = static_cast<WebCore::HTMLLabelElement*>(
1351 list->item(i));
1352 if (label->correspondingControl() == node) {
1353 Node* node = label;
1354 String result;
1355 while ((node = node->traverseNextNode(label))) {
1356 if (node->isTextNode()) {
1357 Text* textNode = static_cast<Text*>(node);
1358 result += textNode->dataImpl();
1359 }
1360 }
1361 return result;
1362 }
1363 }
1364 }
1365 return WebCore::String();
1366 }
1367
updateCacheOnNodeChange()1368 void WebViewCore::updateCacheOnNodeChange()
1369 {
1370 gCursorBoundsMutex.lock();
1371 bool hasCursorBounds = m_hasCursorBounds;
1372 Frame* frame = (Frame*) m_cursorFrame;
1373 Node* node = (Node*) m_cursorNode;
1374 IntRect bounds = m_cursorHitBounds;
1375 gCursorBoundsMutex.unlock();
1376 if (!hasCursorBounds || !node)
1377 return;
1378 if (CacheBuilder::validNode(m_mainFrame, frame, node)) {
1379 RenderObject* renderer = node->renderer();
1380 if (renderer && renderer->style()->visibility() != HIDDEN) {
1381 IntRect absBox = renderer->absoluteBoundingBoxRect();
1382 int globalX, globalY;
1383 CacheBuilder::GetGlobalOffset(frame, &globalX, &globalY);
1384 absBox.move(globalX, globalY);
1385 if (absBox == bounds)
1386 return;
1387 DBG_NAV_LOGD("absBox=(%d,%d,%d,%d) bounds=(%d,%d,%d,%d)",
1388 absBox.x(), absBox.y(), absBox.width(), absBox.height(),
1389 bounds.x(), bounds.y(), bounds.width(), bounds.height());
1390 }
1391 }
1392 DBG_NAV_LOGD("updateFrameCache node=%p", node);
1393 updateFrameCache();
1394 }
1395
updateFrameCache()1396 void WebViewCore::updateFrameCache()
1397 {
1398 if (!m_frameCacheOutOfDate) {
1399 DBG_NAV_LOG("!m_frameCacheOutOfDate");
1400 return;
1401 }
1402 #ifdef ANDROID_INSTRUMENT
1403 TimeCounterAuto counter(TimeCounter::WebViewCoreBuildNavTimeCounter);
1404 #endif
1405 m_frameCacheOutOfDate = false;
1406 #if DEBUG_NAV_UI
1407 m_now = SkTime::GetMSecs();
1408 #endif
1409 m_temp = new CachedRoot();
1410 m_temp->init(m_mainFrame, &m_history);
1411 #if USE(ACCELERATED_COMPOSITING)
1412 GraphicsLayerAndroid* graphicsLayer = graphicsRootLayer();
1413 if (graphicsLayer)
1414 m_temp->setRootLayer(graphicsLayer->contentLayer());
1415 #endif
1416 CacheBuilder& builder = cacheBuilder();
1417 WebCore::Settings* settings = m_mainFrame->page()->settings();
1418 builder.allowAllTextDetection();
1419 #ifdef ANDROID_META_SUPPORT
1420 if (settings) {
1421 if (!settings->formatDetectionAddress())
1422 builder.disallowAddressDetection();
1423 if (!settings->formatDetectionEmail())
1424 builder.disallowEmailDetection();
1425 if (!settings->formatDetectionTelephone())
1426 builder.disallowPhoneDetection();
1427 }
1428 #endif
1429 builder.buildCache(m_temp);
1430 m_tempPict = new SkPicture();
1431 recordPicture(m_tempPict);
1432 m_temp->setPicture(m_tempPict);
1433 m_temp->setTextGeneration(m_textGeneration);
1434 WebCoreViewBridge* window = m_mainFrame->view()->platformWidget();
1435 m_temp->setVisibleRect(WebCore::IntRect(m_scrollOffsetX,
1436 m_scrollOffsetY, window->width(), window->height()));
1437 gFrameCacheMutex.lock();
1438 delete m_frameCacheKit;
1439 delete m_navPictureKit;
1440 m_frameCacheKit = m_temp;
1441 m_navPictureKit = m_tempPict;
1442 m_updatedFrameCache = true;
1443 #if DEBUG_NAV_UI
1444 const CachedNode* cachedFocusNode = m_frameCacheKit->currentFocus();
1445 DBG_NAV_LOGD("cachedFocusNode=%d (nodePointer=%p)",
1446 cachedFocusNode ? cachedFocusNode->index() : 0,
1447 cachedFocusNode ? cachedFocusNode->nodePointer() : 0);
1448 #endif
1449 gFrameCacheMutex.unlock();
1450 }
1451
updateFrameCacheIfLoading()1452 void WebViewCore::updateFrameCacheIfLoading()
1453 {
1454 if (!m_check_domtree_version)
1455 updateFrameCache();
1456 }
1457
1458 ///////////////////////////////////////////////////////////////////////////////
1459
addPlugin(PluginWidgetAndroid * w)1460 void WebViewCore::addPlugin(PluginWidgetAndroid* w)
1461 {
1462 // SkDebugf("----------- addPlugin %p", w);
1463 /* The plugin must be appended to the end of the array. This ensures that if
1464 the plugin is added while iterating through the array (e.g. sendEvent(...))
1465 that the iteration process is not corrupted.
1466 */
1467 *m_plugins.append() = w;
1468 }
1469
removePlugin(PluginWidgetAndroid * w)1470 void WebViewCore::removePlugin(PluginWidgetAndroid* w)
1471 {
1472 // SkDebugf("----------- removePlugin %p", w);
1473 int index = m_plugins.find(w);
1474 if (index < 0) {
1475 SkDebugf("--------------- pluginwindow not found! %p\n", w);
1476 } else {
1477 m_plugins.removeShuffle(index);
1478 }
1479 }
1480
isPlugin(PluginWidgetAndroid * w) const1481 bool WebViewCore::isPlugin(PluginWidgetAndroid* w) const
1482 {
1483 return m_plugins.find(w) >= 0;
1484 }
1485
invalPlugin(PluginWidgetAndroid * w)1486 void WebViewCore::invalPlugin(PluginWidgetAndroid* w)
1487 {
1488 const double PLUGIN_INVAL_DELAY = 1.0 / 60;
1489
1490 if (!m_pluginInvalTimer.isActive()) {
1491 m_pluginInvalTimer.startOneShot(PLUGIN_INVAL_DELAY);
1492 }
1493 }
1494
drawPlugins()1495 void WebViewCore::drawPlugins()
1496 {
1497 SkRegion inval; // accumualte what needs to be redrawn
1498 PluginWidgetAndroid** iter = m_plugins.begin();
1499 PluginWidgetAndroid** stop = m_plugins.end();
1500
1501 for (; iter < stop; ++iter) {
1502 PluginWidgetAndroid* w = *iter;
1503 SkIRect dirty;
1504 if (w->isDirty(&dirty)) {
1505 w->draw();
1506 inval.op(dirty, SkRegion::kUnion_Op);
1507 }
1508 }
1509
1510 if (!inval.isEmpty()) {
1511 // inval.getBounds() is our rectangle
1512 const SkIRect& bounds = inval.getBounds();
1513 WebCore::IntRect r(bounds.fLeft, bounds.fTop,
1514 bounds.width(), bounds.height());
1515 this->viewInvalidate(r);
1516 }
1517 }
1518
notifyPluginsOnFrameLoad(const Frame * frame)1519 void WebViewCore::notifyPluginsOnFrameLoad(const Frame* frame) {
1520 // if frame is the parent then notify all plugins
1521 if (!frame->tree()->parent()) {
1522 // trigger an event notifying the plugins that the page has loaded
1523 ANPEvent event;
1524 SkANP::InitEvent(&event, kLifecycle_ANPEventType);
1525 event.data.lifecycle.action = kOnLoad_ANPLifecycleAction;
1526 sendPluginEvent(event);
1527 }
1528 // else if frame's parent has completed
1529 else if (!frame->tree()->parent()->loader()->isLoading()) {
1530 // send to all plugins who have this frame in their heirarchy
1531 PluginWidgetAndroid** iter = m_plugins.begin();
1532 PluginWidgetAndroid** stop = m_plugins.end();
1533 for (; iter < stop; ++iter) {
1534 Frame* currentFrame = (*iter)->pluginView()->parentFrame();
1535 while (currentFrame) {
1536 if (frame == currentFrame) {
1537 ANPEvent event;
1538 SkANP::InitEvent(&event, kLifecycle_ANPEventType);
1539 event.data.lifecycle.action = kOnLoad_ANPLifecycleAction;
1540 (*iter)->sendEvent(event);
1541 break;
1542 }
1543 currentFrame = currentFrame->tree()->parent();
1544 }
1545 }
1546 }
1547 }
1548
sendPluginVisibleScreen()1549 void WebViewCore::sendPluginVisibleScreen()
1550 {
1551 /* We may want to cache the previous values and only send the notification
1552 to the plugin in the event that one of the values has changed.
1553 */
1554
1555 ANPRectI visibleRect;
1556 visibleRect.left = m_scrollOffsetX;
1557 visibleRect.top = m_scrollOffsetY;
1558 visibleRect.right = m_scrollOffsetX + m_screenWidth;
1559 visibleRect.bottom = m_scrollOffsetY + m_screenHeight;
1560
1561 PluginWidgetAndroid** iter = m_plugins.begin();
1562 PluginWidgetAndroid** stop = m_plugins.end();
1563 for (; iter < stop; ++iter) {
1564 (*iter)->setVisibleScreen(visibleRect, m_scale);
1565 }
1566 }
1567
sendPluginEvent(const ANPEvent & evt)1568 void WebViewCore::sendPluginEvent(const ANPEvent& evt)
1569 {
1570 /* The list of plugins may be manipulated as we iterate through the list.
1571 This implementation allows for the addition of new plugins during an
1572 iteration, but may fail if a plugin is removed. Currently, there are not
1573 any use cases where a plugin is deleted while processing this loop, but
1574 if it does occur we will have to use an alternate data structure and/or
1575 iteration mechanism.
1576 */
1577 for (int x = 0; x < m_plugins.count(); x++) {
1578 m_plugins[x]->sendEvent(evt);
1579 }
1580 }
1581
getPluginWidget(NPP npp)1582 PluginWidgetAndroid* WebViewCore::getPluginWidget(NPP npp)
1583 {
1584 PluginWidgetAndroid** iter = m_plugins.begin();
1585 PluginWidgetAndroid** stop = m_plugins.end();
1586 for (; iter < stop; ++iter) {
1587 if ((*iter)->pluginView()->instance() == npp) {
1588 return (*iter);
1589 }
1590 }
1591 return NULL;
1592 }
1593
nodeIsPlugin(Node * node)1594 static PluginView* nodeIsPlugin(Node* node) {
1595 RenderObject* renderer = node->renderer();
1596 if (renderer && renderer->isWidget()) {
1597 Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
1598 if (widget && widget->isPluginView())
1599 return static_cast<PluginView*>(widget);
1600 }
1601 return 0;
1602 }
1603
cursorNodeIsPlugin()1604 Node* WebViewCore::cursorNodeIsPlugin() {
1605 gCursorBoundsMutex.lock();
1606 bool hasCursorBounds = m_hasCursorBounds;
1607 Frame* frame = (Frame*) m_cursorFrame;
1608 Node* node = (Node*) m_cursorNode;
1609 gCursorBoundsMutex.unlock();
1610 if (hasCursorBounds && CacheBuilder::validNode(m_mainFrame, frame, node)
1611 && nodeIsPlugin(node)) {
1612 return node;
1613 }
1614 return 0;
1615 }
1616
1617 ///////////////////////////////////////////////////////////////////////////////
moveMouseIfLatest(int moveGeneration,WebCore::Frame * frame,int x,int y)1618 void WebViewCore::moveMouseIfLatest(int moveGeneration,
1619 WebCore::Frame* frame, int x, int y)
1620 {
1621 DBG_NAV_LOGD("m_moveGeneration=%d moveGeneration=%d"
1622 " frame=%p x=%d y=%d",
1623 m_moveGeneration, moveGeneration, frame, x, y);
1624 if (m_moveGeneration > moveGeneration) {
1625 DBG_NAV_LOGD("m_moveGeneration=%d > moveGeneration=%d",
1626 m_moveGeneration, moveGeneration);
1627 return; // short-circuit if a newer move has already been generated
1628 }
1629 m_lastGeneration = moveGeneration;
1630 moveMouse(frame, x, y);
1631 }
1632
moveFocus(WebCore::Frame * frame,WebCore::Node * node)1633 void WebViewCore::moveFocus(WebCore::Frame* frame, WebCore::Node* node)
1634 {
1635 DBG_NAV_LOGD("frame=%p node=%p", frame, node);
1636 if (!node || !CacheBuilder::validNode(m_mainFrame, frame, node)
1637 || !node->isElementNode())
1638 return;
1639 // Code borrowed from FocusController::advanceFocus
1640 WebCore::FocusController* focusController
1641 = m_mainFrame->page()->focusController();
1642 WebCore::Document* oldDoc
1643 = focusController->focusedOrMainFrame()->document();
1644 if (oldDoc->focusedNode() == node)
1645 return;
1646 if (node->document() != oldDoc)
1647 oldDoc->setFocusedNode(0);
1648 focusController->setFocusedFrame(frame);
1649 static_cast<WebCore::Element*>(node)->focus(false);
1650 }
1651
1652 // Update mouse position
moveMouse(WebCore::Frame * frame,int x,int y)1653 void WebViewCore::moveMouse(WebCore::Frame* frame, int x, int y)
1654 {
1655 DBG_NAV_LOGD("frame=%p x=%d y=%d scrollOffset=(%d,%d)", frame,
1656 x, y, m_scrollOffsetX, m_scrollOffsetY);
1657 if (!frame || CacheBuilder::validNode(m_mainFrame, frame, NULL) == false)
1658 frame = m_mainFrame;
1659 // mouse event expects the position in the window coordinate
1660 m_mousePos = WebCore::IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY);
1661 // validNode will still return true if the node is null, as long as we have
1662 // a valid frame. Do not want to make a call on frame unless it is valid.
1663 WebCore::PlatformMouseEvent mouseEvent(m_mousePos, m_mousePos,
1664 WebCore::NoButton, WebCore::MouseEventMoved, 1, false, false, false,
1665 false, WTF::currentTime());
1666 frame->eventHandler()->handleMouseMoveEvent(mouseEvent);
1667 updateCacheOnNodeChange();
1668 }
1669
setSelection(int start,int end)1670 void WebViewCore::setSelection(int start, int end)
1671 {
1672 WebCore::Node* focus = currentFocus();
1673 if (!focus)
1674 return;
1675 WebCore::RenderObject* renderer = focus->renderer();
1676 if (!renderer || (!renderer->isTextField() && !renderer->isTextArea()))
1677 return;
1678 WebCore::RenderTextControl* rtc = static_cast<WebCore::RenderTextControl*>(renderer);
1679 if (start > end) {
1680 int temp = start;
1681 start = end;
1682 end = temp;
1683 }
1684 // Tell our EditorClient that this change was generated from the UI, so it
1685 // does not need to echo it to the UI.
1686 EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
1687 m_mainFrame->editor()->client());
1688 client->setUiGeneratedSelectionChange(true);
1689 rtc->setSelectionRange(start, end);
1690 client->setUiGeneratedSelectionChange(false);
1691 WebCore::Frame* focusedFrame = focus->document()->frame();
1692 focusedFrame->revealSelection();
1693 setFocusControllerActive(focusedFrame, true);
1694 }
1695
deleteSelection(int start,int end,int textGeneration)1696 void WebViewCore::deleteSelection(int start, int end, int textGeneration)
1697 {
1698 setSelection(start, end);
1699 if (start == end)
1700 return;
1701 WebCore::Node* focus = currentFocus();
1702 if (!focus)
1703 return;
1704 // Prevent our editor client from passing a message to change the
1705 // selection.
1706 EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
1707 m_mainFrame->editor()->client());
1708 client->setUiGeneratedSelectionChange(true);
1709 PlatformKeyboardEvent down(AKEYCODE_DEL, 0, 0, true, false, false, false);
1710 PlatformKeyboardEvent up(AKEYCODE_DEL, 0, 0, false, false, false, false);
1711 key(down);
1712 key(up);
1713 client->setUiGeneratedSelectionChange(false);
1714 m_textGeneration = textGeneration;
1715 }
1716
replaceTextfieldText(int oldStart,int oldEnd,const WebCore::String & replace,int start,int end,int textGeneration)1717 void WebViewCore::replaceTextfieldText(int oldStart,
1718 int oldEnd, const WebCore::String& replace, int start, int end,
1719 int textGeneration)
1720 {
1721 WebCore::Node* focus = currentFocus();
1722 if (!focus)
1723 return;
1724 setSelection(oldStart, oldEnd);
1725 // Prevent our editor client from passing a message to change the
1726 // selection.
1727 EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
1728 m_mainFrame->editor()->client());
1729 client->setUiGeneratedSelectionChange(true);
1730 WebCore::TypingCommand::insertText(focus->document(), replace,
1731 false);
1732 client->setUiGeneratedSelectionChange(false);
1733 setSelection(start, end);
1734 m_textGeneration = textGeneration;
1735 }
1736
passToJs(int generation,const WebCore::String & current,const PlatformKeyboardEvent & event)1737 void WebViewCore::passToJs(int generation, const WebCore::String& current,
1738 const PlatformKeyboardEvent& event)
1739 {
1740 WebCore::Node* focus = currentFocus();
1741 if (!focus) {
1742 DBG_NAV_LOG("!focus");
1743 clearTextEntry();
1744 return;
1745 }
1746 WebCore::RenderObject* renderer = focus->renderer();
1747 if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) {
1748 DBG_NAV_LOGD("renderer==%p || not text", renderer);
1749 clearTextEntry();
1750 return;
1751 }
1752 // Block text field updates during a key press.
1753 m_blockTextfieldUpdates = true;
1754 // Also prevent our editor client from passing a message to change the
1755 // selection.
1756 EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
1757 m_mainFrame->editor()->client());
1758 client->setUiGeneratedSelectionChange(true);
1759 key(event);
1760 client->setUiGeneratedSelectionChange(false);
1761 m_blockTextfieldUpdates = false;
1762 m_textGeneration = generation;
1763 setFocusControllerActive(focus->document()->frame(), true);
1764 WebCore::RenderTextControl* renderText =
1765 static_cast<WebCore::RenderTextControl*>(renderer);
1766 WebCore::String test = renderText->text();
1767 if (test == current) {
1768 DBG_NAV_LOG("test == current");
1769 return;
1770 }
1771 // If the text changed during the key event, update the UI text field.
1772 updateTextfield(focus, false, test);
1773 }
1774
scrollFocusedTextInput(float xPercent,int y)1775 void WebViewCore::scrollFocusedTextInput(float xPercent, int y)
1776 {
1777 WebCore::Node* focus = currentFocus();
1778 if (!focus) {
1779 DBG_NAV_LOG("!focus");
1780 clearTextEntry();
1781 return;
1782 }
1783 WebCore::RenderObject* renderer = focus->renderer();
1784 if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) {
1785 DBG_NAV_LOGD("renderer==%p || not text", renderer);
1786 clearTextEntry();
1787 return;
1788 }
1789 WebCore::RenderTextControl* renderText =
1790 static_cast<WebCore::RenderTextControl*>(renderer);
1791 int x = (int) (xPercent * (renderText->scrollWidth() -
1792 renderText->clientWidth()));
1793 DBG_NAV_LOGD("x=%d y=%d xPercent=%g scrollW=%d clientW=%d", x, y,
1794 xPercent, renderText->scrollWidth(), renderText->clientWidth());
1795 renderText->setScrollLeft(x);
1796 renderText->setScrollTop(y);
1797 }
1798
setFocusControllerActive(WebCore::Frame * frame,bool active)1799 void WebViewCore::setFocusControllerActive(WebCore::Frame* frame, bool active)
1800 {
1801 if (!frame) {
1802 WebCore::Node* focus = currentFocus();
1803 if (focus)
1804 frame = focus->document()->frame();
1805 else
1806 frame = m_mainFrame;
1807 }
1808 WebCore::FocusController* controller = frame->page()->focusController();
1809 controller->setActive(active);
1810 controller->setFocused(active);
1811 }
1812
saveDocumentState(WebCore::Frame * frame)1813 void WebViewCore::saveDocumentState(WebCore::Frame* frame)
1814 {
1815 if (!CacheBuilder::validNode(m_mainFrame, frame, 0))
1816 frame = m_mainFrame;
1817 WebCore::HistoryItem *item = frame->loader()->history()->currentItem();
1818
1819 // item can be null when there is no offical URL for the current page. This happens
1820 // when the content is loaded using with WebCoreFrameBridge::LoadData() and there
1821 // is no failing URL (common case is when content is loaded using data: scheme)
1822 if (item) {
1823 item->setDocumentState(frame->document()->formElementsState());
1824 }
1825 }
1826
1827 // Convert a WebCore::String into an array of characters where the first
1828 // character represents the length, for easy conversion to java.
stringConverter(const WebCore::String & text)1829 static uint16_t* stringConverter(const WebCore::String& text)
1830 {
1831 size_t length = text.length();
1832 uint16_t* itemName = new uint16_t[length+1];
1833 itemName[0] = (uint16_t)length;
1834 uint16_t* firstChar = &(itemName[1]);
1835 memcpy((void*)firstChar, text.characters(), sizeof(UChar)*length);
1836 return itemName;
1837 }
1838
1839 // Response to dropdown created for a listbox.
1840 class ListBoxReply : public WebCoreReply {
1841 public:
ListBoxReply(WebCore::HTMLSelectElement * select,WebCore::Frame * frame,WebViewCore * view)1842 ListBoxReply(WebCore::HTMLSelectElement* select, WebCore::Frame* frame, WebViewCore* view)
1843 : m_select(select)
1844 , m_frame(frame)
1845 , m_viewImpl(view)
1846 {}
1847
1848 // Response used if the listbox only allows single selection.
1849 // index is listIndex of the selected item, or -1 if nothing is selected.
replyInt(int index)1850 virtual void replyInt(int index)
1851 {
1852 if (-2 == index) {
1853 // Special value for cancel. Do nothing.
1854 return;
1855 }
1856 // If the select element no longer exists, due to a page change, etc,
1857 // silently return.
1858 if (!m_select || !CacheBuilder::validNode(m_viewImpl->m_mainFrame,
1859 m_frame, m_select))
1860 return;
1861 // Use a pointer to HTMLSelectElement's superclass, where
1862 // listToOptionIndex is public.
1863 SelectElement* selectElement = m_select;
1864 int optionIndex = selectElement->listToOptionIndex(index);
1865 m_select->setSelectedIndex(optionIndex, true);
1866 m_select->dispatchFormControlChangeEvent();
1867 m_viewImpl->contentInvalidate(m_select->getRect());
1868 }
1869
1870 // Response if the listbox allows multiple selection. array stores the listIndices
1871 // of selected positions.
replyIntArray(const int * array,int count)1872 virtual void replyIntArray(const int* array, int count)
1873 {
1874 // If the select element no longer exists, due to a page change, etc,
1875 // silently return.
1876 if (!m_select || !CacheBuilder::validNode(m_viewImpl->m_mainFrame,
1877 m_frame, m_select))
1878 return;
1879
1880 // If count is 1 or 0, use replyInt.
1881 SkASSERT(count > 1);
1882
1883 const WTF::Vector<Element*>& items = m_select->listItems();
1884 int totalItems = static_cast<int>(items.size());
1885 // Keep track of the position of the value we are comparing against.
1886 int arrayIndex = 0;
1887 // The value we are comparing against.
1888 int selection = array[arrayIndex];
1889 WebCore::HTMLOptionElement* option;
1890 for (int listIndex = 0; listIndex < totalItems; listIndex++) {
1891 if (items[listIndex]->hasLocalName(WebCore::HTMLNames::optionTag)) {
1892 option = static_cast<WebCore::HTMLOptionElement*>(
1893 items[listIndex]);
1894 if (listIndex == selection) {
1895 option->setSelectedState(true);
1896 arrayIndex++;
1897 if (arrayIndex == count)
1898 selection = -1;
1899 else
1900 selection = array[arrayIndex];
1901 } else
1902 option->setSelectedState(false);
1903 }
1904 }
1905 m_select->dispatchFormControlChangeEvent();
1906 m_viewImpl->contentInvalidate(m_select->getRect());
1907 }
1908 private:
1909 // The select element associated with this listbox.
1910 WebCore::HTMLSelectElement* m_select;
1911 // The frame of this select element, to verify that it is valid.
1912 WebCore::Frame* m_frame;
1913 // For calling invalidate and checking the select element's validity
1914 WebViewCore* m_viewImpl;
1915 };
1916
1917 // Create an array of java Strings.
makeLabelArray(JNIEnv * env,const uint16_t ** labels,size_t count)1918 static jobjectArray makeLabelArray(JNIEnv* env, const uint16_t** labels, size_t count)
1919 {
1920 jclass stringClass = env->FindClass("java/lang/String");
1921 LOG_ASSERT(stringClass, "Could not find java/lang/String");
1922 jobjectArray array = env->NewObjectArray(count, stringClass, 0);
1923 LOG_ASSERT(array, "Could not create new string array");
1924
1925 for (size_t i = 0; i < count; i++) {
1926 jobject newString = env->NewString(&labels[i][1], labels[i][0]);
1927 env->SetObjectArrayElement(array, i, newString);
1928 env->DeleteLocalRef(newString);
1929 checkException(env);
1930 }
1931 env->DeleteLocalRef(stringClass);
1932 return array;
1933 }
1934
openFileChooser(PassRefPtr<WebCore::FileChooser> chooser)1935 void WebViewCore::openFileChooser(PassRefPtr<WebCore::FileChooser> chooser) {
1936 if (!chooser)
1937 return;
1938 JNIEnv* env = JSC::Bindings::getJNIEnv();
1939 jstring jName = (jstring) env->CallObjectMethod(
1940 m_javaGlue->object(env).get(), m_javaGlue->m_openFileChooser);
1941 checkException(env);
1942 const UChar* string = (const UChar*) env->GetStringChars(jName, NULL);
1943 if (!string)
1944 return;
1945 WebCore::String webcoreString = to_string(env, jName);
1946 env->ReleaseStringChars(jName, string);
1947 chooser->chooseFile(webcoreString);
1948 }
1949
listBoxRequest(WebCoreReply * reply,const uint16_t ** labels,size_t count,const int enabled[],size_t enabledCount,bool multiple,const int selected[],size_t selectedCountOrSelection)1950 void WebViewCore::listBoxRequest(WebCoreReply* reply, const uint16_t** labels, size_t count, const int enabled[], size_t enabledCount,
1951 bool multiple, const int selected[], size_t selectedCountOrSelection)
1952 {
1953 // If m_popupReply is not null, then we already have a list showing.
1954 if (m_popupReply != 0)
1955 return;
1956
1957 LOG_ASSERT(m_javaGlue->m_obj, "No java widget associated with this view!");
1958
1959 // Create an array of java Strings for the drop down.
1960 JNIEnv* env = JSC::Bindings::getJNIEnv();
1961 jobjectArray labelArray = makeLabelArray(env, labels, count);
1962
1963 // Create an array determining whether each item is enabled.
1964 jintArray enabledArray = env->NewIntArray(enabledCount);
1965 checkException(env);
1966 jint* ptrArray = env->GetIntArrayElements(enabledArray, 0);
1967 checkException(env);
1968 for (size_t i = 0; i < enabledCount; i++) {
1969 ptrArray[i] = enabled[i];
1970 }
1971 env->ReleaseIntArrayElements(enabledArray, ptrArray, 0);
1972 checkException(env);
1973
1974 if (multiple) {
1975 // Pass up an array representing which items are selected.
1976 jintArray selectedArray = env->NewIntArray(selectedCountOrSelection);
1977 checkException(env);
1978 jint* selArray = env->GetIntArrayElements(selectedArray, 0);
1979 checkException(env);
1980 for (size_t i = 0; i < selectedCountOrSelection; i++) {
1981 selArray[i] = selected[i];
1982 }
1983 env->ReleaseIntArrayElements(selectedArray, selArray, 0);
1984
1985 env->CallVoidMethod(m_javaGlue->object(env).get(),
1986 m_javaGlue->m_requestListBox, labelArray, enabledArray,
1987 selectedArray);
1988 env->DeleteLocalRef(selectedArray);
1989 } else {
1990 // Pass up the single selection.
1991 env->CallVoidMethod(m_javaGlue->object(env).get(),
1992 m_javaGlue->m_requestSingleListBox, labelArray, enabledArray,
1993 selectedCountOrSelection);
1994 }
1995
1996 env->DeleteLocalRef(labelArray);
1997 env->DeleteLocalRef(enabledArray);
1998 checkException(env);
1999
2000 Retain(reply);
2001 m_popupReply = reply;
2002 }
2003
key(const PlatformKeyboardEvent & event)2004 bool WebViewCore::key(const PlatformKeyboardEvent& event)
2005 {
2006 WebCore::EventHandler* eventHandler = m_mainFrame->eventHandler();
2007 WebCore::Node* focusNode = currentFocus();
2008 if (focusNode)
2009 eventHandler = focusNode->document()->frame()->eventHandler();
2010 DBG_NAV_LOGD("keyCode=%s unichar=%d focusNode=%p",
2011 event.keyIdentifier().utf8().data(), event.unichar(), focusNode);
2012 return eventHandler->keyEvent(event);
2013 }
2014
2015 // For when the user clicks the trackball
click(WebCore::Frame * frame,WebCore::Node * node)2016 void WebViewCore::click(WebCore::Frame* frame, WebCore::Node* node) {
2017 if (!node) {
2018 WebCore::IntPoint pt = m_mousePos;
2019 pt.move(m_scrollOffsetX, m_scrollOffsetY);
2020 WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()->
2021 hitTestResultAtPoint(pt, false);
2022 node = hitTestResult.innerNode();
2023 frame = node->document()->frame();
2024 DBG_NAV_LOGD("m_mousePos=(%d,%d) m_scrollOffset=(%d,%d) pt=(%d,%d)"
2025 " node=%p", m_mousePos.x(), m_mousePos.y(),
2026 m_scrollOffsetX, m_scrollOffsetY, pt.x(), pt.y(), node);
2027 }
2028 if (node) {
2029 EditorClientAndroid* client
2030 = static_cast<EditorClientAndroid*>(
2031 m_mainFrame->editor()->client());
2032 client->setShouldChangeSelectedRange(false);
2033 handleMouseClick(frame, node);
2034 client->setShouldChangeSelectedRange(true);
2035 }
2036 }
2037
2038 #if USE(ACCELERATED_COMPOSITING)
graphicsRootLayer() const2039 GraphicsLayerAndroid* WebViewCore::graphicsRootLayer() const
2040 {
2041 RenderView* contentRenderer = m_mainFrame->contentRenderer();
2042 if (!contentRenderer)
2043 return 0;
2044 return static_cast<GraphicsLayerAndroid*>(
2045 contentRenderer->compositor()->rootPlatformLayer());
2046 }
2047 #endif
2048
handleTouchEvent(int action,int x,int y,int metaState)2049 bool WebViewCore::handleTouchEvent(int action, int x, int y, int metaState)
2050 {
2051 bool preventDefault = false;
2052
2053 #if USE(ACCELERATED_COMPOSITING)
2054 GraphicsLayerAndroid* rootLayer = graphicsRootLayer();
2055 if (rootLayer)
2056 rootLayer->pauseDisplay(true);
2057 #endif
2058
2059 #if ENABLE(TOUCH_EVENTS) // Android
2060 WebCore::TouchEventType type = WebCore::TouchStart;
2061 WebCore::PlatformTouchPoint::State touchState = WebCore::PlatformTouchPoint::TouchPressed;
2062 switch (action) {
2063 case 0: // MotionEvent.ACTION_DOWN
2064 type = WebCore::TouchStart;
2065 break;
2066 case 1: // MotionEvent.ACTION_UP
2067 type = WebCore::TouchEnd;
2068 touchState = WebCore::PlatformTouchPoint::TouchReleased;
2069 break;
2070 case 2: // MotionEvent.ACTION_MOVE
2071 type = WebCore::TouchMove;
2072 touchState = WebCore::PlatformTouchPoint::TouchMoved;
2073 break;
2074 case 3: // MotionEvent.ACTION_CANCEL
2075 type = WebCore::TouchCancel;
2076 touchState = WebCore::PlatformTouchPoint::TouchCancelled;
2077 break;
2078 case 0x100: // WebViewCore.ACTION_LONGPRESS
2079 type = WebCore::TouchLongPress;
2080 touchState = WebCore::PlatformTouchPoint::TouchPressed;
2081 break;
2082 case 0x200: // WebViewCore.ACTION_DOUBLETAP
2083 type = WebCore::TouchDoubleTap;
2084 touchState = WebCore::PlatformTouchPoint::TouchPressed;
2085 break;
2086 default:
2087 // We do not support other kinds of touch event inside WebCore
2088 // at the moment.
2089 LOGW("Java passed a touch event type that we do not support in WebCore: %d", action);
2090 return 0;
2091 }
2092
2093 // Track previous touch and if stationary set the state.
2094 WebCore::IntPoint pt(x - m_scrollOffsetX, y - m_scrollOffsetY);
2095
2096 // handleTouchEvent() in EventHandler.cpp doesn't handle TouchStationary, which
2097 // causes preventDefault be false when it returns. As our Java side may continue
2098 // process the events if WebKit doesn't, it can cause unexpected result.
2099 // if (type == WebCore::TouchMove && pt == m_lastTouchPoint)
2100 // touchState = WebCore::PlatformTouchPoint::TouchStationary;
2101
2102 m_lastTouchPoint = pt;
2103
2104 WebCore::PlatformTouchEvent te(pt, type, touchState, metaState);
2105 preventDefault = m_mainFrame->eventHandler()->handleTouchEvent(te);
2106 #endif
2107
2108 #if USE(ACCELERATED_COMPOSITING)
2109 if (rootLayer)
2110 rootLayer->pauseDisplay(false);
2111 #endif
2112 return preventDefault;
2113 }
2114
touchUp(int touchGeneration,WebCore::Frame * frame,WebCore::Node * node,int x,int y)2115 void WebViewCore::touchUp(int touchGeneration,
2116 WebCore::Frame* frame, WebCore::Node* node, int x, int y)
2117 {
2118 if (m_touchGeneration > touchGeneration) {
2119 DBG_NAV_LOGD("m_touchGeneration=%d > touchGeneration=%d"
2120 " x=%d y=%d", m_touchGeneration, touchGeneration, x, y);
2121 return; // short circuit if a newer touch has been generated
2122 }
2123 // This moves m_mousePos to the correct place, and handleMouseClick uses
2124 // m_mousePos to determine where the click happens.
2125 moveMouse(frame, x, y);
2126 m_lastGeneration = touchGeneration;
2127 if (frame && CacheBuilder::validNode(m_mainFrame, frame, 0)) {
2128 frame->loader()->resetMultipleFormSubmissionProtection();
2129 }
2130 DBG_NAV_LOGD("touchGeneration=%d handleMouseClick frame=%p node=%p"
2131 " x=%d y=%d", touchGeneration, frame, node, x, y);
2132 handleMouseClick(frame, node);
2133 }
2134
2135 // Common code for both clicking with the trackball and touchUp
handleMouseClick(WebCore::Frame * framePtr,WebCore::Node * nodePtr)2136 bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* nodePtr)
2137 {
2138 bool valid = framePtr == NULL
2139 || CacheBuilder::validNode(m_mainFrame, framePtr, nodePtr);
2140 WebFrame* webFrame = WebFrame::getWebFrame(m_mainFrame);
2141 if (valid && nodePtr) {
2142 // Need to special case area tags because an image map could have an area element in the middle
2143 // so when attempting to get the default, the point chosen would be follow the wrong link.
2144 if (nodePtr->hasTagName(WebCore::HTMLNames::areaTag)) {
2145 webFrame->setUserInitiatedClick(true);
2146 nodePtr->dispatchSimulatedClick(0, true, true);
2147 webFrame->setUserInitiatedClick(false);
2148 DBG_NAV_LOG("area");
2149 return true;
2150 }
2151 WebCore::RenderObject* renderer = nodePtr->renderer();
2152 if (renderer && (renderer->isMenuList() || renderer->isListBox())) {
2153 WebCore::HTMLSelectElement* select = static_cast<WebCore::HTMLSelectElement*>(nodePtr);
2154 const WTF::Vector<WebCore::Element*>& listItems = select->listItems();
2155 SkTDArray<const uint16_t*> names;
2156 // Possible values for enabledArray. Keep in Sync with values in
2157 // InvokeListBox.Container in WebView.java
2158 enum OptionStatus {
2159 OPTGROUP = -1,
2160 OPTION_DISABLED = 0,
2161 OPTION_ENABLED = 1,
2162 };
2163 SkTDArray<int> enabledArray;
2164 SkTDArray<int> selectedArray;
2165 int size = listItems.size();
2166 bool multiple = select->multiple();
2167 for (int i = 0; i < size; i++) {
2168 if (listItems[i]->hasTagName(WebCore::HTMLNames::optionTag)) {
2169 WebCore::HTMLOptionElement* option = static_cast<WebCore::HTMLOptionElement*>(listItems[i]);
2170 *names.append() = stringConverter(option->textIndentedToRespectGroupLabel());
2171 *enabledArray.append() = option->disabled() ? OPTION_DISABLED : OPTION_ENABLED;
2172 if (multiple && option->selected())
2173 *selectedArray.append() = i;
2174 } else if (listItems[i]->hasTagName(WebCore::HTMLNames::optgroupTag)) {
2175 WebCore::HTMLOptGroupElement* optGroup = static_cast<WebCore::HTMLOptGroupElement*>(listItems[i]);
2176 *names.append() = stringConverter(optGroup->groupLabelText());
2177 *enabledArray.append() = OPTGROUP;
2178 }
2179 }
2180 WebCoreReply* reply = new ListBoxReply(select, select->document()->frame(), this);
2181 // Use a pointer to HTMLSelectElement's superclass, where
2182 // optionToListIndex is public.
2183 SelectElement* selectElement = select;
2184 listBoxRequest(reply, names.begin(), size, enabledArray.begin(), enabledArray.count(),
2185 multiple, selectedArray.begin(), multiple ? selectedArray.count() :
2186 selectElement->optionToListIndex(select->selectedIndex()));
2187 DBG_NAV_LOG("menu list");
2188 return true;
2189 }
2190 }
2191 if (!valid || !framePtr)
2192 framePtr = m_mainFrame;
2193 webFrame->setUserInitiatedClick(true);
2194 WebCore::PlatformMouseEvent mouseDown(m_mousePos, m_mousePos, WebCore::LeftButton,
2195 WebCore::MouseEventPressed, 1, false, false, false, false,
2196 WTF::currentTime());
2197 // ignore the return from as it will return true if the hit point can trigger selection change
2198 framePtr->eventHandler()->handleMousePressEvent(mouseDown);
2199 WebCore::PlatformMouseEvent mouseUp(m_mousePos, m_mousePos, WebCore::LeftButton,
2200 WebCore::MouseEventReleased, 1, false, false, false, false,
2201 WTF::currentTime());
2202 bool handled = framePtr->eventHandler()->handleMouseReleaseEvent(mouseUp);
2203 webFrame->setUserInitiatedClick(false);
2204
2205 // If the user clicked on a textfield, make the focusController active
2206 // so we show the blinking cursor.
2207 WebCore::Node* focusNode = currentFocus();
2208 DBG_NAV_LOGD("m_mousePos={%d,%d} focusNode=%p handled=%s", m_mousePos.x(),
2209 m_mousePos.y(), focusNode, handled ? "true" : "false");
2210 if (focusNode) {
2211 WebCore::RenderObject* renderer = focusNode->renderer();
2212 if (renderer && (renderer->isTextField() || renderer->isTextArea())) {
2213 bool ime = !(static_cast<WebCore::HTMLInputElement*>(focusNode))
2214 ->readOnly();
2215 setFocusControllerActive(framePtr, ime);
2216 if (ime) {
2217 RenderTextControl* rtc
2218 = static_cast<RenderTextControl*> (renderer);
2219 requestKeyboardWithSelection(focusNode, rtc->selectionStart(),
2220 rtc->selectionEnd());
2221 } else {
2222 requestKeyboard(false);
2223 }
2224 }
2225 }
2226 return handled;
2227 }
2228
popupReply(int index)2229 void WebViewCore::popupReply(int index)
2230 {
2231 if (m_popupReply) {
2232 m_popupReply->replyInt(index);
2233 Release(m_popupReply);
2234 m_popupReply = 0;
2235 }
2236 }
2237
popupReply(const int * array,int count)2238 void WebViewCore::popupReply(const int* array, int count)
2239 {
2240 if (m_popupReply) {
2241 m_popupReply->replyIntArray(array, count);
2242 Release(m_popupReply);
2243 m_popupReply = NULL;
2244 }
2245 }
2246
addMessageToConsole(const WebCore::String & message,unsigned int lineNumber,const WebCore::String & sourceID,int msgLevel)2247 void WebViewCore::addMessageToConsole(const WebCore::String& message, unsigned int lineNumber, const WebCore::String& sourceID, int msgLevel) {
2248 JNIEnv* env = JSC::Bindings::getJNIEnv();
2249 jstring jMessageStr = env->NewString((unsigned short *)message.characters(), message.length());
2250 jstring jSourceIDStr = env->NewString((unsigned short *)sourceID.characters(), sourceID.length());
2251 env->CallVoidMethod(m_javaGlue->object(env).get(),
2252 m_javaGlue->m_addMessageToConsole, jMessageStr, lineNumber,
2253 jSourceIDStr, msgLevel);
2254 env->DeleteLocalRef(jMessageStr);
2255 env->DeleteLocalRef(jSourceIDStr);
2256 checkException(env);
2257 }
2258
jsAlert(const WebCore::String & url,const WebCore::String & text)2259 void WebViewCore::jsAlert(const WebCore::String& url, const WebCore::String& text)
2260 {
2261 JNIEnv* env = JSC::Bindings::getJNIEnv();
2262 jstring jInputStr = env->NewString((unsigned short *)text.characters(), text.length());
2263 jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length());
2264 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsAlert, jUrlStr, jInputStr);
2265 env->DeleteLocalRef(jInputStr);
2266 env->DeleteLocalRef(jUrlStr);
2267 checkException(env);
2268 }
2269
exceededDatabaseQuota(const WebCore::String & url,const WebCore::String & databaseIdentifier,const unsigned long long currentQuota,unsigned long long estimatedSize)2270 void WebViewCore::exceededDatabaseQuota(const WebCore::String& url, const WebCore::String& databaseIdentifier, const unsigned long long currentQuota, unsigned long long estimatedSize)
2271 {
2272 #if ENABLE(DATABASE)
2273 JNIEnv* env = JSC::Bindings::getJNIEnv();
2274 jstring jDatabaseIdentifierStr = env->NewString((unsigned short *)databaseIdentifier.characters(), databaseIdentifier.length());
2275 jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length());
2276 env->CallVoidMethod(m_javaGlue->object(env).get(),
2277 m_javaGlue->m_exceededDatabaseQuota, jUrlStr,
2278 jDatabaseIdentifierStr, currentQuota, estimatedSize);
2279 env->DeleteLocalRef(jDatabaseIdentifierStr);
2280 env->DeleteLocalRef(jUrlStr);
2281 checkException(env);
2282 #endif
2283 }
2284
reachedMaxAppCacheSize(const unsigned long long spaceNeeded)2285 void WebViewCore::reachedMaxAppCacheSize(const unsigned long long spaceNeeded)
2286 {
2287 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
2288 JNIEnv* env = JSC::Bindings::getJNIEnv();
2289 env->CallVoidMethod(m_javaGlue->object(env).get(),
2290 m_javaGlue->m_reachedMaxAppCacheSize, spaceNeeded);
2291 checkException(env);
2292 #endif
2293 }
2294
populateVisitedLinks(WebCore::PageGroup * group)2295 void WebViewCore::populateVisitedLinks(WebCore::PageGroup* group)
2296 {
2297 m_groupForVisitedLinks = group;
2298 JNIEnv* env = JSC::Bindings::getJNIEnv();
2299 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_populateVisitedLinks);
2300 checkException(env);
2301 }
2302
geolocationPermissionsShowPrompt(const WebCore::String & origin)2303 void WebViewCore::geolocationPermissionsShowPrompt(const WebCore::String& origin)
2304 {
2305 JNIEnv* env = JSC::Bindings::getJNIEnv();
2306 jstring originString = env->NewString((unsigned short *)origin.characters(), origin.length());
2307 env->CallVoidMethod(m_javaGlue->object(env).get(),
2308 m_javaGlue->m_geolocationPermissionsShowPrompt,
2309 originString);
2310 env->DeleteLocalRef(originString);
2311 checkException(env);
2312 }
2313
geolocationPermissionsHidePrompt()2314 void WebViewCore::geolocationPermissionsHidePrompt()
2315 {
2316 JNIEnv* env = JSC::Bindings::getJNIEnv();
2317 env->CallVoidMethod(m_javaGlue->object(env).get(),
2318 m_javaGlue->m_geolocationPermissionsHidePrompt);
2319 checkException(env);
2320 }
2321
jsConfirm(const WebCore::String & url,const WebCore::String & text)2322 bool WebViewCore::jsConfirm(const WebCore::String& url, const WebCore::String& text)
2323 {
2324 JNIEnv* env = JSC::Bindings::getJNIEnv();
2325 jstring jInputStr = env->NewString((unsigned short *)text.characters(), text.length());
2326 jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length());
2327 jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsConfirm, jUrlStr, jInputStr);
2328 env->DeleteLocalRef(jInputStr);
2329 env->DeleteLocalRef(jUrlStr);
2330 checkException(env);
2331 return result;
2332 }
2333
jsPrompt(const WebCore::String & url,const WebCore::String & text,const WebCore::String & defaultValue,WebCore::String & result)2334 bool WebViewCore::jsPrompt(const WebCore::String& url, const WebCore::String& text, const WebCore::String& defaultValue, WebCore::String& result)
2335 {
2336 JNIEnv* env = JSC::Bindings::getJNIEnv();
2337 jstring jInputStr = env->NewString((unsigned short *)text.characters(), text.length());
2338 jstring jDefaultStr = env->NewString((unsigned short *)defaultValue.characters(), defaultValue.length());
2339 jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length());
2340 jstring returnVal = (jstring) env->CallObjectMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsPrompt, jUrlStr, jInputStr, jDefaultStr);
2341 // If returnVal is null, it means that the user cancelled the dialog.
2342 if (!returnVal)
2343 return false;
2344
2345 result = to_string(env, returnVal);
2346 env->DeleteLocalRef(jInputStr);
2347 env->DeleteLocalRef(jDefaultStr);
2348 env->DeleteLocalRef(jUrlStr);
2349 checkException(env);
2350 return true;
2351 }
2352
jsUnload(const WebCore::String & url,const WebCore::String & message)2353 bool WebViewCore::jsUnload(const WebCore::String& url, const WebCore::String& message)
2354 {
2355 JNIEnv* env = JSC::Bindings::getJNIEnv();
2356 jstring jInputStr = env->NewString((unsigned short *)message.characters(), message.length());
2357 jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length());
2358 jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsUnload, jUrlStr, jInputStr);
2359 env->DeleteLocalRef(jInputStr);
2360 env->DeleteLocalRef(jUrlStr);
2361 checkException(env);
2362 return result;
2363 }
2364
jsInterrupt()2365 bool WebViewCore::jsInterrupt()
2366 {
2367 JNIEnv* env = JSC::Bindings::getJNIEnv();
2368 jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsInterrupt);
2369 checkException(env);
2370 return result;
2371 }
2372
2373 AutoJObject
getJavaObject()2374 WebViewCore::getJavaObject()
2375 {
2376 return getRealObject(JSC::Bindings::getJNIEnv(), m_javaGlue->m_obj);
2377 }
2378
2379 jobject
getWebViewJavaObject()2380 WebViewCore::getWebViewJavaObject()
2381 {
2382 JNIEnv* env = JSC::Bindings::getJNIEnv();
2383 return env->GetObjectField(m_javaGlue->object(env).get(), gWebViewCoreFields.m_webView);
2384 }
2385
updateTextSelection()2386 void WebViewCore::updateTextSelection() {
2387 WebCore::Node* focusNode = currentFocus();
2388 if (!focusNode)
2389 return;
2390 RenderObject* renderer = focusNode->renderer();
2391 if (!renderer || (!renderer->isTextArea() && !renderer->isTextField()))
2392 return;
2393 RenderTextControl* rtc = static_cast<RenderTextControl*>(renderer);
2394 JNIEnv* env = JSC::Bindings::getJNIEnv();
2395 env->CallVoidMethod(m_javaGlue->object(env).get(),
2396 m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(focusNode),
2397 rtc->selectionStart(), rtc->selectionEnd(), m_textGeneration);
2398 checkException(env);
2399 }
2400
updateTextfield(WebCore::Node * ptr,bool changeToPassword,const WebCore::String & text)2401 void WebViewCore::updateTextfield(WebCore::Node* ptr, bool changeToPassword,
2402 const WebCore::String& text)
2403 {
2404 if (m_blockTextfieldUpdates)
2405 return;
2406 JNIEnv* env = JSC::Bindings::getJNIEnv();
2407 if (changeToPassword) {
2408 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateTextfield,
2409 (int) ptr, true, 0, m_textGeneration);
2410 checkException(env);
2411 return;
2412 }
2413 int length = text.length();
2414 jstring string = env->NewString((unsigned short *) text.characters(), length);
2415 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateTextfield,
2416 (int) ptr, false, string, m_textGeneration);
2417 env->DeleteLocalRef(string);
2418 checkException(env);
2419 }
2420
clearTextEntry()2421 void WebViewCore::clearTextEntry()
2422 {
2423 JNIEnv* env = JSC::Bindings::getJNIEnv();
2424 env->CallVoidMethod(m_javaGlue->object(env).get(),
2425 m_javaGlue->m_clearTextEntry);
2426 }
2427
setBackgroundColor(SkColor c)2428 void WebViewCore::setBackgroundColor(SkColor c)
2429 {
2430 WebCore::FrameView* view = m_mainFrame->view();
2431 if (!view)
2432 return;
2433
2434 // need (int) cast to find the right constructor
2435 WebCore::Color bcolor((int)SkColorGetR(c), (int)SkColorGetG(c),
2436 (int)SkColorGetB(c), (int)SkColorGetA(c));
2437 view->setBaseBackgroundColor(bcolor);
2438
2439 // Background color of 0 indicates we want a transparent background
2440 if (c == 0)
2441 view->setTransparent(true);
2442 }
2443
getPluginClass(const WebCore::String & libName,const char * className)2444 jclass WebViewCore::getPluginClass(const WebCore::String& libName, const char* className)
2445 {
2446 JNIEnv* env = JSC::Bindings::getJNIEnv();
2447
2448 jstring libString = env->NewString(libName.characters(), libName.length());
2449 jstring classString = env->NewStringUTF(className);
2450 jobject pluginClass = env->CallObjectMethod(m_javaGlue->object(env).get(),
2451 m_javaGlue->m_getPluginClass,
2452 libString, classString);
2453 checkException(env);
2454
2455 // cleanup unneeded local JNI references
2456 env->DeleteLocalRef(libString);
2457 env->DeleteLocalRef(classString);
2458
2459 if (pluginClass != NULL) {
2460 return static_cast<jclass>(pluginClass);
2461 } else {
2462 return NULL;
2463 }
2464 }
2465
showFullScreenPlugin(jobject childView,NPP npp)2466 void WebViewCore::showFullScreenPlugin(jobject childView, NPP npp)
2467 {
2468 JNIEnv* env = JSC::Bindings::getJNIEnv();
2469 AutoJObject obj = m_javaGlue->object(env);
2470
2471 env->CallVoidMethod(obj.get(),
2472 m_javaGlue->m_showFullScreenPlugin, childView, (int)npp);
2473 checkException(env);
2474 }
2475
hideFullScreenPlugin()2476 void WebViewCore::hideFullScreenPlugin()
2477 {
2478 JNIEnv* env = JSC::Bindings::getJNIEnv();
2479 env->CallVoidMethod(m_javaGlue->object(env).get(),
2480 m_javaGlue->m_hideFullScreenPlugin);
2481 checkException(env);
2482 }
2483
addSurface(jobject view,int x,int y,int width,int height)2484 jobject WebViewCore::addSurface(jobject view, int x, int y, int width, int height)
2485 {
2486 JNIEnv* env = JSC::Bindings::getJNIEnv();
2487 jobject result = env->CallObjectMethod(m_javaGlue->object(env).get(),
2488 m_javaGlue->m_addSurface,
2489 view, x, y, width, height);
2490 checkException(env);
2491 return result;
2492 }
2493
updateSurface(jobject childView,int x,int y,int width,int height)2494 void WebViewCore::updateSurface(jobject childView, int x, int y, int width, int height)
2495 {
2496 JNIEnv* env = JSC::Bindings::getJNIEnv();
2497 env->CallVoidMethod(m_javaGlue->object(env).get(),
2498 m_javaGlue->m_updateSurface, childView,
2499 x, y, width, height);
2500 checkException(env);
2501 }
2502
destroySurface(jobject childView)2503 void WebViewCore::destroySurface(jobject childView)
2504 {
2505 JNIEnv* env = JSC::Bindings::getJNIEnv();
2506 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_destroySurface, childView);
2507 checkException(env);
2508 }
2509
getContext()2510 jobject WebViewCore::getContext()
2511 {
2512 JNIEnv* env = JSC::Bindings::getJNIEnv();
2513 AutoJObject obj = m_javaGlue->object(env);
2514
2515 jobject result = env->CallObjectMethod(obj.get(), m_javaGlue->m_getContext);
2516 checkException(env);
2517 return result;
2518 }
2519
validNodeAndBounds(Frame * frame,Node * node,const IntRect & originalAbsoluteBounds)2520 bool WebViewCore::validNodeAndBounds(Frame* frame, Node* node,
2521 const IntRect& originalAbsoluteBounds)
2522 {
2523 bool valid = CacheBuilder::validNode(m_mainFrame, frame, node);
2524 if (!valid)
2525 return false;
2526 RenderObject* renderer = node->renderer();
2527 if (!renderer)
2528 return false;
2529 IntRect absBounds = node->hasTagName(HTMLNames::areaTag)
2530 ? CacheBuilder::getAreaRect(static_cast<HTMLAreaElement*>(node))
2531 : renderer->absoluteBoundingBoxRect();
2532 return absBounds == originalAbsoluteBounds;
2533 }
2534
showRect(int left,int top,int width,int height,int contentWidth,int contentHeight,float xPercentInDoc,float xPercentInView,float yPercentInDoc,float yPercentInView)2535 void WebViewCore::showRect(int left, int top, int width, int height,
2536 int contentWidth, int contentHeight, float xPercentInDoc,
2537 float xPercentInView, float yPercentInDoc, float yPercentInView)
2538 {
2539 JNIEnv* env = JSC::Bindings::getJNIEnv();
2540 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_showRect,
2541 left, top, width, height, contentWidth, contentHeight,
2542 xPercentInDoc, xPercentInView, yPercentInDoc, yPercentInView);
2543 checkException(env);
2544 }
2545
centerFitRect(int x,int y,int width,int height)2546 void WebViewCore::centerFitRect(int x, int y, int width, int height)
2547 {
2548 JNIEnv* env = JSC::Bindings::getJNIEnv();
2549 env->CallVoidMethod(m_javaGlue->object(env).get(),
2550 m_javaGlue->m_centerFitRect, x, y, width, height);
2551 checkException(env);
2552 }
2553
2554
setScrollbarModes(ScrollbarMode horizontalMode,ScrollbarMode verticalMode)2555 void WebViewCore::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode)
2556 {
2557 JNIEnv* env = JSC::Bindings::getJNIEnv();
2558 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_setScrollbarModes,
2559 horizontalMode, verticalMode);
2560 checkException(env);
2561 }
2562
2563 //----------------------------------------------------------------------
2564 // Native JNI methods
2565 //----------------------------------------------------------------------
WebCoreStringToJString(JNIEnv * env,WebCore::String string)2566 static jstring WebCoreStringToJString(JNIEnv *env, WebCore::String string)
2567 {
2568 int length = string.length();
2569 if (!length)
2570 return 0;
2571 jstring ret = env->NewString((jchar *)string.characters(), length);
2572 env->DeleteLocalRef(ret);
2573 return ret;
2574 }
2575
RequestLabel(JNIEnv * env,jobject obj,int framePointer,int nodePointer)2576 static jstring RequestLabel(JNIEnv *env, jobject obj, int framePointer,
2577 int nodePointer)
2578 {
2579 return WebCoreStringToJString(env, GET_NATIVE_VIEW(env, obj)->requestLabel(
2580 (WebCore::Frame*) framePointer, (WebCore::Node*) nodePointer));
2581 }
2582
UpdateFrameCacheIfLoading(JNIEnv * env,jobject obj)2583 static void UpdateFrameCacheIfLoading(JNIEnv *env, jobject obj)
2584 {
2585 GET_NATIVE_VIEW(env, obj)->updateFrameCacheIfLoading();
2586 }
2587
SetSize(JNIEnv * env,jobject obj,jint width,jint height,jint screenWidth,jfloat scale,jint realScreenWidth,jint screenHeight,jint anchorX,jint anchorY,jboolean ignoreHeight)2588 static void SetSize(JNIEnv *env, jobject obj, jint width, jint height,
2589 jint screenWidth, jfloat scale, jint realScreenWidth, jint screenHeight,
2590 jint anchorX, jint anchorY, jboolean ignoreHeight)
2591 {
2592 #ifdef ANDROID_INSTRUMENT
2593 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2594 #endif
2595 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2596 LOGV("webviewcore::nativeSetSize(%u %u)\n viewImpl: %p", (unsigned)width, (unsigned)height, viewImpl);
2597 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetSize");
2598 viewImpl->setSizeScreenWidthAndScale(width, height, screenWidth, scale,
2599 realScreenWidth, screenHeight, anchorX, anchorY, ignoreHeight);
2600 }
2601
SetScrollOffset(JNIEnv * env,jobject obj,jint gen,jint x,jint y)2602 static void SetScrollOffset(JNIEnv *env, jobject obj, jint gen, jint x, jint y)
2603 {
2604 #ifdef ANDROID_INSTRUMENT
2605 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2606 #endif
2607 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2608 LOG_ASSERT(viewImpl, "need viewImpl");
2609
2610 viewImpl->setScrollOffset(gen, x, y);
2611 }
2612
SetGlobalBounds(JNIEnv * env,jobject obj,jint x,jint y,jint h,jint v)2613 static void SetGlobalBounds(JNIEnv *env, jobject obj, jint x, jint y, jint h,
2614 jint v)
2615 {
2616 #ifdef ANDROID_INSTRUMENT
2617 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2618 #endif
2619 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2620 LOG_ASSERT(viewImpl, "need viewImpl");
2621
2622 viewImpl->setGlobalBounds(x, y, h, v);
2623 }
2624
Key(JNIEnv * env,jobject obj,jint keyCode,jint unichar,jint repeatCount,jboolean isShift,jboolean isAlt,jboolean isSym,jboolean isDown)2625 static jboolean Key(JNIEnv *env, jobject obj, jint keyCode, jint unichar,
2626 jint repeatCount, jboolean isShift, jboolean isAlt, jboolean isSym,
2627 jboolean isDown)
2628 {
2629 #ifdef ANDROID_INSTRUMENT
2630 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2631 #endif
2632 return GET_NATIVE_VIEW(env, obj)->key(PlatformKeyboardEvent(keyCode,
2633 unichar, repeatCount, isDown, isShift, isAlt, isSym));
2634 }
2635
Click(JNIEnv * env,jobject obj,int framePtr,int nodePtr)2636 static void Click(JNIEnv *env, jobject obj, int framePtr, int nodePtr)
2637 {
2638 #ifdef ANDROID_INSTRUMENT
2639 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2640 #endif
2641 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2642 LOG_ASSERT(viewImpl, "viewImpl not set in Click");
2643
2644 viewImpl->click(reinterpret_cast<WebCore::Frame*>(framePtr),
2645 reinterpret_cast<WebCore::Node*>(nodePtr));
2646 }
2647
DeleteSelection(JNIEnv * env,jobject obj,jint start,jint end,jint textGeneration)2648 static void DeleteSelection(JNIEnv *env, jobject obj, jint start, jint end,
2649 jint textGeneration)
2650 {
2651 #ifdef ANDROID_INSTRUMENT
2652 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2653 #endif
2654 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2655 viewImpl->deleteSelection(start, end, textGeneration);
2656 }
2657
SetSelection(JNIEnv * env,jobject obj,jint start,jint end)2658 static void SetSelection(JNIEnv *env, jobject obj, jint start, jint end)
2659 {
2660 #ifdef ANDROID_INSTRUMENT
2661 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2662 #endif
2663 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2664 viewImpl->setSelection(start, end);
2665 }
2666
2667
ReplaceTextfieldText(JNIEnv * env,jobject obj,jint oldStart,jint oldEnd,jstring replace,jint start,jint end,jint textGeneration)2668 static void ReplaceTextfieldText(JNIEnv *env, jobject obj,
2669 jint oldStart, jint oldEnd, jstring replace, jint start, jint end,
2670 jint textGeneration)
2671 {
2672 #ifdef ANDROID_INSTRUMENT
2673 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2674 #endif
2675 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2676 WebCore::String webcoreString = to_string(env, replace);
2677 viewImpl->replaceTextfieldText(oldStart,
2678 oldEnd, webcoreString, start, end, textGeneration);
2679 }
2680
PassToJs(JNIEnv * env,jobject obj,jint generation,jstring currentText,jint keyCode,jint keyValue,jboolean down,jboolean cap,jboolean fn,jboolean sym)2681 static void PassToJs(JNIEnv *env, jobject obj,
2682 jint generation, jstring currentText, jint keyCode,
2683 jint keyValue, jboolean down, jboolean cap, jboolean fn, jboolean sym)
2684 {
2685 #ifdef ANDROID_INSTRUMENT
2686 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2687 #endif
2688 WebCore::String current = to_string(env, currentText);
2689 GET_NATIVE_VIEW(env, obj)->passToJs(generation, current,
2690 PlatformKeyboardEvent(keyCode, keyValue, 0, down, cap, fn, sym));
2691 }
2692
ScrollFocusedTextInput(JNIEnv * env,jobject obj,jfloat xPercent,jint y)2693 static void ScrollFocusedTextInput(JNIEnv *env, jobject obj, jfloat xPercent,
2694 jint y)
2695 {
2696 #ifdef ANDROID_INSTRUMENT
2697 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2698 #endif
2699 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2700 viewImpl->scrollFocusedTextInput(xPercent, y);
2701 }
2702
SetFocusControllerActive(JNIEnv * env,jobject obj,jboolean active)2703 static void SetFocusControllerActive(JNIEnv *env, jobject obj, jboolean active)
2704 {
2705 #ifdef ANDROID_INSTRUMENT
2706 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2707 #endif
2708 LOGV("webviewcore::nativeSetFocusControllerActive()\n");
2709 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2710 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetFocusControllerActive");
2711 viewImpl->setFocusControllerActive(0, active);
2712 }
2713
SaveDocumentState(JNIEnv * env,jobject obj,jint frame)2714 static void SaveDocumentState(JNIEnv *env, jobject obj, jint frame)
2715 {
2716 #ifdef ANDROID_INSTRUMENT
2717 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2718 #endif
2719 LOGV("webviewcore::nativeSaveDocumentState()\n");
2720 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2721 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSaveDocumentState");
2722 viewImpl->saveDocumentState((WebCore::Frame*) frame);
2723 }
2724
addVisitedLink(const UChar * string,int length)2725 void WebViewCore::addVisitedLink(const UChar* string, int length)
2726 {
2727 if (m_groupForVisitedLinks)
2728 m_groupForVisitedLinks->addVisitedLink(string, length);
2729 }
2730
RecordContent(JNIEnv * env,jobject obj,jobject region,jobject pt)2731 static bool RecordContent(JNIEnv *env, jobject obj, jobject region, jobject pt)
2732 {
2733 #ifdef ANDROID_INSTRUMENT
2734 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2735 #endif
2736 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2737 SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region);
2738 SkIPoint nativePt;
2739 bool result = viewImpl->recordContent(nativeRegion, &nativePt);
2740 GraphicsJNI::ipoint_to_jpoint(nativePt, env, pt);
2741 return result;
2742 }
2743
SplitContent(JNIEnv * env,jobject obj)2744 static void SplitContent(JNIEnv *env, jobject obj)
2745 {
2746 #ifdef ANDROID_INSTRUMENT
2747 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2748 #endif
2749 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2750 viewImpl->splitContent();
2751 }
2752
SendListBoxChoice(JNIEnv * env,jobject obj,jint choice)2753 static void SendListBoxChoice(JNIEnv* env, jobject obj, jint choice)
2754 {
2755 #ifdef ANDROID_INSTRUMENT
2756 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2757 #endif
2758 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2759 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoice");
2760 viewImpl->popupReply(choice);
2761 }
2762
2763 // Set aside a predetermined amount of space in which to place the listbox
2764 // choices, to avoid unnecessary allocations.
2765 // The size here is arbitrary. We want the size to be at least as great as the
2766 // number of items in the average multiple-select listbox.
2767 #define PREPARED_LISTBOX_STORAGE 10
2768
SendListBoxChoices(JNIEnv * env,jobject obj,jbooleanArray jArray,jint size)2769 static void SendListBoxChoices(JNIEnv* env, jobject obj, jbooleanArray jArray,
2770 jint size)
2771 {
2772 #ifdef ANDROID_INSTRUMENT
2773 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2774 #endif
2775 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2776 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices");
2777 jboolean* ptrArray = env->GetBooleanArrayElements(jArray, 0);
2778 SkAutoSTMalloc<PREPARED_LISTBOX_STORAGE, int> storage(size);
2779 int* array = storage.get();
2780 int count = 0;
2781 for (int i = 0; i < size; i++) {
2782 if (ptrArray[i]) {
2783 array[count++] = i;
2784 }
2785 }
2786 env->ReleaseBooleanArrayElements(jArray, ptrArray, JNI_ABORT);
2787 viewImpl->popupReply(array, count);
2788 }
2789
FindAddress(JNIEnv * env,jobject obj,jstring addr,jboolean caseInsensitive)2790 static jstring FindAddress(JNIEnv *env, jobject obj, jstring addr,
2791 jboolean caseInsensitive)
2792 {
2793 #ifdef ANDROID_INSTRUMENT
2794 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2795 #endif
2796 if (!addr)
2797 return 0;
2798 int length = env->GetStringLength(addr);
2799 if (!length)
2800 return 0;
2801 const jchar* addrChars = env->GetStringChars(addr, 0);
2802 int start, end;
2803 bool success = CacheBuilder::FindAddress(addrChars, length,
2804 &start, &end, caseInsensitive) == CacheBuilder::FOUND_COMPLETE;
2805 jstring ret = 0;
2806 if (success) {
2807 ret = env->NewString((jchar*) addrChars + start, end - start);
2808 env->DeleteLocalRef(ret);
2809 }
2810 env->ReleaseStringChars(addr, addrChars);
2811 return ret;
2812 }
2813
HandleTouchEvent(JNIEnv * env,jobject obj,jint action,jint x,jint y,jint metaState)2814 static jboolean HandleTouchEvent(JNIEnv *env, jobject obj, jint action, jint x, jint y, jint metaState)
2815 {
2816 #ifdef ANDROID_INSTRUMENT
2817 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2818 #endif
2819 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2820 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
2821 return viewImpl->handleTouchEvent(action, x, y, metaState);
2822 }
2823
TouchUp(JNIEnv * env,jobject obj,jint touchGeneration,jint frame,jint node,jint x,jint y)2824 static void TouchUp(JNIEnv *env, jobject obj, jint touchGeneration,
2825 jint frame, jint node, jint x, jint y)
2826 {
2827 #ifdef ANDROID_INSTRUMENT
2828 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2829 #endif
2830 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2831 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
2832 viewImpl->touchUp(touchGeneration,
2833 (WebCore::Frame*) frame, (WebCore::Node*) node, x, y);
2834 }
2835
RetrieveHref(JNIEnv * env,jobject obj,jint frame,jint node)2836 static jstring RetrieveHref(JNIEnv *env, jobject obj, jint frame,
2837 jint node)
2838 {
2839 #ifdef ANDROID_INSTRUMENT
2840 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2841 #endif
2842 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2843 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
2844 WebCore::String result = viewImpl->retrieveHref((WebCore::Frame*) frame,
2845 (WebCore::Node*) node);
2846 if (!result.isEmpty())
2847 return WebCoreStringToJString(env, result);
2848 return 0;
2849 }
2850
RetrieveAnchorText(JNIEnv * env,jobject obj,jint frame,jint node)2851 static jstring RetrieveAnchorText(JNIEnv *env, jobject obj, jint frame,
2852 jint node)
2853 {
2854 #ifdef ANDROID_INSTRUMENT
2855 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2856 #endif
2857 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2858 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
2859 WebCore::String result = viewImpl->retrieveAnchorText((WebCore::Frame*) frame,
2860 (WebCore::Node*) node);
2861 if (!result.isEmpty())
2862 return WebCoreStringToJString(env, result);
2863 return 0;
2864 }
2865
2866
MoveFocus(JNIEnv * env,jobject obj,jint framePtr,jint nodePtr)2867 static void MoveFocus(JNIEnv *env, jobject obj, jint framePtr, jint nodePtr)
2868 {
2869 #ifdef ANDROID_INSTRUMENT
2870 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2871 #endif
2872 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2873 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
2874 viewImpl->moveFocus((WebCore::Frame*) framePtr, (WebCore::Node*) nodePtr);
2875 }
2876
MoveMouse(JNIEnv * env,jobject obj,jint frame,jint x,jint y)2877 static void MoveMouse(JNIEnv *env, jobject obj, jint frame,
2878 jint x, jint y)
2879 {
2880 #ifdef ANDROID_INSTRUMENT
2881 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2882 #endif
2883 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2884 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
2885 viewImpl->moveMouse((WebCore::Frame*) frame, x, y);
2886 }
2887
MoveMouseIfLatest(JNIEnv * env,jobject obj,jint moveGeneration,jint frame,jint x,jint y)2888 static void MoveMouseIfLatest(JNIEnv *env, jobject obj, jint moveGeneration,
2889 jint frame, jint x, jint y)
2890 {
2891 #ifdef ANDROID_INSTRUMENT
2892 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2893 #endif
2894 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2895 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
2896 viewImpl->moveMouseIfLatest(moveGeneration,
2897 (WebCore::Frame*) frame, x, y);
2898 }
2899
UpdateFrameCache(JNIEnv * env,jobject obj)2900 static void UpdateFrameCache(JNIEnv *env, jobject obj)
2901 {
2902 #ifdef ANDROID_INSTRUMENT
2903 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2904 #endif
2905 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2906 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
2907 viewImpl->updateFrameCache();
2908 }
2909
GetContentMinPrefWidth(JNIEnv * env,jobject obj)2910 static jint GetContentMinPrefWidth(JNIEnv *env, jobject obj)
2911 {
2912 #ifdef ANDROID_INSTRUMENT
2913 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2914 #endif
2915 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2916 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
2917
2918 WebCore::Frame* frame = viewImpl->mainFrame();
2919 if (frame) {
2920 WebCore::Document* document = frame->document();
2921 if (document) {
2922 WebCore::RenderObject* renderer = document->renderer();
2923 if (renderer && renderer->isRenderView()) {
2924 return renderer->minPrefWidth();
2925 }
2926 }
2927 }
2928 return 0;
2929 }
2930
SetViewportSettingsFromNative(JNIEnv * env,jobject obj)2931 static void SetViewportSettingsFromNative(JNIEnv *env, jobject obj)
2932 {
2933 #ifdef ANDROID_INSTRUMENT
2934 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2935 #endif
2936 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2937 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
2938
2939 WebCore::Settings* s = viewImpl->mainFrame()->page()->settings();
2940 if (!s)
2941 return;
2942
2943 #ifdef ANDROID_META_SUPPORT
2944 env->SetIntField(obj, gWebViewCoreFields.m_viewportWidth, s->viewportWidth());
2945 env->SetIntField(obj, gWebViewCoreFields.m_viewportHeight, s->viewportHeight());
2946 env->SetIntField(obj, gWebViewCoreFields.m_viewportInitialScale, s->viewportInitialScale());
2947 env->SetIntField(obj, gWebViewCoreFields.m_viewportMinimumScale, s->viewportMinimumScale());
2948 env->SetIntField(obj, gWebViewCoreFields.m_viewportMaximumScale, s->viewportMaximumScale());
2949 env->SetBooleanField(obj, gWebViewCoreFields.m_viewportUserScalable, s->viewportUserScalable());
2950 env->SetIntField(obj, gWebViewCoreFields.m_viewportDensityDpi, s->viewportTargetDensityDpi());
2951 #endif
2952 }
2953
SetBackgroundColor(JNIEnv * env,jobject obj,jint color)2954 static void SetBackgroundColor(JNIEnv *env, jobject obj, jint color)
2955 {
2956 #ifdef ANDROID_INSTRUMENT
2957 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2958 #endif
2959 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2960 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
2961
2962 viewImpl->setBackgroundColor((SkColor) color);
2963 }
2964
DumpDomTree(JNIEnv * env,jobject obj,jboolean useFile)2965 static void DumpDomTree(JNIEnv *env, jobject obj, jboolean useFile)
2966 {
2967 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2968 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
2969
2970 viewImpl->dumpDomTree(useFile);
2971 }
2972
DumpRenderTree(JNIEnv * env,jobject obj,jboolean useFile)2973 static void DumpRenderTree(JNIEnv *env, jobject obj, jboolean useFile)
2974 {
2975 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2976 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
2977
2978 viewImpl->dumpRenderTree(useFile);
2979 }
2980
DumpNavTree(JNIEnv * env,jobject obj)2981 static void DumpNavTree(JNIEnv *env, jobject obj)
2982 {
2983 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2984 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
2985
2986 viewImpl->dumpNavTree();
2987 }
2988
DumpV8Counters(JNIEnv *,jobject)2989 static void DumpV8Counters(JNIEnv*, jobject)
2990 {
2991 #if USE(V8)
2992 #ifdef ANDROID_INSTRUMENT
2993 V8Counters::dumpCounters();
2994 #endif
2995 #endif
2996 }
2997
SetJsFlags(JNIEnv * env,jobject obj,jstring flags)2998 static void SetJsFlags(JNIEnv *env, jobject obj, jstring flags)
2999 {
3000 #if USE(V8)
3001 WebCore::String flagsString = to_string(env, flags);
3002 WebCore::CString utf8String = flagsString.utf8();
3003 WebCore::ScriptController::setFlags(utf8String.data(), utf8String.length());
3004 #endif
3005 }
3006
3007
3008 // Called from the Java side to set a new quota for the origin or new appcache
3009 // max size in response to a notification that the original quota was exceeded or
3010 // that the appcache has reached its maximum size.
SetNewStorageLimit(JNIEnv * env,jobject obj,jlong quota)3011 static void SetNewStorageLimit(JNIEnv* env, jobject obj, jlong quota) {
3012 #if ENABLE(DATABASE) || ENABLE(OFFLINE_WEB_APPLICATIONS)
3013 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3014 Frame* frame = viewImpl->mainFrame();
3015
3016 // The main thread is blocked awaiting this response, so now we can wake it
3017 // up.
3018 ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client());
3019 chromeC->wakeUpMainThreadWithNewQuota(quota);
3020 #endif
3021 }
3022
3023 // Called from Java to provide a Geolocation permission state for the specified origin.
GeolocationPermissionsProvide(JNIEnv * env,jobject obj,jstring origin,jboolean allow,jboolean remember)3024 static void GeolocationPermissionsProvide(JNIEnv* env, jobject obj, jstring origin, jboolean allow, jboolean remember) {
3025 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3026 Frame* frame = viewImpl->mainFrame();
3027
3028 ChromeClientAndroid* chromeClient = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client());
3029 chromeClient->provideGeolocationPermissions(to_string(env, origin), allow, remember);
3030 }
3031
RegisterURLSchemeAsLocal(JNIEnv * env,jobject obj,jstring scheme)3032 static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jstring scheme) {
3033 #ifdef ANDROID_INSTRUMENT
3034 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3035 #endif
3036 WebCore::SecurityOrigin::registerURLSchemeAsLocal(to_string(env, scheme));
3037 }
3038
ClearContent(JNIEnv * env,jobject obj)3039 static void ClearContent(JNIEnv *env, jobject obj)
3040 {
3041 #ifdef ANDROID_INSTRUMENT
3042 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3043 #endif
3044 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3045 viewImpl->clearContent();
3046 }
3047
CopyContentToPicture(JNIEnv * env,jobject obj,jobject pict)3048 static void CopyContentToPicture(JNIEnv *env, jobject obj, jobject pict)
3049 {
3050 #ifdef ANDROID_INSTRUMENT
3051 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3052 #endif
3053 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3054 if (!viewImpl)
3055 return;
3056 SkPicture* picture = GraphicsJNI::getNativePicture(env, pict);
3057 viewImpl->copyContentToPicture(picture);
3058 }
3059
DrawContent(JNIEnv * env,jobject obj,jobject canv,jint color)3060 static bool DrawContent(JNIEnv *env, jobject obj, jobject canv, jint color)
3061 {
3062 // Note: this is called from UI thread, don't count it for WebViewCoreTimeCounter
3063 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3064 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
3065 return viewImpl->drawContent(canvas, color);
3066 }
3067
FocusBoundsChanged(JNIEnv * env,jobject obj)3068 static bool FocusBoundsChanged(JNIEnv* env, jobject obj)
3069 {
3070 return GET_NATIVE_VIEW(env, obj)->focusBoundsChanged();
3071 }
3072
PictureReady(JNIEnv * env,jobject obj)3073 static bool PictureReady(JNIEnv* env, jobject obj)
3074 {
3075 return GET_NATIVE_VIEW(env, obj)->pictureReady();
3076 }
3077
Pause(JNIEnv * env,jobject obj)3078 static void Pause(JNIEnv* env, jobject obj)
3079 {
3080 // This is called for the foreground tab when the browser is put to the
3081 // background (and also for any tab when it is put to the background of the
3082 // browser). The browser can only be killed by the system when it is in the
3083 // background, so saving the Geolocation permission state now ensures that
3084 // is maintained when the browser is killed.
3085 ChromeClient* chromeClient = GET_NATIVE_VIEW(env, obj)->mainFrame()->page()->chrome()->client();
3086 ChromeClientAndroid* chromeClientAndroid = static_cast<ChromeClientAndroid*>(chromeClient);
3087 chromeClientAndroid->storeGeolocationPermissions();
3088
3089 Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame();
3090 for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) {
3091 Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation();
3092 if (geolocation)
3093 geolocation->suspend();
3094 }
3095
3096 ANPEvent event;
3097 SkANP::InitEvent(&event, kLifecycle_ANPEventType);
3098 event.data.lifecycle.action = kPause_ANPLifecycleAction;
3099 GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event);
3100
3101 GET_NATIVE_VIEW(env, obj)->setIsPaused(true);
3102 }
3103
Resume(JNIEnv * env,jobject obj)3104 static void Resume(JNIEnv* env, jobject obj)
3105 {
3106 Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame();
3107 for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) {
3108 Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation();
3109 if (geolocation)
3110 geolocation->resume();
3111 }
3112
3113 ANPEvent event;
3114 SkANP::InitEvent(&event, kLifecycle_ANPEventType);
3115 event.data.lifecycle.action = kResume_ANPLifecycleAction;
3116 GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event);
3117
3118 GET_NATIVE_VIEW(env, obj)->setIsPaused(false);
3119 }
3120
FreeMemory(JNIEnv * env,jobject obj)3121 static void FreeMemory(JNIEnv* env, jobject obj)
3122 {
3123 ANPEvent event;
3124 SkANP::InitEvent(&event, kLifecycle_ANPEventType);
3125 event.data.lifecycle.action = kFreeMemory_ANPLifecycleAction;
3126 GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event);
3127 }
3128
ProvideVisitedHistory(JNIEnv * env,jobject obj,jobject hist)3129 static void ProvideVisitedHistory(JNIEnv *env, jobject obj, jobject hist)
3130 {
3131 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3132 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3133
3134 jobjectArray array = static_cast<jobjectArray>(hist);
3135
3136 jsize len = env->GetArrayLength(array);
3137 for (jsize i = 0; i < len; i++) {
3138 jstring item = static_cast<jstring>(env->GetObjectArrayElement(array, i));
3139 const UChar* str = static_cast<const UChar*>(env->GetStringChars(item, NULL));
3140 jsize len = env->GetStringLength(item);
3141 viewImpl->addVisitedLink(str, len);
3142 env->ReleaseStringChars(item, str);
3143 env->DeleteLocalRef(item);
3144 }
3145 }
3146
3147 // Notification from the UI thread that the plugin's full-screen surface has been discarded
FullScreenPluginHidden(JNIEnv * env,jobject obj,jint npp)3148 static void FullScreenPluginHidden(JNIEnv* env, jobject obj, jint npp)
3149 {
3150 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3151 PluginWidgetAndroid* plugin = viewImpl->getPluginWidget((NPP)npp);
3152 if (plugin)
3153 plugin->exitFullScreen(false);
3154 }
3155
jrect_to_webrect(JNIEnv * env,jobject obj)3156 static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj)
3157 {
3158 int L, T, R, B;
3159 GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B);
3160 return WebCore::IntRect(L, T, R - L, B - T);
3161 }
3162
ValidNodeAndBounds(JNIEnv * env,jobject obj,int frame,int node,jobject rect)3163 static bool ValidNodeAndBounds(JNIEnv *env, jobject obj, int frame, int node,
3164 jobject rect)
3165 {
3166 IntRect nativeRect = jrect_to_webrect(env, rect);
3167 return GET_NATIVE_VIEW(env, obj)->validNodeAndBounds(
3168 reinterpret_cast<Frame*>(frame),
3169 reinterpret_cast<Node*>(node), nativeRect);
3170 }
3171
3172 // ----------------------------------------------------------------------------
3173
3174 /*
3175 * JNI registration.
3176 */
3177 static JNINativeMethod gJavaWebViewCoreMethods[] = {
3178 { "nativeClearContent", "()V",
3179 (void*) ClearContent },
3180 { "nativeCopyContentToPicture", "(Landroid/graphics/Picture;)V",
3181 (void*) CopyContentToPicture },
3182 { "nativeDrawContent", "(Landroid/graphics/Canvas;I)Z",
3183 (void*) DrawContent } ,
3184 { "nativeFocusBoundsChanged", "()Z",
3185 (void*) FocusBoundsChanged } ,
3186 { "nativeKey", "(IIIZZZZ)Z",
3187 (void*) Key },
3188 { "nativeClick", "(II)V",
3189 (void*) Click },
3190 { "nativePictureReady", "()Z",
3191 (void*) PictureReady } ,
3192 { "nativeSendListBoxChoices", "([ZI)V",
3193 (void*) SendListBoxChoices },
3194 { "nativeSendListBoxChoice", "(I)V",
3195 (void*) SendListBoxChoice },
3196 { "nativeSetSize", "(IIIFIIIIZ)V",
3197 (void*) SetSize },
3198 { "nativeSetScrollOffset", "(III)V",
3199 (void*) SetScrollOffset },
3200 { "nativeSetGlobalBounds", "(IIII)V",
3201 (void*) SetGlobalBounds },
3202 { "nativeSetSelection", "(II)V",
3203 (void*) SetSelection } ,
3204 { "nativeDeleteSelection", "(III)V",
3205 (void*) DeleteSelection } ,
3206 { "nativeReplaceTextfieldText", "(IILjava/lang/String;III)V",
3207 (void*) ReplaceTextfieldText } ,
3208 { "nativeMoveFocus", "(II)V",
3209 (void*) MoveFocus },
3210 { "nativeMoveMouse", "(III)V",
3211 (void*) MoveMouse },
3212 { "nativeMoveMouseIfLatest", "(IIII)V",
3213 (void*) MoveMouseIfLatest },
3214 { "passToJs", "(ILjava/lang/String;IIZZZZ)V",
3215 (void*) PassToJs },
3216 { "nativeScrollFocusedTextInput", "(FI)V",
3217 (void*) ScrollFocusedTextInput },
3218 { "nativeSetFocusControllerActive", "(Z)V",
3219 (void*) SetFocusControllerActive },
3220 { "nativeSaveDocumentState", "(I)V",
3221 (void*) SaveDocumentState },
3222 { "nativeFindAddress", "(Ljava/lang/String;Z)Ljava/lang/String;",
3223 (void*) FindAddress },
3224 { "nativeHandleTouchEvent", "(IIII)Z",
3225 (void*) HandleTouchEvent },
3226 { "nativeTouchUp", "(IIIII)V",
3227 (void*) TouchUp },
3228 { "nativeRetrieveHref", "(II)Ljava/lang/String;",
3229 (void*) RetrieveHref },
3230 { "nativeRetrieveAnchorText", "(II)Ljava/lang/String;",
3231 (void*) RetrieveAnchorText },
3232 { "nativeUpdateFrameCache", "()V",
3233 (void*) UpdateFrameCache },
3234 { "nativeGetContentMinPrefWidth", "()I",
3235 (void*) GetContentMinPrefWidth },
3236 { "nativeRecordContent", "(Landroid/graphics/Region;Landroid/graphics/Point;)Z",
3237 (void*) RecordContent },
3238 { "setViewportSettingsFromNative", "()V",
3239 (void*) SetViewportSettingsFromNative },
3240 { "nativeSplitContent", "()V",
3241 (void*) SplitContent },
3242 { "nativeSetBackgroundColor", "(I)V",
3243 (void*) SetBackgroundColor },
3244 { "nativeRegisterURLSchemeAsLocal", "(Ljava/lang/String;)V",
3245 (void*) RegisterURLSchemeAsLocal },
3246 { "nativeDumpDomTree", "(Z)V",
3247 (void*) DumpDomTree },
3248 { "nativeDumpRenderTree", "(Z)V",
3249 (void*) DumpRenderTree },
3250 { "nativeDumpNavTree", "()V",
3251 (void*) DumpNavTree },
3252 { "nativeDumpV8Counters", "()V",
3253 (void*) DumpV8Counters },
3254 { "nativeSetNewStorageLimit", "(J)V",
3255 (void*) SetNewStorageLimit },
3256 { "nativeGeolocationPermissionsProvide", "(Ljava/lang/String;ZZ)V",
3257 (void*) GeolocationPermissionsProvide },
3258 { "nativePause", "()V", (void*) Pause },
3259 { "nativeResume", "()V", (void*) Resume },
3260 { "nativeFreeMemory", "()V", (void*) FreeMemory },
3261 { "nativeSetJsFlags", "(Ljava/lang/String;)V", (void*) SetJsFlags },
3262 { "nativeRequestLabel", "(II)Ljava/lang/String;",
3263 (void*) RequestLabel },
3264 { "nativeUpdateFrameCacheIfLoading", "()V",
3265 (void*) UpdateFrameCacheIfLoading },
3266 { "nativeProvideVisitedHistory", "([Ljava/lang/String;)V",
3267 (void*) ProvideVisitedHistory },
3268 { "nativeFullScreenPluginHidden", "(I)V",
3269 (void*) FullScreenPluginHidden },
3270 { "nativeValidNodeAndBounds", "(IILandroid/graphics/Rect;)Z",
3271 (void*) ValidNodeAndBounds },
3272 };
3273
register_webviewcore(JNIEnv * env)3274 int register_webviewcore(JNIEnv* env)
3275 {
3276 jclass widget = env->FindClass("android/webkit/WebViewCore");
3277 LOG_ASSERT(widget,
3278 "Unable to find class android/webkit/WebViewCore");
3279 gWebViewCoreFields.m_nativeClass = env->GetFieldID(widget, "mNativeClass",
3280 "I");
3281 LOG_ASSERT(gWebViewCoreFields.m_nativeClass,
3282 "Unable to find android/webkit/WebViewCore.mNativeClass");
3283 gWebViewCoreFields.m_viewportWidth = env->GetFieldID(widget,
3284 "mViewportWidth", "I");
3285 LOG_ASSERT(gWebViewCoreFields.m_viewportWidth,
3286 "Unable to find android/webkit/WebViewCore.mViewportWidth");
3287 gWebViewCoreFields.m_viewportHeight = env->GetFieldID(widget,
3288 "mViewportHeight", "I");
3289 LOG_ASSERT(gWebViewCoreFields.m_viewportHeight,
3290 "Unable to find android/webkit/WebViewCore.mViewportHeight");
3291 gWebViewCoreFields.m_viewportInitialScale = env->GetFieldID(widget,
3292 "mViewportInitialScale", "I");
3293 LOG_ASSERT(gWebViewCoreFields.m_viewportInitialScale,
3294 "Unable to find android/webkit/WebViewCore.mViewportInitialScale");
3295 gWebViewCoreFields.m_viewportMinimumScale = env->GetFieldID(widget,
3296 "mViewportMinimumScale", "I");
3297 LOG_ASSERT(gWebViewCoreFields.m_viewportMinimumScale,
3298 "Unable to find android/webkit/WebViewCore.mViewportMinimumScale");
3299 gWebViewCoreFields.m_viewportMaximumScale = env->GetFieldID(widget,
3300 "mViewportMaximumScale", "I");
3301 LOG_ASSERT(gWebViewCoreFields.m_viewportMaximumScale,
3302 "Unable to find android/webkit/WebViewCore.mViewportMaximumScale");
3303 gWebViewCoreFields.m_viewportUserScalable = env->GetFieldID(widget,
3304 "mViewportUserScalable", "Z");
3305 LOG_ASSERT(gWebViewCoreFields.m_viewportUserScalable,
3306 "Unable to find android/webkit/WebViewCore.mViewportUserScalable");
3307 gWebViewCoreFields.m_viewportDensityDpi = env->GetFieldID(widget,
3308 "mViewportDensityDpi", "I");
3309 LOG_ASSERT(gWebViewCoreFields.m_viewportDensityDpi,
3310 "Unable to find android/webkit/WebViewCore.mViewportDensityDpi");
3311 gWebViewCoreFields.m_webView = env->GetFieldID(widget,
3312 "mWebView", "Landroid/webkit/WebView;");
3313 LOG_ASSERT(gWebViewCoreFields.m_webView,
3314 "Unable to find android/webkit/WebViewCore.mWebView");
3315
3316 gWebViewCoreStaticMethods.m_supportsMimeType =
3317 env->GetStaticMethodID(widget, "supportsMimeType", "(Ljava/lang/String;)Z");
3318 LOG_ASSERT(gWebViewCoreStaticMethods.m_supportsMimeType == NULL,
3319 "Could not find static method supportsMimeType from WebViewCore");
3320
3321 return jniRegisterNativeMethods(env, "android/webkit/WebViewCore",
3322 gJavaWebViewCoreMethods, NELEM(gJavaWebViewCoreMethods));
3323 }
3324
3325 } /* namespace android */
3326