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